This commit is contained in:
Martín Lucas Golini
2020-07-04 03:04:44 -03:00
parent 16f58f2018
commit 1e0324be3a
13 changed files with 1360 additions and 859 deletions

View File

@@ -0,0 +1,91 @@
#ifndef EE_UI_MODEL_MODEL_HPP
#define EE_UI_MODEL_MODEL_HPP
#include <eepp/ui/abstract/modelindex.hpp>
#include <functional>
#include <string>
#include <unordered_set>
namespace EE { namespace UI {
class UIAbstractView;
}} // namespace EE::UI
namespace EE { namespace UI { namespace Abstract {
enum class SortOrder { None, Ascending, Descending };
class Variant;
class EE_API Model {
public:
enum UpdateFlag {
DontInvalidateIndexes = 0,
InvalidateAllIndexes = 1 << 0,
};
enum class Role {
Display,
Sort,
Custom,
ForegroundColor,
BackgroundColor,
Icon,
Font,
DragData,
TextAlignment,
};
virtual ~Model(){};
virtual int rowCount( const ModelIndex& = ModelIndex() ) const = 0;
virtual int columnCount( const ModelIndex& = ModelIndex() ) const = 0;
virtual std::string columnName( int ) const { return {}; }
virtual Variant data( const ModelIndex&, Role = Role::Display ) const = 0;
virtual void update() = 0;
virtual ModelIndex parentIndex( const ModelIndex& ) const { return {}; }
virtual ModelIndex index( int row, int column = 0, const ModelIndex& = ModelIndex() ) const {
return createIndex( row, column );
}
virtual ModelIndex sibling( int row, int column, const ModelIndex& parent ) const;
virtual void setData( const ModelIndex&, const Variant& ) {}
virtual int treeColumn() const { return 0; }
virtual bool acceptsDrag( const ModelIndex&, const std::string& dataType );
virtual bool isColumnSortable( int /*columnIndex*/ ) const { return true; }
virtual std::string dragDataType() const { return {}; }
bool isValid( const ModelIndex& index ) const {
auto parentIndex = this->parentIndex( index );
return index.row() >= 0 && index.row() < rowCount( parentIndex ) && index.column() >= 0 &&
index.column() < columnCount( parentIndex );
}
virtual int keyColumn() const { return -1; }
virtual SortOrder sortOrder() const { return SortOrder::None; }
virtual void setKeyColumnAndSortOrder( int, SortOrder ) {}
void registerView( UIAbstractView* );
void unregisterView( UIAbstractView* );
std::function<void()> onUpdate;
protected:
Model(){};
void forEachView( std::function<void( UIAbstractView* )> );
void didUpdate( unsigned flags = UpdateFlag::InvalidateAllIndexes );
ModelIndex createIndex( int row, int column, const void* data = nullptr ) const;
private:
std::unordered_set<UIAbstractView*> mViews;
};
inline ModelIndex ModelIndex::parent() const {
return mModel ? mModel->parentIndex( *this ) : ModelIndex();
}
}}} // namespace EE::UI::Abstract
#endif // EE_UI_MODEL_MODEL_HPP

View File

@@ -0,0 +1,48 @@
#ifndef EE_UI_MODELEDITINGDELEGATE_HPP
#define EE_UI_MODELEDITINGDELEGATE_HPP
#include <eepp/ui/abstract/model.hpp>
#include <eepp/ui/uiwidget.hpp>
#include <memory>
namespace EE { namespace UI { namespace Abstract {
class EE_API ModelEditingDelegate {
public:
virtual ~ModelEditingDelegate() {}
void bind( std::shared_ptr<Model> model, const ModelIndex& index ) {
if ( mModel.get() == model.get() && mIndex == index )
return;
mModel = model;
mIndex = index;
mWidget = createWidget();
}
UIWidget* getWidget() { return mWidget; }
UIWidget* getWidget() const { return mWidget; }
std::function<void()> onCommit;
virtual Variant value() const = 0;
virtual void setValue( const Variant& ) = 0;
virtual void willBeginEditing() {}
protected:
ModelEditingDelegate() {}
virtual UIWidget* createWidget() = 0;
void commit() {
if ( onCommit )
onCommit();
}
std::shared_ptr<Model> mModel;
ModelIndex mIndex;
UIWidget* mWidget;
};
}}} // namespace EE::UI::Abstract
#endif // MODELEDITINGDELEGATE_HPP

View File

