Moved and improved the widget inspector to a new UI tool class: UIWidgetInspector.

This commit is contained in:
Martín Lucas Golini
2022-10-21 02:28:12 -03:00
parent 7e605d8fac
commit de04dd3984
14 changed files with 229 additions and 99 deletions

View File

@@ -9,10 +9,6 @@
* Implement a "float" layout.
* Expose properties implemented by each widget.
* Implement a model to view each widget property.
* Implement a rich text view.
### CSS

View File

@@ -12,6 +12,7 @@ class KeyEvent;
class DropEvent;
class TextEvent;
class TextInputEvent;
class WindowEvent;
class EE_API Event {
public:
@@ -92,6 +93,8 @@ class EE_API Event {
OnMenuHide,
OnEditorTabReady,
OnTitleChange,
OnWindowAdded,
OnWindowRemoved,
NoEvent = eeINDEX_NOT_FOUND
};
@@ -115,6 +118,8 @@ class EE_API Event {
const TextInputEvent* asTextInputEvent() const;
const WindowEvent* asWindowEvent() const;
protected:
friend class Node;
Node* mNode;
@@ -143,6 +148,16 @@ class EE_API TextEvent : public Event {
std::string text;
};
class EE_API WindowEvent : public Event {
public:
WindowEvent( Node* node, Node* window, const Uint32& eventType ) :
Event( node, eventType ), window( window ) {}
Node* getWindow() const { return window; }
protected:
Node* window;
};
}} // namespace EE::Scene
#endif

View File

@@ -75,6 +75,7 @@
#include <eepp/ui/tools/uicodeeditorsplitter.hpp>
#include <eepp/ui/tools/uicolorpicker.hpp>
#include <eepp/ui/tools/uidocfindreplace.hpp>
#include <eepp/ui/tools/uiwidgetinspector.hpp>
#include <eepp/ui/models/csspropertiesmodel.hpp>
#include <eepp/ui/models/filesystemmodel.hpp>

View File

@@ -14,6 +14,8 @@ class EE_API WidgetTreeModel : public Model {
enum Column {
Type = 0,
ID,
Classes,
PseudoClasses,
Count,
};

View File

@@ -0,0 +1,30 @@
#ifndef EE_UI_TOOLS_UIWIDGETINSPECTOR_HPP
#define EE_UI_TOOLS_UIWIDGETINSPECTOR_HPP
#include <eepp/config.hpp>
#include <functional>
namespace EE { namespace UI {
class UISceneNode;
class UITreeView;
class UITableView;
class UIWindow;
}} // namespace EE::UI
namespace EE { namespace UI { namespace Tools {
class EE_API UIWidgetInspector {
public:
static UIWindow* create( UISceneNode* sceneNode, const Float& menuIconSize = 16.f,
std::function<void()> highlightToggle = std::function<void()>(),
std::function<void()> drawBoxesToggle = std::function<void()>(),
std::function<void()> drawDebugDataToggle = std::function<void()>() );
protected:
static void checkWidgetPick( UISceneNode* sceneNode, UITreeView* widgetTree,
bool wasHighlightOver, UITableView* tableView );
};
}}} // namespace EE::UI::Tools
#endif // EE_UI_TOOLS_

View File

@@ -355,6 +355,7 @@
../../include/eepp/ui/tools/uicodeeditorsplitter.hpp
../../include/eepp/ui/tools/uicolorpicker.hpp
../../include/eepp/ui/tools/uidocfindreplace.hpp
../../include/eepp/ui/tools/uiwidgetinspector.hpp
../../include/eepp/ui/uiabstractview.hpp
../../include/eepp/ui/uibackgrounddrawable.hpp
../../include/eepp/ui/uiborderdrawable.hpp
@@ -841,6 +842,7 @@
../../src/eepp/ui/tools/uicodeeditorsplitter.cpp
../../src/eepp/ui/tools/uicolorpicker.cpp
../../src/eepp/ui/tools/uidocfindreplace.cpp
../../src/eepp/ui/tools/uiwidgetinspector.cpp
../../src/eepp/ui/uiabstractview.cpp
../../src/eepp/ui/uibackgrounddrawable.cpp
../../src/eepp/ui/uiborderdrawable.cpp

View File

@@ -41,4 +41,8 @@ const TextInputEvent* Event::asTextInputEvent() const {
return static_cast<const TextInputEvent*>( this );
}
const WindowEvent* Event::asWindowEvent() const {
return static_cast<const WindowEvent*>( this );
}
}} // namespace EE::Scene

