Ember
Loading...
Searching...
No Matches
TabContainer.cpp
Go to the documentation of this file.
2#include <algorithm>
3#include <wx/menu.h>
4
5namespace EmberForge {
6namespace ui {
7
8// Event table
9wxBEGIN_EVENT_TABLE(TabContainer, wxNotebook) EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, TabContainer::OnTabChanged)
10 EVT_NOTEBOOK_PAGE_CHANGING(wxID_ANY, TabContainer::OnTabChanging) EVT_RIGHT_UP(TabContainer::OnTabRightClick)
11 EVT_MIDDLE_UP(TabContainer::OnTabMiddleClick) wxEND_EVENT_TABLE()
12
13 TabContainer::TabContainer(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size,
14 long style)
15 : wxNotebook(parent, id, pos, size, style), m_activeTabIndex(-1), m_allowTabReorder(true), m_showCloseButton(true) {
16}
17
19
20int TabContainer::AddTab(std::unique_ptr<ITab> tab, const wxString &title, const wxString &tooltip) {
21 if (!tab) {
22 return -1;
23 }
24
25 // Create the tab window
26 wxWindow *tabWindow = tab->GetWidget();
27 if (!tabWindow) {
28 return -1;
29 }
30
31 // Add to notebook
32 int index = GetPageCount();
33 if (!AddPage(tabWindow, title, true)) {
34 return -1;
35 }
36
37 // Store tab info
38 TabInfo tabInfo(std::move(tab), title);
39 tabInfo.tooltip = tooltip;
40 m_tabs.push_back(std::move(tabInfo));
41
42 // Set tooltip if provided
43 if (!tooltip.IsEmpty()) {
44 // wxNotebook doesn't have SetPageToolTip in all versions
45 // The tooltip functionality can be added later if needed
46 }
47
48 // Update active tab
49 m_activeTabIndex = index;
50
51 // Notify callback
52 NotifyTabCreated(index);
53
54 return index;
55}
56
57bool TabContainer::RemoveTab(int index) {
58 if (!ValidateTabIndex(index)) {
59 return false;
60 }
61
62 // Check if tab can be closed
63 if (!CanCloseTab(index)) {
64 return false;
65 }
66
67 // Notify callback before removal
68 NotifyTabClosed(index);
69
70 // Remove from notebook
71 if (!RemovePage(index)) {
72 return false;
73 }
74
75 // Remove from our container
76 m_tabs.erase(m_tabs.begin() + index);
77
78 // Update active tab index
79 if (m_activeTabIndex == index) {
80 m_activeTabIndex = GetPageCount() > 0 ? 0 : -1;
81 } else if (m_activeTabIndex > index) {
83 }
84
85 return true;
86}
87
89 int index = GetTabIndex(tab);
90 if (index >= 0) {
91 return RemoveTab(index);
92 }
93 return false;
94}
95
97 while (GetTabCount() > 0) {
98 RemoveTab(0);
99 }
100}
101
102ITab *TabContainer::GetTab(int index) const {
103 if (ValidateTabIndex(index)) {
104 return m_tabs[index].tab.get();
105 }
106 return nullptr;
107}
108
110
111int TabContainer::GetTabCount() const { return static_cast<int>(m_tabs.size()); }
112
114 for (int i = 0; i < static_cast<int>(m_tabs.size()); ++i) {
115 if (m_tabs[i].tab.get() == tab) {
116 return i;
117 }
118 }
119 return -1;
120}
121
122void TabContainer::SetTabTitle(int index, const wxString &title) {
123 if (ValidateTabIndex(index)) {
124 m_tabs[index].title = title;
125 SetPageText(index, title);
126 }
127}
128
129wxString TabContainer::GetTabTitle(int index) const {
130 if (ValidateTabIndex(index)) {
131 return m_tabs[index].title;
132 }
133 return wxEmptyString;
134}
135
136void TabContainer::SetTabTooltip(int index, const wxString &tooltip) {
137 if (ValidateTabIndex(index)) {
138 m_tabs[index].tooltip = tooltip;
139 // wxNotebook doesn't have SetPageToolTip in all versions
140 // The tooltip functionality can be added later if needed
141 }
142}
143
144wxString TabContainer::GetTabTooltip(int index) const {
145 if (ValidateTabIndex(index)) {
146 return m_tabs[index].tooltip;
147 }
148 return wxEmptyString;
149}
150
151void TabContainer::SetTabState(int index, TabState state) {
152 if (ValidateTabIndex(index)) {
153 m_tabs[index].state = state;
154 UpdateTabAppearance(index);
155 }
156}
157
159 if (ValidateTabIndex(index)) {
160 return m_tabs[index].state;
161 }
162 return TabState::Inactive;
163}
164
165void TabContainer::SetTabClosable(int index, bool closable) {
166 if (ValidateTabIndex(index)) {
167 m_tabs[index].canClose = closable;
168 }
169}
170
171bool TabContainer::IsTabClosable(int index) const {
172 if (ValidateTabIndex(index)) {
173 return m_tabs[index].canClose;
174 }
175 return false;
176}
177
179 if (ValidateTabIndex(index) && index != m_activeTabIndex) {
180 SetSelection(index);
181 m_activeTabIndex = index;
182 NotifyTabActivated(index);
183 }
184}
185
187 int index = GetTabIndex(tab);
188 if (index >= 0) {
189 SetActiveTab(index);
190 }
191}
192
193int TabContainer::GetActiveTabIndex() const { return GetSelection(); }
194
196 int current = GetActiveTabIndex();
197 int next = (current + 1) % GetTabCount();
198 if (next != current) {
199 SetActiveTab(next);
200 }
201}
202
204 int current = GetActiveTabIndex();
205 int prev = (current - 1 + GetTabCount()) % GetTabCount();
206 if (prev != current) {
207 SetActiveTab(prev);
208 }
209}
210
212 if (ValidateTabIndex(index)) {
213 ITab *tab = m_tabs[index].tab.get();
214 if (tab) {
215 tab->Refresh();
216 }
217 }
218}
219
221 for (int i = 0; i < GetTabCount(); ++i) {
222 RefreshTab(i);
223 }
224}
225
227 if (!ValidateTabIndex(index)) {
228 return false;
229 }
230
231 return m_tabs[index].canClose;
232}
233
235 for (const auto &tabInfo : m_tabs) {
236 if (!tabInfo.canClose) {
237 return false;
238 }
239 }
240 return true;
241}
242
244
246
248
249void TabContainer::SetTabUserData(int index, void *userData) {
250 if (ValidateTabIndex(index)) {
251 m_tabs[index].userData = userData;
252 }
253}
254
255void *TabContainer::GetTabUserData(int index) const {
256 if (ValidateTabIndex(index)) {
257 return m_tabs[index].userData;
258 }
259 return nullptr;
260}
261
262bool TabContainer::SerializeState(wxString &data) const {
263 // Simple serialization - can be enhanced later
264 data = wxString::Format("tabs:%d,active:%d", GetTabCount(), GetActiveTabIndex());
265 return true;
266}
267
268bool TabContainer::DeserializeState(const wxString &data) {
269 // Simple deserialization - can be enhanced later
270 return true;
271}
272
273// Event handlers
274void TabContainer::OnTabChanged(wxBookCtrlEvent &event) {
275 int newIndex = event.GetSelection();
276 m_activeTabIndex = newIndex;
277 NotifyTabActivated(newIndex);
278 event.Skip();
279}
280
281void TabContainer::OnTabChanging(wxBookCtrlEvent &event) {
282 // Allow the change by default
283 event.Skip();
284}
285
286void TabContainer::OnTabRightClick(wxMouseEvent &event) {
287 wxPoint pos = event.GetPosition();
288 int hitTab = HitTest(pos);
289 if (hitTab != wxNOT_FOUND) {
290 CreateTabContextMenu(hitTab);
291 }
292 event.Skip();
293}
294
295void TabContainer::OnTabMiddleClick(wxMouseEvent &event) {
296 wxPoint pos = event.GetPosition();
297 int hitTab = HitTest(pos);
298 if (hitTab != wxNOT_FOUND && CanCloseTab(hitTab)) {
299 RemoveTab(hitTab);
300 }
301 event.Skip();
302}
303
304// Helper methods
306 if (!ValidateTabIndex(index)) {
307 return;
308 }
309
310 // Update visual appearance based on state
311 TabState state = m_tabs[index].state;
312 wxString title = m_tabs[index].title;
313
314 switch (state) {
316 SetPageText(index, title + "*");
317 break;
319 SetPageText(index, title + "...");
320 break;
321 case TabState::Error:
322 SetPageText(index, title + "!");
323 break;
324 default:
325 SetPageText(index, title);
326 break;
327 }
328}
329
331 if (!ValidateTabIndex(index)) {
332 return;
333 }
334
335 wxMenu menu;
336 menu.Append(wxID_CLOSE, "Close");
337 menu.Append(wxID_ANY, "Close Others");
338 menu.Append(wxID_ANY, "Close All");
339
340 // Enable/disable based on tab properties
341 menu.Enable(wxID_CLOSE, CanCloseTab(index));
342
343 PopupMenu(&menu);
344}
345
346bool TabContainer::ValidateTabIndex(int index) const { return index >= 0 && index < static_cast<int>(m_tabs.size()); }
347
350 m_tabActivatedCallback(m_tabs[index].tab.get(), index);
351 }
352}
353
356 m_tabClosedCallback(m_tabs[index].tab.get(), index);
357 }
358}
359
362 m_tabCreatedCallback(m_tabs[index].tab.get(), index);
363 }
364}
365
366} // namespace ui
367} // namespace EmberForge
BehaviorTreeProjectDialog::OnProjectNameChanged BehaviorTreeProjectDialog::OnRemoveFiles wxEND_EVENT_TABLE() BehaviorTreeProjectDialog
Generic container for managing tabbed UI components.
void OnTabChanged(wxBookCtrlEvent &event)
TabActivatedCallback m_tabActivatedCallback
void * GetTabUserData(int index) const
void OnTabChanging(wxBookCtrlEvent &event)
TabCreatedCallback m_tabCreatedCallback
int AddTab(std::unique_ptr< ITab > tab, const wxString &title, const wxString &tooltip=wxEmptyString)
void SetTabCreatedCallback(TabCreatedCallback callback)
void OnTabMiddleClick(wxMouseEvent &event)
void SetTabClosable(int index, bool closable)
void SetTabUserData(int index, void *userData)
void SetTabTooltip(int index, const wxString &tooltip)
bool SerializeState(wxString &data) const
ITab * GetTab(int index) const
void SetTabState(int index, TabState state)
std::function< void(ITab *tab, int index)> TabActivatedCallback
TabState GetTabState(int index) const
void OnTabRightClick(wxMouseEvent &event)
bool IsTabClosable(int index) const
std::vector< TabInfo > m_tabs
bool ValidateTabIndex(int index) const
void SetTabTitle(int index, const wxString &title)
void SetTabActivatedCallback(TabActivatedCallback callback)
wxString GetTabTitle(int index) const
bool DeserializeState(const wxString &data)
int GetTabIndex(ITab *tab) const
void UpdateTabAppearance(int index)
TabClosedCallback m_tabClosedCallback
wxString GetTabTooltip(int index) const
std::function< void(ITab *tab, int index)> TabClosedCallback
void CreateTabContextMenu(int index)
std::function< void(ITab *tab, int index)> TabCreatedCallback
void SetTabClosedCallback(TabClosedCallback callback)
Interface for tab-based UI components in the application.
Definition ITab.h:7
virtual void Refresh()
Refreshes the tab content.
Definition ITab.h:23
wxBEGIN_EVENT_TABLE(SceneContainer, wxPanel) EVT_SIZE(SceneContainer
TabContainer::OnTabChanged EVT_NOTEBOOK_PAGE_CHANGING(wxID_ANY, TabContainer::OnTabChanging) EVT_RIGHT_UP(TabContainer