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:
Martín Lucas Golini
2022-09-30 01:58:12 -03:00
parent a64696d03b
commit 994cee2bbf
12 changed files with 176 additions and 35 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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,

View File

@@ -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

View File

@@ -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(

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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();
}

View File

@@ -345,6 +345,8 @@ class App : public UICodeEditorSplitter::Client {
void renameFile( const FileInfo& file );
void initPluginManager();
void checkWidgetPick( UITreeView* widgetTree );
};
} // namespace ecode

View File

@@ -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 );