mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-13 04:42:12 +03:00
Improved UITreeView selection.
ecode: Widget picker in scene node inspector. Added support for @string(key, "fallback_text") in translator and text properties.
This commit is contained in:
@@ -98,6 +98,10 @@ class EE_API EventDispatcher {
|
||||
|
||||
Node* getNodeWasDragging() const;
|
||||
|
||||
bool getDisableMousePress() const;
|
||||
|
||||
void setDisableMousePress( bool disableMousePress );
|
||||
|
||||
protected:
|
||||
EE::Window::Window* mWindow;
|
||||
Input* mInput;
|
||||
@@ -113,6 +117,8 @@ class EE_API EventDispatcher {
|
||||
Vector2i mClickPos;
|
||||
Int32 mCbId;
|
||||
bool mFirstPress;
|
||||
bool mDisableMousePress{ false };
|
||||
bool mJustDisabledMousePress{ false };
|
||||
Node* mNodeWasDragging;
|
||||
Node* mNodeDragging;
|
||||
Time mElapsed;
|
||||
|
||||
@@ -69,7 +69,8 @@ class EE_API UIAbstractTableView : public UIAbstractView {
|
||||
|
||||
void moveSelection( int steps );
|
||||
|
||||
virtual void setSelection( const ModelIndex& index, bool scrollToSelection = true );
|
||||
virtual void setSelection( const ModelIndex& index, bool scrollToSelection = true,
|
||||
bool openModelIndexTree = false );
|
||||
|
||||
const size_t& getIconSize() const;
|
||||
|
||||
|
||||
@@ -34,6 +34,10 @@ class EE_API WidgetTreeModel : public Model {
|
||||
|
||||
virtual void update() override;
|
||||
|
||||
ModelIndex getRoot() const;
|
||||
|
||||
ModelIndex getModelIndex( const Node* node ) const;
|
||||
|
||||
protected:
|
||||
Node* mRoot;
|
||||
|
||||
|
||||
@@ -131,12 +131,17 @@ class EE_API UITreeView : public UIAbstractTableView {
|
||||
|
||||
virtual ModelIndex selectRowWithPath( std::string path );
|
||||
|
||||
virtual void setSelection( const ModelIndex& index, bool scrollToSelection = true );
|
||||
virtual void setSelection( const ModelIndex& index, bool scrollToSelection = true,
|
||||
bool openModelIndexTree = true );
|
||||
|
||||
virtual void openModelIndexParentTree( const ModelIndex& index );
|
||||
|
||||
bool getFocusOnSelection() const;
|
||||
|
||||
void setFocusOnSelection( bool focusOnSelection );
|
||||
|
||||
bool tryOpenModelIndex( const ModelIndex& index, bool forceUpdate = true );
|
||||
|
||||
protected:
|
||||
enum class IterationDecision {
|
||||
Continue,
|
||||
|
||||
@@ -89,6 +89,11 @@ void EventDispatcher::update( const Time& time ) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( mDisableMousePress || mJustDisabledMousePress ) {
|
||||
mJustDisabledMousePress = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( NULL != mNodeDragging )
|
||||
mNodeDragging->onCalculateDrag( mMousePos, mInput->getPressTrigger() );
|
||||
|
||||
@@ -331,4 +336,15 @@ Node* EventDispatcher::getNodeWasDragging() const {
|
||||
return mNodeWasDragging;
|
||||
}
|
||||
|
||||
bool EventDispatcher::getDisableMousePress() const {
|
||||
return mDisableMousePress;
|
||||
}
|
||||
|
||||
void EventDispatcher::setDisableMousePress( bool disableMousePress ) {
|
||||
if ( mDisableMousePress && !disableMousePress )
|
||||
mJustDisabledMousePress = true;
|
||||
mDisableMousePress = disableMousePress;
|
||||
|
||||
}
|
||||
|
||||
}} // namespace EE::Scene
|
||||
|
||||
@@ -489,11 +489,14 @@ void UIAbstractTableView::moveSelection( int steps ) {
|
||||
setSelection( newIndex );
|
||||
}
|
||||
|
||||
void UIAbstractTableView::setSelection( const ModelIndex& index, bool scrollToSelection ) {
|
||||
void UIAbstractTableView::setSelection( const ModelIndex& index, bool scrollToSelection,
|
||||
bool openModelIndexTree ) {
|
||||
if ( !getModel() )
|
||||
return;
|
||||
auto& model = *this->getModel();
|
||||
if ( model.isValid( index ) ) {
|
||||
if ( openModelIndexTree )
|
||||
onOpenMenuModelIndex( index );
|
||||
getSelection().set( index );
|
||||
if ( scrollToSelection )
|
||||
scrollToPosition(
|
||||
|
||||
@@ -77,4 +77,21 @@ void WidgetTreeModel::update() {
|
||||
onModelUpdate();
|
||||
}
|
||||
|
||||
ModelIndex WidgetTreeModel::getRoot() const {
|
||||
return createIndex( 0, 0, mRoot );
|
||||
}
|
||||
|
||||
ModelIndex WidgetTreeModel::getModelIndex( const Node* node ) const {
|
||||
eeASSERT( node != nullptr );
|
||||
const Node* fNode = node;
|
||||
while ( fNode ) {
|
||||
if ( fNode == mRoot )
|
||||
break;
|
||||
fNode = fNode->getParent();
|
||||
}
|
||||
if ( fNode != mRoot || nullptr == node->getParent() )
|
||||
return {};
|
||||
return createIndex( node->getNodeIndex(), 0, node );
|
||||
}
|
||||
|
||||
}}} // namespace EE::UI::Models
|
||||
|
||||
@@ -162,24 +162,43 @@ Translator& UISceneNode::getTranslator() {
|
||||
}
|
||||
|
||||
String UISceneNode::getTranslatorString( const std::string& str ) {
|
||||
if ( String::startsWith( str, "@string/" ) ) {
|
||||
String tstr = mTranslator.getString( str.substr( 8 ) );
|
||||
if ( str.size() >= 8 && String::startsWith( str, "@string" ) ) {
|
||||
if ( str[7] == '/' ) {
|
||||
String tstr = mTranslator.getString( str.substr( 8 ) );
|
||||
|
||||
if ( !tstr.empty() )
|
||||
return tstr;
|
||||
if ( !tstr.empty() )
|
||||
return tstr;
|
||||
} else if ( str[7] == '(' ) {
|
||||
FunctionString fun( FunctionString::parse( str ) );
|
||||
if ( !fun.isEmpty() ) {
|
||||
String tstr( mTranslator.getString( fun.getParameters()[0] ) );
|
||||
if ( !tstr.empty() )
|
||||
return tstr;
|
||||
if ( fun.getParameters().size() >= 2 )
|
||||
return fun.getParameters()[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return String( str );
|
||||
}
|
||||
|
||||
String UISceneNode::getTranslatorString( const std::string& str, const String& defaultValue ) {
|
||||
if ( String::startsWith( str, "@string/" ) ) {
|
||||
String tstr = mTranslator.getString( str.substr( 8 ) );
|
||||
|
||||
if ( !tstr.empty() )
|
||||
return tstr;
|
||||
if ( str.size() >= 8 && String::startsWith( str, "@string" ) ) {
|
||||
if ( str[7] == '/' ) {
|
||||
String tstr( mTranslator.getString( str.substr( 8 ) ) );
|
||||
if ( !tstr.empty() )
|
||||
return tstr;
|
||||
} else if ( str[7] == '(' ) {
|
||||
FunctionString fun( FunctionString::parse( str ) );
|
||||
if ( !fun.isEmpty() ) {
|
||||
String tstr( mTranslator.getString( fun.getParameters()[0] ) );
|
||||
if ( !tstr.empty() )
|
||||
return tstr;
|
||||
if ( fun.getParameters().size() >= 2 )
|
||||
return fun.getParameters()[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <eepp/ui/uiscenenode.hpp>
|
||||
#include <eepp/ui/uiscrollbar.hpp>
|
||||
#include <eepp/ui/uitreeview.hpp>
|
||||
#include <stack>
|
||||
|
||||
namespace EE { namespace UI {
|
||||
|
||||
@@ -140,6 +141,26 @@ void UITreeView::bindNavigationClick( UIWidget* widget ) {
|
||||
} );
|
||||
}
|
||||
|
||||
bool UITreeView::tryOpenModelIndex( const ModelIndex& index, bool forceUpdate ) {
|
||||
size_t rowCount = 0;
|
||||
{
|
||||
ConditionalLock l( getModel() != nullptr,
|
||||
getModel() ? &getModel()->resourceMutex() : nullptr );
|
||||
rowCount = getModel()->rowCount( index );
|
||||
}
|
||||
if ( rowCount ) {
|
||||
auto& data = getIndexMetadata( index );
|
||||
if ( !data.open ) {
|
||||
data.open = true;
|
||||
if ( forceUpdate )
|
||||
createOrUpdateColumns();
|
||||
onOpenTreeModelIndex( index, data.open );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UIWidget* UITreeView::setupCell( UITableCell* widget, UIWidget* rowWidget,
|
||||
const ModelIndex& index ) {
|
||||
widget->setParent( rowWidget );
|
||||
@@ -701,20 +722,7 @@ ModelIndex UITreeView::selectRowWithPath( std::string path ) {
|
||||
if ( foundIndex == ModelIndex() )
|
||||
break;
|
||||
|
||||
size_t rowCount = 0;
|
||||
{
|
||||
ConditionalLock l( getModel() != nullptr,
|
||||
getModel() ? &getModel()->resourceMutex() : nullptr );
|
||||
rowCount = getModel()->rowCount( foundIndex );
|
||||
}
|
||||
if ( rowCount ) {
|
||||
auto& data = getIndexMetadata( foundIndex );
|
||||
if ( !data.open ) {
|
||||
data.open = true;
|
||||
createOrUpdateColumns();
|
||||
onOpenTreeModelIndex( foundIndex, data.open );
|
||||
}
|
||||
}
|
||||
tryOpenModelIndex( foundIndex );
|
||||
|
||||
parentIndex = foundIndex;
|
||||
|
||||
@@ -726,13 +734,20 @@ ModelIndex UITreeView::selectRowWithPath( std::string path ) {
|
||||
return {};
|
||||
}
|
||||
|
||||
void UITreeView::setSelection( const ModelIndex& index, bool scrollToSelection ) {
|
||||
void UITreeView::setSelection( const ModelIndex& index, bool scrollToSelection,
|
||||
bool openModelIndexTree ) {
|
||||
if ( !getModel() )
|
||||
return;
|
||||
auto& model = *this->getModel();
|
||||
if ( model.isValid( index ) && scrollToSelection ) {
|
||||
if ( model.isValid( index ) ) {
|
||||
if ( openModelIndexTree )
|
||||
openModelIndexParentTree( index );
|
||||
|
||||
getSelection().set( index );
|
||||
|
||||
if ( !scrollToSelection )
|
||||
return;
|
||||
|
||||
ModelIndex prevIndex;
|
||||
ModelIndex foundIndex;
|
||||
Float curY = 0;
|
||||
@@ -759,6 +774,26 @@ void UITreeView::setSelection( const ModelIndex& index, bool scrollToSelection )
|
||||
}
|
||||
}
|
||||
|
||||
void UITreeView::openModelIndexParentTree( const ModelIndex& index ) {
|
||||
if ( !index.hasParent() )
|
||||
return;
|
||||
|
||||
std::stack<ModelIndex> indexes;
|
||||
ModelIndex parent = index;
|
||||
while ( parent.hasParent() ) {
|
||||
indexes.push( parent );
|
||||
parent = parent.parent();
|
||||
}
|
||||
|
||||
while ( !indexes.empty() ) {
|
||||
if ( !tryOpenModelIndex( indexes.top() ) )
|
||||
return;
|
||||
indexes.pop();
|
||||
}
|
||||
|
||||
createOrUpdateColumns();
|
||||
}
|
||||
|
||||
bool UITreeView::getFocusOnSelection() const {
|
||||
return mFocusOnSelection;
|
||||
}
|
||||
|
||||
@@ -519,18 +519,50 @@ App::~App() {
|
||||
eeSAFE_DELETE( mConsole );
|
||||
}
|
||||
|
||||
void App::checkWidgetPick( UITreeView* widgetTree ) {
|
||||
Input* input = mWindow->getInput();
|
||||
if ( input->getClickTrigger() & EE_BUTTON_LMASK ) {
|
||||
Node* node = mUISceneNode->getEventDispatcher()->getMouseOverNode();
|
||||
WidgetTreeModel* model = static_cast<WidgetTreeModel*>( widgetTree->getModel() );
|
||||
ModelIndex index( model->getModelIndex( node ) );
|
||||
widgetTree->setSelection( index );
|
||||
mUISceneNode->setHighlightOver( false );
|
||||
mUISceneNode->getEventDispatcher()->setDisableMousePress( false );
|
||||
} else {
|
||||
mUISceneNode->runOnMainThread( [this, widgetTree]() { checkWidgetPick( widgetTree ); } );
|
||||
}
|
||||
}
|
||||
|
||||
void App::createWidgetTreeView() {
|
||||
UIWindow* uiWin = UIWindow::NewOpt( UIWindow::LINEAR_LAYOUT );
|
||||
UIWindow* uiWin = UIWindow::New();
|
||||
uiWin->setMinWindowSize( 600, 400 );
|
||||
uiWin->setWindowFlags( UI_WIN_DEFAULT_FLAGS | UI_WIN_RESIZEABLE | UI_WIN_MAXIMIZE_BUTTON );
|
||||
UITreeView* widgetTree = UITreeView::New();
|
||||
widgetTree->setLayoutSizePolicy( SizePolicy::MatchParent, SizePolicy::MatchParent );
|
||||
widgetTree->setParent( uiWin );
|
||||
UIWidget* cont = mUISceneNode->loadLayoutFromString( R"xml(
|
||||
<vbox lw="mp" lh="mp">
|
||||
<hbox lw="mp" lh="wc">
|
||||
<pushbutton id="pick_widget" text='@string(pick_widget, "Pick Widget")' />
|
||||
</hbox>
|
||||
<treeview lw="mp" lh="fixed" lw8="1" />
|
||||
</vbox>
|
||||
)xml",
|
||||
uiWin->getContainer() );
|
||||
UITreeView* widgetTree = cont->findByType<UITreeView>( UI_TYPE_TREEVIEW );
|
||||
widgetTree->setHeadersVisible( true );
|
||||
widgetTree->setAutoExpandOnSingleColumn( true );
|
||||
widgetTree->setExpanderIconSize( mMenuIconSize );
|
||||
widgetTree->setAutoColumnsWidth( true );
|
||||
widgetTree->setModel( WidgetTreeModel::New( mUISceneNode ) );
|
||||
auto model = WidgetTreeModel::New( mUISceneNode );
|
||||
widgetTree->setModel( model );
|
||||
widgetTree->tryOpenModelIndex( model->getRoot() );
|
||||
UIPushButton* button = cont->find<UIPushButton>( "pick_widget" );
|
||||
button->addEventListener( Event::MouseClick, [&, widgetTree]( const Event* event ) {
|
||||
if ( event->asMouseEvent()->getFlags() & EE_BUTTON_LMASK ) {
|
||||
mUISceneNode->setHighlightOver( true );
|
||||
mUISceneNode->getEventDispatcher()->setDisableMousePress( true );
|
||||
mUISceneNode->runOnMainThread(
|
||||
[this, widgetTree]() { checkWidgetPick( widgetTree ); } );
|
||||
}
|
||||
} );
|
||||
uiWin->center();
|
||||
}
|
||||
|
||||
|
||||
@@ -345,6 +345,8 @@ class App : public UICodeEditorSplitter::Client {
|
||||
void renameFile( const FileInfo& file );
|
||||
|
||||
void initPluginManager();
|
||||
|
||||
void checkWidgetPick( UITreeView* widgetTree );
|
||||
};
|
||||
|
||||
} // namespace ecode
|
||||
|
||||
@@ -445,6 +445,7 @@ std::string LinterPlugin::getMatchString( const LinterType& type ) {
|
||||
return "error";
|
||||
}
|
||||
|
||||
// TODO: Implement error lens
|
||||
void LinterPlugin::drawAfterLineText( UICodeEditor* editor, const Int64& index, Vector2f position,
|
||||
const Float& /*fontSize*/, const Float& lineHeight ) {
|
||||
Lock l( mMatchesMutex );
|
||||
|
||||
Reference in New Issue
Block a user