Overview
EmberForge's user interface is built on a flexible panel and tab system that allows users to customize their workspace. This document explains the component hierarchy and how the pieces fit together.
Component Hierarchy
App (wxApp)
└── MainFrame (wxFrame)
├── wxAuiManager (docking system)
│ ├── LeftSidePanel
│ │ └── wxAuiNotebook
│ │ ├── FileExplorerTab
│ │ └── SceneHierarchyTab
│ ├── MainPanel (center)
│ │ └── SceneContainer
│ │ └── BehaviorTreeScene
│ │ └── TreeVisualization
│ ├── RightSidePanel
│ │ └── wxAuiNotebook
│ │ └── PropertiesTab
│ └── BottomPanel
│ └── wxAuiNotebook
│ └── LogTab
└── Menu/Toolbar
Panel System
All panels implement the IPanel interface:
public:
virtual wxWindow* GetWindow() = 0;
};
Interface for panel-based UI components in the application.
virtual wxString GetPanelType() const =0
Returns the panel type identifier.
virtual void Refresh()
Refreshes the panel content.
virtual void OnActivated()
Called when the panel becomes active.
virtual void OnDeactivated()
Called when the panel becomes inactive.
virtual wxString GetTitle() const =0
Returns the display title of the panel.
Panel Base Class
The Panel base class provides common functionality:
| Method | Purpose |
| CreateLayout() | Set up panel UI (virtual) |
| ApplyTheme() | Apply color theme |
| Refresh() | Refresh panel content |
| Save() / Load() | Serialize/deserialize state |
SidePanel extends Panel for side dock panels with tab support:
public:
int GetActiveTabIndex();
protected:
virtual void CreateToolbar();
virtual bool ShouldShowToolbar() const;
};
std::unique_ptr< ITab > ITabPtr
Panel(wxWindow *parent, const wxString &name="Panel", long style=wxTAB_TRAVERSAL)
Constructs the panel with optional name and style.
ITab * GetTab(int index) const
Returns the tab at the given index, or nullptr.
bool SetActiveTab(int index) override
Sets the active tab by index; returns true on success.
void CreateNotebook() override
Hook: creates the notebook control. Override to customize.
int AddTab(ITabPtr tab) override
Adds a tab and returns its index.
ITabPtr RemoveTab(int index) override
Removes the tab at the given index; returns the removed tab.
Concrete Panels
Tab System
ITab Interface
Tabs are content components within panels:
public:
virtual wxBitmap
GetIcon()
const = 0;
};
Interface for tab-based UI components in the application.
virtual void OnDeactivated()
Called when the tab becomes inactive.
virtual bool CanMove() const
Returns true if the tab can be moved/reordered.
virtual bool CanClose() const
Returns true if the tab can be closed.
virtual wxBitmap GetIcon() const
Returns the tab icon bitmap; defaults to null.
virtual wxString GetTitle() const =0
Returns the display title of the tab.
virtual wxWindow * GetWidget()=0
Returns the wxWidgets window used as the tab content.
virtual void OnActivated()
Called when the tab becomes active.
virtual void OnClosed()
Called when the tab is closed.
virtual wxString GetTabType() const =0
Returns the tab type identifier.
virtual void Refresh()
Refreshes the tab content.
virtual bool IsValid() const
Returns true if the tab is in a valid state.
virtual void Initialize()
Called once when the tab is first created.
Tab Implementations
| Tab | Purpose | Features |
| FileExplorerTab | Browse project files | Tree/grid view, drag-drop, search |
| SceneHierarchyTab | Navigate tree structure | Node selection, expand/collapse |
| PropertiesTab | Edit node properties | Property grid, blackboard editing |
| LogTab | Display log messages | Filtering, search, virtual list |
| ToolTab | Tool palette | (Future: node creation tools) |
TabFactory
Creates tabs by type name:
auto& factory = EmberForge::TabFactory::GetInstance();
auto tab = factory.CreateTab("FileExplorer", parentWindow);
auto types = factory.GetAvailableTabTypes();
TabContainer
Manages a collection of tabs:
class TabContainer {
public:
void RemoveTab(int index);
void CloseTab(int index);
void SetTabTitle(int index, const wxString& title);
void SetTabState(int index, TabState state);
void SetTabActivatedCallback(Callback cb);
void SetTabClosedCallback(Callback cb);
};
Scene System
Scenes are visual content areas in the MainPanel:
public:
};
Interface for scene-based UI components (e.g., views or screens).
virtual bool HasUnsavedChanges() const
Returns true if the scene has unsaved changes.
virtual void OnActivated()
Called when the scene becomes active.
virtual wxString GetSceneType() const =0
Returns the scene type identifier.
virtual void Refresh()
Refreshes the scene content.
virtual wxString GetTitle() const =0
Returns the display title of the scene.
virtual wxPanel * GetPanel()=0
Returns the wxPanel used as the scene content.
virtual bool Save()
Saves the scene content; returns true on success.
virtual void OnDeactivated()
Called when the scene becomes inactive.
The primary scene type for visualizing behavior trees:
public:
void SetTreeStructure(std::shared_ptr<ITreeStructure> tree);
void UpdateTreeSelector(const std::vector<std::string>& names,
const std::string& current);
void SetTreeSelectionCallback(TreeSelectionCallback cb);
};
Scene implementation for behavior tree visualization.
void SetNodeSelectionCallback(NodeSelectionCallback callback)
Set callback for node selection events.
void SetBehaviorTree(std::shared_ptr< EmberCore::Node > root)
Set the behavior tree for this scene using legacy Node interface.
std::function< void(EmberCore::ITreeNode *)> NodeSelectionCallback
SceneContainer
Manages multiple scenes with tabs:
class SceneContainer {
public:
int AddScene(std::unique_ptr<IScene> scene);
void RemoveScene(int index);
void SuspendInactiveScenes();
void ResumeAllScenes();
void SetSceneActivatedCallback(Callback cb);
void SetSceneDeactivatedCallback(Callback cb);
};
TreeVisualization
Canvas component for rendering behavior trees:
class TreeVisualization : public wxPanel {
public:
void SetTreeStructure(std::shared_ptr<ITreeStructure> tree);
void SetZoom(float zoom);
void CenterView();
void FitToWindow();
void SelectNode(ITreeNode* node);
void ClearSelection();
void SetConfig(const VisualizationConfig& config);
};
Dialogs
Common Dialogs
Dialog Pattern
Dialogs typically follow this pattern:
if (dlg.ShowModal() == wxID_OK) {
}
Preferences dialog for configuring EmberForge application settings.
Event Flow
Node Selection
User clicks node in TreeVisualization
│
▼
TreeVisualization::OnMouseDown()
│
▼
NodeSelectionCallback invoked
│
▼
MainFrame::OnNodeSelected()
│
├─► SceneHierarchyTab::SelectNode()
│
└─► PropertiesTab::SetSelectedNode()
File Open
User selects File > Open
│
▼
MainFrame::OnFileOpen()
│
▼
wxFileDialog for file selection
│
▼
LibXMLBehaviorTreeParser::ParseFile()
│
▼
MainFrame::LoadBehaviorTree()
│
├─► Create DirectTreeAdapter
│
├─► BehaviorTreeScene::SetTreeStructure()
│
└─► Update hierarchy and properties
Layout Management
EmberForge uses wxAuiManager for dockable panels:
m_auiManager.SetManagedWindow(this);
m_auiManager.AddPane(m_leftPanel, wxAuiPaneInfo()
.Left()
.Caption("Explorer")
.MinSize(200, -1)
.BestSize(250, -1));
m_auiManager.AddPane(m_mainPanel, wxAuiPaneInfo()
.CenterPane()
.Caption("Scene"));
m_auiManager.Update();
Saving/Restoring Layout
wxString layout = m_auiManager.SavePerspective();
prefs.SetString("window/layout", layout);
wxString layout = prefs.GetString("window/layout", "");
if (!layout.empty()) {
m_auiManager.LoadPerspective(layout);
}
Theming
Panels and tabs support theming through AppPreferences:
void Panel::ApplyTheme() {
auto& prefs = AppPreferencesManager::GetInstance();
wxColour bg = prefs.GetPanelBackgroundColor();
wxColour fg = prefs.GetPanelForegroundColor();
SetBackgroundColour(bg);
SetForegroundColour(fg);
Refresh();
}
See Also