View File

@@ -19,11 +19,15 @@ size_t WidgetTreeModel::rowCount( const ModelIndex& index ) const {
}
size_t WidgetTreeModel::columnCount( const ModelIndex& ) const {
return 2;
return Column::Count;
}
std::string WidgetTreeModel::columnName( const size_t& col ) const {
switch ( col ) {
case Column::PseudoClasses:
return "Pseudo Classes";
case Column::Classes:
return "Classes";
case Column::Type:
return "Type";
case Column::ID:
@@ -38,6 +42,20 @@ Variant WidgetTreeModel::data( const ModelIndex& index, ModelRole role ) const {
if ( role == ModelRole::Display ) {
switch ( index.column() ) {
case Column::PseudoClasses: {
if ( node->isWidget() ) {
return Variant(
String::join( node->asType<UIWidget>()->getStyleSheetPseudoClasses() ) );
}
break;
}
case Column::Classes: {
if ( node->isWidget() ) {
return Variant(
String::join( node->asType<UIWidget>()->getStyleSheetClasses() ) );
}
break;
}
case Column::Type: {
if ( node->isWidget() ) {
return Variant( node->asType<UIWidget>()->getElementTag().c_str() );

View File

@@ -0,0 +1,144 @@
#include <eepp/ui/models/csspropertiesmodel.hpp>
#include <eepp/ui/models/widgettreemodel.hpp>
#include <eepp/ui/tools/uiwidgetinspector.hpp>
#include <eepp/ui/uicheckbox.hpp>
#include <eepp/ui/uiscenenode.hpp>
#include <eepp/ui/uitableview.hpp>
#include <eepp/ui/uitreeview.hpp>
#include <eepp/ui/uiwindow.hpp>
#include <eepp/window/input.hpp>
#include <eepp/window/window.hpp>
using namespace EE::Window;
using namespace EE::UI::Models;
namespace EE { namespace UI { namespace Tools {
UIWindow* UIWidgetInspector::create( UISceneNode* sceneNode, const Float& menuIconSize,
std::function<void()> highlightToggle,
std::function<void()> drawBoxesToggle,
std::function<void()> drawDebugDataToggle ) {
if ( sceneNode->getRoot()->hasChild( "widget-tree-view" ) )
return nullptr;
UIWindow* uiWin = UIWindow::New();
uiWin->setId( "widget-tree-view" );
uiWin->setMinWindowSize( 600, 400 );
uiWin->setWindowFlags( UI_WIN_DEFAULT_FLAGS | UI_WIN_RESIZEABLE | UI_WIN_MAXIMIZE_BUTTON );
UIWidget* cont = sceneNode->loadLayoutFromString( R"xml(
<vbox lw="mp" lh="mp">
<hbox lw="wc" lh="wc">
<pushbutton id="pick_widget" icon="icon(cursor-pointer, 16dp)" text='@string(pick_widget, "Pick Widget")' text-as-fallback="true" />
<CheckBox id="debug-draw-highlight" text='@string(debug_draw_highlight, "Highlight Focus & Hover")' margin-left="4dp" lg="center" />
<CheckBox id="debug-draw-boxes" text='@string(debug_draw_boxes, "Draw Boxes")' margin-left="4dp" lg="center" />
<CheckBox id="debug-draw-debug-data" text='@string(debug_draw_debug_data, "Draw Debug Data")' margin-left="4dp" lg="center" />
</hbox>
<Splitter layout_width="match_parent" lh="fixed" lw8="1" splitter-partition="50%">
<treeview lw="fixed" lh="mp" />
<tableview lw="fixed" lh="mp" />
</Splitter>
</vbox>
)xml",
uiWin->getContainer() );
UITreeView* widgetTree = cont->findByType<UITreeView>( UI_TYPE_TREEVIEW );
widgetTree->setHeadersVisible( true );
widgetTree->setExpanderIconSize( menuIconSize );
widgetTree->setAutoColumnsWidth( true );
auto model = WidgetTreeModel::New( sceneNode );
widgetTree->setModel( model );
widgetTree->tryOpenModelIndex( model->getRoot() );
UITableView* tableView = cont->findByType<UITableView>( UI_TYPE_TABLEVIEW );
tableView->setAutoColumnsWidth( true );
tableView->setHeadersVisible( true );
widgetTree->setOnSelection( [&, tableView]( const ModelIndex& index ) {
Node* node = static_cast<Node*>( index.internalData() );
if ( node->isWidget() ) {
tableView->setModel( node->isWidget()
? CSSPropertiesModel::create( node->asType<UIWidget>() )
: CSSPropertiesModel::create() );
}
} );
UIPushButton* button = cont->find<UIPushButton>( "pick_widget" );
button->addEventListener(
Event::MouseClick, [sceneNode, widgetTree, tableView]( const Event* event ) {
if ( event->asMouseEvent()->getFlags() & EE_BUTTON_LMASK ) {
bool wasHighlightOver = sceneNode->getHighlightOver();
sceneNode->setHighlightOver( true );
sceneNode->getEventDispatcher()->setDisableMousePress( true );
sceneNode->runOnMainThread( [sceneNode, widgetTree, tableView, wasHighlightOver]() {
checkWidgetPick( sceneNode, widgetTree, wasHighlightOver, tableView );
} );
}
} );
cont->find<UICheckBox>( "debug-draw-highlight" )
->setChecked( sceneNode->getHighlightOver() )
->addEventListener( Event::OnValueChange, [sceneNode, highlightToggle]( const auto* ) {
if ( highlightToggle ) {
highlightToggle();
} else {
sceneNode->setHighlightFocus( !sceneNode->getHighlightFocus() );
sceneNode->setHighlightOver( !sceneNode->getHighlightOver() );
}
} );
cont->find<UICheckBox>( "debug-draw-boxes" )
->setChecked( sceneNode->getDrawBoxes() )
->addEventListener( Event::OnValueChange, [sceneNode, drawBoxesToggle]( const auto* ) {
if ( drawBoxesToggle ) {
drawBoxesToggle();
} else {
sceneNode->setDrawBoxes( !sceneNode->getDrawBoxes() );
}
} );
cont->find<UICheckBox>( "debug-draw-debug-data" )
->setChecked( sceneNode->getDrawDebugData() )
->addEventListener( Event::OnValueChange, [sceneNode, drawDebugDataToggle]( const auto* ) {
if ( drawDebugDataToggle ) {
drawDebugDataToggle();
} else {
sceneNode->setDrawDebugData( !sceneNode->getDrawDebugData() );
}
} );
uiWin->center();
Uint32 winCb = sceneNode->addEventListener( Event::OnWindowAdded, [&, sceneNode, uiWin](
const Event* event ) {
UIWindow* eWin = event->asWindowEvent()->getWindow()->asType<UIWindow>();
if ( eWin != uiWin ) {
Uint32 winRdCb =
eWin->addEventListener( Event::OnWindowReady, [uiWin]( const Event* eWinEvent ) {
uiWin->toFront();
eWinEvent->getNode()->removeEventListener( eWinEvent->getCallbackId() );
} );
uiWin->addEventListener( Event::OnWindowClose, [sceneNode, winRdCb]( const Event* ) {
sceneNode->removeEventListener( winRdCb );
} );
}
} );
uiWin->addEventListener( Event::OnWindowClose, [sceneNode, winCb]( const Event* ) {
sceneNode->removeEventListener( winCb );
} );
return uiWin;
}
void UIWidgetInspector::checkWidgetPick( UISceneNode* sceneNode, UITreeView* widgetTree,
bool wasHighlightOver, UITableView* tableView ) {
Input* input = sceneNode->getWindow()->getInput();
if ( input->getClickTrigger() & EE_BUTTON_LMASK ) {
Node* node = sceneNode->getEventDispatcher()->getMouseOverNode();
WidgetTreeModel* model = static_cast<WidgetTreeModel*>( widgetTree->getModel() );
ModelIndex index( model->getModelIndex( node ) );
widgetTree->setSelection( index );
sceneNode->setHighlightOver( wasHighlightOver );
sceneNode->getEventDispatcher()->setDisableMousePress( false );
} else {
sceneNode->runOnMainThread( [sceneNode, widgetTree, wasHighlightOver, tableView]() {
checkWidgetPick( sceneNode, widgetTree, wasHighlightOver, tableView );
} );
}
}
}}} // namespace EE::UI::Tools

View File

@@ -256,7 +256,6 @@ UIFileDialog::~UIFileDialog() {}
void UIFileDialog::onWindowReady() {
updateClickStep();
UIWindow::onWindowReady();
sendCommonEvent( Event::OnWindowReady );
}
Uint32 UIFileDialog::getType() const {

View File

@@ -226,6 +226,8 @@ void UISceneNode::setFocusLastWindow( UIWindow* window ) {
void UISceneNode::windowAdd( UIWindow* win ) {
if ( !windowExists( win ) ) {
mWindowsList.push_front( win );
WindowEvent wevent( this, win, Event::OnWindowAdded );
sendEvent( &wevent );
} else {
//! Send to front
mWindowsList.remove( win );
@@ -235,6 +237,8 @@ void UISceneNode::windowAdd( UIWindow* win ) {
void UISceneNode::windowRemove( UIWindow* win ) {
if ( windowExists( win ) ) {
WindowEvent wevent( this, win, Event::OnWindowRemoved );
sendEvent( &wevent );
mWindowsList.remove( win );
}
}

View File

@@ -447,6 +447,8 @@ void UIWindow::onWindowReady() {
mShowWhenReady = false;
show();
}
sendCommonEvent( Event::OnWindowReady );
}
void UIWindow::createModalNode() {

View File

@@ -548,95 +548,6 @@ App::~App() {
eeSAFE_DELETE( mConsole );
}
void App::checkWidgetPick( UITreeView* widgetTree, bool wasHighlightOver, UITableView* tableView ) {
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( wasHighlightOver );
mUISceneNode->getEventDispatcher()->setDisableMousePress( false );
} else {
mUISceneNode->runOnMainThread( [this, widgetTree, wasHighlightOver, tableView]() {
checkWidgetPick( widgetTree, wasHighlightOver, tableView );
} );
}
}
void App::createWidgetInspector() {
if ( mUISceneNode->getRoot()->hasChild( "widget-tree-view" ) )
return;
UIWindow* uiWin = UIWindow::New();
uiWin->setId( "widget-tree-view" );
uiWin->setMinWindowSize( 600, 400 );
uiWin->setWindowFlags( UI_WIN_DEFAULT_FLAGS | UI_WIN_RESIZEABLE | UI_WIN_MAXIMIZE_BUTTON );
UIWidget* cont = mUISceneNode->loadLayoutFromString( R"xml(
<vbox lw="mp" lh="mp">
<hbox lw="wc" lh="wc">
<pushbutton id="pick_widget" icon="icon(cursor-pointer, 16dp)" text='@string(pick_widget, "Pick Widget")' text-as-fallback="true" />
<CheckBox id="debug-draw-highlight" text='@string(debug_draw_highlight, "Highlight Focus & Hover")' margin-left="4dp" lg="center" />
<CheckBox id="debug-draw-boxes" text='@string(debug_draw_boxes, "Draw Boxes")' margin-left="4dp" lg="center" />
<CheckBox id="debug-draw-debug-data" text='@string(debug_draw_debug_data, "Draw Debug Data")' margin-left="4dp" lg="center" />
</hbox>
<Splitter layout_width="match_parent" lh="fixed" lw8="1" splitter-partition="50%">
<treeview lw="fixed" lh="mp" />
<tableview lw="fixed" lh="mp" />
</Splitter>
</vbox>
)xml",
uiWin->getContainer() );
UITreeView* widgetTree = cont->findByType<UITreeView>( UI_TYPE_TREEVIEW );
widgetTree->setHeadersVisible( true );
widgetTree->setAutoExpandOnSingleColumn( true );
widgetTree->setExpanderIconSize( mMenuIconSize );
widgetTree->setAutoColumnsWidth( true );
auto model = WidgetTreeModel::New( mUISceneNode );
widgetTree->setModel( model );
widgetTree->tryOpenModelIndex( model->getRoot() );
UITableView* tableView = cont->findByType<UITableView>( UI_TYPE_TABLEVIEW );
tableView->setAutoColumnsWidth( true );
tableView->setHeadersVisible( true );
widgetTree->setOnSelection( [&, tableView]( const ModelIndex& index ) {
Node* node = static_cast<Node*>( index.internalData() );
if ( node->isWidget() ) {
tableView->setModel( node->isWidget()
? CSSPropertiesModel::create( node->asType<UIWidget>() )
: CSSPropertiesModel::create() );
}
} );
UIPushButton* button = cont->find<UIPushButton>( "pick_widget" );
button->addEventListener( Event::MouseClick, [&, widgetTree, tableView]( const Event* event ) {
if ( event->asMouseEvent()->getFlags() & EE_BUTTON_LMASK ) {
bool wasHighlightOver = mUISceneNode->getHighlightOver();
mUISceneNode->setHighlightOver( true );
mUISceneNode->getEventDispatcher()->setDisableMousePress( true );
mUISceneNode->runOnMainThread( [this, widgetTree, tableView, wasHighlightOver]() {
checkWidgetPick( widgetTree, wasHighlightOver, tableView );
} );
}
} );
cont->find<UICheckBox>( "debug-draw-highlight" )
->setChecked( mUISceneNode->getHighlightOver() )
->addEventListener( Event::OnValueChange, [this]( const auto* ) {
runCommand( "debug-draw-highlight-toggle" );
} );
cont->find<UICheckBox>( "debug-draw-boxes" )
->setChecked( mUISceneNode->getDrawBoxes() )
->addEventListener( Event::OnValueChange,
[this]( const auto* ) { runCommand( "debug-draw-boxes-toggle" ); } );
cont->find<UICheckBox>( "debug-draw-debug-data" )
->setChecked( mUISceneNode->getDrawDebugData() )
->addEventListener( Event::OnValueChange,
[this]( const auto* ) { runCommand( "debug-draw-debug-data" ); } );
uiWin->center();
}
void App::updateRecentFiles() {
UINode* node = nullptr;
if ( mSettingsMenu && ( node = mSettingsMenu->getItemId( "menu-recent-files" ) ) ) {
@@ -2494,6 +2405,10 @@ void App::showFindView() {
mDocSearchController->showFindView();
}
void App::createWidgetInspector() {
UIWidgetInspector::create( mUISceneNode, mMenuIconSize );
}
void App::onCodeEditorCreated( UICodeEditor* editor, TextDocument& doc ) {
const CodeEditorConfig& config = mConfig.editor;
const DocumentConfig& docc = !mCurrentProject.empty() && !mProjectDocConfig.useGlobalSettings

View File

@@ -30,12 +30,12 @@ class App : public UICodeEditorSplitter::Client {
~App();
void createWidgetInspector();
void init( const LogLevel& logLevel, std::string file, const Float& pidelDensity,
const std::string& colorScheme, bool terminal, bool frameBuffer,
bool benchmarkMode );
void createWidgetInspector();
void setAppTitle( const std::string& title );
void openFileDialog();
@@ -357,8 +357,6 @@ class App : public UICodeEditorSplitter::Client {
void initPluginManager();
void checkWidgetPick( UITreeView* widgetTree, bool wasHighlightOver, UITableView* tableView );
void onPluginEnabled( UICodeEditorPlugin* plugin );
};