mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Added UIListView.
UIFileDialog now uses UIListView. UITreeView/UITableView/UIListView allow selecting row by writing its name. Styling fixes.
This commit is contained in:
@@ -186,7 +186,7 @@ its submodules, in order to achieve this easily you can simply clone with:
|
||||
|
||||
### ecode - Text Editor
|
||||
|
||||
Text editor inspired in [lite](https://github.com/rxi/lite) (in development, already fully functional).
|
||||
Text editor inspired in [lite](https://github.com/rxi/lite).
|
||||
It's using the newest pure CSS theme based on the default [Plasma](https://kde.org/plasma-desktop)
|
||||
dark theme: Breeze Dark.
|
||||
|
||||
@@ -635,7 +635,7 @@ Probably deprecate the Maps module, since I will focus my efforts on the UI syst
|
||||
|
||||
* Yuri Kobets for [litehtml](https://github.com/litehtml/litehtml)
|
||||
|
||||
* Michael R. P. Ragazzon [RmlUI](https://github.com/mikke89/RmlUi)
|
||||
* Michael R. P. Ragazzon for [RmlUI](https://github.com/mikke89/RmlUi)
|
||||
|
||||
* rxi for [lite](https://github.com/rxi/lite)
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ TextInputPassword,
|
||||
TextView,
|
||||
Tooltip,
|
||||
MenuBar::button,
|
||||
Window::title {
|
||||
Window::title,
|
||||
ListView::cell {
|
||||
color: var(--font);
|
||||
}
|
||||
|
||||
@@ -157,7 +158,8 @@ RadioButton::active {
|
||||
ListBox,
|
||||
DropDownList::ListBox,
|
||||
ComboBox::DropDownList::ListBox,
|
||||
Table {
|
||||
Table,
|
||||
ListView {
|
||||
background-color: var(--list-back);
|
||||
border-color: var(--button-border);
|
||||
border-radius: var(--button-radius);
|
||||
@@ -173,15 +175,29 @@ ListBox::item {
|
||||
background-position: left bottom, right bottom;
|
||||
}
|
||||
|
||||
ListBox:hover {
|
||||
ListView::row {
|
||||
background-color: transparent;
|
||||
background-image: linear-gradient( to right, var(--list-back), var(--separator) ), linear-gradient( to right, var(--separator), var(--list-back) );
|
||||
background-size: 50% 1dp, 50% 1dp;
|
||||
background-position: left bottom, right bottom;
|
||||
}
|
||||
|
||||
ListView::cell {
|
||||
padding-left: 4dp;
|
||||
}
|
||||
|
||||
ListBox:hover,
|
||||
ListView:hover {
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
ListBox::item:hover {
|
||||
ListBox::item:hover,
|
||||
ListView::row:hover {
|
||||
background-color: var(--item-hover);
|
||||
}
|
||||
|
||||
ListBox::item:selected {
|
||||
ListBox::item:selected,
|
||||
ListView::row:selected {
|
||||
background-color: var(--primary);
|
||||
}
|
||||
|
||||
@@ -734,11 +750,14 @@ Splitter::separator:hover {
|
||||
background-color: var(--primary);
|
||||
}
|
||||
|
||||
table::header {
|
||||
tableview::header,
|
||||
listview::header {
|
||||
background-color: var(--back);
|
||||
}
|
||||
|
||||
table::header::column {
|
||||
tableview::header::column,
|
||||
treeview::header::column,
|
||||
listview::header::column {
|
||||
background-color: var(--back);
|
||||
border-right-color: var(--tab-line);
|
||||
border-right-width: 1dp;
|
||||
@@ -751,24 +770,29 @@ table::header::column {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
table::header::column:hover {
|
||||
tableview::header::column:hover,
|
||||
treeview::header::column:hover,
|
||||
listview::header::column:hover {
|
||||
background-color: var(--tab-hover);
|
||||
}
|
||||
|
||||
table::row {
|
||||
tableview::row,
|
||||
treeview::row {
|
||||
background-color: var(--list-back);
|
||||
}
|
||||
|
||||
table::row:hover {
|
||||
tableview::row:hover,
|
||||
treeview::row:hover {
|
||||
background-color: var(--tab-hover);
|
||||
}
|
||||
|
||||
table::row:selected {
|
||||
tableview::row:selected,
|
||||
treeview::row:selected {
|
||||
background-color: var(--primary);
|
||||
}
|
||||
|
||||
table::cell,
|
||||
TreeView::cell {
|
||||
tableview::cell,
|
||||
treeview::cell {
|
||||
padding-left: 6dp;
|
||||
padding-right: 6dp;
|
||||
}
|
||||
@@ -783,13 +807,17 @@ TableView > ScrollBar {
|
||||
background-color: var(--list-back);
|
||||
}
|
||||
|
||||
table::header::column::arrow-up {
|
||||
tableview::header::column::arrow-up,
|
||||
treeview::header::column::arrow-up,
|
||||
listview::header::column::arrow-up {
|
||||
width: 16dp;
|
||||
height: 12dp;
|
||||
foreground-image: poly(line, var(--icon), "1dp 4dp, 5dp 7dp"), poly(line, var(--icon), "5dp 7dp, 9dp 4dp");
|
||||
}
|
||||
|
||||
table::header::column::arrow-down {
|
||||
tableview::header::column::arrow-down,
|
||||
treeview::header::column::arrow-down,
|
||||
listview::header::column::arrow-down {
|
||||
width: 16dp;
|
||||
height: 12dp;
|
||||
foreground-image: poly(line, var(--icon), "1dp 7dp, 5dp 4dp"), poly(line, var(--icon), "5dp 4dp, 9dp 7dp");
|
||||
|
||||
@@ -65,7 +65,8 @@ Menu::SubMenu:hover,
|
||||
ListBox::item:hover,
|
||||
Tab:selected,
|
||||
Tab:hover,
|
||||
Tab:pressed {
|
||||
Tab:pressed,
|
||||
ListView::cell:hover, {
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
@@ -92,6 +93,18 @@ Tab::text {
|
||||
padding-right: 4dp;
|
||||
}
|
||||
|
||||
ListView {
|
||||
row-height: 16dp;
|
||||
}
|
||||
|
||||
ListView::cell {
|
||||
padding-left: 4dp;
|
||||
}
|
||||
|
||||
ListView::row {
|
||||
skin: listboxitem;
|
||||
}
|
||||
|
||||
Tooltip {
|
||||
padding: 8dp;
|
||||
color: #020203;
|
||||
|
||||
@@ -1282,7 +1282,7 @@ rotation-origin-point-y: 100%;
|
||||
|
||||
Sets the row height in any element that contains fixed size rows.
|
||||
|
||||
* Applicable to: EE::UI::UIListBox (ListBox), EE::UI::UIDropDownList (DropDownList), EE::UI::UIWidgetTable (WidgetTable), EE::UI::UIGridLayout (GridLayout)
|
||||
* Applicable to: EE::UI::UIListBox (ListBox), EE::UI::UIDropDownList (DropDownList), EE::UI::UIWidgetTable (WidgetTable), EE::UI::UIGridLayout (GridLayout), EE::UI::TableView (TableView), EE::UI::TreeView (TreeView), EE::UI::ListView (ListView)
|
||||
* Data Type: [length](#length-data-type)
|
||||
* Default value: Varies on each case. ListBox and DropDownList will guess the value based on the [font-size](#font-size). Table requires this value to be manually set in order to work. GridLayout
|
||||
will require the value only if [row-mode](#row-mode) is `size`.
|
||||
|
||||
@@ -78,6 +78,15 @@ class EE_API UIAbstractTableView : public UIAbstractView {
|
||||
|
||||
void setColumnsVisible( const std::vector<size_t> columns );
|
||||
|
||||
virtual bool applyProperty( const StyleSheetProperty& attribute );
|
||||
|
||||
virtual std::string getPropertyString( const PropertyDefinition* propertyDef,
|
||||
const Uint32& propertyIndex = 0 );
|
||||
|
||||
bool getRowSearchByName() const;
|
||||
|
||||
void setRowSearchByName( bool rowSearchByName );
|
||||
|
||||
protected:
|
||||
friend class EE::UI::UITableHeaderColumn;
|
||||
|
||||
@@ -97,6 +106,9 @@ class EE_API UIAbstractTableView : public UIAbstractView {
|
||||
size_t mIconSize{12};
|
||||
size_t mSortIconSize{16};
|
||||
bool mAutoExpandOnSingleColumn{false};
|
||||
bool mRowSearchByName{true};
|
||||
Action* mSearchTextAction{nullptr};
|
||||
std::string mSearchText;
|
||||
|
||||
virtual ~UIAbstractTableView();
|
||||
|
||||
@@ -134,6 +146,10 @@ class EE_API UIAbstractTableView : public UIAbstractView {
|
||||
|
||||
virtual void onSortColumn( const size_t& colIndex );
|
||||
|
||||
virtual Uint32 onTextInput( const TextInputEvent& event );
|
||||
|
||||
virtual ModelIndex findRowWithText( const std::string& text );
|
||||
|
||||
void updateHeaderSize();
|
||||
|
||||
int visibleColumn();
|
||||
|
||||
@@ -14,14 +14,20 @@ class EE_API FileSystemModel : public Model {
|
||||
|
||||
struct DisplayConfig {
|
||||
DisplayConfig() {}
|
||||
DisplayConfig( bool sortByName, bool foldersFirst, bool ignoreHidden ) :
|
||||
sortByName( sortByName ), foldersFirst( foldersFirst ), ignoreHidden( ignoreHidden ) {}
|
||||
DisplayConfig( bool sortByName, bool foldersFirst, bool ignoreHidden,
|
||||
std::vector<std::string> acceptedExtensions = {} ) :
|
||||
sortByName( sortByName ),
|
||||
foldersFirst( foldersFirst ),
|
||||
ignoreHidden( ignoreHidden ),
|
||||
acceptedExtensions( acceptedExtensions ) {}
|
||||
bool sortByName{true};
|
||||
bool foldersFirst{true};
|
||||
bool ignoreHidden{false};
|
||||
std::vector<std::string> acceptedExtensions;
|
||||
bool operator==( const DisplayConfig& other ) {
|
||||
return sortByName == other.sortByName && foldersFirst == other.foldersFirst &&
|
||||
ignoreHidden == other.ignoreHidden;
|
||||
ignoreHidden == other.ignoreHidden &&
|
||||
acceptedExtensions == other.acceptedExtensions;
|
||||
}
|
||||
bool operator!=( const DisplayConfig& other ) { return !( *this == other ); }
|
||||
};
|
||||
|
||||
@@ -76,6 +76,8 @@ class EE_API Model {
|
||||
|
||||
virtual SortOrder sortOrder() const { return SortOrder::None; }
|
||||
|
||||
virtual bool isSortable() { return false; }
|
||||
|
||||
virtual void setKeyColumnAndSortOrder( const size_t& /*column*/, const SortOrder& /*order*/ ) {}
|
||||
|
||||
void registerView( UIAbstractView* );
|
||||
|
||||
@@ -28,6 +28,10 @@ class EE_API SortingProxyModel final : public Model, private Model::Client {
|
||||
|
||||
virtual int keyColumn() const;
|
||||
|
||||
virtual size_t treeColumn() const;
|
||||
|
||||
virtual bool isSortable() { return true; }
|
||||
|
||||
virtual SortOrder sortOrder() const;
|
||||
|
||||
virtual void setKeyColumnAndSortOrder( const size_t&, const SortOrder& );
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <eepp/ui/base.hpp>
|
||||
#include <eepp/ui/keyboardshortcut.hpp>
|
||||
#include <eepp/ui/uicombobox.hpp>
|
||||
#include <eepp/ui/uilistbox.hpp>
|
||||
#include <eepp/ui/uilistview.hpp>
|
||||
#include <eepp/ui/uipushbutton.hpp>
|
||||
#include <eepp/ui/uitextinput.hpp>
|
||||
#include <eepp/ui/uiwidget.hpp>
|
||||
@@ -60,7 +60,7 @@ class EE_API UIFileDialog : public UIWindow {
|
||||
|
||||
UIPushButton* getButtonUp() const;
|
||||
|
||||
UIListBox* getList() const;
|
||||
UIListView* getList() const;
|
||||
|
||||
UITextInput* getPathInput() const;
|
||||
|
||||
@@ -103,7 +103,7 @@ class EE_API UIFileDialog : public UIWindow {
|
||||
UIPushButton* mButtonOpen;
|
||||
UIPushButton* mButtonCancel;
|
||||
UIPushButton* mButtonUp;
|
||||
UIListBox* mList;
|
||||
UIListView* mList;
|
||||
UITextInput* mPath;
|
||||
UITextInput* mFile;
|
||||
UIDropDownList* mFiletype;
|
||||
@@ -120,8 +120,6 @@ class EE_API UIFileDialog : public UIWindow {
|
||||
|
||||
void openSaveClick();
|
||||
|
||||
std::string getTempFullPath();
|
||||
|
||||
void disableButtons();
|
||||
|
||||
void openFileOrFolder();
|
||||
|
||||
@@ -97,6 +97,7 @@ enum UINodeType {
|
||||
UI_TYPE_TREEVIEW_CELL,
|
||||
UI_TYPE_TABLEVIEW,
|
||||
UI_TYPE_TABLECELL,
|
||||
UI_TYPE_LISTVIEW,
|
||||
UI_TYPE_USER = 10000
|
||||
};
|
||||
|
||||
|
||||
24
include/eepp/ui/uilistview.hpp
Normal file
24
include/eepp/ui/uilistview.hpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef EE_UI_UILISTVIEW_HPP
|
||||
#define EE_UI_UILISTVIEW_HPP
|
||||
|
||||
#include <eepp/ui/uitableview.hpp>
|
||||
|
||||
namespace EE { namespace UI {
|
||||
|
||||
class EE_API UIListView : public UITableView {
|
||||
public:
|
||||
static UIListView* New();
|
||||
|
||||
Uint32 getType() const;
|
||||
|
||||
bool isType( const Uint32& type ) const;
|
||||
|
||||
void setTheme( UITheme* Theme );
|
||||
|
||||
protected:
|
||||
UIListView();
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
#endif // EE_UI_UILISTVIEW_HPP
|
||||
@@ -24,12 +24,18 @@ class EE_API UITableCell : public UIPushButton {
|
||||
|
||||
void setCurIndex( const ModelIndex& curIndex ) { mCurIndex = curIndex; }
|
||||
|
||||
void setTheme( UITheme* Theme ) {
|
||||
UIPushButton::setTheme( Theme );
|
||||
setThemeSkin( Theme, "tablerow" );
|
||||
onThemeLoaded();
|
||||
}
|
||||
|
||||
protected:
|
||||
ModelIndex mCurIndex;
|
||||
|
||||
UITableCell() : UIPushButton( "table::cell" ) {}
|
||||
UITableCell() : UITableCell( "table::cell" ) {}
|
||||
|
||||
UITableCell( const std::string& tag ) : UIPushButton( tag ) {}
|
||||
UITableCell( const std::string& tag ) : UIPushButton( tag ) { applyDefaultTheme(); }
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -12,7 +12,8 @@ using namespace Abstract;
|
||||
|
||||
class EE_API UITableHeaderColumn : public UIPushButton {
|
||||
public:
|
||||
UITableHeaderColumn( UIAbstractTableView* view, const size_t& colIndex );
|
||||
UITableHeaderColumn( const std::string& parentTag, UIAbstractTableView* view,
|
||||
const size_t& colIndex );
|
||||
|
||||
virtual UIWidget* getExtraInnerWidget() const;
|
||||
|
||||
|
||||
@@ -18,8 +18,14 @@ class EE_API UITableRow : public UIWidget {
|
||||
|
||||
void setCurIndex( const ModelIndex& curIndex ) { mCurIndex = curIndex; }
|
||||
|
||||
void setTheme( UITheme* Theme ) {
|
||||
UIWidget::setTheme( Theme );
|
||||
setThemeSkin( Theme, "tablerow" );
|
||||
onThemeLoaded();
|
||||
}
|
||||
|
||||
protected:
|
||||
UITableRow( const std::string& tag ) : UIWidget( tag ) {}
|
||||
UITableRow( const std::string& tag ) : UIWidget( tag ) { applyDefaultTheme(); }
|
||||
|
||||
UITableRow() : UIWidget( "table::row" ) {}
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@ class EE_API UITableView : public UIAbstractTableView {
|
||||
|
||||
UITableView();
|
||||
|
||||
UITableView( const std::string& tag );
|
||||
|
||||
virtual void createOrUpdateColumns();
|
||||
|
||||
void updateContentSize();
|
||||
@@ -34,6 +36,7 @@ class EE_API UITableView : public UIAbstractTableView {
|
||||
|
||||
virtual Uint32 onKeyDown( const KeyEvent& event );
|
||||
|
||||
virtual ModelIndex findRowWithText( const std::string& text );
|
||||
};
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -100,6 +100,10 @@ class EE_API UITreeView : public UIAbstractTableView {
|
||||
|
||||
virtual void onOpenTreeModelIndex( const ModelIndex& index, bool open );
|
||||
|
||||
virtual void onSortColumn( const size_t& colIndex );
|
||||
|
||||
virtual ModelIndex findRowWithText( const std::string& text );
|
||||
|
||||
void updateContentSize();
|
||||
|
||||
void setAllExpanded( const ModelIndex& index = {}, bool expanded = true );
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 4.12.2, 2020-08-16T20:36:39. -->
|
||||
<!-- Written by QtCreator 4.12.2, 2020-08-17T01:30:18. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
@@ -89,7 +89,7 @@
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{6d057187-158a-4883-8d5b-d470a6b6b025}</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">10</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">15</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">19</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">../../make/linux</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
|
||||
@@ -369,6 +369,7 @@
|
||||
../../include/eepp/ui/uilinearlayout.hpp
|
||||
../../include/eepp/ui/uilistbox.hpp
|
||||
../../include/eepp/ui/uilistboxitem.hpp
|
||||
../../include/eepp/ui/uilistview.hpp
|
||||
../../include/eepp/ui/uiloader.hpp
|
||||
../../include/eepp/ui/uimanager.hpp
|
||||
../../include/eepp/ui/uimenubar.hpp
|
||||
@@ -842,6 +843,7 @@
|
||||
../../src/eepp/ui/uilinearlayout.cpp
|
||||
../../src/eepp/ui/uilistbox.cpp
|
||||
../../src/eepp/ui/uilistboxitem.cpp
|
||||
../../src/eepp/ui/uilistview.cpp
|
||||
../../src/eepp/ui/uiloader.cpp
|
||||
../../src/eepp/ui/uimanager.cpp
|
||||
../../src/eepp/ui/uimenubar.cpp
|
||||
|
||||
@@ -13,7 +13,7 @@ UIAbstractTableView::UIAbstractTableView( const std::string& tag ) :
|
||||
mDragBorderDistance( PixelDensity::dpToPx( 4 ) ),
|
||||
mIconSize( PixelDensity::dpToPxI( 12 ) ),
|
||||
mSortIconSize( PixelDensity::dpToPxI( 20 ) ) {
|
||||
mHeader = UILinearLayout::NewWithTag( "table::header", UIOrientation::Horizontal );
|
||||
mHeader = UILinearLayout::NewWithTag( mTag + "::header", UIOrientation::Horizontal );
|
||||
mHeader->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
|
||||
mHeader->setParent( this );
|
||||
mHeader->setVisible( true );
|
||||
@@ -87,7 +87,7 @@ void UIAbstractTableView::createOrUpdateColumns() {
|
||||
for ( size_t i = 0; i < count; i++ ) {
|
||||
ColumnData& col = columnData( i );
|
||||
if ( !col.widget ) {
|
||||
col.widget = eeNew( UITableHeaderColumn, ( this, i ) );
|
||||
col.widget = eeNew( UITableHeaderColumn, ( mTag, this, i ) );
|
||||
col.widget->setParent( mHeader );
|
||||
col.widget->setEnabled( true );
|
||||
col.widget->setVisible( true );
|
||||
@@ -273,7 +273,7 @@ void UIAbstractTableView::setColumnsVisible( const std::vector<size_t> columns )
|
||||
if ( !getModel() )
|
||||
return;
|
||||
for ( size_t i = 0; i < getModel()->columnCount(); i++ )
|
||||
columnData( i).visible = false;
|
||||
columnData( i ).visible = false;
|
||||
for ( auto col : columns )
|
||||
columnData( col ).visible = true;
|
||||
createOrUpdateColumns();
|
||||
@@ -282,7 +282,7 @@ void UIAbstractTableView::setColumnsVisible( const std::vector<size_t> columns )
|
||||
UITableRow* UIAbstractTableView::createRow() {
|
||||
mUISceneNode->invalidateStyle( this );
|
||||
mUISceneNode->invalidateStyleState( this, true );
|
||||
UITableRow* rowWidget = UITableRow::New();
|
||||
UITableRow* rowWidget = UITableRow::New( mTag + "::row" );
|
||||
rowWidget->setParent( this );
|
||||
rowWidget->setLayoutSizePolicy( SizePolicy::Fixed, SizePolicy::Fixed );
|
||||
rowWidget->reloadStyle( true, true, true );
|
||||
@@ -324,7 +324,7 @@ void UIAbstractTableView::onScrollChange() {
|
||||
}
|
||||
|
||||
UIWidget* UIAbstractTableView::createCell( UIWidget* rowWidget, const ModelIndex& index ) {
|
||||
UITableCell* widget = UITableCell::New();
|
||||
UITableCell* widget = UITableCell::New( mTag + "::cell" );
|
||||
widget->setParent( rowWidget );
|
||||
widget->unsetFlags( UI_AUTO_SIZE );
|
||||
widget->clipEnable();
|
||||
@@ -424,7 +424,7 @@ void UIAbstractTableView::onSortColumn( const size_t& colIndex ) {
|
||||
Model* model = getModel();
|
||||
if ( !model )
|
||||
return;
|
||||
if ( model->isColumnSortable( colIndex ) ) {
|
||||
if ( model->isSortable() && model->isColumnSortable( colIndex ) ) {
|
||||
if ( -1 != model->keyColumn() && (Int64)colIndex != model->keyColumn() &&
|
||||
columnData( model->keyColumn() ).widget ) {
|
||||
UIImage* image =
|
||||
@@ -448,4 +448,63 @@ void UIAbstractTableView::onSortColumn( const size_t& colIndex ) {
|
||||
}
|
||||
}
|
||||
|
||||
Uint32 UIAbstractTableView::onTextInput( const TextInputEvent& event ) {
|
||||
if ( !mRowSearchByName )
|
||||
return 0;
|
||||
if ( mSearchTextAction )
|
||||
removeAction( mSearchTextAction );
|
||||
mSearchTextAction = Actions::Runnable::New(
|
||||
[&] {
|
||||
mSearchTextAction = nullptr;
|
||||
mSearchText = "";
|
||||
},
|
||||
Milliseconds( 350 ) );
|
||||
runAction( mSearchTextAction );
|
||||
mSearchText += String::toLower( event.getText() );
|
||||
ModelIndex index = findRowWithText( mSearchText );
|
||||
if ( index.isValid() )
|
||||
getSelection().set( index );
|
||||
return 1;
|
||||
}
|
||||
|
||||
ModelIndex UIAbstractTableView::findRowWithText( const std::string& ) {
|
||||
return {};
|
||||
}
|
||||
|
||||
bool UIAbstractTableView::applyProperty( const StyleSheetProperty& attribute ) {
|
||||
if ( !checkPropertyDefinition( attribute ) )
|
||||
return false;
|
||||
|
||||
switch ( attribute.getPropertyDefinition()->getPropertyId() ) {
|
||||
case PropertyId::RowHeight:
|
||||
setRowHeight( lengthFromValue( attribute.getValue(), PropertyRelativeTarget::None ) );
|
||||
break;
|
||||
default:
|
||||
return UIAbstractView::applyProperty( attribute );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string UIAbstractTableView::getPropertyString( const PropertyDefinition* propertyDef,
|
||||
const Uint32& propertyIndex ) {
|
||||
if ( NULL == propertyDef )
|
||||
return "";
|
||||
|
||||
switch ( propertyDef->getPropertyId() ) {
|
||||
case PropertyId::RowHeight:
|
||||
return String::format( "%.2fdp", getRowHeight() );
|
||||
default:
|
||||
return UIAbstractView::getPropertyString( propertyDef, propertyIndex );
|
||||
}
|
||||
}
|
||||
|
||||
bool UIAbstractTableView::getRowSearchByName() const {
|
||||
return mRowSearchByName;
|
||||
}
|
||||
|
||||
void UIAbstractTableView::setRowSearchByName( bool rowSearchByName ) {
|
||||
mRowSearchByName = rowSearchByName;
|
||||
}
|
||||
|
||||
}}} // namespace EE::UI::Abstract
|
||||
|
||||
@@ -54,10 +54,29 @@ void FileSystemModel::Node::traverseIfNeeded( const FileSystemModel& model ) {
|
||||
mInfo.getFilepath(), true, model.getDisplayConfig().sortByName,
|
||||
model.getDisplayConfig().foldersFirst, model.getDisplayConfig().ignoreHidden );
|
||||
|
||||
const auto& patterns = model.getDisplayConfig().acceptedExtensions;
|
||||
bool accepted;
|
||||
for ( auto file : files ) {
|
||||
if ( ( model.getMode() == Mode::DirectoriesOnly && file.isDirectory() ) ||
|
||||
model.getMode() == Mode::FilesAndDirectories )
|
||||
mChildren.emplace_back( Node( std::move( file ), this ) );
|
||||
model.getMode() == Mode::FilesAndDirectories ) {
|
||||
if ( file.isDirectory() || patterns.empty() ) {
|
||||
mChildren.emplace_back( Node( std::move( file ), this ) );
|
||||
} else {
|
||||
accepted = false;
|
||||
if ( patterns.size() ) {
|
||||
for ( size_t z = 0; z < patterns.size(); z++ ) {
|
||||
if ( patterns[z] == FileSystem::fileExtension( file.getFilepath() ) ) {
|
||||
accepted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
accepted = true;
|
||||
}
|
||||
if ( accepted )
|
||||
mChildren.emplace_back( Node( std::move( file ), this ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,13 +285,8 @@ UIIcon* FileSystemModel::iconFor( const Node& node, const ModelIndex& index ) co
|
||||
if ( index.column() == (Int64)treeColumn() || Column::Icon == index.column() ) {
|
||||
auto* scene = SceneManager::instance()->getUISceneNode();
|
||||
auto* d = scene->findIcon( node.getMimeType() );
|
||||
if ( !d ) {
|
||||
if ( !node.info().isDirectory() ) {
|
||||
return scene->findIcon( "file" );
|
||||
} else {
|
||||
return scene->findIcon( "folder" );
|
||||
}
|
||||
}
|
||||
if ( !d )
|
||||
return scene->findIcon( !node.info().isDirectory() ? "file" : "folder" );
|
||||
return d;
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
@@ -75,6 +75,10 @@ int SortingProxyModel::keyColumn() const {
|
||||
return mKeyColumn;
|
||||
}
|
||||
|
||||
size_t SortingProxyModel::treeColumn() const {
|
||||
return target().treeColumn();
|
||||
}
|
||||
|
||||
SortOrder SortingProxyModel::sortOrder() const {
|
||||
return mSortOrder;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <algorithm>
|
||||
#include <eepp/system/filesystem.hpp>
|
||||
#include <eepp/ui/models/filesystemmodel.hpp>
|
||||
#include <eepp/ui/uifiledialog.hpp>
|
||||
#include <eepp/ui/uilinearlayout.hpp>
|
||||
#include <eepp/ui/uilistboxitem.hpp>
|
||||
@@ -83,7 +84,7 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa
|
||||
->setLayoutSizePolicy( SizePolicy::WrapContent, SizePolicy::MatchParent )
|
||||
->setParent( hLayout );
|
||||
|
||||
mList = UIListBox::New();
|
||||
mList = UIListView::New();
|
||||
mList->setParent( linearLayout );
|
||||
mList->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
|
||||
->setLayoutWeight( 1 )
|
||||
@@ -94,14 +95,27 @@ UIFileDialog::UIFileDialog( Uint32 dialogFlags, const std::string& defaultFilePa
|
||||
goFolderUp();
|
||||
}
|
||||
} );
|
||||
mList->addEventListener( Event::OnItemKeyDown, [&]( const Event* event ) {
|
||||
const KeyEvent* KEvent = reinterpret_cast<const KeyEvent*>( event );
|
||||
if ( KEvent->getKeyCode() == KEY_RETURN || KEvent->getKeyCode() == KEY_KP_ENTER ) {
|
||||
openFileOrFolder();
|
||||
} else if ( KEvent->getKeyCode() == KEY_BACKSPACE ) {
|
||||
goFolderUp();
|
||||
mList->addEventListener( Event::OnModelEvent, [&]( const Event* event ) {
|
||||
const ModelEvent* modelEvent = static_cast<const ModelEvent*>( event );
|
||||
if ( modelEvent->getModelEventType() == ModelEventType::Open ) {
|
||||
Variant vPath(
|
||||
modelEvent->getModel()->data( modelEvent->getModelIndex(), Model::Role::Custom ) );
|
||||
if ( vPath.isValid() && vPath.is( Variant::Type::cstr ) )
|
||||
openFileOrFolder();
|
||||
}
|
||||
} );
|
||||
mList->setOnSelectionChange( [&] {
|
||||
if ( mList->getSelection().isEmpty() )
|
||||
return;
|
||||
auto* node = (FileSystemModel::Node*)mList->getSelection().first().data();
|
||||
if ( !isSaveDialog() ) {
|
||||
if ( getAllowFolderSelect() || !FileSystem::isDirectory( node->fullPath() ) )
|
||||
mFile->setText( node->getName() );
|
||||
} else if ( !FileSystem::isDirectory( node->fullPath() ) ) {
|
||||
mFile->setText( node->getName() );
|
||||
}
|
||||
} );
|
||||
mList->setAutoExpandOnSingleColumn( true );
|
||||
|
||||
hLayout = UILinearLayout::NewHorizontal();
|
||||
hLayout->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::WrapContent )
|
||||
@@ -203,41 +217,23 @@ void UIFileDialog::refreshFolder() {
|
||||
String( mCurPath ), getSortAlphabetically(), getFoldersFirst(), !getShowHidden() );
|
||||
std::vector<String> files;
|
||||
std::vector<std::string> patterns;
|
||||
bool accepted;
|
||||
Uint32 i, z;
|
||||
|
||||
if ( "*" != mFiletype->getText() ) {
|
||||
patterns = String::split( mFiletype->getText().toUtf8(), ';' );
|
||||
|
||||
for ( i = 0; i < patterns.size(); i++ )
|
||||
for ( size_t i = 0; i < patterns.size(); i++ )
|
||||
patterns[i] = FileSystem::fileExtension( patterns[i] );
|
||||
}
|
||||
|
||||
for ( i = 0; i < flist.size(); i++ ) {
|
||||
if ( FileSystem::isDirectory( mCurPath + flist[i] ) ) {
|
||||
files.push_back( flist[i] );
|
||||
} else if ( !getShowOnlyFolders() ) {
|
||||
accepted = false;
|
||||
mList->setModel( FileSystemModel::New(
|
||||
mCurPath,
|
||||
getShowOnlyFolders() ? FileSystemModel::Mode::DirectoriesOnly
|
||||
: FileSystemModel::Mode::FilesAndDirectories,
|
||||
FileSystemModel::DisplayConfig( getSortAlphabetically(), getFoldersFirst(),
|
||||
!getShowHidden(), patterns ) ) );
|
||||
|
||||
if ( patterns.size() ) {
|
||||
for ( z = 0; z < patterns.size(); z++ ) {
|
||||
if ( patterns[z] == FileSystem::fileExtension( flist[i] ) ) {
|
||||
accepted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
accepted = true;
|
||||
}
|
||||
|
||||
if ( accepted )
|
||||
files.push_back( flist[i] );
|
||||
}
|
||||
}
|
||||
|
||||
mList->clear();
|
||||
|
||||
mList->addListBoxItems( files );
|
||||
mList->setColumnsVisible( {FileSystemModel::Name} );
|
||||
mList->setHeadersVisible( false );
|
||||
|
||||
updateClickStep();
|
||||
|
||||
@@ -247,7 +243,7 @@ void UIFileDialog::refreshFolder() {
|
||||
void UIFileDialog::updateClickStep() {
|
||||
if ( NULL != mList->getVerticalScrollBar() ) {
|
||||
mList->getVerticalScrollBar()->setClickStep(
|
||||
1.f / ( ( mList->getCount() * mList->getRowHeight() ) /
|
||||
1.f / ( ( mList->getModel()->rowCount() * mList->getRowHeight() ) /
|
||||
(Float)mList->getSize().getHeight() ) );
|
||||
}
|
||||
}
|
||||
@@ -287,7 +283,11 @@ void UIFileDialog::disableButtons() {
|
||||
}
|
||||
|
||||
void UIFileDialog::openFileOrFolder() {
|
||||
std::string newPath = mCurPath + mList->getItemSelectedText();
|
||||
if ( mList->getSelection().isEmpty() )
|
||||
return;
|
||||
auto* node = (FileSystemModel::Node*)mList->getSelection().first().data();
|
||||
|
||||
std::string newPath = mCurPath + node->getName();
|
||||
|
||||
if ( FileSystem::isDirectory( newPath ) ) {
|
||||
setCurPath( newPath );
|
||||
@@ -327,21 +327,7 @@ Uint32 UIFileDialog::onMessage( const NodeMessage* Msg ) {
|
||||
break;
|
||||
}
|
||||
case NodeMessage::Selected: {
|
||||
if ( Msg->getSender() == mList ) {
|
||||
if ( !isSaveDialog() ) {
|
||||
if ( getAllowFolderSelect() ) {
|
||||
mFile->setText( mList->getItemSelectedText() );
|
||||
} else {
|
||||
if ( !FileSystem::isDirectory( getTempFullPath() ) ) {
|
||||
mFile->setText( mList->getItemSelectedText() );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( !FileSystem::isDirectory( getTempFullPath() ) ) {
|
||||
mFile->setText( mList->getItemSelectedText() );
|
||||
}
|
||||
}
|
||||
} else if ( Msg->getSender() == mFiletype ) {
|
||||
if ( Msg->getSender() == mFiletype ) {
|
||||
refreshFolder();
|
||||
}
|
||||
|
||||
@@ -361,7 +347,12 @@ void UIFileDialog::save() {
|
||||
}
|
||||
|
||||
void UIFileDialog::open() {
|
||||
if ( "" != mList->getItemSelectedText() || getAllowFolderSelect() ) {
|
||||
if ( mList->getSelection().isEmpty() )
|
||||
return;
|
||||
|
||||
auto* node = (FileSystemModel::Node*)mList->getSelection().first().data();
|
||||
|
||||
if ( "" != node->getName() || getAllowFolderSelect() ) {
|
||||
if ( !getAllowFolderSelect() ) {
|
||||
if ( FileSystem::isDirectory( getFullPath() ) )
|
||||
return;
|
||||
@@ -453,16 +444,6 @@ std::string UIFileDialog::getFullPath() {
|
||||
return tPath;
|
||||
}
|
||||
|
||||
std::string UIFileDialog::getTempFullPath() {
|
||||
std::string tPath = mCurPath;
|
||||
|
||||
FileSystem::dirAddSlashAtEnd( tPath );
|
||||
|
||||
tPath += mList->getItemSelectedText().toUtf8();
|
||||
|
||||
return tPath;
|
||||
}
|
||||
|
||||
std::string UIFileDialog::getCurPath() const {
|
||||
return mCurPath;
|
||||
}
|
||||
@@ -470,8 +451,10 @@ std::string UIFileDialog::getCurPath() const {
|
||||
std::string UIFileDialog::getCurFile() const {
|
||||
if ( mDialogFlags & SaveDialog )
|
||||
return mFile->getText();
|
||||
|
||||
return mList->getItemSelectedText().toUtf8();
|
||||
if ( mList->getSelection().isEmpty() )
|
||||
return "";
|
||||
auto* node = (FileSystemModel::Node*)mList->getSelection().first().data();
|
||||
return node->getName();
|
||||
}
|
||||
|
||||
UIPushButton* UIFileDialog::getButtonOpen() const {
|
||||
@@ -486,7 +469,7 @@ UIPushButton* UIFileDialog::getButtonUp() const {
|
||||
return mButtonUp;
|
||||
}
|
||||
|
||||
UIListBox* UIFileDialog::getList() const {
|
||||
UIListView* UIFileDialog::getList() const {
|
||||
return mList;
|
||||
}
|
||||
|
||||
@@ -518,9 +501,8 @@ const KeyBindings::Shortcut& UIFileDialog::getCloseShortcut() const {
|
||||
}
|
||||
|
||||
void UIFileDialog::setFileName( const std::string& name ) {
|
||||
if ( mFile ) {
|
||||
if ( mFile )
|
||||
mFile->setText( name );
|
||||
}
|
||||
}
|
||||
|
||||
void UIFileDialog::setCloseShortcut( const KeyBindings::Shortcut& closeWithKey ) {
|
||||
|
||||
@@ -306,7 +306,7 @@ void UIListBox::setRowHeight() {
|
||||
FontSize = fontStyleConfig.getFont()->getFontHeight(
|
||||
PixelDensity::dpToPxI( fontStyleConfig.getFontCharacterSize() ) );
|
||||
|
||||
mRowHeight = (Uint32)PixelDensity::pxToDpI( FontSize ) + 4;
|
||||
mRowHeight = (Uint32)PixelDensity::pxToDpI( FontSize + 4 );
|
||||
}
|
||||
|
||||
if ( tOldRowHeight != mRowHeight ) {
|
||||
|
||||
28
src/eepp/ui/uilistview.cpp
Normal file
28
src/eepp/ui/uilistview.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include <eepp/ui/uilistview.hpp>
|
||||
|
||||
namespace EE { namespace UI {
|
||||
|
||||
UIListView* UIListView::New() {
|
||||
return eeNew( UIListView, () );
|
||||
}
|
||||
|
||||
UIListView::UIListView() : UITableView( "listview" ) {
|
||||
setHeadersVisible( false );
|
||||
applyDefaultTheme();
|
||||
}
|
||||
|
||||
Uint32 UIListView::getType() const {
|
||||
return UI_TYPE_LISTVIEW;
|
||||
}
|
||||
|
||||
bool UIListView::isType( const Uint32& type ) const {
|
||||
return UIListView::getType() == type ? true : UITableView::isType( type );
|
||||
}
|
||||
|
||||
void UIListView::setTheme( UITheme* Theme ) {
|
||||
UIWidget::setTheme( Theme );
|
||||
setThemeSkin( Theme, "listbox" );
|
||||
onThemeLoaded();
|
||||
}
|
||||
|
||||
}} // namespace EE::UI
|
||||
@@ -4,8 +4,9 @@
|
||||
|
||||
namespace EE { namespace UI {
|
||||
|
||||
UITableHeaderColumn::UITableHeaderColumn( UIAbstractTableView* view, const size_t& colIndex ) :
|
||||
UIPushButton( "table::header::column" ), mView( view ), mColIndex( colIndex ) {
|
||||
UITableHeaderColumn::UITableHeaderColumn( const std::string& parentTag, UIAbstractTableView* view,
|
||||
const size_t& colIndex ) :
|
||||
UIPushButton( parentTag + "::header::column" ), mView( view ), mColIndex( colIndex ) {
|
||||
setDragEnabled( true );
|
||||
mInnerWidgetOrientation = InnerWidgetOrientation::Right;
|
||||
auto cb = [&]( const Event* ) { updateLayout(); };
|
||||
|
||||
@@ -10,10 +10,12 @@ UITableView* UITableView::New() {
|
||||
return eeNew( UITableView, () );
|
||||
}
|
||||
|
||||
UITableView::UITableView() : UIAbstractTableView( "tableview" ) {
|
||||
UITableView::UITableView( const std::string& tag ) : UIAbstractTableView( tag ) {
|
||||
clipEnable();
|
||||
}
|
||||
|
||||
UITableView::UITableView() : UITableView( "tableview" ) {}
|
||||
|
||||
Uint32 UITableView::getType() const {
|
||||
return UI_TYPE_TABLEVIEW;
|
||||
}
|
||||
@@ -238,4 +240,20 @@ Uint32 UITableView::onKeyDown( const KeyEvent& event ) {
|
||||
return UIAbstractTableView::onKeyDown( event );
|
||||
}
|
||||
|
||||
ModelIndex UITableView::findRowWithText( const std::string& text ) {
|
||||
Model* model = getModel();
|
||||
if ( !model || model->rowCount() == 0 )
|
||||
return {};
|
||||
size_t rc = model->rowCount();
|
||||
for ( size_t i = 0; i < rc; i++ ) {
|
||||
ModelIndex index = model->index(
|
||||
i, model->keyColumn() != -1 ? model->keyColumn()
|
||||
: ( model->treeColumn() >= 0 ? model->treeColumn() : 0 ) );
|
||||
Variant var = model->data( index );
|
||||
if ( var.isValid() && String::startsWith( String::toLower( var.toString() ), text ) )
|
||||
return model->index( index.row(), 0 );
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -664,4 +664,25 @@ void UITreeView::onOpenTreeModelIndex( const ModelIndex& index, bool open ) {
|
||||
sendEvent( &event );
|
||||
}
|
||||
|
||||
void UITreeView::onSortColumn( const size_t& ) {
|
||||
// Do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
ModelIndex UITreeView::findRowWithText( const std::string& text ) {
|
||||
Model* model = getModel();
|
||||
if ( !model || model->rowCount() == 0 )
|
||||
return {};
|
||||
ModelIndex foundIndex = {};
|
||||
traverseTree( [&]( const int&, const ModelIndex& index, const size_t&, const Float& ) {
|
||||
Variant var = model->data( index );
|
||||
if ( var.isValid() && String::startsWith( String::toLower( var.toString() ), text ) ) {
|
||||
foundIndex = index;
|
||||
return IterationDecision::Stop;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
} );
|
||||
return foundIndex;
|
||||
}
|
||||
|
||||
}} // namespace EE::UI
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <eepp/ui/uiimage.hpp>
|
||||
#include <eepp/ui/uilinearlayout.hpp>
|
||||
#include <eepp/ui/uilistbox.hpp>
|
||||
#include <eepp/ui/uilistview.hpp>
|
||||
#include <eepp/ui/uiloader.hpp>
|
||||
#include <eepp/ui/uimenubar.hpp>
|
||||
#include <eepp/ui/uiprogressbar.hpp>
|
||||
@@ -20,8 +21,6 @@
|
||||
#include <eepp/ui/uisplitter.hpp>
|
||||
#include <eepp/ui/uisprite.hpp>
|
||||
#include <eepp/ui/uitab.hpp>
|
||||
#include <eepp/ui/uiwidgettable.hpp>
|
||||
#include <eepp/ui/uiwidgettablerow.hpp>
|
||||
#include <eepp/ui/uitableview.hpp>
|
||||
#include <eepp/ui/uitabwidget.hpp>
|
||||
#include <eepp/ui/uitextedit.hpp>
|
||||
@@ -33,6 +32,8 @@
|
||||
#include <eepp/ui/uitreeview.hpp>
|
||||
#include <eepp/ui/uiviewpager.hpp>
|
||||
#include <eepp/ui/uiwidgetcreator.hpp>
|
||||
#include <eepp/ui/uiwidgettable.hpp>
|
||||
#include <eepp/ui/uiwidgettablerow.hpp>
|
||||
#include <eepp/ui/uiwindow.hpp>
|
||||
|
||||
namespace EE { namespace UI {
|
||||
@@ -84,6 +85,7 @@ void UIWidgetCreator::createBaseWidgetList() {
|
||||
registeredWidget["splitter"] = UISplitter::New;
|
||||
registeredWidget["treeview"] = UITreeView::New;
|
||||
registeredWidget["tableview"] = UITableView::New;
|
||||
registeredWidget["listview"] = UIListView::New;
|
||||
|
||||
registeredWidget["hbox"] = UILinearLayout::NewHorizontal;
|
||||
registeredWidget["vbox"] = UILinearLayout::NewVertical;
|
||||
|
||||
@@ -203,6 +203,7 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
|
||||
view->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
|
||||
view->setParent( vlay );
|
||||
view->setModel( SortingProxyModel::New( model ) );
|
||||
//view->setModel( model );
|
||||
eePRINTL( "Total time: %.2fms", clock.getElapsedTime().asMilliseconds() );
|
||||
|
||||
UIWindow* uiWin = UIWindow::NewOpt( UIWindow::LINEAR_LAYOUT );
|
||||
|
||||
2
src/thirdparty/SOIL2
vendored
2
src/thirdparty/SOIL2
vendored
Submodule src/thirdparty/SOIL2 updated: 5adc6cd56b...200fac61db
2
src/thirdparty/efsw
vendored
2
src/thirdparty/efsw
vendored
Submodule src/thirdparty/efsw updated: 36f27d7ccf...2dd7e484d3
@@ -2016,10 +2016,10 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
|
||||
#search_replace.error {
|
||||
border-color: #ff4040;
|
||||
}
|
||||
TableView#locate_bar_table > table::row > table::cell:nth-child(2) {
|
||||
TableView#locate_bar_table > tableview::row > tableview::cell:nth-child(2) {
|
||||
color: var(--font-hint);
|
||||
}
|
||||
TableView#locate_bar_table > table::row:selected > table::cell:nth-child(2) {
|
||||
TableView#locate_bar_table > tableview::row:selected > tableview::cell:nth-child(2) {
|
||||
color: var(--font);
|
||||
}
|
||||
#search_tree treeview::cell {
|
||||
@@ -2127,7 +2127,6 @@ void App::init( const std::string& file, const Float& pidelDensity ) {
|
||||
addIcon( "tree-expanded", 0xea50 );
|
||||
addIcon( "tree-contracted", 0xea54 );
|
||||
addIcon( "search", 0xf0d1 );
|
||||
|
||||
addIcon( "go-up", 0xea78 );
|
||||
addIcon( "ok", 0xeb7a );
|
||||
addIcon( "cancel", 0xeb98 );
|
||||
|
||||
Reference in New Issue
Block a user