2017-11-04 07:03:53 +01:00
|
|
|
/***********************************************************************
|
|
|
|
* flistview.cpp - Widget FListView and FListViewItem *
|
|
|
|
* *
|
|
|
|
* This file is part of the Final Cut widget toolkit *
|
|
|
|
* *
|
2018-01-02 20:38:45 +01:00
|
|
|
* Copyright 2017-2018 Markus Gans *
|
2017-11-04 07:03:53 +01:00
|
|
|
* *
|
|
|
|
* The Final Cut is free software; you can redistribute it and/or *
|
|
|
|
* modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details. *
|
|
|
|
* *
|
|
|
|
* You should have received a copy of the GNU Lesser General Public *
|
|
|
|
* License along with this program. If not, see *
|
|
|
|
* <http://www.gnu.org/licenses/>. *
|
|
|
|
***********************************************************************/
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-09-11 03:06:02 +02:00
|
|
|
#include <vector>
|
|
|
|
|
2017-09-17 21:32:46 +02:00
|
|
|
#include "final/fapplication.h"
|
|
|
|
#include "final/flistview.h"
|
|
|
|
#include "final/fscrollbar.h"
|
|
|
|
#include "final/fstatusbar.h"
|
|
|
|
#include "final/ftermbuffer.h"
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-09-20 23:59:01 +02:00
|
|
|
namespace finalcut
|
|
|
|
{
|
|
|
|
|
2017-12-25 21:17:08 +01:00
|
|
|
// Static class attribute
|
|
|
|
FObject::FObjectIterator FListView::null_iter;
|
2017-11-02 16:05:34 +01:00
|
|
|
|
2018-09-28 06:45:02 +02:00
|
|
|
// Function prototypes
|
|
|
|
long firstNumberFromString (const FString&);
|
|
|
|
bool sortAscendingByName (const FObject*, const FObject*);
|
|
|
|
bool sortDescendingByName (const FObject*, const FObject*);
|
|
|
|
bool sortAscendingByNumber (const FObject*, const FObject*);
|
|
|
|
bool sortDescendingByNumber (const FObject*, const FObject*);
|
|
|
|
|
|
|
|
// non-member functions
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
long firstNumberFromString (const FString& str)
|
|
|
|
{
|
|
|
|
const FString::iterator last = str.end();
|
|
|
|
FString::iterator iter = str.begin();
|
|
|
|
FString::iterator first_pos;
|
|
|
|
FString::iterator last_pos;
|
2018-10-14 06:25:33 +02:00
|
|
|
std::size_t pos;
|
|
|
|
std::size_t length;
|
2018-09-28 06:45:02 +02:00
|
|
|
long number;
|
|
|
|
|
|
|
|
while ( iter != last )
|
|
|
|
{
|
|
|
|
if ( wchar_t(*iter) >= L'0' && wchar_t(*iter) <= L'9' )
|
2018-09-28 06:53:27 +02:00
|
|
|
{
|
|
|
|
if ( wchar_t(*(iter - 1)) == L'-' )
|
|
|
|
--iter;
|
|
|
|
|
2018-09-28 06:45:02 +02:00
|
|
|
break;
|
2018-09-28 06:53:27 +02:00
|
|
|
}
|
2018-09-28 06:45:02 +02:00
|
|
|
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
first_pos = iter;
|
|
|
|
|
|
|
|
if ( first_pos == last )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
while ( iter != last )
|
|
|
|
{
|
|
|
|
if ( wchar_t(*iter) < L'0' || wchar_t(*iter) > L'9' )
|
|
|
|
break;
|
|
|
|
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_pos = iter;
|
|
|
|
|
|
|
|
if ( last_pos == last )
|
|
|
|
return 0;
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
pos = std::size_t(std::distance(str.begin(), first_pos)) + 1;
|
|
|
|
length = std::size_t(std::distance(first_pos, last_pos));
|
2018-09-28 06:45:02 +02:00
|
|
|
const FString num_str = str.mid(pos, length);
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
number = num_str.toLong();
|
|
|
|
}
|
|
|
|
catch (const std::exception&)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return number;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool sortAscendingByName (const FObject* lhs, const FObject* rhs)
|
|
|
|
{
|
|
|
|
const FListViewItem* l_item = static_cast<const FListViewItem*>(lhs);
|
|
|
|
const FListViewItem* r_item = static_cast<const FListViewItem*>(rhs);
|
|
|
|
const int column = l_item->getSortColumn();
|
|
|
|
const FString l_string = l_item->getText(column);
|
|
|
|
const FString r_string = r_item->getText(column);
|
|
|
|
|
|
|
|
// lhs < rhs
|
|
|
|
return bool( strcasecmp(l_string.c_str(), r_string.c_str()) < 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool sortDescendingByName (const FObject* lhs, const FObject* rhs)
|
|
|
|
{
|
|
|
|
const FListViewItem* l_item = static_cast<const FListViewItem*>(lhs);
|
|
|
|
const FListViewItem* r_item = static_cast<const FListViewItem*>(rhs);
|
|
|
|
const int column = l_item->getSortColumn();
|
|
|
|
const FString l_string = l_item->getText(column);
|
|
|
|
const FString r_string = r_item->getText(column);
|
|
|
|
|
|
|
|
// lhs > rhs
|
|
|
|
return bool( strcasecmp(l_string.c_str(), r_string.c_str()) > 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool sortAscendingByNumber (const FObject* lhs, const FObject* rhs)
|
|
|
|
{
|
|
|
|
const FListViewItem* l_item = static_cast<const FListViewItem*>(lhs);
|
|
|
|
const FListViewItem* r_item = static_cast<const FListViewItem*>(rhs);
|
|
|
|
const int column = l_item->getSortColumn();
|
|
|
|
const long l_number = firstNumberFromString(l_item->getText(column));
|
|
|
|
const long r_number = firstNumberFromString(r_item->getText(column));
|
|
|
|
|
|
|
|
// lhs < rhs
|
|
|
|
return bool( l_number < r_number );
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool sortDescendingByNumber (const FObject* lhs, const FObject* rhs)
|
|
|
|
{
|
|
|
|
const FListViewItem* l_item = static_cast<const FListViewItem*>(lhs);
|
|
|
|
const FListViewItem* r_item = static_cast<const FListViewItem*>(rhs);
|
|
|
|
const int column = l_item->getSortColumn();
|
|
|
|
const long l_number = firstNumberFromString(l_item->getText(column));
|
|
|
|
const long r_number = firstNumberFromString(r_item->getText(column));
|
|
|
|
|
|
|
|
// lhs > rhs
|
|
|
|
return bool( l_number > r_number );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// class FListViewItem
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
// constructor and destructor
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FListViewItem::FListViewItem (const FListViewItem& item)
|
|
|
|
: FObject(item.getParent())
|
2017-09-15 01:31:02 +02:00
|
|
|
, column_list(item.column_list)
|
2017-07-18 23:50:51 +02:00
|
|
|
, data_pointer(item.data_pointer)
|
2018-09-28 06:45:02 +02:00
|
|
|
, root()
|
2017-08-20 17:30:30 +02:00
|
|
|
, visible_lines(1)
|
|
|
|
, expandable(false)
|
|
|
|
, is_expand(false)
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-07-23 01:19:59 +02:00
|
|
|
FObject* parent = getParent();
|
|
|
|
|
2017-09-16 01:21:16 +02:00
|
|
|
if ( ! parent )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( parent->isInstanceOf("FListView") )
|
|
|
|
{
|
2017-07-23 01:19:59 +02:00
|
|
|
static_cast<FListView*>(parent)->insert (this);
|
2017-09-16 01:21:16 +02:00
|
|
|
}
|
|
|
|
else if ( parent->isInstanceOf("FListViewItem") )
|
|
|
|
{
|
|
|
|
static_cast<FListViewItem*>(parent)->insert (this);
|
|
|
|
}
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
2017-07-28 22:18:42 +02:00
|
|
|
//----------------------------------------------------------------------
|
2017-09-15 01:31:02 +02:00
|
|
|
FListViewItem::FListViewItem (FObjectIterator parent_iter)
|
2017-10-14 22:20:19 +02:00
|
|
|
: FObject((*parent_iter)->getParent())
|
2017-09-15 01:31:02 +02:00
|
|
|
, column_list()
|
2017-08-20 17:30:30 +02:00
|
|
|
, data_pointer(0)
|
2018-09-28 06:45:02 +02:00
|
|
|
, root()
|
2017-08-20 17:30:30 +02:00
|
|
|
, visible_lines(1)
|
|
|
|
, expandable(false)
|
|
|
|
, is_expand(false)
|
2017-07-28 22:18:42 +02:00
|
|
|
{
|
2017-09-16 01:21:16 +02:00
|
|
|
insert (this, parent_iter);
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2017-09-20 16:56:20 +02:00
|
|
|
FListViewItem::FListViewItem ( const FStringList& cols
|
2017-07-18 23:50:51 +02:00
|
|
|
, FWidget::data_ptr data
|
2017-09-15 01:31:02 +02:00
|
|
|
, FObjectIterator parent_iter )
|
|
|
|
: FObject(0)
|
|
|
|
, column_list(cols)
|
2017-07-18 23:50:51 +02:00
|
|
|
, data_pointer(data)
|
2018-09-28 06:45:02 +02:00
|
|
|
, root()
|
2017-08-20 17:30:30 +02:00
|
|
|
, visible_lines(1)
|
|
|
|
, expandable(false)
|
|
|
|
, is_expand(false)
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-09-15 01:31:02 +02:00
|
|
|
if ( cols.empty() )
|
|
|
|
return;
|
|
|
|
|
2017-09-16 01:21:16 +02:00
|
|
|
replaceControlCodes();
|
|
|
|
insert (this, parent_iter);
|
2017-08-20 17:30:30 +02:00
|
|
|
}
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
//----------------------------------------------------------------------
|
2017-09-11 03:06:02 +02:00
|
|
|
FListViewItem::~FListViewItem() // destructor
|
2017-07-18 23:50:51 +02:00
|
|
|
{ }
|
|
|
|
|
2017-08-20 17:30:30 +02:00
|
|
|
|
2017-08-01 00:56:12 +02:00
|
|
|
// public methods of FListViewItem
|
2018-09-28 06:45:02 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
int FListViewItem::getSortColumn() const
|
|
|
|
{
|
|
|
|
if ( ! *root )
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
FListView* root_obj = static_cast<FListView*>(*root);
|
|
|
|
return root_obj->getSortColumn();
|
|
|
|
}
|
|
|
|
|
2017-08-01 00:56:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString FListViewItem::getText (int column) const
|
|
|
|
{
|
2017-09-03 18:32:43 +02:00
|
|
|
if ( column < 1
|
2017-11-26 22:37:18 +01:00
|
|
|
|| column_list.empty()
|
|
|
|
|| column > int(column_list.size()) )
|
2017-12-17 01:06:53 +01:00
|
|
|
return fc::emptyFString::get();
|
2017-08-01 00:56:12 +02:00
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
// Convert column position to address offset (index)
|
|
|
|
std::size_t index = uInt(column - 1);
|
|
|
|
return column_list[index];
|
2017-08-01 00:56:12 +02:00
|
|
|
}
|
|
|
|
|
2017-09-19 06:18:03 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
uInt FListViewItem::getDepth() const
|
|
|
|
{
|
|
|
|
FObject* parent = getParent();
|
|
|
|
|
|
|
|
if ( parent && parent->isInstanceOf("FListViewItem") )
|
|
|
|
{
|
|
|
|
FListViewItem* parent_item = static_cast<FListViewItem*>(parent);
|
|
|
|
return parent_item->getDepth() + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-08-01 00:56:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListViewItem::setText (int column, const FString& text)
|
|
|
|
{
|
2017-09-03 18:32:43 +02:00
|
|
|
if ( column < 1
|
2017-11-26 22:37:18 +01:00
|
|
|
|| column_list.empty()
|
|
|
|
|| column > int(column_list.size()) )
|
2017-08-01 00:56:12 +02:00
|
|
|
return;
|
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
// Convert column position to address offset (index)
|
|
|
|
std::size_t index = uInt(column - 1);
|
2017-08-01 00:56:12 +02:00
|
|
|
FObject* parent = getParent();
|
|
|
|
|
|
|
|
if ( parent && parent->isInstanceOf("FListView") )
|
|
|
|
{
|
|
|
|
FListView* listview = static_cast<FListView*>(parent);
|
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
if ( ! listview->header[index].fixed_width )
|
2017-08-01 00:56:12 +02:00
|
|
|
{
|
|
|
|
int length = int(text.getLength());
|
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
if ( length > listview->header[index].width )
|
|
|
|
listview->header[index].width = length;
|
2017-08-01 00:56:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
column_list[index] = text;
|
2017-08-01 00:56:12 +02:00
|
|
|
}
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-08-20 17:30:30 +02:00
|
|
|
//----------------------------------------------------------------------
|
2017-09-16 01:21:16 +02:00
|
|
|
FObject::FObjectIterator FListViewItem::insert (FListViewItem* child)
|
2017-08-20 17:30:30 +02:00
|
|
|
{
|
2017-09-09 22:03:17 +02:00
|
|
|
// Add a FListViewItem as child element
|
2017-09-17 01:50:41 +02:00
|
|
|
if ( ! child )
|
2017-12-25 21:17:08 +01:00
|
|
|
return FListView::null_iter;
|
2017-08-20 17:30:30 +02:00
|
|
|
|
2017-09-16 01:21:16 +02:00
|
|
|
return appendItem(child);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FObject::FObjectIterator FListViewItem::insert ( FListViewItem* child
|
|
|
|
, FObjectIterator parent_iter )
|
|
|
|
{
|
2017-12-25 21:17:08 +01:00
|
|
|
if ( parent_iter == FListView::null_iter )
|
|
|
|
return FListView::null_iter;
|
2017-09-16 01:21:16 +02:00
|
|
|
|
|
|
|
if ( *parent_iter )
|
|
|
|
{
|
|
|
|
if ( (*parent_iter)->isInstanceOf("FListView") )
|
|
|
|
{
|
|
|
|
// Add FListViewItem to a FListView parent
|
|
|
|
FListView* parent = static_cast<FListView*>(*parent_iter);
|
|
|
|
return parent->insert (child);
|
|
|
|
}
|
|
|
|
else if ( (*parent_iter)->isInstanceOf("FListViewItem") )
|
|
|
|
{
|
|
|
|
// Add FListViewItem to a FListViewItem parent
|
|
|
|
FListViewItem* parent = static_cast<FListViewItem*>(*parent_iter);
|
|
|
|
return parent->insert (child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-25 21:17:08 +01:00
|
|
|
return FListView::null_iter;
|
2017-08-20 17:30:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListViewItem::expand()
|
|
|
|
{
|
|
|
|
if ( is_expand || ! hasChildren() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
is_expand = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListViewItem::collapse()
|
|
|
|
{
|
|
|
|
if ( ! is_expand )
|
|
|
|
return;
|
|
|
|
|
|
|
|
is_expand = false;
|
2017-10-14 22:20:19 +02:00
|
|
|
visible_lines = 1;
|
2017-08-20 17:30:30 +02:00
|
|
|
}
|
|
|
|
|
2017-09-16 01:21:16 +02:00
|
|
|
// private methods of FListView
|
2018-09-28 06:45:02 +02:00
|
|
|
//----------------------------------------------------------------------
|
2018-10-20 22:50:35 +02:00
|
|
|
template <typename Compare>
|
2018-09-28 06:45:02 +02:00
|
|
|
void FListViewItem::sort (Compare cmp)
|
|
|
|
{
|
|
|
|
if ( ! expandable )
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Sort the top level
|
2018-10-08 04:14:20 +02:00
|
|
|
FObject::FObjectList& children = getChildren();
|
2018-09-28 06:45:02 +02:00
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
if ( ! children.empty() )
|
|
|
|
children.sort(cmp);
|
2018-09-28 06:45:02 +02:00
|
|
|
|
|
|
|
// Sort the sublevels
|
2018-10-08 04:14:20 +02:00
|
|
|
FListViewIterator iter = begin();
|
2018-09-28 06:45:02 +02:00
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
while ( iter != end() )
|
2018-09-28 06:45:02 +02:00
|
|
|
{
|
|
|
|
if ( *iter )
|
|
|
|
{
|
|
|
|
FListViewItem* item = static_cast<FListViewItem*>(*iter);
|
|
|
|
item->sort(cmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-16 01:21:16 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FObject::FObjectIterator FListViewItem::appendItem (FListViewItem* child)
|
|
|
|
{
|
|
|
|
expandable = true;
|
2017-10-14 22:20:19 +02:00
|
|
|
resetVisibleLineCounter();
|
2018-09-28 06:45:02 +02:00
|
|
|
child->root = root;
|
2017-09-16 01:21:16 +02:00
|
|
|
addChild (child);
|
2017-10-14 22:20:19 +02:00
|
|
|
// Return iterator to child/last element
|
2017-09-17 01:50:41 +02:00
|
|
|
return --FObject::end();
|
2017-09-16 01:21:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListViewItem::replaceControlCodes()
|
|
|
|
{
|
|
|
|
// Replace the control codes characters
|
2017-09-20 16:56:20 +02:00
|
|
|
FStringList::iterator iter = column_list.begin();
|
2017-09-16 01:21:16 +02:00
|
|
|
|
|
|
|
while ( iter != column_list.end() )
|
|
|
|
{
|
|
|
|
*iter = iter->replaceControlCodes();
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-20 17:30:30 +02:00
|
|
|
//----------------------------------------------------------------------
|
2018-10-17 22:12:52 +02:00
|
|
|
std::size_t FListViewItem::getVisibleLines()
|
2017-08-20 17:30:30 +02:00
|
|
|
{
|
|
|
|
if ( visible_lines > 1 )
|
|
|
|
return visible_lines;
|
|
|
|
|
|
|
|
if ( ! isExpand() || ! hasChildren() )
|
|
|
|
{
|
2017-09-09 22:03:17 +02:00
|
|
|
visible_lines = 1;
|
|
|
|
return visible_lines;
|
2017-08-20 17:30:30 +02:00
|
|
|
}
|
|
|
|
|
2017-09-17 01:50:41 +02:00
|
|
|
constFObjectIterator iter = FObject::begin();
|
2017-08-20 17:30:30 +02:00
|
|
|
|
2017-09-17 01:50:41 +02:00
|
|
|
while ( iter != FObject::end() )
|
2017-08-20 17:30:30 +02:00
|
|
|
{
|
|
|
|
FListViewItem* child = static_cast<FListViewItem*>(*iter);
|
|
|
|
visible_lines += child->getVisibleLines();
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
return visible_lines;
|
|
|
|
}
|
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListViewItem::resetVisibleLineCounter()
|
|
|
|
{
|
|
|
|
visible_lines = 0;
|
|
|
|
FObject* parent = getParent();
|
|
|
|
|
|
|
|
if ( parent && parent->isInstanceOf("FListViewItem") )
|
|
|
|
{
|
|
|
|
FListViewItem* parent_item = static_cast<FListViewItem*>(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 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-01-02 20:38:45 +01:00
|
|
|
FListViewIterator& FListViewIterator::operator += (volatile int n)
|
2017-10-14 22:20:19 +02:00
|
|
|
{
|
|
|
|
while ( n > 0 )
|
|
|
|
{
|
|
|
|
nextElement(node);
|
|
|
|
n--;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-01-02 20:38:45 +01:00
|
|
|
FListViewIterator& FListViewIterator::operator -= (volatile int n)
|
2017-10-14 22:20:19 +02:00
|
|
|
{
|
|
|
|
while ( n > 0 )
|
|
|
|
{
|
|
|
|
prevElement(node);
|
|
|
|
n--;
|
|
|
|
}
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
// private methods of FListViewIterator
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListViewIterator::nextElement (FObjectIterator& iter)
|
|
|
|
{
|
|
|
|
FListViewItem* item = static_cast<FListViewItem*>(*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<FListViewItem*>(*iter);
|
|
|
|
|
|
|
|
if ( iter == start_iter )
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
position--;
|
|
|
|
|
|
|
|
while ( item->isExpandable() && item->isExpand() )
|
|
|
|
{
|
|
|
|
iter_path.push(iter);
|
|
|
|
iter = item->end();
|
|
|
|
--iter;
|
|
|
|
item = static_cast<FListViewItem*>(*iter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListViewIterator::parentElement()
|
|
|
|
{
|
|
|
|
if ( iter_path.empty() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
FObjectIterator& parent_iter = iter_path.top();
|
|
|
|
|
|
|
|
while ( node != parent_iter )
|
|
|
|
prevElement(node);
|
|
|
|
}
|
|
|
|
|
2017-08-20 17:30:30 +02:00
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// class FListView
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
|
|
|
// constructor and destructor
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FListView::FListView (FWidget* parent)
|
|
|
|
: FWidget(parent)
|
2017-09-15 01:31:02 +02:00
|
|
|
, root()
|
|
|
|
, selflist()
|
|
|
|
, itemlist()
|
2017-10-14 22:20:19 +02:00
|
|
|
, current_iter()
|
|
|
|
, first_visible_line()
|
|
|
|
, last_visible_line()
|
2017-07-18 23:50:51 +02:00
|
|
|
, header()
|
|
|
|
, headerline()
|
|
|
|
, vbar(0)
|
|
|
|
, hbar(0)
|
|
|
|
, drag_scroll(fc::noScroll)
|
|
|
|
, scroll_repeat(100)
|
|
|
|
, scroll_distance(1)
|
2017-08-20 17:30:30 +02:00
|
|
|
, scroll_timer(false)
|
|
|
|
, tree_view(false)
|
2018-11-10 00:53:57 +01:00
|
|
|
, hide_sort_indicator(false)
|
2017-10-23 16:16:06 +02:00
|
|
|
, clicked_expander_pos(-1, -1)
|
2018-11-12 22:40:16 +01:00
|
|
|
, clicked_column_pos(-1, -1)
|
2017-07-18 23:50:51 +02:00
|
|
|
, xoffset(0)
|
|
|
|
, nf_offset(0)
|
|
|
|
, max_line_width(1)
|
2018-09-28 06:45:02 +02:00
|
|
|
, sort_column(-1)
|
|
|
|
, sort_type()
|
|
|
|
, sort_order(fc::unsorted)
|
|
|
|
, user_defined_ascending(0)
|
|
|
|
, user_defined_descending(0)
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FListView::~FListView() // destructor
|
|
|
|
{
|
|
|
|
delOwnTimer();
|
|
|
|
delete vbar;
|
|
|
|
delete hbar;
|
|
|
|
}
|
|
|
|
|
|
|
|
// public methods of FListView
|
2017-10-14 22:20:19 +02:00
|
|
|
//----------------------------------------------------------------------
|
2018-10-14 06:25:33 +02:00
|
|
|
std::size_t FListView::getCount()
|
2017-10-14 22:20:19 +02:00
|
|
|
{
|
|
|
|
int n = 0;
|
|
|
|
FObjectIterator iter = itemlist.begin();
|
|
|
|
|
|
|
|
while ( iter != itemlist.end() )
|
|
|
|
{
|
|
|
|
FListViewItem* item = static_cast<FListViewItem*>(*iter);
|
|
|
|
n += item->getVisibleLines();
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
return std::size_t(n);
|
2017-10-14 22:20:19 +02:00
|
|
|
}
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
//----------------------------------------------------------------------
|
2017-08-01 00:56:12 +02:00
|
|
|
fc::text_alignment FListView::getColumnAlignment (int column) const
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-07-28 22:18:42 +02:00
|
|
|
// Get the alignment for a column
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-09-03 18:32:43 +02:00
|
|
|
if ( column < 1 || header.empty() || column > int(header.size()) )
|
2017-07-28 22:18:42 +02:00
|
|
|
return fc::alignLeft;
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
// Convert column position to address offset (index)
|
|
|
|
std::size_t index = uInt(column - 1);
|
|
|
|
return header[index].alignment;
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 00:56:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FString FListView::getColumnText (int column) const
|
|
|
|
{
|
|
|
|
// Get the text of column
|
|
|
|
|
2017-09-03 18:32:43 +02:00
|
|
|
if ( column < 1 || header.empty() || column > int(header.size()) )
|
2017-12-17 01:06:53 +01:00
|
|
|
return fc::emptyFString::get();
|
2017-08-01 00:56:12 +02:00
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
// Convert column position to address offset (index)
|
|
|
|
std::size_t index = uInt(column - 1);
|
|
|
|
return header[index].name;
|
2017-08-01 00:56:12 +02:00
|
|
|
}
|
|
|
|
|
2018-09-28 06:45:02 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
fc::sorting_type FListView::getColumnSortType (int column) const
|
|
|
|
{
|
|
|
|
fc::sorting_type type;
|
2018-10-08 04:14:20 +02:00
|
|
|
std::size_t col = uInt(column);
|
2018-09-28 06:45:02 +02:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2018-10-08 04:14:20 +02:00
|
|
|
type = sort_type.at(col);
|
2018-09-28 06:45:02 +02:00
|
|
|
}
|
|
|
|
catch (const std::out_of_range&)
|
|
|
|
{
|
|
|
|
type = fc::unknown;
|
|
|
|
}
|
|
|
|
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
//----------------------------------------------------------------------
|
2018-10-24 00:16:45 +02:00
|
|
|
void FListView::setGeometry ( int x, int y
|
|
|
|
, std::size_t w, std::size_t h
|
|
|
|
, bool adjust )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-08-06 17:02:19 +02:00
|
|
|
// Set the widget geometry
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
FWidget::setGeometry(x, y, w, h, adjust);
|
|
|
|
|
|
|
|
if ( isNewFont() )
|
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
vbar->setGeometry (int(getWidth()), 2, 2, getHeight() - 2);
|
|
|
|
hbar->setGeometry (1, int(getHeight()), getWidth() - 2, 1);
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
vbar->setGeometry (int(getWidth()), 2, 1, getHeight() - 2);
|
|
|
|
hbar->setGeometry (2, int(getHeight()), getWidth() - 2, 1);
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-28 22:18:42 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::setColumnAlignment (int column, fc::text_alignment align)
|
|
|
|
{
|
|
|
|
// Set the alignment for a column
|
|
|
|
|
2017-09-03 18:32:43 +02:00
|
|
|
if ( column < 1 || header.empty() || column > int(header.size()) )
|
2017-09-15 01:31:02 +02:00
|
|
|
return;
|
2017-07-28 22:18:42 +02:00
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
// Convert column position to address offset (index)
|
|
|
|
std::size_t index = uInt(column - 1);
|
|
|
|
header[index].alignment = align;
|
2017-07-28 22:18:42 +02:00
|
|
|
}
|
|
|
|
|
2017-08-01 00:56:12 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::setColumnText (int column, const FString& label)
|
|
|
|
{
|
|
|
|
// Set the text for a column
|
|
|
|
|
2017-09-03 18:32:43 +02:00
|
|
|
if ( column < 1 || header.empty() || column > int(header.size()) )
|
2017-08-01 00:56:12 +02:00
|
|
|
return;
|
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
// Convert column position to address offset (index)
|
|
|
|
std::size_t index = uInt(column - 1);
|
2017-09-06 02:15:00 +02:00
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
if ( ! header[index].fixed_width )
|
2017-08-01 00:56:12 +02:00
|
|
|
{
|
|
|
|
int length = int(label.getLength());
|
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
if ( length > header[index].width )
|
|
|
|
header[index].width = length;
|
2017-08-01 00:56:12 +02:00
|
|
|
}
|
|
|
|
|
2018-10-08 04:14:20 +02:00
|
|
|
header[index].name = label;
|
2017-08-01 00:56:12 +02:00
|
|
|
}
|
|
|
|
|
2018-09-28 06:45:02 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::setColumnSortType (int column, fc::sorting_type type)
|
|
|
|
{
|
|
|
|
// Sets the sort type by which the list is to be sorted
|
|
|
|
|
|
|
|
if ( column < 1 || header.empty() || column > int(header.size()) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::size_t size = uInt(column + 1);
|
|
|
|
|
|
|
|
if ( sort_type.empty() || sort_type.size() < size )
|
|
|
|
sort_type.resize(size);
|
|
|
|
|
|
|
|
sort_type[uInt(column)] = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::setColumnSort (int column, fc::sorting_order order)
|
|
|
|
{
|
|
|
|
// Sets the column to sort by + the sorting order
|
|
|
|
|
|
|
|
if ( column < 1 || header.empty() || column > int(header.size()) )
|
|
|
|
column = -1;
|
|
|
|
|
|
|
|
sort_column = column;
|
|
|
|
sort_order = order;
|
|
|
|
}
|
|
|
|
|
2017-07-28 22:18:42 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
int FListView::addColumn (const FString& label, int width)
|
|
|
|
{
|
2017-09-03 18:32:43 +02:00
|
|
|
Header new_column;
|
|
|
|
new_column.name = label;
|
|
|
|
new_column.width = width;
|
2017-07-28 22:18:42 +02:00
|
|
|
|
2017-09-03 18:32:43 +02:00
|
|
|
if ( new_column.width == USE_MAX_SIZE )
|
2017-07-28 22:18:42 +02:00
|
|
|
{
|
2017-09-03 18:32:43 +02:00
|
|
|
new_column.fixed_width = false;
|
|
|
|
new_column.width = int(label.getLength());
|
2017-07-28 22:18:42 +02:00
|
|
|
}
|
|
|
|
else
|
2017-09-03 18:32:43 +02:00
|
|
|
new_column.fixed_width = true;
|
2017-07-28 22:18:42 +02:00
|
|
|
|
2017-09-03 18:32:43 +02:00
|
|
|
header.push_back (new_column);
|
2017-07-28 22:18:42 +02:00
|
|
|
return int(std::distance(header.begin(), header.end()));
|
|
|
|
}
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
//----------------------------------------------------------------------
|
2017-09-15 01:31:02 +02:00
|
|
|
FObject::FObjectIterator FListView::insert ( FListViewItem* item
|
|
|
|
, FObjectIterator parent_iter )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-09-15 01:31:02 +02:00
|
|
|
FObjectIterator item_iter;
|
2018-10-01 22:27:54 +02:00
|
|
|
int line_width;
|
|
|
|
int element_count;
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-12-25 21:17:08 +01:00
|
|
|
if ( parent_iter == FListView::null_iter )
|
|
|
|
return FListView::null_iter;
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-10-01 22:27:54 +02:00
|
|
|
line_width = determineLineWidth (item);
|
2017-07-18 23:50:51 +02:00
|
|
|
recalculateHorizontalBar (line_width);
|
|
|
|
|
2017-09-15 01:31:02 +02:00
|
|
|
if ( parent_iter == root )
|
|
|
|
{
|
2017-09-16 01:21:16 +02:00
|
|
|
item_iter = appendItem (item);
|
2017-09-15 01:31:02 +02:00
|
|
|
}
|
|
|
|
else if ( *parent_iter )
|
|
|
|
{
|
|
|
|
if ( (*parent_iter)->isInstanceOf("FListView") )
|
|
|
|
{
|
|
|
|
// Add FListViewItem to a FListView parent
|
|
|
|
FListView* parent = static_cast<FListView*>(*parent_iter);
|
2017-09-16 01:21:16 +02:00
|
|
|
item_iter = parent->appendItem (item);
|
2017-09-15 01:31:02 +02:00
|
|
|
}
|
|
|
|
else if ( (*parent_iter)->isInstanceOf("FListViewItem") )
|
|
|
|
{
|
|
|
|
// Add FListViewItem to a FListViewItem parent
|
|
|
|
FListViewItem* parent = static_cast<FListViewItem*>(*parent_iter);
|
2017-09-16 01:21:16 +02:00
|
|
|
item_iter = parent->appendItem (item);
|
2017-09-15 01:31:02 +02:00
|
|
|
}
|
2017-10-14 22:20:19 +02:00
|
|
|
else
|
2017-12-25 21:17:08 +01:00
|
|
|
item_iter = FListView::null_iter;
|
2017-09-15 01:31:02 +02:00
|
|
|
}
|
2017-09-19 06:18:03 +02:00
|
|
|
else
|
2017-12-25 21:17:08 +01:00
|
|
|
item_iter = FListView::null_iter;
|
2017-09-15 01:31:02 +02:00
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2018-09-28 06:45:02 +02:00
|
|
|
// Sort list by a column (only if activated)
|
|
|
|
sort();
|
|
|
|
|
2018-10-01 22:27:54 +02:00
|
|
|
element_count = int(getCount());
|
2017-07-18 23:50:51 +02:00
|
|
|
recalculateVerticalBar (element_count);
|
2017-09-15 01:31:02 +02:00
|
|
|
return item_iter;
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2017-09-20 16:56:20 +02:00
|
|
|
FObject::FObjectIterator FListView::insert ( const FStringList& cols
|
2017-09-15 01:31:02 +02:00
|
|
|
, data_ptr d
|
|
|
|
, FObjectIterator parent_iter )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-09-15 01:31:02 +02:00
|
|
|
FListViewItem* item;
|
|
|
|
|
2017-12-25 21:17:08 +01:00
|
|
|
if ( cols.empty() || parent_iter == FListView::null_iter )
|
|
|
|
return FListView::null_iter;
|
2017-09-16 01:21:16 +02:00
|
|
|
|
2017-09-15 01:31:02 +02:00
|
|
|
if ( ! *parent_iter )
|
|
|
|
parent_iter = root;
|
|
|
|
|
2017-08-12 22:55:29 +02:00
|
|
|
try
|
|
|
|
{
|
2017-12-25 21:17:08 +01:00
|
|
|
item = new FListViewItem (cols, d, FListView::null_iter);
|
2017-08-12 22:55:29 +02:00
|
|
|
}
|
|
|
|
catch (const std::bad_alloc& ex)
|
|
|
|
{
|
|
|
|
std::cerr << "not enough memory to alloc " << ex.what() << std::endl;
|
2017-12-25 21:17:08 +01:00
|
|
|
return FListView::null_iter;
|
2017-08-12 22:55:29 +02:00
|
|
|
}
|
2017-09-15 01:31:02 +02:00
|
|
|
|
2017-09-16 01:21:16 +02:00
|
|
|
item->replaceControlCodes();
|
2017-09-15 01:31:02 +02:00
|
|
|
return insert(item, parent_iter);
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2017-09-15 01:31:02 +02:00
|
|
|
FObject::FObjectIterator FListView::insert ( const std::vector<long>& cols
|
|
|
|
, data_ptr d
|
|
|
|
, FObjectIterator parent_iter )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-09-15 01:31:02 +02:00
|
|
|
FObjectIterator item_iter;
|
2017-09-20 16:56:20 +02:00
|
|
|
FStringList str_cols;
|
2017-07-18 23:50:51 +02:00
|
|
|
|
|
|
|
if ( ! cols.empty() )
|
|
|
|
{
|
2017-08-27 09:50:30 +02:00
|
|
|
for (uInt i = 0; i < cols.size(); i++)
|
2017-07-18 23:50:51 +02:00
|
|
|
str_cols.push_back (FString().setNumber(cols[i]));
|
|
|
|
}
|
|
|
|
|
2017-09-15 01:31:02 +02:00
|
|
|
item_iter = insert (str_cols, d, parent_iter);
|
|
|
|
|
|
|
|
return item_iter;
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
2018-09-28 06:45:02 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::sort()
|
|
|
|
{
|
|
|
|
// Sorts the list view according to the specified setting
|
|
|
|
|
|
|
|
if ( sort_column < 1 && sort_column > int(header.size()) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch ( getColumnSortType(sort_column) )
|
|
|
|
{
|
|
|
|
case fc::unknown:
|
|
|
|
case fc::by_name:
|
|
|
|
if ( sort_order == fc::ascending )
|
|
|
|
{
|
|
|
|
sort (sortAscendingByName);
|
|
|
|
}
|
|
|
|
else if ( sort_order == fc::descending )
|
|
|
|
{
|
|
|
|
sort (sortDescendingByName);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::by_number:
|
|
|
|
if ( sort_order == fc::ascending )
|
|
|
|
{
|
|
|
|
sort (sortAscendingByNumber);
|
|
|
|
}
|
|
|
|
else if ( sort_order == fc::descending )
|
|
|
|
{
|
|
|
|
sort (sortDescendingByNumber);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::user_defined:
|
|
|
|
if ( sort_order == fc::ascending && user_defined_ascending )
|
|
|
|
{
|
|
|
|
sort (user_defined_ascending);
|
|
|
|
}
|
|
|
|
else if ( sort_order == fc::descending && user_defined_descending )
|
|
|
|
{
|
|
|
|
sort (user_defined_descending);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
current_iter = itemlist.begin();
|
|
|
|
first_visible_line = itemlist.begin();
|
|
|
|
}
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::onKeyPress (FKeyEvent* ev)
|
|
|
|
{
|
2017-12-03 21:06:21 +01:00
|
|
|
int position_before = current_iter.getPosition()
|
2017-10-14 22:20:19 +02:00
|
|
|
, xoffset_before = xoffset
|
|
|
|
, first_line_position_before = first_visible_line.getPosition()
|
2018-10-14 06:25:33 +02:00
|
|
|
, pagesize = int(getClientHeight()) - 1
|
2017-10-14 22:20:19 +02:00
|
|
|
, key = ev->key();
|
2017-10-23 16:16:06 +02:00
|
|
|
clicked_expander_pos.setPoint(-1, -1);
|
2017-07-18 23:50:51 +02:00
|
|
|
|
|
|
|
switch ( key )
|
|
|
|
{
|
|
|
|
case fc::Fkey_return:
|
|
|
|
case fc::Fkey_enter:
|
|
|
|
processClick();
|
|
|
|
ev->accept();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::Fkey_up:
|
2017-10-14 22:20:19 +02:00
|
|
|
stepBackward();
|
2017-07-18 23:50:51 +02:00
|
|
|
ev->accept();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::Fkey_down:
|
2017-10-14 22:20:19 +02:00
|
|
|
stepForward();
|
2017-07-18 23:50:51 +02:00
|
|
|
ev->accept();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::Fkey_left:
|
2017-12-03 21:06:21 +01:00
|
|
|
keyLeft (first_line_position_before);
|
2017-07-18 23:50:51 +02:00
|
|
|
ev->accept();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::Fkey_right:
|
2017-12-03 21:06:21 +01:00
|
|
|
keyRight(first_line_position_before);
|
2017-07-18 23:50:51 +02:00
|
|
|
ev->accept();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::Fkey_ppage:
|
2017-10-14 22:20:19 +02:00
|
|
|
stepBackward(pagesize);
|
2017-07-18 23:50:51 +02:00
|
|
|
ev->accept();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::Fkey_npage:
|
2017-10-14 22:20:19 +02:00
|
|
|
stepForward(pagesize);
|
2017-07-18 23:50:51 +02:00
|
|
|
ev->accept();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::Fkey_home:
|
2017-12-03 21:06:21 +01:00
|
|
|
keyHome();
|
2017-07-18 23:50:51 +02:00
|
|
|
ev->accept();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::Fkey_end:
|
2017-12-03 21:06:21 +01:00
|
|
|
keyEnd();
|
2017-07-18 23:50:51 +02:00
|
|
|
ev->accept();
|
|
|
|
break;
|
|
|
|
|
2017-09-16 01:21:16 +02:00
|
|
|
case int('+'):
|
2017-12-03 21:06:21 +01:00
|
|
|
if ( keyPlus() )
|
2017-11-03 05:04:27 +01:00
|
|
|
ev->accept();
|
2017-09-16 01:21:16 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case int('-'):
|
2017-12-03 21:06:21 +01:00
|
|
|
if ( keyMinus() )
|
2017-11-03 05:04:27 +01:00
|
|
|
ev->accept();
|
2017-09-16 01:21:16 +02:00
|
|
|
break;
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
default:
|
|
|
|
ev->ignore();
|
|
|
|
}
|
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( position_before != current_iter.getPosition() )
|
2017-07-18 23:50:51 +02:00
|
|
|
processChanged();
|
|
|
|
|
|
|
|
if ( ev->isAccepted() )
|
|
|
|
{
|
2017-12-03 21:06:21 +01:00
|
|
|
bool draw_vbar = first_line_position_before
|
|
|
|
!= first_visible_line.getPosition();
|
|
|
|
bool draw_hbar = xoffset_before != xoffset;
|
|
|
|
updateDrawing (draw_vbar, draw_hbar);
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::onMouseDown (FMouseEvent* ev)
|
|
|
|
{
|
2017-10-23 16:16:06 +02:00
|
|
|
if ( ev->getButton() != fc::LeftButton )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-10-23 16:16:06 +02:00
|
|
|
clicked_expander_pos.setPoint(-1, -1);
|
2017-07-18 23:50:51 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
int first_line_position_before = first_visible_line.getPosition()
|
|
|
|
, mouse_x = ev->getX()
|
|
|
|
, mouse_y = ev->getY();
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-11-12 22:40:16 +01:00
|
|
|
if ( mouse_x > 1 && mouse_x < int(getWidth()) && mouse_y == 1 )
|
|
|
|
{
|
|
|
|
clicked_column_pos = ev->getPos();
|
|
|
|
}
|
|
|
|
else if ( mouse_x > 1 && mouse_x < int(getWidth())
|
|
|
|
&& mouse_y > 1 && mouse_y < int(getHeight()) )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
int new_pos = first_visible_line.getPosition() + mouse_y - 2;
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( new_pos < int(getCount()) )
|
2017-10-15 15:27:36 +02:00
|
|
|
setRelativePosition (mouse_y - 2);
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-10-23 16:16:06 +02:00
|
|
|
if ( tree_view )
|
|
|
|
{
|
|
|
|
const FListViewItem* item = getCurrentItem();
|
|
|
|
int indent = int(item->getDepth() << 1); // indent = 2 * depth
|
|
|
|
|
|
|
|
if ( item->isExpandable() && mouse_x - 2 == indent - xoffset )
|
|
|
|
clicked_expander_pos = ev->getPos();
|
|
|
|
}
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
if ( isVisible() )
|
|
|
|
drawList();
|
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
vbar->setValue (first_visible_line.getPosition());
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( vbar->isVisible()
|
2017-11-26 22:37:18 +01:00
|
|
|
&& first_line_position_before != first_visible_line.getPosition() )
|
2017-07-18 23:50:51 +02:00
|
|
|
vbar->drawBar();
|
|
|
|
|
|
|
|
updateTerminal();
|
|
|
|
flush_out();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::onMouseUp (FMouseEvent* ev)
|
|
|
|
{
|
|
|
|
if ( drag_scroll != fc::noScroll )
|
2018-02-18 21:49:58 +01:00
|
|
|
stopDragScroll();
|
2017-07-18 23:50:51 +02:00
|
|
|
|
|
|
|
if ( ev->getButton() == fc::LeftButton )
|
|
|
|
{
|
|
|
|
int mouse_x = ev->getX();
|
|
|
|
int mouse_y = ev->getY();
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
if ( mouse_x > 1 && mouse_x < int(getWidth())
|
2018-11-12 22:40:16 +01:00
|
|
|
&& mouse_y == 1 && clicked_column_pos == ev->getPos() )
|
|
|
|
{
|
|
|
|
mouseColumnClicked();
|
|
|
|
}
|
|
|
|
else if ( mouse_x > 1 && mouse_x < int(getWidth())
|
|
|
|
&& mouse_y > 1 && mouse_y < int(getHeight()) )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-10-23 16:16:06 +02:00
|
|
|
if ( tree_view )
|
|
|
|
{
|
|
|
|
FListViewItem* item = getCurrentItem();
|
|
|
|
|
|
|
|
if ( item->isExpandable() && clicked_expander_pos == ev->getPos() )
|
|
|
|
{
|
|
|
|
if ( item->isExpand() )
|
|
|
|
item->collapse();
|
|
|
|
else
|
|
|
|
item->expand();
|
|
|
|
|
|
|
|
adjustSize();
|
|
|
|
|
|
|
|
if ( isVisible() )
|
|
|
|
draw();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
processChanged();
|
|
|
|
}
|
|
|
|
}
|
2017-10-23 16:16:06 +02:00
|
|
|
|
|
|
|
clicked_expander_pos.setPoint(-1, -1);
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::onMouseMove (FMouseEvent* ev)
|
|
|
|
{
|
2017-10-23 16:16:06 +02:00
|
|
|
if ( ev->getButton() != fc::LeftButton )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-10-23 16:16:06 +02:00
|
|
|
clicked_expander_pos.setPoint(-1, -1);
|
2017-07-18 23:50:51 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
int first_line_position_before = first_visible_line.getPosition()
|
|
|
|
, mouse_x = ev->getX()
|
|
|
|
, mouse_y = ev->getY();
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
if ( mouse_x > 1 && mouse_x < int(getWidth())
|
|
|
|
&& mouse_y > 1 && mouse_y < int(getHeight()) )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
int new_pos = first_visible_line.getPosition() + mouse_y - 2;
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( new_pos < int(getCount()) )
|
2017-10-15 15:27:36 +02:00
|
|
|
setRelativePosition (mouse_y - 2);
|
2017-07-18 23:50:51 +02:00
|
|
|
|
|
|
|
if ( isVisible() )
|
|
|
|
drawList();
|
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
vbar->setValue (first_visible_line.getPosition());
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( vbar->isVisible()
|
2017-11-26 22:37:18 +01:00
|
|
|
&& first_line_position_before != first_visible_line.getPosition() )
|
2017-07-18 23:50:51 +02:00
|
|
|
vbar->drawBar();
|
|
|
|
|
|
|
|
updateTerminal();
|
|
|
|
flush_out();
|
|
|
|
}
|
|
|
|
|
|
|
|
// auto-scrolling when dragging mouse outside the widget
|
|
|
|
if ( mouse_y < 2 )
|
2018-02-18 21:49:58 +01:00
|
|
|
dragUp (ev->getButton());
|
2018-10-14 06:25:33 +02:00
|
|
|
else if ( mouse_y >= int(getHeight()) )
|
2018-02-18 21:49:58 +01:00
|
|
|
dragDown (ev->getButton());
|
2017-07-18 23:50:51 +02:00
|
|
|
else
|
2018-02-18 21:49:58 +01:00
|
|
|
stopDragScroll();
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::onMouseDoubleClick (FMouseEvent* ev)
|
|
|
|
{
|
|
|
|
int mouse_x, mouse_y;
|
|
|
|
|
|
|
|
if ( ev->getButton() != fc::LeftButton )
|
|
|
|
return;
|
|
|
|
|
|
|
|
mouse_x = ev->getX();
|
|
|
|
mouse_y = ev->getY();
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
if ( mouse_x > 1 && mouse_x < int(getWidth())
|
|
|
|
&& mouse_y > 1 && mouse_y < int(getHeight()) )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( first_visible_line.getPosition() + mouse_y - 1 > int(getCount()) )
|
2017-07-18 23:50:51 +02:00
|
|
|
return;
|
|
|
|
|
2017-10-18 23:07:15 +02:00
|
|
|
FListViewItem* item = getCurrentItem();
|
|
|
|
|
2017-11-03 05:04:27 +01:00
|
|
|
if ( tree_view && item->isExpandable() )
|
2017-10-18 23:07:15 +02:00
|
|
|
{
|
|
|
|
if ( item->isExpand() )
|
|
|
|
item->collapse();
|
|
|
|
else
|
|
|
|
item->expand();
|
|
|
|
|
|
|
|
adjustSize();
|
|
|
|
|
|
|
|
if ( isVisible() )
|
|
|
|
draw();
|
|
|
|
}
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
processClick();
|
|
|
|
}
|
2017-10-23 16:16:06 +02:00
|
|
|
|
|
|
|
clicked_expander_pos.setPoint(-1, -1);
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::onTimer (FTimerEvent*)
|
|
|
|
{
|
2018-02-11 23:41:23 +01:00
|
|
|
int position_before = current_iter.getPosition()
|
2017-10-14 22:20:19 +02:00
|
|
|
, first_line_position_before = first_visible_line.getPosition();
|
2017-07-18 23:50:51 +02:00
|
|
|
|
|
|
|
switch ( int(drag_scroll) )
|
|
|
|
{
|
|
|
|
case fc::noScroll:
|
|
|
|
return;
|
|
|
|
|
|
|
|
case fc::scrollUp:
|
|
|
|
case fc::scrollUpSelect:
|
2018-02-11 23:41:23 +01:00
|
|
|
if ( ! dragScrollUp(position_before) )
|
2017-07-18 23:50:51 +02:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::scrollDown:
|
|
|
|
case fc::scrollDownSelect:
|
2018-02-11 23:41:23 +01:00
|
|
|
if ( ! dragScrollDown(position_before) )
|
2017-07-18 23:50:51 +02:00
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( isVisible() )
|
|
|
|
drawList();
|
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
vbar->setValue (first_visible_line.getPosition());
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-11-26 22:37:18 +01:00
|
|
|
if ( vbar->isVisible()
|
|
|
|
&& first_line_position_before != first_visible_line.getPosition() )
|
2017-07-18 23:50:51 +02:00
|
|
|
vbar->drawBar();
|
|
|
|
|
|
|
|
updateTerminal();
|
|
|
|
flush_out();
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::onWheel (FWheelEvent* ev)
|
|
|
|
{
|
2018-02-11 23:41:23 +01:00
|
|
|
int position_before = current_iter.getPosition()
|
2017-10-14 22:20:19 +02:00
|
|
|
, first_line_position_before = first_visible_line.getPosition()
|
|
|
|
, pagesize = 4;
|
2017-07-18 23:50:51 +02:00
|
|
|
|
|
|
|
if ( drag_scroll != fc::noScroll )
|
2018-02-18 21:49:58 +01:00
|
|
|
stopDragScroll();
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-02-11 23:41:23 +01:00
|
|
|
switch ( ev->getWheel() )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
|
|
|
case fc::WheelUp:
|
2018-02-11 23:41:23 +01:00
|
|
|
wheelUp (pagesize);
|
2017-07-18 23:50:51 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case fc::WheelDown:
|
2018-02-11 23:41:23 +01:00
|
|
|
wheelDown (pagesize);
|
2017-07-18 23:50:51 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( position_before != current_iter.getPosition() )
|
2017-07-18 23:50:51 +02:00
|
|
|
processChanged();
|
|
|
|
|
|
|
|
if ( isVisible() )
|
|
|
|
drawList();
|
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
vbar->setValue (first_visible_line.getPosition());
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( vbar->isVisible()
|
|
|
|
&& first_line_position_before != first_visible_line.getPosition() )
|
2017-07-18 23:50:51 +02:00
|
|
|
vbar->drawBar();
|
|
|
|
|
|
|
|
updateTerminal();
|
|
|
|
flush_out();
|
|
|
|
}
|
2017-08-27 09:50:30 +02:00
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::onFocusIn (FFocusEvent*)
|
|
|
|
{
|
|
|
|
if ( getStatusBar() )
|
|
|
|
getStatusBar()->drawMessage();
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::onFocusOut (FFocusEvent*)
|
|
|
|
{
|
|
|
|
if ( getStatusBar() )
|
|
|
|
{
|
|
|
|
getStatusBar()->clearMessage();
|
|
|
|
getStatusBar()->drawMessage();
|
|
|
|
}
|
|
|
|
|
|
|
|
delOwnTimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// protected methods of FListView
|
|
|
|
//----------------------------------------------------------------------
|
2017-10-14 22:20:19 +02:00
|
|
|
void FListView::adjustViewport()
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-09-16 01:21:16 +02:00
|
|
|
int element_count = int(getCount());
|
2018-10-14 06:25:33 +02:00
|
|
|
int height = int(getClientHeight());
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-10-18 23:07:15 +02:00
|
|
|
if ( element_count == 0 || height <= 0 )
|
2017-10-14 22:20:19 +02:00
|
|
|
return;
|
|
|
|
|
2017-10-18 23:07:15 +02:00
|
|
|
if ( element_count < height )
|
2017-10-14 22:20:19 +02:00
|
|
|
{
|
|
|
|
first_visible_line = itemlist.begin();
|
|
|
|
last_visible_line = first_visible_line;
|
|
|
|
last_visible_line += element_count - 1;
|
|
|
|
}
|
|
|
|
|
2017-10-18 23:07:15 +02:00
|
|
|
if ( first_visible_line.getPosition() > element_count - height )
|
2017-10-14 22:20:19 +02:00
|
|
|
{
|
2017-10-18 23:07:15 +02:00
|
|
|
int difference = first_visible_line.getPosition()
|
|
|
|
- (element_count - height);
|
2017-10-14 22:20:19 +02:00
|
|
|
|
2018-01-02 20:38:45 +01:00
|
|
|
if ( first_visible_line.getPosition() >= difference )
|
2017-10-14 22:20:19 +02:00
|
|
|
{
|
|
|
|
first_visible_line -= difference;
|
|
|
|
last_visible_line -= difference;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-02 20:38:45 +01:00
|
|
|
int after_last_visible_line = first_visible_line.getPosition()
|
|
|
|
+ height;
|
2017-10-14 22:20:19 +02:00
|
|
|
|
2018-01-02 20:38:45 +01:00
|
|
|
if ( last_visible_line.getPosition() >= after_last_visible_line )
|
2017-10-14 22:20:19 +02:00
|
|
|
{
|
2017-10-18 23:07:15 +02:00
|
|
|
last_visible_line = first_visible_line;
|
|
|
|
last_visible_line += height - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( current_iter.getPosition() > last_visible_line.getPosition() )
|
|
|
|
current_iter = last_visible_line;
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::adjustSize()
|
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
std::size_t element_count;
|
2017-07-18 23:50:51 +02:00
|
|
|
FWidget::adjustSize();
|
2017-10-14 22:20:19 +02:00
|
|
|
adjustViewport();
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
element_count = getCount();
|
|
|
|
vbar->setMaximum (int(element_count - getClientHeight()));
|
|
|
|
vbar->setPageSize (int(element_count), int(getClientHeight()));
|
|
|
|
vbar->setX (int(getWidth()));
|
2017-07-18 23:50:51 +02:00
|
|
|
vbar->setHeight (getClientHeight(), false);
|
|
|
|
vbar->resize();
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
hbar->setMaximum (max_line_width - int(getClientWidth()));
|
|
|
|
hbar->setPageSize (max_line_width, int(getClientWidth()));
|
|
|
|
hbar->setY (int(getHeight()));
|
2017-07-18 23:50:51 +02:00
|
|
|
hbar->setWidth (getClientWidth(), false);
|
|
|
|
hbar->resize();
|
|
|
|
|
|
|
|
if ( element_count <= getClientHeight() )
|
|
|
|
vbar->hide();
|
|
|
|
else
|
|
|
|
vbar->setVisible();
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
if ( max_line_width <= int(getClientWidth()) )
|
2017-07-18 23:50:51 +02:00
|
|
|
hbar->hide();
|
|
|
|
else
|
|
|
|
hbar->setVisible();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// private methods of FListView
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::init()
|
|
|
|
{
|
2017-09-15 01:31:02 +02:00
|
|
|
selflist.push_back(this);
|
|
|
|
root = selflist.begin();
|
2017-11-04 07:03:53 +01:00
|
|
|
null_iter = selflist.end();
|
2017-09-15 01:31:02 +02:00
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
setForegroundColor (wc.dialog_fg);
|
|
|
|
setBackgroundColor (wc.dialog_bg);
|
|
|
|
|
2017-08-12 22:55:29 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
vbar = new FScrollbar(fc::vertical, this);
|
|
|
|
vbar->setMinimum(0);
|
|
|
|
vbar->setValue(0);
|
|
|
|
vbar->hide();
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-08-12 22:55:29 +02:00
|
|
|
hbar = new FScrollbar(fc::horizontal, this);
|
|
|
|
hbar->setMinimum(0);
|
|
|
|
hbar->setValue(0);
|
|
|
|
hbar->hide();
|
|
|
|
}
|
|
|
|
catch (const std::bad_alloc& ex)
|
|
|
|
{
|
|
|
|
std::cerr << "not enough memory to alloc " << ex.what() << std::endl;
|
|
|
|
return;
|
|
|
|
}
|
2017-07-18 23:50:51 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-09-28 06:45:02 +02:00
|
|
|
//----------------------------------------------------------------------
|
2018-10-20 22:50:35 +02:00
|
|
|
template <typename Compare>
|
2018-09-28 06:45:02 +02:00
|
|
|
void FListView::sort (Compare cmp)
|
|
|
|
{
|
|
|
|
// Sort the top level
|
|
|
|
itemlist.sort(cmp);
|
|
|
|
|
|
|
|
// Sort the sublevels
|
|
|
|
FListViewIterator iter = itemlist.begin();
|
|
|
|
|
|
|
|
while ( iter != itemlist.end() )
|
|
|
|
{
|
|
|
|
if ( *iter )
|
|
|
|
{
|
|
|
|
FListViewItem* item = static_cast<FListViewItem*>(*iter);
|
|
|
|
item->sort(cmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-28 22:18:42 +02:00
|
|
|
//----------------------------------------------------------------------
|
2018-10-14 06:25:33 +02:00
|
|
|
std::size_t FListView::getAlignOffset ( fc::text_alignment align
|
|
|
|
, std::size_t txt_length
|
|
|
|
, std::size_t width )
|
2017-07-28 22:18:42 +02:00
|
|
|
{
|
|
|
|
switch ( align )
|
|
|
|
{
|
|
|
|
case fc::alignLeft:
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case fc::alignCenter:
|
|
|
|
if ( txt_length < width )
|
2018-10-20 22:50:35 +02:00
|
|
|
return (width - txt_length) / 2;
|
2017-07-28 22:18:42 +02:00
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case fc::alignRight:
|
|
|
|
if ( txt_length < width )
|
|
|
|
return width - txt_length;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::draw()
|
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( current_iter.getPosition() < 1 )
|
|
|
|
current_iter = itemlist.begin();
|
2017-07-18 23:50:51 +02:00
|
|
|
|
|
|
|
setColor();
|
|
|
|
|
|
|
|
if ( isMonochron() )
|
|
|
|
setReverse(true);
|
|
|
|
|
|
|
|
if ( isNewFont() )
|
2018-10-14 06:25:33 +02:00
|
|
|
drawBorder (1, 1, int(getWidth()) - 1, int(getHeight()));
|
2017-07-18 23:50:51 +02:00
|
|
|
else
|
|
|
|
drawBorder();
|
|
|
|
|
|
|
|
if ( isNewFont() && ! vbar->isVisible() )
|
|
|
|
{
|
|
|
|
setColor();
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
for (int y = 2; y < int(getHeight()); y++)
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
setPrintPos (int(getWidth()), y);
|
2017-09-03 18:32:43 +02:00
|
|
|
print (' '); // clear right side of the scrollbar
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
drawColumnLabels();
|
|
|
|
|
|
|
|
if ( isMonochron() )
|
|
|
|
setReverse(false);
|
|
|
|
|
|
|
|
if ( vbar->isVisible() )
|
|
|
|
vbar->redraw();
|
|
|
|
|
|
|
|
if ( hbar->isVisible() )
|
|
|
|
hbar->redraw();
|
|
|
|
|
|
|
|
drawList();
|
|
|
|
|
2018-11-04 23:00:06 +01:00
|
|
|
if ( flags.focus && getStatusBar() )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
|
|
|
const FString& msg = getStatusbarMessage();
|
|
|
|
const FString& curMsg = getStatusBar()->getMessage();
|
|
|
|
|
|
|
|
if ( curMsg != msg )
|
|
|
|
{
|
|
|
|
getStatusBar()->setMessage(msg);
|
|
|
|
getStatusBar()->drawMessage();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::drawColumnLabels()
|
|
|
|
{
|
2018-06-25 00:14:53 +02:00
|
|
|
std::vector<charData>::const_iterator first, last;
|
2017-07-18 23:50:51 +02:00
|
|
|
headerItems::const_iterator iter;
|
|
|
|
|
|
|
|
if ( header.empty()
|
2017-11-26 22:37:18 +01:00
|
|
|
|| getHeight() <= 2
|
|
|
|
|| getWidth() <= 4
|
|
|
|
|| max_line_width < 1 )
|
2017-07-18 23:50:51 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
iter = header.begin();
|
|
|
|
headerline.clear();
|
|
|
|
|
|
|
|
while ( iter != header.end() )
|
|
|
|
{
|
2018-03-16 01:05:45 +01:00
|
|
|
const FString& text = iter->name;
|
2017-07-18 23:50:51 +02:00
|
|
|
|
|
|
|
if ( text.isNull() || text.isEmpty() )
|
|
|
|
{
|
|
|
|
++iter;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-02-11 23:41:23 +01:00
|
|
|
drawColumnText(iter);
|
2017-07-18 23:50:51 +02:00
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
|
2018-06-25 00:14:53 +02:00
|
|
|
std::vector<charData> h;
|
2017-08-06 17:02:19 +02:00
|
|
|
h << headerline;
|
2017-07-18 23:50:51 +02:00
|
|
|
first = h.begin() + xoffset;
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
if ( h.size() <= getClientWidth() )
|
2017-11-03 22:57:40 +01:00
|
|
|
last = h.end();
|
2017-07-18 23:50:51 +02:00
|
|
|
else
|
2017-09-03 18:32:43 +02:00
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
int len = int(getClientWidth()) + xoffset - 1;
|
2017-09-03 18:32:43 +02:00
|
|
|
|
|
|
|
if ( len > int(h.size()) )
|
|
|
|
len = int(h.size());
|
|
|
|
|
|
|
|
last = h.begin() + len;
|
|
|
|
}
|
2017-07-23 01:19:59 +02:00
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
setPrintPos (2, 1);
|
2018-06-25 00:14:53 +02:00
|
|
|
print() << std::vector<charData>(first, last);
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::drawList()
|
|
|
|
{
|
2017-09-16 01:21:16 +02:00
|
|
|
uInt page_height, y;
|
2017-10-14 22:20:19 +02:00
|
|
|
FListViewIterator iter;
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-09-15 01:31:02 +02:00
|
|
|
if ( itemlist.empty() || getHeight() <= 2 || getWidth() <= 4 )
|
2017-07-18 23:50:51 +02:00
|
|
|
return;
|
|
|
|
|
2018-11-12 22:40:16 +01:00
|
|
|
y = 0;
|
2017-09-16 01:21:16 +02:00
|
|
|
page_height = uInt(getHeight() - 2);
|
2018-11-12 22:40:16 +01:00
|
|
|
iter = first_visible_line;
|
2017-09-16 01:21:16 +02:00
|
|
|
|
|
|
|
while ( iter != itemlist.end() && y < page_height )
|
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
bool is_current_line = bool( iter == current_iter );
|
2017-09-16 01:21:16 +02:00
|
|
|
const FListViewItem* item = static_cast<FListViewItem*>(*iter);
|
|
|
|
setPrintPos (2, 2 + int(y));
|
|
|
|
|
|
|
|
// Draw one FListViewItem
|
2018-11-04 23:00:06 +01:00
|
|
|
drawListLine (item, flags.focus, is_current_line);
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-11-04 23:00:06 +01:00
|
|
|
if ( flags.focus && is_current_line )
|
2017-09-16 01:21:16 +02:00
|
|
|
setCursorPos (3, 2 + int(y)); // first character
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
last_visible_line = iter;
|
|
|
|
y++;
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset color
|
|
|
|
setColor();
|
|
|
|
|
|
|
|
// Clean empty space after last element
|
|
|
|
while ( y < uInt(getClientHeight()) )
|
|
|
|
{
|
|
|
|
setPrintPos (2, 2 + int(y));
|
2018-10-14 06:25:33 +02:00
|
|
|
print (FString(std::size_t(getClientWidth()), ' '));
|
2017-09-16 01:21:16 +02:00
|
|
|
y++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::drawListLine ( const FListViewItem* item
|
|
|
|
, bool is_focus
|
|
|
|
, bool is_current )
|
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
std::size_t indent = item->getDepth() << 1; // indent = 2 * depth
|
2017-09-19 06:18:03 +02:00
|
|
|
|
2018-01-21 16:21:41 +01:00
|
|
|
// Set line color and attributes
|
|
|
|
setLineAttributes (is_current, is_focus);
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-01-21 16:21:41 +01:00
|
|
|
// Print the entry
|
|
|
|
FString line = getLinePrefix (item, indent);
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-01-21 16:21:41 +01:00
|
|
|
// Print columns
|
2017-09-16 01:21:16 +02:00
|
|
|
if ( ! item->column_list.empty() )
|
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
for (std::size_t i = 0; i < item->column_list.size(); )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
static const std::size_t leading_space = 1;
|
|
|
|
static const std::size_t ellipsis_length = 2;
|
2017-09-16 01:21:16 +02:00
|
|
|
|
|
|
|
const FString& text = item->column_list[i];
|
2018-10-14 06:25:33 +02:00
|
|
|
std::size_t width = std::size_t(header[i].width);
|
|
|
|
std::size_t txt_length = text.getLength();
|
2017-09-16 01:21:16 +02:00
|
|
|
// Increment the value of i for the column position
|
|
|
|
// and the next iteration
|
|
|
|
i++;
|
|
|
|
fc::text_alignment align = getColumnAlignment(int(i));
|
2018-10-14 06:25:33 +02:00
|
|
|
std::size_t align_offset = getAlignOffset (align, txt_length, width);
|
2017-09-16 01:21:16 +02:00
|
|
|
|
|
|
|
if ( tree_view && i == 1 )
|
|
|
|
{
|
2017-09-19 06:18:03 +02:00
|
|
|
width -= indent;
|
2017-09-16 01:21:16 +02:00
|
|
|
width--;
|
|
|
|
}
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-09-16 01:21:16 +02:00
|
|
|
// Insert alignment spaces
|
|
|
|
if ( align_offset > 0 )
|
|
|
|
line += FString(align_offset, L' ');
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
if ( align_offset + txt_length <= width )
|
2017-09-15 01:31:02 +02:00
|
|
|
{
|
2017-12-19 02:06:27 +01:00
|
|
|
// Insert text and trailing space
|
2017-09-16 01:21:16 +02:00
|
|
|
line += text.left(width);
|
|
|
|
line += FString ( leading_space + width
|
2018-10-17 22:12:52 +02:00
|
|
|
- align_offset - txt_length, L' ');
|
2017-09-16 01:21:16 +02:00
|
|
|
}
|
|
|
|
else if ( align == fc::alignRight )
|
|
|
|
{
|
|
|
|
// Ellipse right align text
|
|
|
|
line += FString (L"..");
|
|
|
|
line += text.right(width - ellipsis_length);
|
2017-09-15 01:31:02 +02:00
|
|
|
line += L' ';
|
|
|
|
}
|
|
|
|
else
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2017-09-16 01:21:16 +02:00
|
|
|
// Ellipse left align text and center text
|
|
|
|
line += text.left(width - ellipsis_length);
|
|
|
|
line += FString (L".. ");
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
}
|
2017-09-16 01:21:16 +02:00
|
|
|
}
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
line = line.mid ( std::size_t(xoffset) + 1
|
|
|
|
, getWidth() - std::size_t(nf_offset) - 2);
|
2017-09-16 01:21:16 +02:00
|
|
|
const wchar_t* const& element_str = line.wc_str();
|
2018-10-14 06:25:33 +02:00
|
|
|
std::size_t len = line.getLength();
|
|
|
|
std::size_t i;
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2017-09-16 01:21:16 +02:00
|
|
|
for (i = 0; i < len; i++)
|
2017-09-17 21:32:46 +02:00
|
|
|
*this << element_str[i];
|
2017-07-18 23:50:51 +02:00
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
for (; i < getWidth() - std::size_t(nf_offset) - 2; i++)
|
2017-09-16 01:21:16 +02:00
|
|
|
print (' ');
|
2017-07-18 23:50:51 +02:00
|
|
|
}
|
|
|
|
|
2018-01-21 16:21:41 +01:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
inline void FListView::setLineAttributes ( bool is_current
|
|
|
|
, bool is_focus )
|
|
|
|
{
|
|
|
|
setColor (wc.list_fg, wc.list_bg);
|
|
|
|
|
|
|
|
if ( is_current )
|
|
|
|
{
|
|
|
|
if ( is_focus && getMaxColor() < 16 )
|
|
|
|
setBold();
|
|
|
|
|
|
|
|
if ( isMonochron() )
|
|
|
|
unsetBold();
|
|
|
|
|
|
|
|
if ( is_focus )
|
|
|
|
{
|
|
|
|
setColor ( wc.current_element_focus_fg
|
|
|
|
, wc.current_element_focus_bg );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
setColor ( wc.current_element_fg
|
|
|
|
, wc.current_element_bg );
|
|
|
|
|
|
|
|
if ( isMonochron() )
|
|
|
|
setReverse(false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( isMonochron() )
|
|
|
|
setReverse(true);
|
|
|
|
else if ( is_focus && getMaxColor() < 16 )
|
|
|
|
unsetBold();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
inline FString FListView::getLinePrefix ( const FListViewItem* item
|
2018-10-14 06:25:33 +02:00
|
|
|
, std::size_t indent )
|
2018-01-21 16:21:41 +01:00
|
|
|
{
|
|
|
|
FString line = "";
|
|
|
|
|
|
|
|
if ( tree_view )
|
|
|
|
{
|
|
|
|
if ( indent > 0 )
|
|
|
|
line = FString(indent, L' ');
|
|
|
|
|
|
|
|
if ( item->expandable )
|
|
|
|
{
|
|
|
|
if ( item->is_expand )
|
|
|
|
{
|
|
|
|
line += wchar_t(fc::BlackDownPointingTriangle); // ▼
|
|
|
|
line += L' ';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
line += wchar_t(fc::BlackRightPointingPointer); // ►
|
|
|
|
line += L' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
line += L" ";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
line = L" ";
|
|
|
|
|
|
|
|
return line;
|
|
|
|
}
|
|
|
|
|
2018-11-10 00:53:57 +01:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
inline void FListView::drawSortIndicator ( std::size_t& length
|
|
|
|
, std::size_t column_width )
|
|
|
|
{
|
|
|
|
if ( length >= column_width )
|
|
|
|
return;
|
|
|
|
|
|
|
|
setColor();
|
|
|
|
length++;
|
|
|
|
|
|
|
|
if ( sort_order == fc::ascending )
|
|
|
|
headerline << wchar_t(fc::BlackDownPointingTriangle); // ▼
|
|
|
|
else if ( sort_order == fc::descending )
|
|
|
|
headerline << wchar_t(fc::BlackUpPointingTriangle); // ▲
|
|
|
|
|
|
|
|
if ( length < column_width )
|
|
|
|
{
|
|
|
|
length++;
|
|
|
|
headerline << ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2018-11-12 22:40:16 +01:00
|
|
|
inline void FListView::drawHeaderBorder (std::size_t length)
|
2018-11-10 00:53:57 +01:00
|
|
|
{
|
|
|
|
setColor();
|
|
|
|
const FString line (length, wchar_t(fc::BoxDrawingsHorizontal));
|
|
|
|
headerline << line; // horizontal line
|
|
|
|
}
|
|
|
|
|
2018-02-11 23:41:23 +01:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::drawColumnText (headerItems::const_iterator& iter)
|
|
|
|
{
|
|
|
|
// Print lable text
|
2018-10-14 06:25:33 +02:00
|
|
|
static const std::size_t leading_space = 1;
|
2018-03-16 01:05:45 +01:00
|
|
|
const FString& text = iter->name;
|
2018-02-11 23:41:23 +01:00
|
|
|
FString txt = " " + text;
|
2018-11-10 00:53:57 +01:00
|
|
|
std::size_t width = std::size_t(iter->width);
|
2018-10-14 06:25:33 +02:00
|
|
|
std::size_t txt_length = txt.getLength();
|
|
|
|
std::size_t column_width = leading_space + width;
|
2018-11-10 00:53:57 +01:00
|
|
|
headerItems::const_iterator first = header.begin();
|
|
|
|
int column = std::distance(first, iter) + 1;
|
2018-11-12 22:40:16 +01:00
|
|
|
bool has_sort_indicator = bool ( sort_column == column
|
|
|
|
&& ! hide_sort_indicator );
|
2018-02-11 23:41:23 +01:00
|
|
|
|
|
|
|
if ( isEnabled() )
|
|
|
|
setColor (wc.label_emphasis_fg, wc.label_bg);
|
|
|
|
else
|
|
|
|
setColor (wc.label_inactive_fg, wc.label_inactive_bg);
|
|
|
|
|
2018-11-12 22:40:16 +01:00
|
|
|
if ( has_sort_indicator && txt_length >= column_width - 1 && txt_length > 1 )
|
2018-11-10 00:53:57 +01:00
|
|
|
{
|
|
|
|
txt_length = column_width - 2;
|
|
|
|
txt = txt.left(txt_length);
|
|
|
|
}
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
if ( txt_length <= column_width )
|
2018-02-11 23:41:23 +01:00
|
|
|
{
|
2018-11-12 22:40:16 +01:00
|
|
|
std::size_t length = txt_length;
|
2018-02-11 23:41:23 +01:00
|
|
|
headerline << txt;
|
|
|
|
|
2018-11-10 00:53:57 +01:00
|
|
|
if ( length < column_width )
|
2018-02-11 23:41:23 +01:00
|
|
|
{
|
2018-11-10 00:53:57 +01:00
|
|
|
length++;
|
|
|
|
headerline << ' '; // trailing space
|
2018-02-11 23:41:23 +01:00
|
|
|
}
|
2018-11-10 00:53:57 +01:00
|
|
|
|
2018-11-12 22:40:16 +01:00
|
|
|
if ( has_sort_indicator )
|
2018-11-10 00:53:57 +01:00
|
|
|
drawSortIndicator (length, column_width );
|
|
|
|
|
|
|
|
if ( length < column_width )
|
2018-11-12 22:40:16 +01:00
|
|
|
drawHeaderBorder (column_width - length);
|
2018-02-11 23:41:23 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
drawColumnEllipsis (iter, text); // Print ellipsis
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::drawColumnEllipsis ( headerItems::const_iterator& iter
|
|
|
|
, const FString& text )
|
|
|
|
{
|
|
|
|
// Print lable ellipsis
|
|
|
|
static const int ellipsis_length = 2;
|
2018-03-16 01:05:45 +01:00
|
|
|
int width = iter->width;
|
2018-02-11 23:41:23 +01:00
|
|
|
|
|
|
|
headerline << ' ';
|
|
|
|
headerline << text.left(uInt(width - ellipsis_length));
|
|
|
|
setColor (wc.label_ellipsis_fg, wc.label_bg);
|
|
|
|
headerline << "..";
|
|
|
|
|
|
|
|
if ( iter == header.end() - 1 ) // Last element
|
|
|
|
headerline << ' ';
|
|
|
|
}
|
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::updateDrawing (bool draw_vbar, bool draw_hbar)
|
|
|
|
{
|
|
|
|
if ( isVisible() )
|
|
|
|
draw();
|
|
|
|
|
|
|
|
vbar->setValue (first_visible_line.getPosition());
|
|
|
|
|
|
|
|
if ( vbar->isVisible() && draw_vbar )
|
|
|
|
vbar->drawBar();
|
|
|
|
|
|
|
|
hbar->setValue (xoffset);
|
|
|
|
|
|
|
|
if ( hbar->isVisible() && draw_hbar )
|
|
|
|
hbar->drawBar();
|
|
|
|
|
|
|
|
updateTerminal();
|
|
|
|
flush_out();
|
|
|
|
}
|
|
|
|
|
2018-10-01 22:27:54 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
int FListView::determineLineWidth (FListViewItem* item)
|
|
|
|
{
|
|
|
|
static const int padding_space = 1;
|
|
|
|
int line_width = padding_space; // leading space
|
|
|
|
uInt column_idx = 0;
|
|
|
|
uInt entries = uInt(item->column_list.size());
|
|
|
|
headerItems::iterator header_iter;
|
|
|
|
header_iter = header.begin();
|
|
|
|
|
|
|
|
while ( header_iter != header.end() )
|
|
|
|
{
|
|
|
|
int width = header_iter->width;
|
|
|
|
bool fixed_width = header_iter->fixed_width;
|
|
|
|
|
|
|
|
if ( ! fixed_width )
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if ( column_idx < entries )
|
|
|
|
len = int(item->column_list[column_idx].getLength());
|
|
|
|
else
|
|
|
|
len = 0;
|
|
|
|
|
|
|
|
if ( len > width )
|
|
|
|
header_iter->width = len;
|
|
|
|
}
|
|
|
|
|
|
|
|
line_width += header_iter->width + padding_space; // width + trailing space
|
|
|
|
column_idx++;
|
|
|
|
++header_iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
return line_width;
|
|
|
|
}
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::recalculateHorizontalBar (int len)
|
|
|
|
{
|
|
|
|
if ( len <= max_line_width )
|
|
|
|
return;
|
|
|
|
|
|
|
|
max_line_width = len;
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
if ( len >= int(getWidth()) - nf_offset - 3 )
|
2017-07-18 23:50:51 +02:00
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
hbar->setMaximum (max_line_width - int(getWidth()) + nf_offset + 4);
|
|
|
|
hbar->setPageSize (max_line_width, int(getWidth()) - nf_offset - 4);
|
2017-07-18 23:50:51 +02:00
|
|
|
hbar->calculateSliderValues();
|
|
|
|
|
|
|
|
if ( ! hbar->isVisible() )
|
|
|
|
hbar->setVisible();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::recalculateVerticalBar (int element_count)
|
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
vbar->setMaximum (element_count - int(getHeight()) + 2);
|
|
|
|
vbar->setPageSize (element_count, int(getHeight()) - 2);
|
2017-07-18 23:50:51 +02:00
|
|
|
vbar->calculateSliderValues();
|
|
|
|
|
2018-10-14 06:25:33 +02:00
|
|
|
if ( ! vbar->isVisible() && element_count >= int(getHeight()) - 1 )
|
2017-07-18 23:50:51 +02:00
|
|
|
vbar->setVisible();
|
|
|
|
}
|
|
|
|
|
2018-11-12 22:40:16 +01:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::mouseColumnClicked()
|
|
|
|
{
|
|
|
|
int column_start = 2;
|
|
|
|
int column = 1;
|
|
|
|
int column_pos = clicked_column_pos.getX() + xoffset;
|
|
|
|
headerItems::const_iterator iter;
|
|
|
|
iter = header.begin();
|
|
|
|
|
|
|
|
while ( iter != header.end() )
|
|
|
|
{
|
|
|
|
static const int leading_space = 1;
|
|
|
|
bool has_sort_indicator = bool( column == sort_column );
|
|
|
|
int click_width = int(iter->name.getLength());
|
|
|
|
|
|
|
|
if ( has_sort_indicator )
|
|
|
|
click_width += 2;
|
|
|
|
|
|
|
|
if ( click_width > iter->width )
|
|
|
|
click_width = iter->width;
|
|
|
|
|
|
|
|
if ( column_pos > column_start
|
|
|
|
&& column_pos <= column_start + click_width )
|
|
|
|
{
|
|
|
|
if ( has_sort_indicator && sort_order == fc::ascending )
|
|
|
|
setColumnSort (column, fc::descending);
|
|
|
|
else
|
|
|
|
setColumnSort (column, fc::ascending);
|
|
|
|
|
|
|
|
sort();
|
|
|
|
|
|
|
|
if ( isVisible() )
|
|
|
|
{
|
|
|
|
drawColumnLabels();
|
|
|
|
drawList();
|
|
|
|
updateTerminal();
|
|
|
|
flush_out();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
column_start += leading_space + iter->width;
|
|
|
|
column++;
|
|
|
|
++iter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-11 23:41:23 +01:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::wheelUp (int pagesize)
|
|
|
|
{
|
|
|
|
if ( current_iter.getPosition() == 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( first_visible_line.getPosition() >= pagesize )
|
|
|
|
{
|
|
|
|
current_iter -= pagesize;
|
|
|
|
first_visible_line -= pagesize;
|
|
|
|
last_visible_line -= pagesize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Save relative position from the first line
|
|
|
|
int ry = current_iter.getPosition() - first_visible_line.getPosition();
|
|
|
|
// Save difference from top
|
|
|
|
int difference = first_visible_line.getPosition();
|
|
|
|
first_visible_line -= difference;
|
|
|
|
last_visible_line -= difference;
|
|
|
|
setRelativePosition(ry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::wheelDown (int pagesize)
|
|
|
|
{
|
|
|
|
int element_count = int(getCount());
|
|
|
|
|
|
|
|
if ( current_iter.getPosition() + 1 == element_count )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( last_visible_line.getPosition() < element_count - pagesize )
|
|
|
|
{
|
|
|
|
current_iter += pagesize;
|
|
|
|
first_visible_line += pagesize;
|
|
|
|
last_visible_line += pagesize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Save relative position from the first line
|
|
|
|
int ry = current_iter.getPosition() - first_visible_line.getPosition();
|
|
|
|
// Save difference from bottom
|
|
|
|
int differenz = element_count - last_visible_line.getPosition() - 1;
|
|
|
|
first_visible_line += differenz;
|
|
|
|
last_visible_line += differenz;
|
|
|
|
setRelativePosition(ry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool FListView::dragScrollUp (int position_before)
|
|
|
|
{
|
|
|
|
if ( position_before == 0 )
|
|
|
|
{
|
|
|
|
drag_scroll = fc::noScroll;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
stepBackward(scroll_distance);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
bool FListView::dragScrollDown (int position_before)
|
|
|
|
{
|
|
|
|
int element_count = int(getCount());
|
|
|
|
|
|
|
|
if ( position_before + 1 == element_count )
|
|
|
|
{
|
|
|
|
drag_scroll = fc::noScroll;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
stepForward(scroll_distance);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-18 21:49:58 +01:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::dragUp (int mouse_button)
|
|
|
|
{
|
|
|
|
if ( drag_scroll != fc::noScroll
|
2018-10-14 06:25:33 +02:00
|
|
|
&& scroll_distance < int(getClientHeight()) )
|
2018-02-18 21:49:58 +01:00
|
|
|
scroll_distance++;
|
|
|
|
|
|
|
|
if ( ! scroll_timer && current_iter.getPosition() > 0 )
|
|
|
|
{
|
|
|
|
scroll_timer = true;
|
|
|
|
addTimer(scroll_repeat);
|
|
|
|
|
|
|
|
if ( mouse_button == fc::RightButton )
|
|
|
|
drag_scroll = fc::scrollUpSelect;
|
|
|
|
else
|
|
|
|
drag_scroll = fc::scrollUp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( current_iter.getPosition() == 0 )
|
|
|
|
{
|
|
|
|
delOwnTimer();
|
|
|
|
drag_scroll = fc::noScroll;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::dragDown (int mouse_button)
|
|
|
|
{
|
|
|
|
if ( drag_scroll != fc::noScroll
|
2018-10-14 06:25:33 +02:00
|
|
|
&& scroll_distance < int(getClientHeight()) )
|
2018-02-18 21:49:58 +01:00
|
|
|
scroll_distance++;
|
|
|
|
|
|
|
|
if ( ! scroll_timer && current_iter.getPosition() <= int(getCount()) )
|
|
|
|
{
|
|
|
|
scroll_timer = true;
|
|
|
|
addTimer(scroll_repeat);
|
|
|
|
|
|
|
|
if ( mouse_button == fc::RightButton )
|
|
|
|
drag_scroll = fc::scrollDownSelect;
|
|
|
|
else
|
|
|
|
drag_scroll = fc::scrollDown;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( current_iter.getPosition() - 1 == int(getCount()) )
|
|
|
|
{
|
|
|
|
delOwnTimer();
|
|
|
|
drag_scroll = fc::noScroll;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::stopDragScroll()
|
|
|
|
{
|
|
|
|
delOwnTimer();
|
|
|
|
scroll_timer = false;
|
|
|
|
scroll_distance = 1;
|
|
|
|
drag_scroll = fc::noScroll;
|
|
|
|
}
|
|
|
|
|
2017-09-16 01:21:16 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
FObject::FObjectIterator FListView::appendItem (FListViewItem* item)
|
|
|
|
{
|
2018-09-28 06:45:02 +02:00
|
|
|
item->root = root;
|
2017-09-16 01:21:16 +02:00
|
|
|
addChild (item);
|
|
|
|
itemlist.push_back (item);
|
|
|
|
return --itemlist.end();
|
|
|
|
}
|
|
|
|
|
2017-07-18 23:50:51 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::processClick()
|
|
|
|
{
|
|
|
|
emitCallback("clicked");
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::processChanged()
|
|
|
|
{
|
|
|
|
emitCallback("row-changed");
|
|
|
|
}
|
2017-07-23 01:19:59 +02:00
|
|
|
|
2017-12-03 21:06:21 +01:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
inline void FListView::keyLeft (int& first_line_position_before)
|
|
|
|
{
|
|
|
|
int position_before = current_iter.getPosition();
|
|
|
|
FListViewItem* item = getCurrentItem();
|
|
|
|
|
|
|
|
if ( xoffset == 0 )
|
|
|
|
{
|
|
|
|
if ( tree_view && item->isExpandable() && item->isExpand() )
|
|
|
|
{
|
|
|
|
// Collapse element
|
|
|
|
item->collapse();
|
|
|
|
adjustSize();
|
2017-12-29 02:10:05 +01:00
|
|
|
int element_count = int(getCount());
|
2017-12-03 21:06:21 +01:00
|
|
|
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 ( 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
|
2018-09-02 22:46:01 +02:00
|
|
|
if ( xoffset > 0 )
|
|
|
|
xoffset--;
|
2017-12-03 21:06:21 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
inline void FListView::keyRight (int& first_line_position_before)
|
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
int xoffset_end = max_line_width - int(getClientWidth());
|
2017-12-03 21:06:21 +01:00
|
|
|
FListViewItem* item = getCurrentItem();
|
|
|
|
|
|
|
|
if ( tree_view && item->isExpandable() && ! item->isExpand() )
|
|
|
|
{
|
|
|
|
// Expand element
|
|
|
|
item->expand();
|
|
|
|
adjustSize();
|
|
|
|
// Force vertical scrollbar redraw
|
|
|
|
first_line_position_before = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Scroll right
|
2018-09-02 22:46:01 +02:00
|
|
|
if ( xoffset < xoffset_end )
|
|
|
|
xoffset++;
|
2017-12-03 21:06:21 +01:00
|
|
|
|
|
|
|
if ( xoffset < 0 )
|
|
|
|
xoffset = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
inline void FListView::keyHome()
|
|
|
|
{
|
|
|
|
current_iter -= current_iter.getPosition();
|
|
|
|
int difference = first_visible_line.getPosition();
|
|
|
|
first_visible_line -= difference;
|
|
|
|
last_visible_line -= difference;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
inline void FListView::keyEnd()
|
|
|
|
{
|
|
|
|
int element_count = int(getCount());
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
inline bool FListView::keyPlus()
|
|
|
|
{
|
|
|
|
FListViewItem* item = getCurrentItem();
|
|
|
|
|
|
|
|
if ( tree_view && item->isExpandable() && ! item->isExpand() )
|
|
|
|
{
|
|
|
|
item->expand();
|
|
|
|
adjustSize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
inline bool FListView::keyMinus()
|
|
|
|
{
|
|
|
|
FListViewItem* item = getCurrentItem();
|
|
|
|
|
|
|
|
if ( tree_view && item->isExpandable() && item->isExpand() )
|
|
|
|
{
|
|
|
|
item->collapse();
|
|
|
|
adjustSize();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-10-15 15:27:36 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::setRelativePosition (int ry)
|
|
|
|
{
|
|
|
|
current_iter = first_visible_line;
|
|
|
|
current_iter += ry;
|
|
|
|
}
|
|
|
|
|
2017-07-23 01:19:59 +02:00
|
|
|
//----------------------------------------------------------------------
|
2017-10-14 22:20:19 +02:00
|
|
|
void FListView::stepForward()
|
2017-09-21 07:22:08 +02:00
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( current_iter == last_visible_line )
|
|
|
|
{
|
|
|
|
++last_visible_line;
|
2017-09-21 07:22:08 +02:00
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
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
|
2017-11-26 22:37:18 +01:00
|
|
|
&& current_iter != itemlist.begin() )
|
2017-09-21 07:22:08 +02:00
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
--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;
|
2017-09-21 07:22:08 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
current_iter += element_count - current_iter.getPosition() - 1;
|
|
|
|
}
|
2017-09-21 07:22:08 +02:00
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( current_iter.getPosition() > last_visible_line.getPosition() )
|
|
|
|
{
|
|
|
|
if ( last_visible_line.getPosition() + distance < element_count )
|
2017-09-21 07:22:08 +02:00
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-21 07:22:08 +02:00
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
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;
|
2017-09-21 07:22:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::scrollToX (int x)
|
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
int xoffset_end = max_line_width - int(getClientWidth());
|
2017-10-14 22:20:19 +02:00
|
|
|
|
|
|
|
if ( xoffset == x )
|
|
|
|
return;
|
|
|
|
|
|
|
|
xoffset = x;
|
|
|
|
|
|
|
|
if ( xoffset > xoffset_end )
|
|
|
|
xoffset = xoffset_end;
|
|
|
|
|
|
|
|
if ( xoffset < 0 )
|
|
|
|
xoffset = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::scrollToY (int y)
|
|
|
|
{
|
2018-10-14 06:25:33 +02:00
|
|
|
int pagesize = int(getClientHeight()) - 1;
|
2017-10-14 22:20:19 +02:00
|
|
|
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;
|
2017-10-15 15:27:36 +02:00
|
|
|
setRelativePosition (ry);
|
2017-10-14 22:20:19 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-09-21 07:22:08 +02:00
|
|
|
//----------------------------------------------------------------------
|
2018-02-20 23:35:10 +01:00
|
|
|
void FListView::scrollBy (int dx, int dy)
|
2017-07-23 01:19:59 +02:00
|
|
|
{
|
2018-02-20 23:35:10 +01:00
|
|
|
scrollToX(xoffset + dx);
|
|
|
|
|
|
|
|
if ( dy > 0 )
|
|
|
|
stepForward(dy);
|
2017-10-14 22:20:19 +02:00
|
|
|
|
2018-02-20 23:35:10 +01:00
|
|
|
if ( dy < 0 )
|
|
|
|
stepBackward(-dy);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::cb_VBarChange (FWidget*, data_ptr)
|
|
|
|
{
|
|
|
|
FScrollbar::sType scrollType = vbar->getScrollType();
|
|
|
|
int distance = 1
|
|
|
|
, pagesize = 4
|
|
|
|
, first_line_position_before = first_visible_line.getPosition();
|
2017-07-23 01:19:59 +02:00
|
|
|
|
|
|
|
switch ( scrollType )
|
|
|
|
{
|
|
|
|
case FScrollbar::noScroll:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FScrollbar::scrollPageBackward:
|
2018-10-14 06:25:33 +02:00
|
|
|
distance = int(getClientHeight());
|
2017-07-23 01:19:59 +02:00
|
|
|
// fall through
|
|
|
|
case FScrollbar::scrollStepBackward:
|
2017-10-14 22:20:19 +02:00
|
|
|
stepBackward(distance);
|
2017-07-23 01:19:59 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FScrollbar::scrollPageForward:
|
2018-10-14 06:25:33 +02:00
|
|
|
distance = int(getClientHeight());
|
2017-07-23 01:19:59 +02:00
|
|
|
// fall through
|
|
|
|
case FScrollbar::scrollStepForward:
|
2017-10-14 22:20:19 +02:00
|
|
|
stepForward(distance);
|
2017-07-23 01:19:59 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FScrollbar::scrollJump:
|
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
int value = vbar->getValue();
|
|
|
|
scrollToY (value);
|
2017-07-23 01:19:59 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case FScrollbar::scrollWheelUp:
|
2018-02-20 23:35:10 +01:00
|
|
|
wheelUp (pagesize);
|
2017-07-23 01:19:59 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FScrollbar::scrollWheelDown:
|
2018-02-20 23:35:10 +01:00
|
|
|
wheelDown (pagesize);
|
2017-07-23 01:19:59 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( isVisible() )
|
|
|
|
drawList();
|
|
|
|
|
|
|
|
if ( scrollType >= FScrollbar::scrollStepBackward
|
2017-11-26 22:37:18 +01:00
|
|
|
&& scrollType <= FScrollbar::scrollPageForward )
|
2017-07-23 01:19:59 +02:00
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
vbar->setValue (first_visible_line.getPosition());
|
2017-07-23 01:19:59 +02:00
|
|
|
|
2017-10-14 22:20:19 +02:00
|
|
|
if ( vbar->isVisible()
|
2017-11-26 22:37:18 +01:00
|
|
|
&& first_line_position_before != first_visible_line.getPosition() )
|
2017-07-23 01:19:59 +02:00
|
|
|
vbar->drawBar();
|
|
|
|
|
|
|
|
updateTerminal();
|
|
|
|
flush_out();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
void FListView::cb_HBarChange (FWidget*, data_ptr)
|
|
|
|
{
|
2018-02-20 23:35:10 +01:00
|
|
|
FScrollbar::sType scrollType = hbar->getScrollType();
|
2017-10-14 22:20:19 +02:00
|
|
|
int distance = 1
|
|
|
|
, pagesize = 4
|
2018-02-20 23:35:10 +01:00
|
|
|
, xoffset_before = xoffset;
|
2017-07-23 01:19:59 +02:00
|
|
|
|
|
|
|
switch ( scrollType )
|
|
|
|
{
|
|
|
|
case FScrollbar::noScroll:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FScrollbar::scrollPageBackward:
|
2018-10-14 06:25:33 +02:00
|
|
|
distance = int(getClientWidth());
|
2017-07-23 01:19:59 +02:00
|
|
|
// fall through
|
|
|
|
case FScrollbar::scrollStepBackward:
|
2018-02-20 23:35:10 +01:00
|
|
|
scrollBy (-distance, 0);
|
2017-07-23 01:19:59 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FScrollbar::scrollPageForward:
|
2018-10-14 06:25:33 +02:00
|
|
|
distance = int(getClientWidth());
|
2017-07-23 01:19:59 +02:00
|
|
|
// fall through
|
|
|
|
case FScrollbar::scrollStepForward:
|
2018-02-20 23:35:10 +01:00
|
|
|
scrollBy (distance, 0);
|
2017-07-23 01:19:59 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FScrollbar::scrollJump:
|
|
|
|
{
|
2017-10-14 22:20:19 +02:00
|
|
|
int value = hbar->getValue();
|
|
|
|
scrollToX(value);
|
2017-07-23 01:19:59 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case FScrollbar::scrollWheelUp:
|
2018-02-20 23:35:10 +01:00
|
|
|
scrollBy (-pagesize, 0);
|
2017-07-23 01:19:59 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case FScrollbar::scrollWheelDown:
|
2018-02-20 23:35:10 +01:00
|
|
|
scrollBy (pagesize, 0);
|
2017-07-23 01:19:59 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( isVisible() )
|
|
|
|
{
|
|
|
|
drawColumnLabels();
|
|
|
|
drawList();
|
|
|
|
updateTerminal();
|
|
|
|
flush_out();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( scrollType >= FScrollbar::scrollStepBackward
|
2017-11-26 22:37:18 +01:00
|
|
|
&& scrollType <= FScrollbar::scrollWheelDown )
|
2017-07-23 01:19:59 +02:00
|
|
|
{
|
|
|
|
hbar->setValue (xoffset);
|
|
|
|
|
|
|
|
if ( hbar->isVisible() && xoffset_before != xoffset )
|
|
|
|
hbar->drawBar();
|
|
|
|
|
|
|
|
updateTerminal();
|
|
|
|
flush_out();
|
|
|
|
}
|
|
|
|
}
|
2018-09-20 23:59:01 +02:00
|
|
|
|
|
|
|
} // namespace finalcut
|