@@ -0,0 +1,42 @@
#ifndef EE_UI_MODEL_MODELINDEX_HPP
#define EE_UI_MODEL_MODELINDEX_HPP
#include <eepp/config.hpp>
namespace EE { namespace UI { namespace Abstract {
class Model;
class EE_API ModelIndex {
public:
ModelIndex() {}
bool isValid() const { return mRow != -1 && mColumn != -1; }
const Int64& row() const { return mRow; }
const Int64& column() const { return mColumn; }
void* data() const { return mData; }
ModelIndex parent() const;
bool hasParent() const { return parent().isValid(); }
bool operator==( const ModelIndex& other ) const {
return mModel == other.mModel && mRow == other.mRow && mColumn == other.mColumn &&
mData == other.mData;
}
bool operator!=( const ModelIndex& other ) const { return !( *this == other ); }
protected:
friend class Model;
const Model* mModel{nullptr};
Int64 mRow{-1};
Int64 mColumn{-1};
void* mData{nullptr};
ModelIndex( const Model& model, int row, int column, void* internalData ) :
mModel( &model ), mRow( row ), mColumn( column ), mData( internalData ) {}
};
}}} // namespace EE::UI::Model
#endif // EE_UI_MODEL_MODELINDEX_HPP

View File

@@ -0,0 +1,70 @@
#ifndef EE_UI_MODEL_MODELSELECTION_HPP
#define EE_UI_MODEL_MODELSELECTION_HPP
#include <algorithm>
#include <eepp/ui/abstract/modelindex.hpp>
#include <functional>
#include <unordered_set>
namespace EE { namespace UI {
class UIAbstractView;
}} // namespace EE::UI
namespace EE { namespace UI { namespace Abstract {
class EE_API ModelSelection {
public:
ModelSelection( UIAbstractView* view ) : mView( view ) {}
int size() const { return mIndexes.size(); }
bool isEmpty() const { return mIndexes.empty(); }
bool contains( const ModelIndex& index ) const {
return std::find( mIndexes.begin(), mIndexes.end(), index ) != mIndexes.end();
}
bool containsRow( int row ) const {
for ( auto& index : mIndexes ) {
if ( index.row() == row )
return true;
}
return false;
}
void set( const ModelIndex& );
void add( const ModelIndex& );
void toggle( const ModelIndex& );
bool remove( const ModelIndex& );
void clear();
template <typename Callback> void forEachIndex( Callback callback ) {
for ( auto& index : indexes() )
callback( index );
}
template <typename Callback> void forEachIndex( Callback callback ) const {
for ( auto& index : indexes() )
callback( index );
}
std::vector<ModelIndex> indexes() const {
std::vector<ModelIndex> selectedIndexes;
for ( auto& index : mIndexes )
selectedIndexes.push_back( index );
return selectedIndexes;
}
ModelIndex first() const {
if ( mIndexes.empty() )
return {};
return *mIndexes.begin();
}
void removeMatching( std::function<bool( const ModelIndex& )> );
protected:
UIAbstractView* mView;
std::vector<ModelIndex> mIndexes;
};
}}} // namespace EE::UI::Abstract
#endif // EE_UI_MODEL_MODELSELECTION_HPP

View File

@@ -0,0 +1,74 @@
#ifndef EE_UI_UIABSTRACTVIEW_HPP
#define EE_UI_UIABSTRACTVIEW_HPP
#include <eepp/ui/abstract/model.hpp>
#include <eepp/ui/abstract/modeleditingdelegate.hpp>
#include <eepp/ui/abstract/modelselection.hpp>
#include <eepp/ui/uiwidget.hpp>
#include <memory>
using namespace EE::UI::Abstract;
namespace EE { namespace UI {
class EE_API UIAbstractView : public UIWidget {
public:
void set_model( std::shared_ptr<Model> );
Model* model() { return m_model.get(); }
const Model* model() const { return m_model.get(); }
ModelSelection& selection() { return m_selection; }
const ModelSelection& selection() const { return m_selection; }
virtual void select_all() = 0;
bool is_editable() const { return m_editable; }
void set_editable( bool editable ) { m_editable = editable; }
virtual void didUpdateModel( unsigned flags );
virtual void didUpdateSelection();
virtual Vector2i content_rect( const ModelIndex& ) const { return {}; }
virtual ModelIndex index_at_event_position( const Vector2i& ) const = 0;
void set_activates_on_selection( bool b ) { m_activates_on_selection = b; }
bool activates_on_selection() const { return m_activates_on_selection; }
std::function<void()> on_selection_change;
std::function<void( const ModelIndex& )> on_activation;
std::function<void( const ModelIndex& )> on_selection;
std::function<void( const ModelIndex&, const DropEvent& )> on_drop;
//std::function<OwnPtr<ModelEditingDelegate>( const ModelIndex& )> aid_create_editing_delegate;
void notifySelectionChange();
protected:
UIAbstractView();
virtual ~UIAbstractView();
virtual void did_scroll();
void set_hovered_index( const ModelIndex& );
void activate( const ModelIndex& );
void activate_selected();
bool m_editable{false};
ModelIndex m_edit_index;
UIWidget* m_edit_widget;
Vector2i m_edit_widget_content_rect;
Vector2i m_left_mousedown_position;
bool m_might_drag{false};
ModelIndex m_hovered_index;
private:
std::shared_ptr<Model> m_model;
std::unique_ptr<ModelEditingDelegate> m_editing_delegate;
ModelSelection m_selection;
bool m_activates_on_selection{false};
};
}} // namespace EE::UI
#endif // EE_UI_UIABSTRACTVIEW_HPP

