From d8c41b879df91107773a2f58225536b87b1f3ff9 Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Tue, 18 Jul 2017 23:50:51 +0200 Subject: [PATCH] New Widget class FListView to allow a multi-column data view --- .gitignore | 1 + ChangeLog | 5 + src/Makefile.am | 2 + src/Makefile.clang | 2 + src/Makefile.gcc | 2 + src/Makefile.in | 15 +- src/flistview.cpp | 1282 ++++++++++++++++++++++++++++++++++++++++++++ src/flistview.h | 219 ++++++++ test/Makefile.am | 2 + test/Makefile.in | 30 +- test/listbox.cpp | 2 +- test/listview.cpp | 174 ++++++ 12 files changed, 1719 insertions(+), 17 deletions(-) create mode 100644 src/flistview.cpp create mode 100644 src/flistview.h create mode 100644 test/listview.cpp diff --git a/.gitignore b/.gitignore index 6e33e1c7..92d6149a 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ test/transparent test/input-dialog test/choice test/listbox +test/listview test/mandelbrot test/keyboard test/mouse diff --git a/ChangeLog b/ChangeLog index 40781480..f97ae2ad 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-07-18 Markus Gans + * New Widget class FListView (filled with FListViewItem) + to allow a multi-column data view + * Add the listview example to demonstrate FListView + 2017-07-11 Markus Gans * New class FTermBuffer to buffer terminal outputs * Add the possibility to print from the terminal buffer diff --git a/src/Makefile.am b/src/Makefile.am index 16b4ea73..10dd7ee8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,6 +23,7 @@ libfinal_la_SOURCES = \ fswitch.cpp \ flabel.cpp \ flistbox.cpp \ + flistview.cpp \ fmenu.cpp \ fdialoglistmenu.cpp \ fmenubar.cpp \ @@ -69,6 +70,7 @@ finalcutinclude_HEADERS = \ flabel.h \ flineedit.h \ flistbox.h \ + flistview.h \ fmenu.h \ fdialoglistmenu.h \ fmenubar.h \ diff --git a/src/Makefile.clang b/src/Makefile.clang index a58ade3a..aa97f97f 100644 --- a/src/Makefile.clang +++ b/src/Makefile.clang @@ -20,6 +20,7 @@ INCLUDE_HEADERS = \ flabel.h \ flineedit.h \ flistbox.h \ + flistview.h \ fmenu.h \ fdialoglistmenu.h \ fmenubar.h \ @@ -72,6 +73,7 @@ OBJS = \ fswitch.o \ flabel.o \ flistbox.o \ + flistview.o \ fmenu.o \ fdialoglistmenu.o \ fmenubar.o \ diff --git a/src/Makefile.gcc b/src/Makefile.gcc index 534f56ef..533cb6de 100644 --- a/src/Makefile.gcc +++ b/src/Makefile.gcc @@ -20,6 +20,7 @@ INCLUDE_HEADERS = \ flabel.h \ flineedit.h \ flistbox.h \ + flistview.h \ fmenu.h \ fdialoglistmenu.h \ fmenubar.h \ @@ -72,6 +73,7 @@ OBJS = \ fswitch.o \ flabel.o \ flistbox.o \ + flistview.o \ fmenu.o \ fdialoglistmenu.o \ fmenubar.o \ diff --git a/src/Makefile.in b/src/Makefile.in index 4af7fc6b..ad384d4a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -131,12 +131,12 @@ libfinal_la_LIBADD = am_libfinal_la_OBJECTS = fstring.lo fpoint.lo frect.lo fscrollbar.lo \ fprogressbar.lo flineedit.lo fbutton.lo fbuttongroup.lo \ ftogglebutton.lo fradiobutton.lo fcheckbox.lo fswitch.lo \ - flabel.lo flistbox.lo fmenu.lo fdialoglistmenu.lo fmenubar.lo \ - fmenuitem.lo fradiomenuitem.lo fcheckmenuitem.lo fmenulist.lo \ - fdialog.lo fscrollview.lo fwindow.lo fmessagebox.lo \ - ftooltip.lo ffiledialog.lo ftextview.lo fstatusbar.lo fterm.lo \ - fvterm.lo fevent.lo foptiattr.lo foptimove.lo ftermbuffer.lo \ - fapp.lo fwidget.lo fobject.lo + flabel.lo flistbox.lo flistview.lo fmenu.lo fdialoglistmenu.lo \ + fmenubar.lo fmenuitem.lo fradiomenuitem.lo fcheckmenuitem.lo \ + fmenulist.lo fdialog.lo fscrollview.lo fwindow.lo \ + fmessagebox.lo ftooltip.lo ffiledialog.lo ftextview.lo \ + fstatusbar.lo fterm.lo fvterm.lo fevent.lo foptiattr.lo \ + foptimove.lo ftermbuffer.lo fapp.lo fwidget.lo fobject.lo libfinal_la_OBJECTS = $(am_libfinal_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -389,6 +389,7 @@ libfinal_la_SOURCES = \ fswitch.cpp \ flabel.cpp \ flistbox.cpp \ + flistview.cpp \ fmenu.cpp \ fdialoglistmenu.cpp \ fmenubar.cpp \ @@ -433,6 +434,7 @@ finalcutinclude_HEADERS = \ flabel.h \ flineedit.h \ flistbox.h \ + flistview.h \ fmenu.h \ fdialoglistmenu.h \ fmenubar.h \ @@ -554,6 +556,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flabel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flineedit.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flistbox.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flistview.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmenu.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmenubar.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fmenuitem.Plo@am__quote@ diff --git a/src/flistview.cpp b/src/flistview.cpp new file mode 100644 index 00000000..7ce61383 --- /dev/null +++ b/src/flistview.cpp @@ -0,0 +1,1282 @@ +// File: flistview.cpp +// Provides: class FListViewItem +// class FListView + +#include "fapp.h" +#include "flistview.h" +#include "fscrollbar.h" +#include "fstatusbar.h" +#include "ftermbuffer.h" + + +//---------------------------------------------------------------------- +// class FListViewItem +//---------------------------------------------------------------------- + +// constructor and destructor +//---------------------------------------------------------------------- +FListViewItem::FListViewItem (const FListViewItem& item) + : FObject(item.getParent()) + , column_line(item.column_line) + , data_pointer(item.data_pointer) +{ + //item.getParentWidget()->insert (this); +} + +//---------------------------------------------------------------------- +FListViewItem::FListViewItem (FListView* parent) + : FObject(parent) + , column_line() + , data_pointer(0) +{ + parent->insert (this); +} + +//---------------------------------------------------------------------- +FListViewItem::FListViewItem ( const std::vector& cols + , FWidget::data_ptr data + , FListView* parent ) + : FObject(parent) + , column_line(cols) + , data_pointer(data) +{ + parent->insert (this); +} + +//---------------------------------------------------------------------- +FListViewItem::~FListViewItem() +{ } + + +//---------------------------------------------------------------------- +// class FListView +//---------------------------------------------------------------------- + +// constructor and destructor +//---------------------------------------------------------------------- +FListView::FListView (FWidget* parent) + : FWidget(parent) + , data() + , header() + , headerline() + , vbar(0) + , hbar(0) + , drag_scroll(fc::noScroll) + , scroll_timer(false) + , scroll_repeat(100) + , scroll_distance(1) + , current(0) + , xoffset(0) + , yoffset(0) + , nf_offset(0) + , max_line_width(1) +{ + init(); +} + +//---------------------------------------------------------------------- +FListView::~FListView() // destructor +{ + delOwnTimer(); + delete vbar; + delete hbar; +} + +// public methods of FListView +//---------------------------------------------------------------------- +int FListView::addColumn (const FString& label, int width) +{ + Header column; + column.name = label; + column.width = width; + + if ( column.width == USE_MAX_SIZE ) + { + column.fixed_width = false; + column.width = int(label.getLength()); + } + else + column.fixed_width = true; + + header.push_back (column); + return int(std::distance(header.begin(), header.end())); +} + +//---------------------------------------------------------------------- +void FListView::setGeometry (int x, int y, int w, int h, bool adjust) +{ + FWidget::setGeometry(x, y, w, h, adjust); + + if ( isNewFont() ) + { + vbar->setGeometry (getWidth(), 2, 2, getHeight()-2); + hbar->setGeometry (1, getHeight(), getWidth()-2, 1); + } + else + { + vbar->setGeometry (getWidth(), 2, 1, getHeight()-2); + hbar->setGeometry (2, getHeight(), getWidth()-2, 1); + } +} + +//---------------------------------------------------------------------- +void FListView::insert (FListViewItem* item) +{ + static const int padding_space = 2; // 1 leading space + 1 tailing space + int line_width = padding_space; + uInt column = 1; + uInt entries = uInt(item->column_line.size()); + headerItems::iterator iter; + + iter = header.begin(); + + while ( iter != header.end() ) + { + int width = (*iter).width; + bool fixed_width = (*iter).fixed_width; + FString text = (*iter).name; + + if ( ! fixed_width ) + { + int len; + + if ( column <= entries ) + len = int(item->column_line[column - 1].getLength()); + else + len = 0; + + if ( len > width ) + (*iter).width = len; + } + + line_width += (*iter).width; + column++; + ++iter; + } + + recalculateHorizontalBar (line_width); + + data.push_back (item); + + int element_count = int(data.size()); + recalculateVerticalBar (element_count); +} + +//---------------------------------------------------------------------- +void FListView::insert ( const std::vector& cols + , data_ptr d + , FListView* parent ) +{ + if ( parent == 0 ) + new FListViewItem (cols, d, this); + else + new FListViewItem (cols, d, parent); +} + +//---------------------------------------------------------------------- +void FListView::insert ( const std::vector& cols + , data_ptr d + , FListView* parent ) +{ + std::vector str_cols; + + if ( ! cols.empty() ) + { + for (uInt i=0; i < cols.size(); i++) + str_cols.push_back (FString().setNumber(cols[i])); + } + + if ( parent == 0 ) + insert (str_cols, d, this); + else + insert (str_cols, d, parent); +} + +//---------------------------------------------------------------------- +void FListView::onKeyPress (FKeyEvent* ev) +{ + static const int padding_space = 2; // 1 leading space + 1 tailing space + int element_count = int(data.size()); + int current_before = current; + int xoffset_before = xoffset; + int xoffset_end = max_line_width - getClientWidth() + padding_space + 2; + int yoffset_before = yoffset; + int yoffset_end = element_count - getClientHeight(); + int key = ev->key(); + + switch ( key ) + { + case fc::Fkey_return: + case fc::Fkey_enter: + processClick(); + ev->accept(); + break; + + case fc::Fkey_up: + current--; + + if ( current < 1 ) + current=1; + + if ( current <= yoffset ) + yoffset--; + + ev->accept(); + break; + + case fc::Fkey_down: + current++; + + if ( current > element_count ) + current = element_count; + + if ( current - yoffset > getClientHeight() ) + yoffset++; + + ev->accept(); + break; + + case fc::Fkey_left: + xoffset--; + + if ( xoffset < 0 ) + xoffset = 0; + + ev->accept(); + break; + + case fc::Fkey_right: + xoffset++; + + if ( xoffset > xoffset_end ) + xoffset = xoffset_end; + + if ( xoffset < 0 ) + xoffset = 0; + + ev->accept(); + break; + + case fc::Fkey_ppage: + current -= getClientHeight() - 1; + + if ( current < 1 ) + current=1; + + if ( current <= yoffset ) + { + yoffset -= getClientHeight() - 1; + + if ( yoffset < 0 ) + yoffset=0; + } + + ev->accept(); + break; + + case fc::Fkey_npage: + current += getClientHeight() - 1; + + if ( current > element_count ) + current = element_count; + + if ( current - yoffset > getClientHeight() ) + { + yoffset += getClientHeight() - 1; + + if ( yoffset > yoffset_end ) + yoffset = yoffset_end; + } + + ev->accept(); + break; + + case fc::Fkey_home: + current = 1; + yoffset = 0; + ev->accept(); + break; + + case fc::Fkey_end: + current = element_count; + + if ( current > getClientHeight() ) + yoffset = yoffset_end; + + ev->accept(); + break; + + default: + ev->ignore(); + } + + if ( current_before != current ) + processChanged(); + + if ( ev->isAccepted() ) + { + if ( isVisible() ) + { + drawColumnLabels(); + drawList(); + } + + vbar->setValue (yoffset); + + if ( vbar->isVisible() && yoffset_before != yoffset ) + vbar->drawBar(); + + hbar->setValue (xoffset); + + if ( hbar->isVisible() && xoffset_before != xoffset ) + hbar->drawBar(); + + updateTerminal(); + flush_out(); + } +} + +//---------------------------------------------------------------------- +void FListView::onMouseDown (FMouseEvent* ev) +{ + int yoffset_before, mouse_x, mouse_y; + + if ( ev->getButton() != fc::LeftButton + && ev->getButton() != fc::RightButton ) + { + return; + } + + if ( ev->getButton() == fc::RightButton ) + return; + + if ( ! hasFocus() ) + { + FWidget* focused_widget = getFocusWidget(); + FFocusEvent out (fc::FocusOut_Event); + FApplication::queueEvent(focused_widget, &out); + setFocus(); + + if ( focused_widget ) + focused_widget->redraw(); + + if ( getStatusBar() ) + getStatusBar()->drawMessage(); + } + + yoffset_before = yoffset; + mouse_x = ev->getX(); + mouse_y = ev->getY(); + + if ( mouse_x > 1 && mouse_x < getWidth() + && mouse_y > 1 && mouse_y < getHeight() ) + { + current = yoffset + mouse_y - 1; + + if ( current > int(data.size()) ) + current = int(data.size()); + + if ( isVisible() ) + drawList(); + + vbar->setValue (yoffset); + + if ( vbar->isVisible() && yoffset_before != yoffset ) + vbar->drawBar(); + + updateTerminal(); + flush_out(); + } +} + +//---------------------------------------------------------------------- +void FListView::onMouseUp (FMouseEvent* ev) +{ + if ( drag_scroll != fc::noScroll ) + { + delOwnTimer(); + drag_scroll = fc::noScroll; + scroll_distance = 1; + scroll_timer = false; + } + + if ( ev->getButton() == fc::LeftButton ) + { + int mouse_x = ev->getX(); + int mouse_y = ev->getY(); + + if ( mouse_x > 1 && mouse_x < getWidth() + && mouse_y > 1 && mouse_y < getHeight() ) + { + processChanged(); + } + } +} + +//---------------------------------------------------------------------- +void FListView::onMouseMove (FMouseEvent* ev) +{ + int yoffset_before, mouse_x, mouse_y; + + if ( ev->getButton() != fc::LeftButton + && ev->getButton() != fc::RightButton ) + { + return; + } + + if ( ev->getButton() == fc::RightButton ) + return; + + yoffset_before = yoffset; + mouse_x = ev->getX(); + mouse_y = ev->getY(); + + if ( mouse_x > 1 && mouse_x < getWidth() + && mouse_y > 1 && mouse_y < getHeight() ) + { + current = yoffset + mouse_y - 1; + + if ( current > int(data.size()) ) + current = int(data.size()); + + if ( isVisible() ) + drawList(); + + vbar->setValue (yoffset); + + if ( vbar->isVisible() && yoffset_before != yoffset ) + vbar->drawBar(); + + updateTerminal(); + flush_out(); + } + + // auto-scrolling when dragging mouse outside the widget + if ( mouse_y < 2 ) + { + // drag up + if ( drag_scroll != fc::noScroll + && scroll_distance < getClientHeight() ) + scroll_distance++; + + if ( ! scroll_timer && current > 1 ) + { + scroll_timer = true; + addTimer(scroll_repeat); + + if ( ev->getButton() == fc::RightButton ) + drag_scroll = fc::scrollUpSelect; + else + drag_scroll = fc::scrollUp; + } + + if ( current == 1 ) + { + delOwnTimer(); + drag_scroll = fc::noScroll; + } + } + else if ( mouse_y >= getHeight() ) + { + // drag down + if ( drag_scroll != fc::noScroll + && scroll_distance < getClientHeight() ) + scroll_distance++; + + if ( ! scroll_timer && current < int(data.size()) ) + { + scroll_timer = true; + addTimer(scroll_repeat); + + if ( ev->getButton() == fc::RightButton ) + drag_scroll = fc::scrollDownSelect; + else + drag_scroll = fc::scrollDown; + } + + if ( current == int(data.size()) ) + { + delOwnTimer(); + drag_scroll = fc::noScroll; + } + } + else + { + // no dragging + delOwnTimer(); + scroll_timer = false; + scroll_distance = 1; + drag_scroll = fc::noScroll; + } +} + +//---------------------------------------------------------------------- +void FListView::onMouseDoubleClick (FMouseEvent* ev) +{ + int mouse_x, mouse_y; + + if ( ev->getButton() != fc::LeftButton ) + return; + + mouse_x = ev->getX(); + mouse_y = ev->getY(); + + if ( mouse_x > 1 && mouse_x < getWidth() + && mouse_y > 1 && mouse_y < getHeight() ) + { + if ( yoffset + mouse_y - 1 > int(data.size()) ) + return; + + processClick(); + } +} + +//---------------------------------------------------------------------- +void FListView::onTimer (FTimerEvent*) +{ + int element_count = int(data.size()); + int current_before = current; + int yoffset_before = yoffset; + int yoffset_end = element_count - getClientHeight(); + + switch ( int(drag_scroll) ) + { + case fc::noScroll: + return; + + case fc::scrollUp: + case fc::scrollUpSelect: + if ( current_before == 1) + { + drag_scroll = fc::noScroll; + return; + } + + current -= scroll_distance; + + if ( current < 1 ) + current=1; + + if ( current <= yoffset ) + yoffset -= scroll_distance; + + if ( yoffset < 0 ) + yoffset=0; + break; + + case fc::scrollDown: + case fc::scrollDownSelect: + if ( current_before == element_count ) + { + drag_scroll = fc::noScroll; + return; + } + + current += scroll_distance; + + if ( current > element_count ) + current = element_count; + + if ( current - yoffset > getClientHeight() ) + yoffset += scroll_distance; + + if ( yoffset > yoffset_end ) + yoffset = yoffset_end; + + break; + + default: + break; + } + + if ( isVisible() ) + drawList(); + + vbar->setValue (yoffset); + + if ( vbar->isVisible() && yoffset_before != yoffset ) + vbar->drawBar(); + + updateTerminal(); + flush_out(); +} + +//---------------------------------------------------------------------- +void FListView::onWheel (FWheelEvent* ev) +{ + int element_count, current_before, yoffset_before, yoffset_end, wheel; + element_count = int(data.size()); + current_before = current; + yoffset_before = yoffset; + yoffset_end = element_count - getClientHeight(); + + if ( yoffset_end < 0 ) + yoffset_end = 0; + + wheel = ev->getWheel(); + + if ( drag_scroll != fc::noScroll ) + { + delOwnTimer(); + scroll_timer = false; + scroll_distance = 1; + drag_scroll = fc::noScroll; + } + + switch ( wheel ) + { + case fc::WheelUp: + if ( yoffset == 0 ) + break; + + yoffset -= 4; + + if ( yoffset < 0 ) + { + current -= 4+yoffset; + yoffset=0; + } + else + current -= 4; + + if ( current < 1 ) + current=1; + + break; + + case fc::WheelDown: + if ( yoffset == yoffset_end ) + break; + + yoffset += 4; + + if ( yoffset > yoffset_end ) + { + current += 4 - (yoffset - yoffset_end); + yoffset = yoffset_end; + } + else + current += 4; + + if ( current > element_count ) + current = element_count; + + break; + + default: + break; + } + + if ( current_before != current ) + processChanged(); + + if ( isVisible() ) + drawList(); + + vbar->setValue (yoffset); + + if ( vbar->isVisible() && yoffset_before != yoffset ) + vbar->drawBar(); + + updateTerminal(); + flush_out(); +} +//---------------------------------------------------------------------- +void FListView::onFocusIn (FFocusEvent*) +{ + if ( getStatusBar() ) + getStatusBar()->drawMessage(); +} + +//---------------------------------------------------------------------- +void FListView::onFocusOut (FFocusEvent*) +{ + if ( getStatusBar() ) + { + getStatusBar()->clearMessage(); + getStatusBar()->drawMessage(); + } + + delOwnTimer(); +} + +//---------------------------------------------------------------------- +void FListView::cb_VBarChange (FWidget*, data_ptr) +{ + FScrollbar::sType scrollType; + int distance = 1; + int element_count = int(data.size()); + int yoffset_before = yoffset; + int yoffset_end = element_count - getClientHeight(); + scrollType = vbar->getScrollType(); + + switch ( scrollType ) + { + case FScrollbar::noScroll: + break; + + case FScrollbar::scrollPageBackward: + distance = getClientHeight(); + // fall through + case FScrollbar::scrollStepBackward: + current -= distance; + + if ( current < 1 ) + current=1; + + if ( current <= yoffset ) + yoffset -= distance; + + if ( yoffset < 0 ) + yoffset = 0; + + break; + + case FScrollbar::scrollPageForward: + distance = getClientHeight(); + // fall through + case FScrollbar::scrollStepForward: + current += distance; + + if ( current > element_count ) + current = element_count; + + if ( current - yoffset > getClientHeight() ) + yoffset += distance; + + if ( yoffset > yoffset_end ) + yoffset = yoffset_end; + + break; + + case FScrollbar::scrollJump: + { + int val = vbar->getValue(); + + if ( yoffset == val ) + break; + + int c = current - yoffset; + yoffset = val; + + if ( yoffset > yoffset_end ) + yoffset = yoffset_end; + + if ( yoffset < 0 ) + yoffset = 0; + + current = yoffset + c; + + if ( current < yoffset ) + current = yoffset; + + if ( current > element_count ) + current = element_count; + + break; + } + + case FScrollbar::scrollWheelUp: + { + FWheelEvent wheel_ev (fc::MouseWheel_Event, FPoint(2,2), fc::WheelUp); + onWheel(&wheel_ev); + } + break; + + case FScrollbar::scrollWheelDown: + { + FWheelEvent wheel_ev (fc::MouseWheel_Event, FPoint(2,2), fc::WheelDown); + onWheel(&wheel_ev); + } + break; + } + + if ( isVisible() ) + drawList(); + + if ( scrollType >= FScrollbar::scrollStepBackward + && scrollType <= FScrollbar::scrollPageForward ) + { + vbar->setValue (yoffset); + + if ( vbar->isVisible() && yoffset_before != yoffset ) + vbar->drawBar(); + + updateTerminal(); + flush_out(); + } +} + +//---------------------------------------------------------------------- +void FListView::cb_HBarChange (FWidget*, data_ptr) +{ + static const int padding_space = 2; // 1 leading space + 1 tailing space + FScrollbar::sType scrollType; + int distance = 1; + int xoffset_before = xoffset; + int xoffset_end = max_line_width - getClientWidth() + padding_space + 2; + scrollType = hbar->getScrollType(); + + switch ( scrollType ) + { + case FScrollbar::noScroll: + break; + + case FScrollbar::scrollPageBackward: + distance = getClientWidth() - padding_space; + // fall through + case FScrollbar::scrollStepBackward: + xoffset -= distance; + + if ( xoffset < 0 ) + xoffset = 0; + break; + + case FScrollbar::scrollPageForward: + distance = getClientWidth() - padding_space; + // fall through + case FScrollbar::scrollStepForward: + xoffset += distance; + + if ( xoffset > xoffset_end ) + xoffset = xoffset_end; + + if ( xoffset < 0 ) + xoffset = 0; + + break; + + case FScrollbar::scrollJump: + { + int val = hbar->getValue(); + + if ( xoffset == val ) + break; + + xoffset = val; + + if ( xoffset > xoffset_end ) + xoffset = xoffset_end; + + if ( xoffset < 0 ) + xoffset = 0; + + break; + } + + case FScrollbar::scrollWheelUp: + if ( xoffset == 0 ) + break; + + xoffset -= 4; + + if ( xoffset < 0 ) + xoffset=0; + + break; + + case FScrollbar::scrollWheelDown: + if ( xoffset == xoffset_end ) + break; + + xoffset += 4; + + if ( xoffset > xoffset_end ) + xoffset = xoffset_end; + + break; + } + + if ( isVisible() ) + { + drawColumnLabels(); + drawList(); + updateTerminal(); + flush_out(); + } + + if ( scrollType >= FScrollbar::scrollStepBackward + && scrollType <= FScrollbar::scrollWheelDown ) + { + hbar->setValue (xoffset); + + if ( hbar->isVisible() && xoffset_before != xoffset ) + hbar->drawBar(); + + updateTerminal(); + flush_out(); + } +} + + +// protected methods of FListView +//---------------------------------------------------------------------- +void FListView::adjustYOffset() +{ + int element_count = int(data.size()); + + if ( yoffset > element_count - getClientHeight() ) + yoffset = element_count - getClientHeight(); + + if ( yoffset < 0 ) + yoffset = 0; + + if ( current < yoffset ) + current = yoffset; + + if ( yoffset < current - getClientHeight() ) + yoffset = current - getClientHeight(); +} + +//---------------------------------------------------------------------- +void FListView::adjustSize() +{ + int element_count; + FWidget::adjustSize(); + adjustYOffset(); + + element_count = int(data.size()); + vbar->setMaximum(element_count - getClientHeight()); + vbar->setPageSize(element_count, getClientHeight()); + vbar->setX(getWidth()); + vbar->setHeight (getClientHeight(), false); + vbar->resize(); + + hbar->setMaximum(max_line_width - getClientWidth() + 2); + hbar->setPageSize(max_line_width, getClientWidth() - 2); + hbar->setY(getHeight() ); + hbar->setWidth (getClientWidth(), false); + hbar->resize(); + + if ( element_count <= getClientHeight() ) + vbar->hide(); + else + vbar->setVisible(); + + if ( max_line_width < getClientWidth() - 1 ) + hbar->hide(); + else + hbar->setVisible(); +} + + +// private methods of FListView +//---------------------------------------------------------------------- +void FListView::init() +{ + setForegroundColor (wc.dialog_fg); + setBackgroundColor (wc.dialog_bg); + + vbar = new FScrollbar(fc::vertical, this); + vbar->setMinimum(0); + vbar->setValue(0); + vbar->hide(); + + hbar = new FScrollbar(fc::horizontal, this); + hbar->setMinimum(0); + hbar->setValue(0); + hbar->hide(); + + setGeometry (1, 1, 5, 4, false); // initialize geometry values + + vbar->addCallback + ( + "change-value", + F_METHOD_CALLBACK (this, &FListView::cb_VBarChange) + ); + + hbar->addCallback + ( + "change-value", + F_METHOD_CALLBACK (this, &FListView::cb_HBarChange) + ); + + nf_offset = isNewFont() ? 1 : 0; + setTopPadding(1); + setLeftPadding(1); + setBottomPadding(1); + setRightPadding(1 + nf_offset); +} + +//---------------------------------------------------------------------- +void FListView::draw() +{ + bool isFocus; + + if ( current < 1 ) + current = 1; + + setColor(); + + if ( isMonochron() ) + setReverse(true); + + if ( isNewFont() ) + drawBorder (1, 1, getWidth() - 1, getHeight()); + else + drawBorder(); + + if ( isNewFont() && ! vbar->isVisible() ) + { + setColor(); + + for (int y=2; y < getHeight(); y++) + { + setPrintPos (getWidth(),y); + print (' '); // clear right side of the scrollbar + } + } + + drawColumnLabels(); + + if ( isMonochron() ) + setReverse(false); + + if ( vbar->isVisible() ) + vbar->redraw(); + + if ( hbar->isVisible() ) + hbar->redraw(); + + drawList(); + isFocus = ((flags & fc::focus) != 0); + + if ( isFocus && getStatusBar() ) + { + const FString& msg = getStatusbarMessage(); + const FString& curMsg = getStatusBar()->getMessage(); + + if ( curMsg != msg ) + { + getStatusBar()->setMessage(msg); + getStatusBar()->drawMessage(); + } + } +} + +//---------------------------------------------------------------------- +void FListView::drawColumnLabels() +{ + static const int leading_space = 1; + static const int tailing_space = 1; + static const int ellipsis_length = 2; + std::vector::const_iterator first, last; + headerItems::const_iterator iter; + FString txt; + uInt txt_length; + + if ( header.empty() + || getHeight() <= 2 + || getWidth() <= 4 + || max_line_width < 1 ) + return; + + iter = header.begin(); + headerline.clear(); + + while ( iter != header.end() ) + { + FString text = (*iter).name; + int width = (*iter).width; + int column_width; + + if ( text.isNull() || text.isEmpty() ) + { + ++iter; + continue; + } + + txt = " " + text; + txt_length = txt.getLength(); + column_width = leading_space + width; + + if ( isEnabled() ) + setColor (wc.label_emphasis_fg, wc.label_bg); + else + setColor (wc.label_inactive_fg, wc.label_inactive_bg); + + if ( txt_length <= uInt(column_width) ) + { + headerline.write (txt); + + if ( txt_length < uInt(column_width) ) + headerline.write (' '); + + if ( txt_length + tailing_space < uInt(column_width) ) + { + setColor(); + FString line ( column_width - int(txt_length) - tailing_space + , wchar_t(fc::BoxDrawingsHorizontal) ); + headerline.write (line); + } + else if ( txt_length + tailing_space == uInt(column_width) ) + { + setColor(); + headerline.write (wchar_t(fc::BoxDrawingsHorizontal)); + } + } + else + { + headerline.write (' '); + headerline.write (text.left(uInt(width - ellipsis_length))); + setColor (wc.label_ellipsis_fg, wc.label_bg); + headerline.write (".."); + + if ( iter == header.end() - 1 ) // Last element + headerline.write (' '); + } + + ++iter; + } + + const std::vector& h = headerline.getBuffer(); + first = h.begin() + xoffset; + + if ( int(h.size()) <= getWidth() - 2 ) + last = h.end() - 1; + else + last = h.begin() + getWidth() + xoffset - 2; + + const std::vector header_part (first, last); + setPrintPos (2, 1); + print (header_part); +} + +//---------------------------------------------------------------------- +void FListView::drawList() +{ + uInt start, end; + bool isFocus; + listViewItems::const_iterator iter; + + if ( data.empty() || getHeight() <= 2 || getWidth() <= 4 ) + return; + + isFocus = ((flags & fc::focus) != 0); + start = 0; + end = uInt(getHeight()-2); + + if ( end > data.size() ) + end = uInt(data.size()); + + iter = index2iterator(int(start) + yoffset); + + for (uInt y=start; y < end; y++) + { + bool isCurrentLine = bool(y + uInt(yoffset) + 1 == uInt(current)); + setPrintPos (2, 2 + int(y)); + setColor (wc.list_fg, wc.list_bg); + + if ( isCurrentLine ) + { + if ( isFocus && getMaxColor() < 16 ) + setBold(); + + if ( isMonochron() ) + unsetBold(); + + if ( isFocus ) + { + setColor ( wc.current_element_focus_fg + , wc.current_element_focus_bg ); + setCursorPos (3, 2 + int(y)); // first character + } + else + setColor ( wc.current_element_fg + , wc.current_element_bg ); + + if ( isMonochron() ) + setReverse(false); + } + else + { + if ( isMonochron() ) + setReverse(true); + else if ( isFocus && getMaxColor() < 16 ) + unsetBold(); + } + + // print the entry + FString line = " "; + + // print columns + if ( ! (*iter)->column_line.empty() ) + { + for (uInt i=0; i < (*iter)->column_line.size(); i++) + { + static const int leading_space = 1; + static const int ellipsis_length = 2; + FString text = (*iter)->column_line[i]; + int width = header[i].width; + uInt txt_length = text.getLength(); + + if ( txt_length <= uInt(width) ) + { + line += text.left(width); + line += FString (leading_space + width - int(txt_length), ' '); + } + else + { + line += text.left(width - ellipsis_length); + line += FString (".. "); + } + } + } + + line = line.mid ( uInt(1 + xoffset) + , uInt(getWidth() - nf_offset - 2) ); + const wchar_t* const& element_str = line.wc_str(); + uInt len = line.getLength(); + uInt i; + + for (i=0; i < len; i++) + print (element_str[i]); + + for (; i < uInt(getWidth() - nf_offset - 2); i++) + print (' '); + + ++iter; + } +} + +//---------------------------------------------------------------------- +void FListView::recalculateHorizontalBar (int len) +{ + if ( len <= max_line_width ) + return; + + max_line_width = len; + + if ( len >= getWidth() - nf_offset - 3 ) + { + hbar->setMaximum(max_line_width - getWidth() + nf_offset + 4); + hbar->setPageSize(max_line_width, getWidth() - nf_offset - 4); + hbar->calculateSliderValues(); + + if ( ! hbar->isVisible() ) + hbar->setVisible(); + } +} + +//---------------------------------------------------------------------- +void FListView::recalculateVerticalBar (int element_count) +{ + vbar->setMaximum (element_count - getHeight() + 2); + vbar->setPageSize (element_count, getHeight() - 2); + vbar->calculateSliderValues(); + + if ( ! vbar->isVisible() && element_count >= getHeight() - 1 ) + vbar->setVisible(); +} + +//---------------------------------------------------------------------- +void FListView::processClick() +{ + emitCallback("clicked"); +} + +//---------------------------------------------------------------------- +void FListView::processChanged() +{ + emitCallback("row-changed"); +} diff --git a/src/flistview.h b/src/flistview.h new file mode 100644 index 00000000..5b31d42b --- /dev/null +++ b/src/flistview.h @@ -0,0 +1,219 @@ +// File: flistview.h +// Provides: class FListViewItem +// class FListView +// +// Inheritance diagram +// ═══════════════════ +// +// ▕▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▏ +// ▕ FObject ▏ ▕ FTerm ▏ +// ▕▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▏ +// ▲ ▲ +// │ │ +// └─────┬─────┘ +// │ +// ▕▔▔▔▔▔▔▔▔▏ +// ▕ FVTerm ▏ +// ▕▁▁▁▁▁▁▁▁▏ +// ▲ +// │ +// ▕▔▔▔▔▔▔▔▔▔▏ +// ▕ FWidget ▏ +// ▕▁▁▁▁▁▁▁▁▁▏ +// ▲ +// │ +// ▕▔▔▔▔▔▔▔▔▔▔▔▏1 *▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏ +// ▕ FListView ▏- - - -▕ FListViewItem ▏ +// ▕▁▁▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏ +// + +#ifndef FLISTVIEW_H +#define FLISTVIEW_H + +#include "fscrollbar.h" +#include "fstring.h" +#include "ftermbuffer.h" +#include "fwidget.h" + +// class forward declaration +class FListView; + +//---------------------------------------------------------------------- +// class FListViewItem +//---------------------------------------------------------------------- + +#pragma pack(push) +#pragma pack(1) + +class FListViewItem : public FObject +{ + public: + FListViewItem (const FListViewItem&); // copy constructor + FListViewItem (FListView*); + FListViewItem ( const std::vector& + , FWidget::data_ptr = 0 + , FListView* = 0); + + // Destructor + ~FListViewItem(); + + // Assignment operator (=) + FListViewItem& operator = (const FListViewItem&); + + // Accessors + const char* getClassName() const; + uInt getCount() const; + + private: + // Friend classes + friend class FListView; + + // Data Member + std::vector column_line; + FWidget::data_ptr data_pointer; +}; +#pragma pack(pop) + + +// FListViewItem inline functions +//---------------------------------------------------------------------- +inline const char* FListViewItem::getClassName() const +{ return "FListViewItem"; } + +//---------------------------------------------------------------------- +inline uInt FListViewItem::getCount() const +{ return uInt(column_line.size()); } + + +//---------------------------------------------------------------------- +// class FListView +//---------------------------------------------------------------------- + +#pragma pack(push) +#pragma pack(1) + +class FListView : public FWidget +{ + public: + // Typedef + typedef std::vector listViewItems; + + // Using-declaration + using FWidget::setGeometry; + + // Constructor + explicit FListView (FWidget* = 0); + + // Destructor + ~FListView(); + + // Accessors + const char* getClassName() const; + + // Mutators + void setGeometry (int, int, int, int, bool = true); + + // Methods + virtual int addColumn (const FString&, int = USE_MAX_SIZE); + void insert (FListViewItem*); + void insert ( const std::vector& + , data_ptr = 0 + , FListView* = 0 ); + void insert ( const std::vector& + , data_ptr = 0 + , FListView* = 0 ); + listViewItems::iterator index2iterator (int); + + // Event handlers + void onKeyPress (FKeyEvent*); + void onMouseDown (FMouseEvent*); + void onMouseUp (FMouseEvent*); + void onMouseMove (FMouseEvent*); + void onMouseDoubleClick (FMouseEvent*); + void onWheel (FWheelEvent*); + void onTimer (FTimerEvent*); + void onFocusIn (FFocusEvent*); + void onFocusOut (FFocusEvent*); + + // Callback methods + void cb_VBarChange (FWidget*, data_ptr); + void cb_HBarChange (FWidget*, data_ptr); + + protected: + // Methods + void adjustYOffset(); + void adjustSize(); + + private: + // Typedef + struct Header + { + public: + Header() + : name() + , width (0) + , fixed_width (-1) + { } + + ~Header() + { } + + FString name; + int width; + bool fixed_width; + }; + + typedef std::vector
headerItems; + + // Constants + static const int USE_MAX_SIZE = -1; + + // Disable copy constructor + FListView (const FListView&); + + // Disable assignment operator (=) + FListView& operator = (const FListView&); + + // Methods + void init(); + void draw(); + void drawColumnLabels(); + void drawList(); + void recalculateHorizontalBar (int); + void recalculateVerticalBar (int); + void processClick(); + void processChanged(); + + // Data Members + listViewItems data; + headerItems header; + FTermBuffer headerline; + FScrollbar* vbar; + FScrollbar* hbar; + fc::dragScroll drag_scroll; + bool scroll_timer; + int scroll_repeat; + int scroll_distance; + int current; + int xoffset; + int yoffset; + int nf_offset; + int max_line_width; +}; +#pragma pack(pop) + + +// FListView inline functions +//---------------------------------------------------------------------- +inline const char* FListView::getClassName() const +{ return "FListView"; } + +//---------------------------------------------------------------------- +inline FListView::listViewItems::iterator FListView::index2iterator (int index) +{ + listViewItems::iterator iter = data.begin(); + std::advance (iter, index); + return iter; +} + +#endif // FLISTVIEW_H diff --git a/test/Makefile.am b/test/Makefile.am index 657b95b8..a6410bcd 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -11,6 +11,7 @@ noinst_PROGRAMS = \ input-dialog \ choice \ listbox \ + listview \ opti-move \ termcap \ string-operations \ @@ -32,6 +33,7 @@ dialog_SOURCES = dialog.cpp input_dialog_SOURCES = input-dialog.cpp choice_SOURCES = choice.cpp listbox_SOURCES = listbox.cpp +listview_SOURCES = listview.cpp opti_move_SOURCES = opti-move.cpp string_operations_SOURCES = string-operations.cpp mandelbrot_SOURCES = mandelbrot.cpp diff --git a/test/Makefile.in b/test/Makefile.in index 5519061d..993fd2b0 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -83,8 +83,8 @@ POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ noinst_PROGRAMS = hello$(EXEEXT) dialog$(EXEEXT) input-dialog$(EXEEXT) \ - choice$(EXEEXT) listbox$(EXEEXT) opti-move$(EXEEXT) \ - termcap$(EXEEXT) string-operations$(EXEEXT) \ + choice$(EXEEXT) listbox$(EXEEXT) listview$(EXEEXT) \ + opti-move$(EXEEXT) termcap$(EXEEXT) string-operations$(EXEEXT) \ mandelbrot$(EXEEXT) calculator$(EXEEXT) watch$(EXEEXT) \ term-attributes$(EXEEXT) transparent$(EXEEXT) \ keyboard$(EXEEXT) mouse$(EXEEXT) timer$(EXEEXT) \ @@ -129,6 +129,9 @@ keyboard_LDADD = $(LDADD) am_listbox_OBJECTS = listbox.$(OBJEXT) listbox_OBJECTS = $(am_listbox_OBJECTS) listbox_LDADD = $(LDADD) +am_listview_OBJECTS = listview.$(OBJEXT) +listview_OBJECTS = $(am_listview_OBJECTS) +listview_LDADD = $(LDADD) am_mandelbrot_OBJECTS = mandelbrot.$(OBJEXT) mandelbrot_OBJECTS = $(am_mandelbrot_OBJECTS) mandelbrot_LDADD = $(LDADD) @@ -204,19 +207,20 @@ am__v_CXXLD_0 = @echo " CXXLD " $@; am__v_CXXLD_1 = SOURCES = $(calculator_SOURCES) $(choice_SOURCES) $(dialog_SOURCES) \ $(hello_SOURCES) $(input_dialog_SOURCES) $(keyboard_SOURCES) \ - $(listbox_SOURCES) $(mandelbrot_SOURCES) $(menu_SOURCES) \ - $(mouse_SOURCES) $(opti_move_SOURCES) $(scrollview_SOURCES) \ - $(string_operations_SOURCES) $(term_attributes_SOURCES) \ - $(termcap_SOURCES) $(timer_SOURCES) $(transparent_SOURCES) \ - $(ui_SOURCES) $(watch_SOURCES) $(windows_SOURCES) -DIST_SOURCES = $(calculator_SOURCES) $(choice_SOURCES) \ - $(dialog_SOURCES) $(hello_SOURCES) $(input_dialog_SOURCES) \ - $(keyboard_SOURCES) $(listbox_SOURCES) $(mandelbrot_SOURCES) \ + $(listbox_SOURCES) $(listview_SOURCES) $(mandelbrot_SOURCES) \ $(menu_SOURCES) $(mouse_SOURCES) $(opti_move_SOURCES) \ $(scrollview_SOURCES) $(string_operations_SOURCES) \ $(term_attributes_SOURCES) $(termcap_SOURCES) $(timer_SOURCES) \ $(transparent_SOURCES) $(ui_SOURCES) $(watch_SOURCES) \ $(windows_SOURCES) +DIST_SOURCES = $(calculator_SOURCES) $(choice_SOURCES) \ + $(dialog_SOURCES) $(hello_SOURCES) $(input_dialog_SOURCES) \ + $(keyboard_SOURCES) $(listbox_SOURCES) $(listview_SOURCES) \ + $(mandelbrot_SOURCES) $(menu_SOURCES) $(mouse_SOURCES) \ + $(opti_move_SOURCES) $(scrollview_SOURCES) \ + $(string_operations_SOURCES) $(term_attributes_SOURCES) \ + $(termcap_SOURCES) $(timer_SOURCES) $(transparent_SOURCES) \ + $(ui_SOURCES) $(watch_SOURCES) $(windows_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -371,6 +375,7 @@ dialog_SOURCES = dialog.cpp input_dialog_SOURCES = input-dialog.cpp choice_SOURCES = choice.cpp listbox_SOURCES = listbox.cpp +listview_SOURCES = listview.cpp opti_move_SOURCES = opti-move.cpp string_operations_SOURCES = string-operations.cpp mandelbrot_SOURCES = mandelbrot.cpp @@ -458,6 +463,10 @@ listbox$(EXEEXT): $(listbox_OBJECTS) $(listbox_DEPENDENCIES) $(EXTRA_listbox_DEP @rm -f listbox$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(listbox_OBJECTS) $(listbox_LDADD) $(LIBS) +listview$(EXEEXT): $(listview_OBJECTS) $(listview_DEPENDENCIES) $(EXTRA_listview_DEPENDENCIES) + @rm -f listview$(EXEEXT) + $(AM_V_CXXLD)$(CXXLINK) $(listview_OBJECTS) $(listview_LDADD) $(LIBS) + mandelbrot$(EXEEXT): $(mandelbrot_OBJECTS) $(mandelbrot_DEPENDENCIES) $(EXTRA_mandelbrot_DEPENDENCIES) @rm -f mandelbrot$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(mandelbrot_OBJECTS) $(mandelbrot_LDADD) $(LIBS) @@ -523,6 +532,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/input-dialog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keyboard.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listbox.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listview.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mandelbrot.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/menu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mouse.Po@am__quote@ diff --git a/test/listbox.cpp b/test/listbox.cpp index 6ab7124b..5b3146a7 100644 --- a/test/listbox.cpp +++ b/test/listbox.cpp @@ -181,7 +181,7 @@ int main (int argc, char* argv[]) Listbox d(&app); d.setText (L"Listbox"); - d.setGeometry (int(1+(app.getWidth()-56)/2), 5, 56, 16); + d.setGeometry (int(1 + (app.getWidth() - 56) / 2), 5, 56, 16); d.setShadow(); app.setMainWidget(&d); diff --git a/test/listview.cpp b/test/listview.cpp new file mode 100644 index 00000000..dab6546f --- /dev/null +++ b/test/listview.cpp @@ -0,0 +1,174 @@ +// File: listview.cpp + +#include +#include + +#include "fapp.h" +#include "fdialog.h" +#include "flistview.h" +#include "fmessagebox.h" + + +//---------------------------------------------------------------------- +// class Listbox +//---------------------------------------------------------------------- + +#pragma pack(push) +#pragma pack(1) + +class Listview : public FDialog +{ + public: + // Constructor + explicit Listview (FWidget* = 0); + // Destructor + ~Listview(); + + private: + // Disable copy constructor + Listview (const Listview&); + // Disable assignment operator (=) + Listview& operator = (const Listview&); + + // Event handlers + void onClose (FCloseEvent*); + + // Callback methods + void cb_exitApp (FWidget*, data_ptr); +}; +#pragma pack(pop) + +//---------------------------------------------------------------------- +Listview::Listview (FWidget* parent) + : FDialog(parent) +{ + // Create FListView object + FListView* listView = new FListView (this); + listView->setGeometry(2, 1, 33, 14); + + // Add columns to the view + listView->addColumn ("City"); + listView->addColumn ("Condition"); + listView->addColumn ("Temp.", 7); + listView->addColumn ("Humidity"); + listView->addColumn ("Pressure"); + + // Populate FListView with a list of items + std::string weather[][5] = + { + { "Alexandria", "Sunny", "31°C", "61%", "1006.4 mb" }, + { "Amsterdam", "Cloudy", "21°C", "82%", "1021.3 mb" }, + { "Baghdad", "Fair", "47°C", "9%", "1001.0 mb" }, + { "Bangkok", "Partly Cloudy", "30°C", "69%", "1002.0 mb" }, + { "Beijing", "Fair", "31°C", "68%", "1007.1 mb" }, + { "Berlin", "Cloudy", "22°C", "53%", "1022.0 mb" }, + { "Bogotá", "Fair", "9°C", "95%", "1028.5 mb" }, + { "Budapest", "Partly Cloudy", "23°C", "37%", "1020.7 mb" }, + { "Buenos Aires", "Cloudy", "7°C", "73%", "1019.0 mb" }, + { "Cairo", "Fair", "39°C", "22%", "1006.1 mb" }, + { "Cape Town", "Partly Cloudy", "12°C", "45%", "1030.1 mb" }, + { "Chicago", "Mostly Cloudy", "21°C", "81%", "1014.9 mb" }, + { "Delhi", "Haze", "33°C", "68%", "998.0 mb" }, + { "Dhaka", "Haze", "32°C", "64%", "996.3 mb" }, + { "Houston", "Cloudy", "23°C", "100%", "1014.2 mb" }, + { "Istanbul", "Mostly Cloudy", "27°C", "61%", "1011.2 mb" }, + { "Jakarta", "Fair", "28°C", "71%", "1009.1 mb" }, + { "Jerusalem", "Sunny", "35°C", "17%", "1005.8 mb" }, + { "Johannesburg", "Fair", "18°C", "16%", "1020.0 mb" }, + { "Karachi", "Mostly Cloudy", "29°C", "76%", "998.0 mb" }, + { "Lagos", "Mostly Cloudy", "27°C", "86%", "1014.6 mb" }, + { "Lima", "Cloudy", "17°C", "83%", "1017.3 mb" }, + { "London", "Cloudy", "23°C", "71%", "1023.0 mb" }, + { "Los Angeles", "Fair", "21°C", "78%", "1011.9 mb" }, + { "Madrid", "Fair", "32°C", "35%", "1020.0 mb" }, + { "Mexico City", "Partly Cloudy", "14°C", "79%", "1028.5 mb" }, + { "Moscow", "Partly Cloudy", "24°C", "54%", "1014.2 mb" }, + { "Mumbai", "Haze", "28°C", "77%", "1003.0 mb" }, + { "New York City", "Sunny", "21°C", "80%", "1014.2 mb" }, + { "Paris", "Partly Cloudy", "27°C", "57%", "1024.4 mb" }, + { "Reykjavík", "Mostly Cloudy", "11°C", "76%", "998.6 mb" }, + { "Rio de Janeiro", "Fair", "24°C", "64%", "1022.0 mb" }, + { "Rome", "Fair", "32°C", "18%", "1014.2 mb" }, + { "Saint Petersburg", "Mostly Cloudy", "18°C", "55%", "1014.6 mb" }, + { "São Paulo", "Fair", "19°C", "53%", "1024.0 mb" }, + { "Seoul", "Cloudy", "26°C", "87%", "1012.2 mb" }, + { "Shanghai", "Fair", "32°C", "69%", "1009.1 mb" }, + { "Singapore", "Mostly Cloudy", "29°C", "73%", "1009.1 mb" }, + { "Tehran", "Fair", "36°C", "14%", "1013.2 mb" }, + { "Tokyo", "Mostly Cloudy", "28°C", "67%", "1009.1 mb" }, + { "Zurich", "Mostly Cloudy", "23°C", "44%", "1023.7 mb" } + }; + + const int lastItem = int(sizeof(weather) / sizeof(weather[0])) - 1; + + for (int i=0; i <= lastItem; i++) + { + std::vector line (&weather[i][0], &weather[i][0] + 5); + listView->insert (line); + } + + // Quit button + FButton* Quit = new FButton (this); + Quit->setGeometry(24, 16, 10, 1); + Quit->setText (L"&Quit"); + + // Add some function callbacks + Quit->addCallback + ( + "clicked", + F_METHOD_CALLBACK (this, &Listview::cb_exitApp) + ); +} + +//---------------------------------------------------------------------- +Listview::~Listview() +{ } + +//---------------------------------------------------------------------- +void Listview::onClose (FCloseEvent* ev) +{ + int ret = FMessageBox::info ( this, "Quit" + , "Do you really want\n" + "to quit the program ?" + , FMessageBox::Yes + , FMessageBox::No ); + if ( ret == FMessageBox::Yes ) + ev->accept(); + else + ev->ignore(); +} + +//---------------------------------------------------------------------- +void Listview::cb_exitApp (FWidget*, data_ptr) +{ + close(); +} + + +//---------------------------------------------------------------------- +// main part +//---------------------------------------------------------------------- + +int main (int argc, char* argv[]) +{ + if ( argv[1] && ( std::strcmp(argv[1], "--help") == 0 + || std::strcmp(argv[1], "-h") == 0 ) ) + { + std::cout << "Generic options:" << std::endl + << " -h, --help " + << "Display this help and exit" << std::endl; + FApplication::print_cmd_Options(); + std::exit(EXIT_SUCCESS); + } + + FApplication app(argc, argv); + + Listview d(&app); + d.setText (L"Listview"); + d.setGeometry (int(1 + (app.getWidth() - 37) / 2), 3, 37, 20); + d.setShadow(); + + app.setMainWidget(&d); + d.show(); + return app.exec(); +}