From 2e506a1367f77e106b5ea3776a5510247465b007 Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Sat, 14 Oct 2017 22:20:19 +0200 Subject: [PATCH] First implementation of a tree view in the FListView class --- ChangeLog | 5 +- examples/treeview.cpp | 260 +++++++++-- include/final/flistview.h | 241 ++++++++--- src/flistbox.cpp | 4 +- src/flistview.cpp | 882 ++++++++++++++++++++++++++------------ 5 files changed, 1020 insertions(+), 372 deletions(-) diff --git a/ChangeLog b/ChangeLog index c6315df3..63d5f74d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ -2017-10-02 Markus Gans +2017-10-14 Markus Gans * Fixed a bug in the FObject check of parent objects + * Replace the deprecated readdir_r function (CVE-2013-4237) + * First implementation of a tree view in the FListView + class (alpha state) 2017-10-02 Markus Gans * DECSCUSR - Set Cursor Style support for VTE >= 0.40.0 and diff --git a/examples/treeview.cpp b/examples/treeview.cpp index a78d8810..9eb5d9d8 100644 --- a/examples/treeview.cpp +++ b/examples/treeview.cpp @@ -1,4 +1,23 @@ -// File: treeview.cpp +/************************************************************************ +* treeview.cpp - Example of a FListView widget with a tree hierarchy * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2017 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 3 of the License, or * +* (at your option) any later version. * +* * +* The Final Cut is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +************************************************************************/ #include #include @@ -27,29 +46,64 @@ class Treeview : public FDialog ~Treeview(); private: + // Typedefs + struct TreeItem; // forward declaration + // Disable copy constructor Treeview (const Treeview&); // Disable assignment operator (=) Treeview& operator = (const Treeview&); + // Method + void adjustSize(); + // Event handlers void onClose (FCloseEvent*); // Callback methods void cb_exitApp (FWidget*, data_ptr); + + // Data Members + FListView* listView; + FButton* Quit; +}; +#pragma pack(pop) + + +//---------------------------------------------------------------------- +// struct Treeview::TreeItem +//---------------------------------------------------------------------- + +#pragma pack(push) +#pragma pack(1) +struct Treeview::TreeItem +{ + const char* const* begin() const + { return &name; } + + const char* const* end() const + { return &density + 1; } + + // Data Members + const char* name; + const char* population; + const char* density; + TreeItem* child_element; }; #pragma pack(pop) //---------------------------------------------------------------------- Treeview::Treeview (FWidget* parent) : FDialog(parent) + , listView() + , Quit() { // Create FListView object - FListView* listView = new FListView (this); - listView->setGeometry(2, 1, 33, 14); + listView = new FListView (this); + listView->setGeometry(2, 1, 53, 14); // Add columns to the view - listView->addColumn ("Name"); + listView->addColumn ("Name", 23); listView->addColumn ("Population"); listView->addColumn ("Density/km²"); @@ -61,40 +115,165 @@ Treeview::Treeview (FWidget* parent) listView->setTreeView(); // Populate FListView with a list of items - std::string continent[][3] = + static TreeItem africa[] = { - { "Africa", "944,000,000", "31.2" }, - { "Asia", "4,010,000,000", "90.3" }, - { "Europe", "733,000,000", "69.9" }, - { "North America", "523,000,000", "21" }, - { "South America", "381,000,000", "21.4" }, - { "Antarctica", "1000", "0" }, - { "Australia/Oceania", "34,000,000", "4" } + { "Algeria", "40,400,000", "15.9", 0 }, + { "Angola", "25,789,024", "20.69", 0 }, + { "Botswana", "2,250,260", "3.7", 0 }, + { "Cameroon", "22,534,532", "39.7", 0 }, + { "Chad", "13,670,084", "8.6", 0 }, + { "Egypt", "94,666,000", "87", 0 }, + { "Ethiopia", "102,374,044", "92.7", 0 }, + { "Ivory Coast", "23,740,424", "63.9", 0 }, + { "Libya", "6,541,948", "3.55", 0 }, + { "Madagascar", "24,430,325", "35.2", 0 }, + { "Mali", "14,517,176", "11.7", 0 }, + { "Mauritania", "4,301,018", "3.4", 0 }, + { "Mozambique", "24,692,144", "28.7", 0 }, + { "Namibia", "2,113,077", "2.54", 0 }, + { "Niger", "20,672,987", "12.1", 0 }, + { "Nigeria", "185,989,640", "197.2", 0 }, + { "Somalia", "14,317,996", "19.31", 0 }, + { "South Africa", "54,956,900", "42.4", 0 }, + { "South Sudan", "12,340,000", "13.33", 0 }, + { "Sudan", "39,578,828", "21.3", 0 }, + { "Tanzania", "51,820,00", "47.5", 0 }, + { "Zambia", "16,212,000", "17.2", 0 }, + { 0, 0, 0, 0 } }; - const int lastItem = int(sizeof(continent) / sizeof(continent[0])) - 1; - - for (int i = 0; i <= lastItem; i++) + static TreeItem asia[] = { - FStringList line (&continent[i][0], &continent[i][0] + 3); - listView->insert (line); + { "Afghanistan", "34,656,032", "49.88", 0 }, + { "China", "1,403,500,365", "145.0", 0 }, + { "India", "1,324,171,354", "393.9", 0 }, + { "Indonesia", "261,115,456", "124.66", 0 }, + { "Iran", "80,829,192", "48.0", 0 }, + { "Iraq", "37,202,572", "82.7", 0 }, + { "Japan", "126,740,000", "336.0", 0 }, + { "Kazakhstan", "17,987,736", "6.49", 0 }, + { "Mongolia", "3,081,677", "1.97", 0 }, + { "Myanmar", "51,486,253", "76.0", 0 }, + { "Pakistan", "207,774,520", "244.4", 0 }, + { "Russia", "144,463,451", "8.4", 0 }, + { "Saudi Arabia", "33,000,000", "15.0", 0 }, + { "Thailand", "68,863,514", "132.1", 0 }, + { "Turkey", "79,814,871", "102.0", 0 }, + { "Turkmenistan", "5,662,544", "10.5", 0 }, + { "Uzbekistan", "32,979,000", "70.5", 0 }, + { "Vietnam", "94,569,072", "276.03", 0 }, + { "Yemen", "27,584,213", "44.7", 0 }, + { 0, 0, 0, 0 } + }; + + static TreeItem europe[] = + { + { "Austria", "8,794,267", "104.0", 0 }, + { "Belarus", "9,498,700", "45.8", 0 }, + { "Bulgaria", "7,101,859", "64.9", 0 }, + { "Czech Republic", "10,610,947", "134.0", 0 }, + { "Finland", "5,506,312", "16.0", 0 }, + { "France", "66,991,000", "103.0", 0 }, + { "Germany", "82,175,700", "227.0", 0 }, + { "Greece", "11,183,716", "82.0", 0 }, + { "Hungary", "9,797,561", "105.3", 0 }, + { "Iceland", "332,529", "3.2", 0 }, + { "Italy", "60,589,445", "201.3", 0 }, + { "Norway", "5,267,146", "15.8", 0 }, + { "Poland", "38,634,007", "123.0", 0 }, + { "Portugal", "10,309,573", "115.0", 0 }, + { "Romania", "19,638,000", "84.4", 0 }, + { "Serbia", "7,058,322", "91.1", 0 }, + { "Spain", "46,468,102", "92.0", 0 }, + { "Sweden", "10,065,389", "22.0", 0 }, + { "United Kingdom", "65,648,000", "270.7", 0 }, + { 0, 0, 0, 0 } + }; + + static TreeItem north_america[] = + { + { "Canada", "35,151,728", "3.92", 0 }, + { "Cuba", "11,239,224", "102.3", 0 }, + { "Greenland", "56,483", "0.028", 0 }, + { "Guatemala", "16,582,469", "129.0", 0 }, + { "Honduras", "9,112,867", "64.0", 0 }, + { "Mexico", "119,530,753", "61.0", 0 }, + { "Nicaragua", "6,167,237", "51.0", 0 }, + { "USA", "325,365,189", "35.0", 0 }, + { 0, 0, 0, 0 } + }; + + static TreeItem south_america[] = + { + { "Argentina", "43,847,430", "14.4", 0 }, + { "Bolivia", "11,410,651", "10.4", 0 }, + { "Brazil", "208,064,000", "24.35", 0 }, + { "Chile", "18,006,407", "24.0", 0 }, + { "Colombia", "49,364,592", "40.74", 0 }, + { "Ecuador", "16,385,068", "58.95", 0 }, + { "Guyana", "773,303", "3.502", 0 }, + { "Paraguay", "6,725,308", "17.2", 0 }, + { "Peru", "31,826,018", "23.0", 0 }, + { "Venezuela", "31,568,179", "33.75", 0 }, + { 0, 0, 0, 0 } + }; + + static TreeItem oceania[] = + { + { "Australia", "24,675,900", "3.2", 0 }, + { "Papua New Guinea", "7,059,653", "15.0", 0 }, + { "Papua", "3,486,432", "11.0", 0 }, + { "New Zealand", "4,823,090", "17.5", 0 }, + { "West Papua", "877,437", "6.3", 0 }, + { "Solomon Islands", "599,419", "18.1", 0 }, + { "New Caledonia", "268,767", "14.5", 0 }, + { "Fiji", "898,76", "46.4", 0 }, + { "Hawaii", "1,428,557", "82.6", 0 }, + { "Vanuatu", "270,402", "19.7", 0 }, + { "French Polynesia", "280,208", "76.0", 0 }, + { "Samoa", "192,342", "68.0", 0 }, + { "Kiribati", "110,136", "152.0", 0 }, + { 0, 0, 0, 0 } + }; + + static TreeItem continent[] = + { + { "Africa", "944,000,000", "31.2", africa }, + { "Asia", "4,010,000,000", "90.3", asia }, + { "Europe", "733,000,000", "69.9", europe }, + { "North America", "523,000,000", "21", north_america }, + { "South America", "381,000,000", "21.4", south_america }, + { "Antarctica", "1000", "0", 0 }, + { "Australia/Oceania", "34,000,000", "4", oceania }, + { 0, 0, 0, 0 } + }; + + TreeItem* continent_list = continent; + + while ( continent_list->name ) + { + TreeItem* country_list = continent_list->child_element; + FStringList continent_line (continent_list->begin(), continent_list->end()); + FObjectIterator iter = listView->insert (continent_line); + + while ( country_list && country_list->name ) + { + FStringList country_line (country_list->begin(), country_list->end()); + listView->insert (country_line, iter); + country_list++; + } + + continent_list++; } - - FObjectIterator iter_africa = listView->beginOfList(); - std::string egypt[3] = { "Egypt", "94,666,000", "87" }; - FStringList egypt_line (&egypt[0], &egypt[0] + 3); - //FObjectIterator iter_africa = listView->insert (egypt_line); - listView->insert (egypt_line, iter_africa); - + FObjectIterator iter = listView->beginOfList(); + FObjectIterator iter_africa = iter++; FListViewItem* item_africa = static_cast(*iter_africa); - FObjectIterator iter_egypt = item_africa->begin(); - FListViewItem* item_egypt = static_cast(*iter_egypt); -item_egypt = item_egypt; -item_africa->expand(); + item_africa->expand(); + // Quit button - FButton* Quit = new FButton (this); + Quit = new FButton (this); Quit->setGeometry(24, 16, 10, 1); Quit->setText (L"&Quit"); @@ -110,6 +289,27 @@ item_africa->expand(); Treeview::~Treeview() // destructor { } +//---------------------------------------------------------------------- +void Treeview::adjustSize() +{ + int h = getParentWidget()->getHeight() - 4; + setHeight (h, false); + int X = int((getParentWidget()->getWidth() - getWidth()) / 2); + + if ( X < 1 ) + X = 1; + + setX (X, false); + + if ( listView ) + listView->setHeight (getHeight() - 6, false); + + if ( Quit ) + Quit->setY(getHeight() - 4); + + FDialog::adjustSize(); +} + //---------------------------------------------------------------------- void Treeview::onClose (FCloseEvent* ev) { @@ -142,7 +342,7 @@ int main (int argc, char* argv[]) // Create main dialog object Treeview d(&app); d.setText (L"Continents"); - d.setGeometry (int(1 + (app.getWidth() - 37) / 2), 3, 37, 20); + d.setGeometry (int(1 + (app.getWidth() - 57) / 2), 3, 57, 20); d.setShadow(); // Set dialog d as main widget diff --git a/include/final/flistview.h b/include/final/flistview.h index 38940578..8f331d75 100644 --- a/include/final/flistview.h +++ b/include/final/flistview.h @@ -1,31 +1,48 @@ -// File: flistview.h -// Provides: class FListViewItem -// class FListView -// -// Inheritance diagram -// ═══════════════════ -// -// ▕▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▏ -// ▕ FObject ▏ ▕ FTerm ▏ -// ▕▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▏ -// ▲ ▲ -// │ │ -// └─────┬─────┘ -// │ -// ▕▔▔▔▔▔▔▔▔▏ -// ▕ FVTerm ▏ -// ▕▁▁▁▁▁▁▁▁▏ -// ▲ -// │ -// ▕▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▏ -// ▕ FWidget ▏ ▕ FObject ▏ -// ▕▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▏ -// ▲ ▲ -// │ │ -// ▕▔▔▔▔▔▔▔▔▔▔▔▏1 *▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏ -// ▕ FListView ▏- - - -▕ FListViewItem ▏ -// ▕▁▁▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏ -// +/************************************************************************ +* flistview.h - Widget FListView and FListViewItem * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2017 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 3 of the License, or * +* (at your option) any later version. * +* * +* The Final Cut is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +************************************************************************/ + +/* Inheritance diagram + * ═══════════════════ + * + * ▕▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▏ + * ▕ FObject ▏ ▕ FTerm ▏ + * ▕▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▏ + * ▲ ▲ + * │ │ + * └─────┬─────┘ + * │ + * ▕▔▔▔▔▔▔▔▔▏ + * ▕ FVTerm ▏ + * ▕▁▁▁▁▁▁▁▁▏ + * ▲ + * │ + * ▕▔▔▔▔▔▔▔▔▔▏ ▕▔▔▔▔▔▔▔▔▔▏ + * ▕ FWidget ▏ ▕ FObject ▏ + * ▕▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▏ + * ▲ ▲ + * │ │ + * ▕▔▔▔▔▔▔▔▔▔▔▔▏1 *▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏ + * ▕ FListView ▏- - - -▕ FListViewItem ▏ + * ▕▁▁▁▁▁▁▁▁▁▁▁▏ ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏ + */ #ifndef FLISTVIEW_H #define FLISTVIEW_H @@ -90,6 +107,7 @@ class FListViewItem : public FObject FObjectIterator appendItem (FListViewItem*); void replaceControlCodes(); int getVisibleLines(); + void resetVisibleLineCounter(); // Data Member FStringList column_list; @@ -100,6 +118,7 @@ class FListViewItem : public FObject // Friend class friend class FListView; + friend class FListViewIterator; }; #pragma pack(pop) @@ -122,6 +141,86 @@ inline bool FListViewItem::isExpandable() { return expandable; } +//---------------------------------------------------------------------- +// class FListViewIterator +//---------------------------------------------------------------------- + +#pragma pack(push) +#pragma pack(1) + +class FListViewIterator +{ + public: + // Typedefs + typedef std::list FObjectList; + typedef FObjectList::iterator FObjectIterator; + typedef std::stack FObjectIteratorStack; + + // Constructor + FListViewIterator (); + FListViewIterator (FObjectIterator); + + // Destructor + ~FListViewIterator(); + + // Overloaded operators + FListViewIterator& operator ++ (); // prefix + FListViewIterator operator ++ (int); // postfix + FListViewIterator& operator -- (); // prefix + FListViewIterator operator -- (int); // postfix + FListViewIterator& operator += (int); + FListViewIterator& operator -= (int); + FObject*& operator * () const; + FObject* operator -> () const; + bool operator == (const FListViewIterator&) const; + bool operator != (const FListViewIterator&) const; + + // Accessor + const char* getClassName() const; + int getPosition() const; + + // Methods + void parentElement(); + + private: + // Methods + void nextElement (FObjectIterator&); + void prevElement (FObjectIterator&); + + // Data Members + FObjectIteratorStack iter_path; + FObjectIterator node; + int position; +}; +#pragma pack(pop) + + +// FListViewIterator inline functions +//---------------------------------------------------------------------- +inline FObject*& FListViewIterator::operator * () const +{ return *node; } + +//---------------------------------------------------------------------- +inline FObject* FListViewIterator::operator -> () const +{ return *node; } + +//---------------------------------------------------------------------- +inline bool FListViewIterator::operator == (const FListViewIterator& rhs) const +{ return node == rhs.node; } + +//---------------------------------------------------------------------- +inline bool FListViewIterator::operator != (const FListViewIterator& rhs) const +{ return node != rhs.node; } + +//---------------------------------------------------------------------- +inline const char* FListViewIterator::getClassName() const +{ return "FListViewIterator"; } + +//---------------------------------------------------------------------- +inline int FListViewIterator::getPosition() const +{ return position; } + + //---------------------------------------------------------------------- // class FListView //---------------------------------------------------------------------- @@ -143,7 +242,7 @@ class FListView : public FWidget // Accessors const char* getClassName() const; - uInt getCount() const; + uInt getCount(); fc::text_alignment getColumnAlignment (int) const; FString getColumnText (int) const; FListViewItem* getCurrentItem(); @@ -190,32 +289,13 @@ class FListView : public FWidget protected: // Methods - void adjustYOffset(); + void adjustViewport(); void adjustSize(); private: // Typedef - struct Header - { - public: - Header() - : name() - , width (0) - , fixed_width (false) - , alignment (fc::alignLeft) - { } - - ~Header() - { } - - FString name; - int width; - bool fixed_width; - fc::text_alignment alignment; - }; - + struct Header; // forward declaration typedef std::vector
headerItems; - typedef std::stack FObjectIteratorStack; // Constants static const int USE_MAX_SIZE = -1; @@ -238,8 +318,14 @@ class FListView : public FWidget FObjectIterator appendItem (FListViewItem*); void processClick(); void processChanged(); - FObjectIterator index2iterator (int); - void nextElement (FObjectIterator&); + void stepForward(); + void stepBackward(); + void stepForward (int); + void stepBackward (int); + void scrollToX (int); + void scrollToY (int); + void scrollTo (const FPoint &); + void scrollTo (int, int); // Callback methods void cb_VBarChange (FWidget*, data_ptr); @@ -249,7 +335,9 @@ class FListView : public FWidget FObjectIterator root; FObjectList selflist; FObjectList itemlist; - FObjectIteratorStack iter_path; + FListViewIterator current_iter; + FListViewIterator first_visible_line; + FListViewIterator last_visible_line; headerItems header; FTermBuffer headerline; FScrollbar* vbar; @@ -259,9 +347,7 @@ class FListView : public FWidget int scroll_distance; bool scroll_timer; bool tree_view; - int current; int xoffset; - int yoffset; int nf_offset; int max_line_width; @@ -271,22 +357,41 @@ class FListView : public FWidget #pragma pack(pop) +//---------------------------------------------------------------------- +// struct FListView::Header +//---------------------------------------------------------------------- + +#pragma pack(push) +#pragma pack(1) +struct FListView::Header +{ + public: + Header() + : name() + , width (0) + , fixed_width (false) + , alignment (fc::alignLeft) + { } + + ~Header() + { } + + FString name; + int width; + bool fixed_width; + fc::text_alignment alignment; +}; +#pragma pack(pop) + + // FListView inline functions //---------------------------------------------------------------------- inline const char* FListView::getClassName() const { return "FListView"; } -//---------------------------------------------------------------------- -inline uInt FListView::getCount() const -{ return uInt(itemlist.size()); } - //---------------------------------------------------------------------- inline FListViewItem* FListView::getCurrentItem() -{ - FObjectIterator iter = itemlist.begin(); - std::advance (iter, current - 1); - return static_cast(*iter); -} +{ return static_cast(*current_iter); } //---------------------------------------------------------------------- inline bool FListView::setTreeView (bool on) @@ -335,11 +440,7 @@ inline FObject::FObjectIterator FListView::endOfList() { return itemlist.end(); } //---------------------------------------------------------------------- -inline FObject::FObjectIterator FListView::index2iterator (int index) -{ - FObjectIterator iter = itemlist.begin(); - std::advance (iter, index); - return iter; -} +inline void FListView::scrollTo (const FPoint& pos) +{ scrollTo(pos.getX(), pos.getY()); } #endif // FLISTVIEW_H diff --git a/src/flistbox.cpp b/src/flistbox.cpp index a350dd13..bc7b1984 100644 --- a/src/flistbox.cpp +++ b/src/flistbox.cpp @@ -1212,8 +1212,8 @@ void FListBox::adjustYOffset() int element_count = int(getCount()); if ( getClientHeight() < 0 ) - beep(); - + return; + if ( element_count == 0 || getClientHeight() <= 0 ) return; diff --git a/src/flistview.cpp b/src/flistview.cpp index 05c23793..59a674e0 100644 --- a/src/flistview.cpp +++ b/src/flistview.cpp @@ -1,6 +1,23 @@ -// File: flistview.cpp -// Provides: class FListViewItem -// class FListView +/************************************************************************ +* flistview.cpp - Widget FListView and FListViewItem * +* * +* This file is part of the Final Cut widget toolkit * +* * +* Copyright 2017 Markus Gans * +* * +* The Final Cut is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 3 of the License, or * +* (at your option) any later version. * +* * +* The Final Cut is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License for more details. * +* * +* You should have received a copy of the GNU General Public License * +* along with this program. If not, see . * +************************************************************************/ #include @@ -41,7 +58,7 @@ FListViewItem::FListViewItem (const FListViewItem& item) //---------------------------------------------------------------------- FListViewItem::FListViewItem (FObjectIterator parent_iter) - : FObject(0) + : FObject((*parent_iter)->getParent()) , column_list() , data_pointer(0) , visible_lines(1) @@ -79,8 +96,8 @@ FListViewItem::~FListViewItem() // destructor FString FListViewItem::getText (int column) const { if ( column < 1 - || column_list.empty() - || column > int(column_list.size()) ) + || column_list.empty() + || column > int(column_list.size()) ) return *fc::empty_string; column--; // Convert column position to address offset (index) @@ -105,8 +122,8 @@ uInt FListViewItem::getDepth() const void FListViewItem::setText (int column, const FString& text) { if ( column < 1 - || column_list.empty() - || column > int(column_list.size()) ) + || column_list.empty() + || column > int(column_list.size()) ) return; FObject* parent = getParent(); @@ -180,6 +197,7 @@ void FListViewItem::collapse() return; is_expand = false; + visible_lines = 1; } // private methods of FListView @@ -187,7 +205,9 @@ void FListViewItem::collapse() FObject::FObjectIterator FListViewItem::appendItem (FListViewItem* child) { expandable = true; + resetVisibleLineCounter(); addChild (child); + // Return iterator to child/last element return --FObject::end(); } @@ -228,6 +248,177 @@ int FListViewItem::getVisibleLines() return visible_lines; } +//---------------------------------------------------------------------- +void FListViewItem::resetVisibleLineCounter() +{ + visible_lines = 0; + FObject* parent = getParent(); + + if ( parent && parent->isInstanceOf("FListViewItem") ) + { + FListViewItem* parent_item = static_cast(parent); + return parent_item->resetVisibleLineCounter(); + } +} + + +//---------------------------------------------------------------------- +// class FListViewIterator +//---------------------------------------------------------------------- + +// constructor and destructor +//---------------------------------------------------------------------- +FListViewIterator::FListViewIterator () + : iter_path() + , node() + , position(0) +{ } + +//---------------------------------------------------------------------- +FListViewIterator::FListViewIterator (FObjectIterator iter) + : iter_path() + , node(iter) + , position(0) +{ } + +//---------------------------------------------------------------------- +FListViewIterator::~FListViewIterator() // destructor +{ } + +// FListViewIterator operators +//---------------------------------------------------------------------- +FListViewIterator& FListViewIterator::operator ++ () // prefix +{ + nextElement(node); + return *this; +} + +//---------------------------------------------------------------------- +FListViewIterator FListViewIterator::operator ++ (int) // postfix +{ + FListViewIterator tmp = *this; + ++(*this); + return tmp; +} + +//---------------------------------------------------------------------- +FListViewIterator& FListViewIterator::operator -- () // prefix +{ + prevElement(node); + return *this; +} + +//---------------------------------------------------------------------- +FListViewIterator FListViewIterator::operator -- (int) // postfix +{ + FListViewIterator tmp = *this; + --(*this); + return tmp; +} + +//---------------------------------------------------------------------- +FListViewIterator& FListViewIterator::operator += (int n) +{ + while ( n > 0 ) + { + nextElement(node); + n--; + } + + return *this; +} + +//---------------------------------------------------------------------- +FListViewIterator& FListViewIterator::operator -= (int n) +{ + while ( n > 0 ) + { + prevElement(node); + n--; + } + + return *this; +} + +// private methods of FListViewIterator +//---------------------------------------------------------------------- +void FListViewIterator::nextElement (FObjectIterator& iter) +{ + FListViewItem* item = static_cast(*iter); + + if ( item->isExpandable() && item->isExpand() ) + { + iter_path.push(iter); + iter = item->begin(); + position++; + } + else + { + ++iter; + position++; + + if ( ! iter_path.empty() ) + { + FObjectIterator& parent_iter = iter_path.top(); + + if ( iter == (*parent_iter)->end() ) + { + iter = parent_iter; + iter_path.pop(); + ++iter; + } + } + } +} + +//---------------------------------------------------------------------- +void FListViewIterator::prevElement (FObjectIterator& iter) +{ + FListViewItem* item; + FObjectIterator start_iter = iter; + + if ( ! iter_path.empty() ) + { + FObjectIterator& parent_iter = iter_path.top(); + + if ( start_iter == (*parent_iter)->begin() ) + { + iter = parent_iter; + position--; + iter_path.pop(); + return; + } + } + + --iter; + item = static_cast(*iter); + + if ( iter == start_iter ) + return; + else + position--; + + while ( item->isExpandable() && item->isExpand() ) + { + iter_path.push(iter); + iter = item->end(); + --iter; + item = static_cast(*iter); + } +} + +//---------------------------------------------------------------------- +void FListViewIterator::parentElement() +{ + if ( iter_path.empty() ) + return; + + FObjectIterator& parent_iter = iter_path.top(); + + while ( node != parent_iter ) + prevElement(node); +} + //---------------------------------------------------------------------- // class FListView @@ -240,7 +431,9 @@ FListView::FListView (FWidget* parent) , root() , selflist() , itemlist() - , iter_path() + , current_iter() + , first_visible_line() + , last_visible_line() , header() , headerline() , vbar(0) @@ -250,9 +443,7 @@ FListView::FListView (FWidget* parent) , scroll_distance(1) , scroll_timer(false) , tree_view(false) - , current(0) , xoffset(0) - , yoffset(0) , nf_offset(0) , max_line_width(1) { @@ -268,6 +459,22 @@ FListView::~FListView() // destructor } // public methods of FListView +//---------------------------------------------------------------------- +uInt FListView::getCount() +{ + int n = 0; + FObjectIterator iter = itemlist.begin(); + + while ( iter != itemlist.end() ) + { + FListViewItem* item = static_cast(*iter); + n += item->getVisibleLines(); + ++iter; + } + + return uInt(n); +} + //---------------------------------------------------------------------- fc::text_alignment FListView::getColumnAlignment (int column) const { @@ -377,6 +584,7 @@ FObject::FObjectIterator FListView::insert ( FListViewItem* item if ( parent_iter == FObjectIterator(0) ) return FObjectIterator(0); + // Determine the line width header_iter = header.begin(); while ( header_iter != header.end() ) @@ -422,10 +630,20 @@ FObject::FObjectIterator FListView::insert ( FListViewItem* item FListViewItem* parent = static_cast(*parent_iter); item_iter = parent->appendItem (item); } + else + item_iter = FObjectIterator(0); } else item_iter = FObjectIterator(0); + if ( itemlist.size() == 1 ) + { + // Select first item on insert + current_iter = itemlist.begin(); + // The visible area of the list begins with the first element + first_visible_line = itemlist.begin(); + } + int element_count = int(getCount()); recalculateVerticalBar (element_count); return item_iter; @@ -480,13 +698,14 @@ FObject::FObjectIterator FListView::insert ( const std::vector& cols //---------------------------------------------------------------------- void FListView::onKeyPress (FKeyEvent* ev) { - int element_count = int(getCount()); - int current_before = current; - int xoffset_before = xoffset; - int xoffset_end = max_line_width - getClientWidth(); - int yoffset_before = yoffset; - int yoffset_end = element_count - getClientHeight(); - int key = ev->key(); + int element_count = int(getCount()) + , position_before = current_iter.getPosition() + , xoffset_before = xoffset + , xoffset_end = max_line_width - getClientWidth() + , first_line_position_before = first_visible_line.getPosition() + , pagesize = getClientHeight() - 1 + , key = ev->key(); + FListViewItem* item = getCurrentItem(); switch ( key ) { @@ -497,133 +716,154 @@ void FListView::onKeyPress (FKeyEvent* ev) break; case fc::Fkey_up: - current--; - - if ( current < 1 ) - current = 1; - - if ( current <= yoffset ) - yoffset--; + stepBackward(); ev->accept(); break; case fc::Fkey_down: - current++; - - if ( current > element_count ) - current = element_count; - - if ( current - yoffset > getClientHeight() ) - yoffset++; + stepForward(); ev->accept(); break; case fc::Fkey_left: - xoffset--; + if ( xoffset == 0 ) + { + if ( item->isExpandable() && item->isExpand() ) + { + // Collapse element + item->collapse(); + adjustSize(); + int element_count = int(getCount()); + recalculateVerticalBar (element_count); + // Force vertical scrollbar redraw + first_line_position_before = -1; + } + else if ( item->hasParent() ) + { + // Jump to parent element + FObject* parent = item->getParent(); - if ( xoffset < 0 ) - xoffset = 0; + if ( parent->isInstanceOf("FListViewItem") ) + { + current_iter.parentElement(); + + if ( current_iter.getPosition() < first_line_position_before ) + { + int difference = position_before - current_iter.getPosition(); + + if ( first_visible_line.getPosition() - difference >= 0 ) + { + first_visible_line -= difference; + last_visible_line -= difference; + } + else + { + int d = first_visible_line.getPosition(); + first_visible_line -= d; + last_visible_line -= d; + } + } + } + } + } + else + { + // Scroll left + xoffset--; + + if ( xoffset < 0 ) + xoffset = 0; + } ev->accept(); break; case fc::Fkey_right: - xoffset++; + if ( item->isExpandable() && ! item->isExpand() ) + { + // Expand element + item->expand(); + adjustSize(); + // Force vertical scrollbar redraw + first_line_position_before = -1; + } + else + { + // Scroll right + xoffset++; - if ( xoffset > xoffset_end ) - xoffset = xoffset_end; + if ( xoffset > xoffset_end ) + xoffset = xoffset_end; - if ( xoffset < 0 ) - xoffset = 0; + 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; - } + stepBackward(pagesize); 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; - } + stepForward(pagesize); ev->accept(); break; case fc::Fkey_home: - current = 1; - yoffset = 0; + { + current_iter -= current_iter.getPosition(); + int difference = first_visible_line.getPosition(); + first_visible_line -= difference; + last_visible_line -= difference; + } ev->accept(); break; case fc::Fkey_end: - current = element_count; - - if ( current > getClientHeight() ) - yoffset = yoffset_end; + { + current_iter += element_count - current_iter.getPosition() - 1; + int difference = element_count - last_visible_line.getPosition() - 1; + first_visible_line += difference; + last_visible_line += difference; + } ev->accept(); break; case int('+'): - { - FListViewItem* item = getCurrentItem(); - item->expand(); - ev->accept(); - } + item->expand(); + adjustSize(); + ev->accept(); break; case int('-'): - { - FListViewItem* item = getCurrentItem(); - item->collapse(); - ev->accept(); - } + item->collapse(); + adjustSize(); + ev->accept(); break; default: ev->ignore(); } - if ( current_before != current ) + if ( position_before != current_iter.getPosition() ) processChanged(); if ( ev->isAccepted() ) { if ( isVisible() ) - { - drawColumnLabels(); - drawList(); - } + draw(); - vbar->setValue (yoffset); + vbar->setValue (first_visible_line.getPosition()); - if ( vbar->isVisible() && yoffset_before != yoffset ) + if ( vbar->isVisible() && first_line_position_before != first_visible_line.getPosition() ) vbar->drawBar(); hbar->setValue (xoffset); @@ -639,8 +879,6 @@ void FListView::onKeyPress (FKeyEvent* ev) //---------------------------------------------------------------------- void FListView::onMouseDown (FMouseEvent* ev) { - int yoffset_before, mouse_x, mouse_y; - if ( ev->getButton() != fc::LeftButton && ev->getButton() != fc::RightButton ) { @@ -664,24 +902,28 @@ void FListView::onMouseDown (FMouseEvent* ev) getStatusBar()->drawMessage(); } - yoffset_before = yoffset; - mouse_x = ev->getX(); - mouse_y = ev->getY(); + int first_line_position_before = first_visible_line.getPosition() + , 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; + int new_pos = first_visible_line.getPosition() + mouse_y - 2; - if ( current > int(getCount()) ) - current = int(getCount()); + if ( new_pos < int(getCount()) ) + { + current_iter = first_visible_line; + current_iter += mouse_y - 2; + } if ( isVisible() ) drawList(); - vbar->setValue (yoffset); + vbar->setValue (first_visible_line.getPosition()); - if ( vbar->isVisible() && yoffset_before != yoffset ) + if ( vbar->isVisible() + && first_line_position_before != first_visible_line.getPosition() ) vbar->drawBar(); updateTerminal(); @@ -716,8 +958,6 @@ void FListView::onMouseUp (FMouseEvent* ev) //---------------------------------------------------------------------- void FListView::onMouseMove (FMouseEvent* ev) { - int yoffset_before, mouse_x, mouse_y; - if ( ev->getButton() != fc::LeftButton && ev->getButton() != fc::RightButton ) { @@ -727,24 +967,28 @@ void FListView::onMouseMove (FMouseEvent* ev) if ( ev->getButton() == fc::RightButton ) return; - yoffset_before = yoffset; - mouse_x = ev->getX(); - mouse_y = ev->getY(); + int first_line_position_before = first_visible_line.getPosition() + , 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; + int new_pos = first_visible_line.getPosition() + mouse_y - 2; - if ( current > int(getCount()) ) - current = int(getCount()); + if ( new_pos < int(getCount()) ) + { + current_iter = first_visible_line; + current_iter += mouse_y - 2; + } if ( isVisible() ) drawList(); - vbar->setValue (yoffset); + vbar->setValue (first_visible_line.getPosition()); - if ( vbar->isVisible() && yoffset_before != yoffset ) + if ( vbar->isVisible() + && first_line_position_before != first_visible_line.getPosition() ) vbar->drawBar(); updateTerminal(); @@ -759,7 +1003,7 @@ void FListView::onMouseMove (FMouseEvent* ev) && scroll_distance < getClientHeight() ) scroll_distance++; - if ( ! scroll_timer && current > 1 ) + if ( ! scroll_timer && current_iter.getPosition() > 0 ) { scroll_timer = true; addTimer(scroll_repeat); @@ -770,7 +1014,7 @@ void FListView::onMouseMove (FMouseEvent* ev) drag_scroll = fc::scrollUp; } - if ( current == 1 ) + if ( current_iter.getPosition() == 0 ) { delOwnTimer(); drag_scroll = fc::noScroll; @@ -783,7 +1027,7 @@ void FListView::onMouseMove (FMouseEvent* ev) && scroll_distance < getClientHeight() ) scroll_distance++; - if ( ! scroll_timer && current < int(getCount()) ) + if ( ! scroll_timer && current_iter.getPosition() <= int(getCount()) ) { scroll_timer = true; addTimer(scroll_repeat); @@ -794,7 +1038,7 @@ void FListView::onMouseMove (FMouseEvent* ev) drag_scroll = fc::scrollDown; } - if ( current == int(getCount()) ) + if ( current_iter.getPosition() - 1 == int(getCount()) ) { delOwnTimer(); drag_scroll = fc::noScroll; @@ -824,7 +1068,7 @@ void FListView::onMouseDoubleClick (FMouseEvent* ev) if ( mouse_x > 1 && mouse_x < getWidth() && mouse_y > 1 && mouse_y < getHeight() ) { - if ( yoffset + mouse_y - 1 > int(getCount()) ) + if ( first_visible_line.getPosition() + mouse_y - 1 > int(getCount()) ) return; processClick(); @@ -834,10 +1078,9 @@ void FListView::onMouseDoubleClick (FMouseEvent* ev) //---------------------------------------------------------------------- void FListView::onTimer (FTimerEvent*) { - int element_count = int(getCount()); - int current_before = current; - int yoffset_before = yoffset; - int yoffset_end = element_count - getClientHeight(); + int element_count = int(getCount()) + , position_before = current_iter.getPosition() + , first_line_position_before = first_visible_line.getPosition(); switch ( int(drag_scroll) ) { @@ -846,43 +1089,24 @@ void FListView::onTimer (FTimerEvent*) case fc::scrollUp: case fc::scrollUpSelect: - if ( current_before == 1) + if ( position_before == 0 ) { drag_scroll = fc::noScroll; return; } - current -= scroll_distance; - - if ( current < 1 ) - current = 1; - - if ( current <= yoffset ) - yoffset -= scroll_distance; - - if ( yoffset < 0 ) - yoffset = 0; + stepBackward(scroll_distance); break; case fc::scrollDown: case fc::scrollDownSelect: - if ( current_before == element_count ) + if ( position_before + 1 == 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; - + stepForward(scroll_distance); break; default: @@ -892,9 +1116,9 @@ void FListView::onTimer (FTimerEvent*) if ( isVisible() ) drawList(); - vbar->setValue (yoffset); + vbar->setValue (first_visible_line.getPosition()); - if ( vbar->isVisible() && yoffset_before != yoffset ) + if ( vbar->isVisible() && first_line_position_before != first_visible_line.getPosition() ) vbar->drawBar(); updateTerminal(); @@ -904,14 +1128,11 @@ void FListView::onTimer (FTimerEvent*) //---------------------------------------------------------------------- void FListView::onWheel (FWheelEvent* ev) { - int element_count, current_before, yoffset_before, yoffset_end, wheel; - element_count = int(getCount()); - current_before = current; - yoffset_before = yoffset; - yoffset_end = element_count - getClientHeight(); - - if ( yoffset_end < 0 ) - yoffset_end = 0; + int wheel + , element_count = int(getCount()) + , position_before = current_iter.getPosition() + , first_line_position_before = first_visible_line.getPosition() + , pagesize = 4; wheel = ev->getWheel(); @@ -926,40 +1147,48 @@ void FListView::onWheel (FWheelEvent* ev) switch ( wheel ) { case fc::WheelUp: - if ( yoffset == 0 ) + if ( current_iter.getPosition() == 0 ) break; - yoffset -= 4; - - if ( yoffset < 0 ) + if ( first_visible_line.getPosition() - pagesize >= 0 ) { - current -= 4 + yoffset; - yoffset=0; + current_iter -= pagesize; + first_visible_line -= pagesize; + last_visible_line -= pagesize; } else - current -= 4; - - if ( current < 1 ) - current=1; + { + // Save relative position from the top line + int ry = current_iter.getPosition() - first_visible_line.getPosition(); + int difference = first_visible_line.getPosition(); + first_visible_line -= difference; + last_visible_line -= difference; + current_iter = first_visible_line; + current_iter += ry; + } break; case fc::WheelDown: - if ( yoffset == yoffset_end ) + if ( current_iter.getPosition() + 1 == element_count ) break; - yoffset += 4; - - if ( yoffset > yoffset_end ) + if ( last_visible_line.getPosition() + pagesize < element_count ) { - current += 4 - (yoffset - yoffset_end); - yoffset = yoffset_end; + current_iter += pagesize; + first_visible_line += pagesize; + last_visible_line += pagesize; } else - current += 4; - - if ( current > element_count ) - current = element_count; + { + // Save relative position from the top line + int ry = current_iter.getPosition() - first_visible_line.getPosition(); + int differenz = element_count - last_visible_line.getPosition() - 1; + first_visible_line += differenz; + last_visible_line += differenz; + current_iter = first_visible_line; + current_iter += ry; + } break; @@ -967,15 +1196,16 @@ void FListView::onWheel (FWheelEvent* ev) break; } - if ( current_before != current ) + if ( position_before != current_iter.getPosition() ) processChanged(); if ( isVisible() ) drawList(); - vbar->setValue (yoffset); + vbar->setValue (first_visible_line.getPosition()); - if ( vbar->isVisible() && yoffset_before != yoffset ) + if ( vbar->isVisible() + && first_line_position_before != first_visible_line.getPosition() ) vbar->drawBar(); updateTerminal(); @@ -1004,21 +1234,49 @@ void FListView::onFocusOut (FFocusEvent*) // protected methods of FListView //---------------------------------------------------------------------- -void FListView::adjustYOffset() +void FListView::adjustViewport() { int element_count = int(getCount()); + if ( element_count == 0 || getClientHeight() <= 0 ) + return; + + if ( element_count < getClientHeight() ) + { + first_visible_line = itemlist.begin(); + last_visible_line = first_visible_line; + last_visible_line += element_count - 1; + } + +/* if ( yoffset > element_count - getClientHeight() ) yoffset = element_count - getClientHeight(); if ( yoffset < 0 ) - yoffset = 0; + yoffset = 0;*/ - if ( current < yoffset ) - current = yoffset; +//setTermXY(1,1); ::printf("(%d > %d)", first_visible_line.getPosition(),element_count - getClientHeight() - 1); fflush(stdout); sleep(1); - if ( yoffset < current - getClientHeight() ) - yoffset = current - getClientHeight(); + if ( first_visible_line.getPosition() > element_count - getClientHeight() ) + { + int difference = first_visible_line.getPosition() - (element_count - getClientHeight()); + + if ( first_visible_line.getPosition() - difference + 1 > 0 ) + { + first_visible_line -= difference; + last_visible_line -= difference; + } + } + +/* + if ( current_iter.getPosition() < first_visible_line.getPosition() ) + current_iter = first_visible_line; + + if ( first_visible_line.getPosition() < current_iter.getPosition() - getClientHeight() ) + { + first_visible_line = current_iter; + first_visible_line -= getClientHeight(); + }*/ } //---------------------------------------------------------------------- @@ -1026,7 +1284,7 @@ void FListView::adjustSize() { int element_count; FWidget::adjustSize(); - adjustYOffset(); + adjustViewport(); element_count = int(getCount()); vbar->setMaximum (element_count - getClientHeight()); @@ -1046,7 +1304,7 @@ void FListView::adjustSize() else vbar->setVisible(); - if ( max_line_width < getClientWidth() - 1 ) + if ( max_line_width <= getClientWidth() ) hbar->hide(); else hbar->setVisible(); @@ -1133,8 +1391,8 @@ void FListView::draw() { bool isFocus; - if ( current < 1 ) - current = 1; + if ( current_iter.getPosition() < 1 ) + current_iter = itemlist.begin(); setColor(); @@ -1279,7 +1537,7 @@ void FListView::drawList() { uInt page_height, y; bool is_focus; - FObjectIterator iter; + FListViewIterator iter; if ( itemlist.empty() || getHeight() <= 2 || getWidth() <= 4 ) return; @@ -1287,11 +1545,11 @@ void FListView::drawList() y = 0; page_height = uInt(getHeight() - 2); is_focus = ((flags & fc::focus) != 0); - iter = index2iterator(yoffset); + iter = first_visible_line; while ( iter != itemlist.end() && y < page_height ) { - bool is_current_line = bool( y + uInt(yoffset) + 1 == uInt(current) ); + bool is_current_line = bool( iter == current_iter ); const FListViewItem* item = static_cast(*iter); setPrintPos (2, 2 + int(y)); @@ -1301,8 +1559,20 @@ void FListView::drawList() if ( is_focus && is_current_line ) setCursorPos (3, 2 + int(y)); // first character + last_visible_line = iter; + y++; + ++iter; + } + + // Reset color + setColor(); + + // Clean empty space after last element + while ( y < uInt(getClientHeight()) ) + { + setPrintPos (2, 2 + int(y)); + print (FString(getClientWidth(), ' ')); y++; - nextElement(iter); } } @@ -1353,7 +1623,7 @@ void FListView::drawListLine ( const FListViewItem* item if ( item->expandable ) { - if (item->is_expand ) + if ( item->is_expand ) { line += wchar_t(fc::BlackDownPointingTriangle); // ▼ line += L' '; @@ -1484,41 +1754,163 @@ void FListView::processChanged() } //---------------------------------------------------------------------- -void FListView::nextElement (FObjectIterator& iter) +void FListView::stepForward() { - FListViewItem* item = static_cast(*iter); - - if ( item->isExpandable() && item->isExpand() ) + if ( current_iter == last_visible_line ) { - iter_path.push(iter); - iter = item->begin(); + ++last_visible_line; + + if ( last_visible_line == itemlist.end() ) + --last_visible_line; + else + ++first_visible_line; + } + + ++current_iter; + + if ( current_iter == itemlist.end() ) + --current_iter; +} + +//---------------------------------------------------------------------- +void FListView::stepBackward() +{ + if ( current_iter == first_visible_line + && current_iter != itemlist.begin() ) + { + --first_visible_line; + --last_visible_line; + } + + if ( current_iter != itemlist.begin() ) + --current_iter; +} + +//---------------------------------------------------------------------- +void FListView::stepForward (int distance) +{ + int element_count = int(getCount()); + + if ( current_iter.getPosition() + 1 == element_count ) + return; + + if ( current_iter.getPosition() + distance < element_count ) + { + current_iter += distance; } else { - ++iter; + current_iter += element_count - current_iter.getPosition() - 1; + } - if ( ! iter_path.empty() ) + if ( current_iter.getPosition() > last_visible_line.getPosition() ) + { + if ( last_visible_line.getPosition() + distance < element_count ) { - FObjectIterator& parent_iter = iter_path.top(); - - if ( iter == (*parent_iter)->end() ) - { - iter = parent_iter; - iter_path.pop(); - ++iter; - } + first_visible_line += distance; + last_visible_line += distance; + } + else + { + int differenz = element_count - last_visible_line.getPosition() - 1; + first_visible_line += differenz; + last_visible_line += differenz; } } } +//---------------------------------------------------------------------- +void FListView::stepBackward (int distance) +{ + if ( current_iter.getPosition() == 0 ) + return; + + if ( current_iter.getPosition() - distance >= 0 ) + { + current_iter -= distance; + } + else + { + current_iter -= current_iter.getPosition(); + } + + if ( current_iter.getPosition() < first_visible_line.getPosition() ) + { + if ( first_visible_line.getPosition() - distance >= 0 ) + { + first_visible_line -= distance; + last_visible_line -= distance; + } + else + { + int difference = first_visible_line.getPosition(); + first_visible_line -= difference; + last_visible_line -= difference; + } + } +} + +//---------------------------------------------------------------------- +void FListView::scrollToX (int x) +{ + int xoffset_end = max_line_width - getClientWidth(); + + if ( xoffset == x ) + return; + + xoffset = x; + + if ( xoffset > xoffset_end ) + xoffset = xoffset_end; + + if ( xoffset < 0 ) + xoffset = 0; +} + +//---------------------------------------------------------------------- +void FListView::scrollToY (int y) +{ + int pagesize = getClientHeight() - 1; + int element_count = int(getCount()); + + if ( first_visible_line.getPosition() == y ) + return; + + // Save relative position from the top line + int ry = current_iter.getPosition() - first_visible_line.getPosition(); + + if ( y + pagesize <= element_count ) + { + first_visible_line = itemlist.begin(); + first_visible_line += y; + current_iter = first_visible_line; + current_iter += ry; + last_visible_line = first_visible_line; + last_visible_line += pagesize; + } + else + { + int differenz = element_count - last_visible_line.getPosition() - 1; + current_iter += differenz; + first_visible_line += differenz; + last_visible_line += differenz; + } +} + +//---------------------------------------------------------------------- +void FListView::scrollTo (int x, int y) +{ + scrollToX(x); + scrollToY(y); +} + //---------------------------------------------------------------------- void FListView::cb_VBarChange (FWidget*, data_ptr) { FScrollbar::sType scrollType; int distance = 1; - int element_count = int(getCount()); - int yoffset_before = yoffset; - int yoffset_end = element_count - getClientHeight(); + int first_line_position_before = first_visible_line.getPosition(); + scrollType = vbar->getScrollType(); switch ( scrollType ) @@ -1530,59 +1922,20 @@ void FListView::cb_VBarChange (FWidget*, data_ptr) distance = getClientHeight(); // fall through case FScrollbar::scrollStepBackward: - current -= distance; - - if ( current < 1 ) - current=1; - - if ( current <= yoffset ) - yoffset -= distance; - - if ( yoffset < 0 ) - yoffset = 0; - + stepBackward(distance); 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; - + stepForward(distance); 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; + int value = vbar->getValue(); + scrollToY (value); break; } @@ -1608,9 +1961,10 @@ void FListView::cb_VBarChange (FWidget*, data_ptr) if ( scrollType >= FScrollbar::scrollStepBackward && scrollType <= FScrollbar::scrollPageForward ) { - vbar->setValue (yoffset); + vbar->setValue (first_visible_line.getPosition()); - if ( vbar->isVisible() && yoffset_before != yoffset ) + if ( vbar->isVisible() + && first_line_position_before != first_visible_line.getPosition() ) vbar->drawBar(); updateTerminal(); @@ -1622,9 +1976,10 @@ void FListView::cb_VBarChange (FWidget*, data_ptr) void FListView::cb_HBarChange (FWidget*, data_ptr) { FScrollbar::sType scrollType; - int distance = 1; - int xoffset_before = xoffset; - int xoffset_end = max_line_width - getClientWidth(); + int distance = 1 + , pagesize = 4 + , xoffset_before = xoffset + , xoffset_end = max_line_width - getClientWidth(); scrollType = hbar->getScrollType(); switch ( scrollType ) @@ -1658,19 +2013,8 @@ void FListView::cb_HBarChange (FWidget*, data_ptr) 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; - + int value = hbar->getValue(); + scrollToX(value); break; } @@ -1678,7 +2022,7 @@ void FListView::cb_HBarChange (FWidget*, data_ptr) if ( xoffset == 0 ) break; - xoffset -= 4; + xoffset -= pagesize; if ( xoffset < 0 ) xoffset = 0; @@ -1689,7 +2033,7 @@ void FListView::cb_HBarChange (FWidget*, data_ptr) if ( xoffset == xoffset_end ) break; - xoffset += 4; + xoffset += pagesize; if ( xoffset > xoffset_end ) xoffset = xoffset_end;