View File

@@ -433,7 +433,7 @@ function build_link_configuration( package_name, use_ee_icon )
end
fix_shared_lib_linking_path( package_name, "libeepp-debug" )
if not os.is_real("emscripten") then
targetname ( package_name .. "-debug" .. extension )
else
@@ -748,7 +748,7 @@ function build_eepp( build_name )
"src/eepp/scene/*.cpp",
"src/eepp/scene/actions/*.cpp",
"src/eepp/ui/*.cpp",
"src/eepp/ui/actions/*.cpp",
"src/eepp/ui/abstract/*.cpp",
"src/eepp/ui/css/*.cpp",
"src/eepp/ui/doc/*.cpp",
"src/eepp/ui/tools/*.cpp",

File diff suppressed because it is too large Load Diff

View File

@@ -82,7 +82,7 @@ CODE_SRCS := \
ui/*.cpp \
ui/css/*.cpp \
ui/doc/*.cpp \
ui/actions/*.cpp \
ui/model/*.cpp \
ui/tools/*.cpp \
maps/*.cpp \
maps/mapeditor/*.cpp

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.12.2, 2020-07-02T20:21:25. -->
<!-- Written by QtCreator 4.12.2, 2020-07-04T03:04:27. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>

View File

@@ -294,8 +294,12 @@
../../include/eepp/thirdparty/chipmunk/cpSpatialIndex.h
../../include/eepp/thirdparty/chipmunk/cpVect.h
../../include/eepp/thirdparty/PlusCallback/callback.hpp
../../include/eepp/ui/abstract/model.hpp
../../include/eepp/ui/base.hpp
../../include/eepp/ui.hpp
../../include/eepp/ui/abstract/modeleditingdelegate.hpp
../../include/eepp/ui/abstract/modelindex.hpp
../../include/eepp/ui/abstract/modelselection.hpp
../../include/eepp/ui/border.hpp
../../include/eepp/ui/css/animationdefinition.hpp
../../include/eepp/ui/css/drawableimageparser.hpp
@@ -331,9 +335,13 @@
../../include/eepp/ui/doc/undostack.hpp
../../include/eepp/ui/keyboardshortcut.hpp
../../include/eepp/ui/marginmove/scale.hpp
../../include/eepp/ui/abstract/model.hpp
../../include/eepp/ui/abstract/modelindex.hpp
../../include/eepp/ui/abstract/modelselection.hpp
../../include/eepp/ui/tools/textureatlaseditor.hpp
../../include/eepp/ui/tools/uicodeeditorsplitter.hpp
../../include/eepp/ui/tools/uicolorpicker.hpp
../../include/eepp/ui/uiabstractview.hpp
../../include/eepp/ui/uibackgrounddrawable.hpp
../../include/eepp/ui/uiborderdrawable.hpp
../../include/eepp/ui/uicheckbox.hpp
@@ -754,6 +762,8 @@
../../src/eepp/system/translator.cpp
../../src/eepp/system/virtualfilesystem.cpp
../../src/eepp/system/zip.cpp
../../src/eepp/ui/abstract/model.cpp
../../src/eepp/ui/abstract/modelselection.cpp
../../src/eepp/ui/border.cpp
../../src/eepp/ui/css/animationdefinition.cpp
../../src/eepp/ui/css/drawableimageparser.cpp
@@ -784,6 +794,8 @@
../../src/eepp/ui/doc/textdocument.cpp
../../src/eepp/ui/doc/undostack.cpp
../../src/eepp/ui/keyboardshortcut.cpp
../../src/eepp/ui/abstract/model.cpp
../../src/eepp/ui/abstract/modelselection.cpp
../../src/eepp/ui/tools/textureatlaseditor.cpp
../../src/eepp/ui/tools/textureatlasnew.cpp
../../src/eepp/ui/tools/textureatlasnew.hpp
@@ -791,6 +803,7 @@
../../src/eepp/ui/tools/textureatlastextureregioneditor.hpp
../../src/eepp/ui/tools/uicodeeditorsplitter.cpp
../../src/eepp/ui/tools/uicolorpicker.cpp
../../src/eepp/ui/uiabstractview.cpp
../../src/eepp/ui/uibackgrounddrawable.cpp
../../src/eepp/ui/uiborderdrawable.cpp
../../src/eepp/ui/uicheckbox.cpp

View File

@@ -0,0 +1,42 @@
#include <eepp/ui/abstract/model.hpp>
#include <eepp/ui/uiabstractview.hpp>
namespace EE { namespace UI { namespace Abstract {
void Model::didUpdate( unsigned flags ) {
if ( onUpdate )
onUpdate();
forEachView( [&]( UIAbstractView* view ) { view->didUpdateModel( flags ); } );
}
void Model::forEachView( std::function<void( UIAbstractView* )> callback ) {
for ( auto view : mViews )
callback( view );
}
void Model::unregisterView( UIAbstractView* view ) {
mViews.erase( view );
}
void Model::registerView( UIAbstractView* view ) {
mViews.insert( view );
}
ModelIndex Model::createIndex( int row, int column, const void* data ) const {
return ModelIndex( *this, row, column, const_cast<void*>( data ) );
}
ModelIndex Model::sibling( int row, int column, const ModelIndex& parent ) const {
if ( !parent.isValid() )
return index( row, column, {} );
int rowCount = this->rowCount( parent );
if ( row < 0 || row > rowCount )
return {};
return index( row, column, parent );
}
bool Model::acceptsDrag( const ModelIndex&, const std::string& dataType ) {
return false;
}
}}} // namespace EE::UI::Abstract

View File

@@ -0,0 +1,62 @@
#include <eepp/core.hpp>
#include <eepp/ui/abstract/modelselection.hpp>
#include <eepp/ui/uiabstractview.hpp>
namespace EE { namespace UI { namespace Abstract {
void ModelSelection::removeMatching( std::function<bool( const ModelIndex& )> filter ) {
std::vector<std::vector<ModelIndex>::iterator> toRemove;
for ( auto it = mIndexes.begin(); it != mIndexes.end(); it++ ) {
if ( filter( *it ) )
toRemove.push_back( it );
}
for ( auto& index : toRemove )
mIndexes.erase( index );
}
void ModelSelection::set( const ModelIndex& index ) {
eeASSERT( index.isValid() );
if ( mIndexes.size() == 1 && contains( index ) )
return;
mIndexes.clear();
mIndexes.push_back( index );
mView->notifySelectionChange();
}
void ModelSelection::add( const ModelIndex& index ) {
eeASSERT( index.isValid() );
auto contains = std::find( mIndexes.begin(), mIndexes.end(), index );
if ( contains == mIndexes.end() )
return;
mIndexes.push_back( index );
mView->notifySelectionChange();
}
void ModelSelection::toggle( const ModelIndex& index ) {
eeASSERT( index.isValid() );
auto contains = std::find( mIndexes.begin(), mIndexes.end(), index );
if ( contains != mIndexes.end() )
mIndexes.erase( contains );
else
mIndexes.push_back( index );
mView->notifySelectionChange();
}
bool ModelSelection::remove( const ModelIndex& index ) {
eeASSERT( index.isValid() );
auto contains = std::find( mIndexes.begin(), mIndexes.end(), index );
if ( contains == mIndexes.end() )
return false;
mIndexes.erase( contains );
mView->notifySelectionChange();
return true;
}
void ModelSelection::clear() {
if ( mIndexes.empty() )
return;
mIndexes.clear();
mView->notifySelectionChange();
}
}}} // namespace EE::UI::Abstract

View File

@@ -0,0 +1,59 @@
#include <eepp/scene/eventdispatcher.hpp>
#include <eepp/ui/uiabstractview.hpp>
#include <eepp/window/input.hpp>
using namespace EE::Scene;
using namespace EE::Window;
namespace EE { namespace UI {
UIAbstractView::UIAbstractView() : m_selection( this ) {}
UIAbstractView::~UIAbstractView() {}
void UIAbstractView::set_model( std::shared_ptr<Model> model ) {
if ( model.get() == m_model.get() )
return;
if ( m_model )
m_model->unregisterView( this );
m_model = model;
if ( m_model )
m_model->registerView( this );
didUpdateModel( Model::InvalidateAllIndexes );
}
void UIAbstractView::didUpdateModel( unsigned flags ) {
m_hovered_index = {};
if ( !model() || ( flags & Model::InvalidateAllIndexes ) ) {
selection().clear();
} else {
selection().removeMatching( [this]( auto& index ) { return !model()->isValid( index ); } );
}
}
void UIAbstractView::didUpdateSelection() {
if ( model() && on_selection && selection().first().isValid() )
on_selection( selection().first() );
}
void UIAbstractView::did_scroll() {}
void UIAbstractView::activate( const ModelIndex& index ) {
if ( on_activation )
on_activation( index );
}
void UIAbstractView::activate_selected() {
if ( !on_activation )
return;
selection().forEachIndex( [this]( auto& index ) { on_activation( index ); } );
}
void UIAbstractView::notifySelectionChange() {
didUpdateSelection();
if ( on_selection_change )
on_selection_change();
}
}} // namespace EE::UI