]> git.saurik.com Git - wxWidgets.git/blame_incremental - samples/menu/menu.cpp
Fixed bug [ 743664 ] wxListCtrl asserts when deleting its m_textCtrl
[wxWidgets.git] / samples / menu / menu.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: samples/menu.cpp
3// Purpose: wxMenu/wxMenuBar sample
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 01.11.99
7// RCS-ID: $Id$
8// Copyright: (c) 1999 Vadim Zeitlin
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx/wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#ifndef WX_PRECOMP
28 #include "wx/app.h"
29 #include "wx/frame.h"
30 #include "wx/menu.h"
31 #include "wx/msgdlg.h"
32 #include "wx/log.h"
33 #include "wx/textctrl.h"
34 #include "wx/textdlg.h"
35#endif
36
37#if !wxUSE_MENUS
38 // nice try...
39 #error "menu sample requires wxUSE_MENUS=1"
40#endif // wxUSE_MENUS
41
42#include "copy.xpm"
43
44// ----------------------------------------------------------------------------
45// classes
46// ----------------------------------------------------------------------------
47
48// Define a new application
49class MyApp: public wxApp
50{
51public:
52 bool OnInit();
53};
54
55// Define a new frame
56class MyFrame: public wxFrame
57{
58public:
59 MyFrame();
60
61 virtual ~MyFrame();
62
63 void LogMenuEvent(const wxCommandEvent& event);
64
65protected:
66 void OnQuit(wxCommandEvent& event);
67 void OnClearLog(wxCommandEvent& event);
68
69 void OnAbout(wxCommandEvent& event);
70
71 void OnDummy(wxCommandEvent& event);
72
73 void OnAppendMenuItem(wxCommandEvent& event);
74 void OnAppendSubMenu(wxCommandEvent& event);
75 void OnDeleteMenuItem(wxCommandEvent& event);
76 void OnInsertMenuItem(wxCommandEvent& event);
77 void OnCheckMenuItem(wxCommandEvent& event);
78 void OnEnableMenuItem(wxCommandEvent& event);
79 void OnGetLabelMenuItem(wxCommandEvent& event);
80 void OnSetLabelMenuItem(wxCommandEvent& event);
81 void OnGetMenuItemInfo(wxCommandEvent& event);
82 void OnFindMenuItem(wxCommandEvent& event);
83
84 void OnAppendMenu(wxCommandEvent& event);
85 void OnInsertMenu(wxCommandEvent& event);
86 void OnDeleteMenu(wxCommandEvent& event);
87 void OnToggleMenu(wxCommandEvent& event);
88 void OnEnableMenu(wxCommandEvent& event);
89 void OnGetLabelMenu(wxCommandEvent& event);
90 void OnSetLabelMenu(wxCommandEvent& event);
91 void OnFindMenu(wxCommandEvent& event);
92
93 void OnTestNormal(wxCommandEvent& event);
94 void OnTestCheck(wxCommandEvent& event);
95 void OnTestRadio(wxCommandEvent& event);
96
97#if defined( __WXMSW__ ) || defined( __WXMAC__ )
98 void OnContextMenu(wxContextMenuEvent& event)
99 { ShowContextMenu(ScreenToClient(event.GetPosition())); }
100#else
101 void OnRightUp(wxMouseEvent& event)
102 { ShowContextMenu(event.GetPosition()); }
103#endif
104
105 void OnMenuOpen(wxMenuEvent& event)
106 { LogMenuOpenOrClose(event, _T("opened")); }
107 void OnMenuClose(wxMenuEvent& event)
108 { LogMenuOpenOrClose(event, _T("closed")); }
109
110 void OnUpdateCheckMenuItemUI(wxUpdateUIEvent& event);
111
112 void OnSize(wxSizeEvent& event);
113
114private:
115 void LogMenuOpenOrClose(const wxMenuEvent& event, const wxChar *what);
116 void ShowContextMenu(const wxPoint& pos);
117
118 wxMenu *CreateDummyMenu(wxString *title);
119
120 wxMenuItem *GetLastMenuItem() const;
121
122 // the menu previously detached from the menubar (may be NULL)
123 wxMenu *m_menu;
124
125 // the count of dummy menus already created
126 size_t m_countDummy;
127
128 // the control used for logging
129 wxTextCtrl *m_textctrl;
130
131 // the previous log target
132 wxLog *m_logOld;
133
134 DECLARE_EVENT_TABLE()
135};
136
137// A small helper class which intercepts all menu events and logs them
138class MyEvtHandler : public wxEvtHandler
139{
140public:
141 MyEvtHandler(MyFrame *frame) { m_frame = frame; }
142
143 void OnMenuEvent(wxCommandEvent& event)
144 {
145 m_frame->LogMenuEvent(event);
146
147 event.Skip();
148 }
149
150private:
151 MyFrame *m_frame;
152
153 DECLARE_EVENT_TABLE()
154};
155
156// ----------------------------------------------------------------------------
157// constants
158// ----------------------------------------------------------------------------
159
160enum
161{
162 Menu_File_Quit = 100,
163 Menu_File_ClearLog,
164
165 Menu_MenuBar_Toggle = 200,
166 Menu_MenuBar_Append,
167 Menu_MenuBar_Insert,
168 Menu_MenuBar_Delete,
169 Menu_MenuBar_Enable,
170 Menu_MenuBar_GetLabel,
171 Menu_MenuBar_SetLabel,
172 Menu_MenuBar_FindMenu,
173
174 Menu_Menu_Append = 300,
175 Menu_Menu_AppendSub,
176 Menu_Menu_Insert,
177 Menu_Menu_Delete,
178 Menu_Menu_Enable,
179 Menu_Menu_Check,
180 Menu_Menu_GetLabel,
181 Menu_Menu_SetLabel,
182 Menu_Menu_GetInfo,
183 Menu_Menu_FindItem,
184
185 Menu_Test_Normal = 400,
186 Menu_Test_Check,
187 Menu_Test_Radio1,
188 Menu_Test_Radio2,
189 Menu_Test_Radio3,
190
191 Menu_Dummy_First = 500,
192 Menu_Dummy_Second,
193 Menu_Dummy_Third,
194 Menu_Dummy_Fourth,
195 Menu_Dummy_Last,
196
197 Menu_Help_About = 1000,
198
199 Menu_Popup_ToBeDeleted = 2000,
200 Menu_Popup_ToBeGreyed,
201 Menu_Popup_ToBeChecked,
202 Menu_Popup_Submenu,
203
204 Menu_Max
205};
206
207// ----------------------------------------------------------------------------
208// event tables
209// ----------------------------------------------------------------------------
210
211BEGIN_EVENT_TABLE(MyFrame, wxFrame)
212 EVT_MENU(Menu_File_Quit, MyFrame::OnQuit)
213 EVT_MENU(Menu_File_ClearLog, MyFrame::OnClearLog)
214
215 EVT_MENU(Menu_Help_About, MyFrame::OnAbout)
216
217 EVT_MENU(Menu_MenuBar_Toggle, MyFrame::OnToggleMenu)
218 EVT_MENU(Menu_MenuBar_Append, MyFrame::OnAppendMenu)
219 EVT_MENU(Menu_MenuBar_Insert, MyFrame::OnInsertMenu)
220 EVT_MENU(Menu_MenuBar_Delete, MyFrame::OnDeleteMenu)
221 EVT_MENU(Menu_MenuBar_Enable, MyFrame::OnEnableMenu)
222 EVT_MENU(Menu_MenuBar_GetLabel, MyFrame::OnGetLabelMenu)
223 EVT_MENU(Menu_MenuBar_SetLabel, MyFrame::OnSetLabelMenu)
224 EVT_MENU(Menu_MenuBar_FindMenu, MyFrame::OnFindMenu)
225
226 EVT_MENU(Menu_Menu_Append, MyFrame::OnAppendMenuItem)
227 EVT_MENU(Menu_Menu_AppendSub, MyFrame::OnAppendSubMenu)
228 EVT_MENU(Menu_Menu_Insert, MyFrame::OnInsertMenuItem)
229 EVT_MENU(Menu_Menu_Delete, MyFrame::OnDeleteMenuItem)
230 EVT_MENU(Menu_Menu_Enable, MyFrame::OnEnableMenuItem)
231 EVT_MENU(Menu_Menu_Check, MyFrame::OnCheckMenuItem)
232 EVT_MENU(Menu_Menu_GetLabel, MyFrame::OnGetLabelMenuItem)
233 EVT_MENU(Menu_Menu_SetLabel, MyFrame::OnSetLabelMenuItem)
234 EVT_MENU(Menu_Menu_GetInfo, MyFrame::OnGetMenuItemInfo)
235 EVT_MENU(Menu_Menu_FindItem, MyFrame::OnFindMenuItem)
236
237 EVT_MENU(Menu_Test_Normal, MyFrame::OnTestNormal)
238 EVT_MENU(Menu_Test_Check, MyFrame::OnTestCheck)
239 EVT_MENU(Menu_Test_Radio1, MyFrame::OnTestRadio)
240 EVT_MENU(Menu_Test_Radio2, MyFrame::OnTestRadio)
241 EVT_MENU(Menu_Test_Radio3, MyFrame::OnTestRadio)
242
243 EVT_MENU_RANGE(Menu_Dummy_First, Menu_Dummy_Last, MyFrame::OnDummy)
244
245 EVT_UPDATE_UI(Menu_Menu_Check, MyFrame::OnUpdateCheckMenuItemUI)
246
247#if defined( __WXMSW__ ) || defined( __WXMAC__ )
248 EVT_CONTEXT_MENU(MyFrame::OnContextMenu)
249#else
250 EVT_RIGHT_UP(MyFrame::OnRightUp)
251#endif
252
253 EVT_MENU_OPEN(MyFrame::OnMenuOpen)
254 EVT_MENU_CLOSE(MyFrame::OnMenuClose)
255
256 EVT_SIZE(MyFrame::OnSize)
257END_EVENT_TABLE()
258
259BEGIN_EVENT_TABLE(MyEvtHandler, wxEvtHandler)
260 EVT_MENU(-1, MyEvtHandler::OnMenuEvent)
261END_EVENT_TABLE()
262
263// ============================================================================
264// implementation
265// ============================================================================
266
267// ----------------------------------------------------------------------------
268// MyApp
269// ----------------------------------------------------------------------------
270
271IMPLEMENT_APP(MyApp)
272
273// The `main program' equivalent, creating the windows and returning the
274// main frame
275bool MyApp::OnInit()
276{
277 // Create the main frame window
278 MyFrame* frame = new MyFrame;
279
280 frame->Show(TRUE);
281
282#if wxUSE_STATUSBAR
283 frame->SetStatusText(_T("Welcome to wxWindows menu sample"));
284#endif // wxUSE_STATUSBAR
285
286 SetTopWindow(frame);
287
288 return TRUE;
289}
290
291// ----------------------------------------------------------------------------
292// MyFrame
293// ----------------------------------------------------------------------------
294
295// Define my frame constructor
296MyFrame::MyFrame()
297 : wxFrame((wxFrame *)NULL, -1, _T("wxWindows menu sample"),
298 wxDefaultPosition, wxSize(400, 250))
299{
300 m_textctrl = NULL;
301 m_menu = NULL;
302 m_countDummy = 0;
303 m_logOld = NULL;
304
305#if wxUSE_STATUSBAR
306 CreateStatusBar();
307#endif // wxUSE_STATUSBAR
308
309 // create the menubar
310 wxMenu *fileMenu = new wxMenu;
311
312 wxMenuItem *item = new wxMenuItem(fileMenu, Menu_File_ClearLog,
313 _T("Clear &log\tCtrl-L"));
314 item->SetBitmap(copy_xpm);
315 fileMenu->Append(item);
316 fileMenu->AppendSeparator();
317 fileMenu->Append(Menu_File_Quit, _T("E&xit\tAlt-X"), _T("Quit menu sample"));
318
319 wxMenu *menubarMenu = new wxMenu;
320 menubarMenu->Append(Menu_MenuBar_Append, _T("&Append menu\tCtrl-A"),
321 _T("Append a menu to the menubar"));
322 menubarMenu->Append(Menu_MenuBar_Insert, _T("&Insert menu\tCtrl-I"),
323 _T("Insert a menu into the menubar"));
324 menubarMenu->Append(Menu_MenuBar_Delete, _T("&Delete menu\tCtrl-D"),
325 _T("Delete the last menu from the menubar"));
326 menubarMenu->Append(Menu_MenuBar_Toggle, _T("&Toggle menu\tCtrl-T"),
327 _T("Toggle the first menu in the menubar"), TRUE);
328 menubarMenu->AppendSeparator();
329 menubarMenu->Append(Menu_MenuBar_Enable, _T("&Enable menu\tCtrl-E"),
330 _T("Enable or disable the last menu"), TRUE);
331 menubarMenu->AppendSeparator();
332 menubarMenu->Append(Menu_MenuBar_GetLabel, _T("&Get menu label\tCtrl-G"),
333 _T("Get the label of the last menu"));
334 menubarMenu->Append(Menu_MenuBar_SetLabel, _T("&Set menu label\tCtrl-S"),
335 _T("Change the label of the last menu"));
336 menubarMenu->AppendSeparator();
337 menubarMenu->Append(Menu_MenuBar_FindMenu, _T("&Find menu from label\tCtrl-F"),
338 _T("Find a menu by searching for its label"));
339
340 wxMenu *menuMenu = new wxMenu;
341 menuMenu->Append(Menu_Menu_Append, _T("&Append menu item\tAlt-A"),
342 _T("Append a menu item to the last menu"));
343 menuMenu->Append(Menu_Menu_AppendSub, _T("&Append sub menu\tAlt-S"),
344 _T("Append a sub menu to the last menu"));
345 menuMenu->Append(Menu_Menu_Insert, _T("&Insert menu item\tAlt-I"),
346 _T("Insert a menu item in head of the last menu"));
347 menuMenu->Append(Menu_Menu_Delete, _T("&Delete menu item\tAlt-D"),
348 _T("Delete the last menu item from the last menu"));
349 menuMenu->AppendSeparator();
350 menuMenu->Append(Menu_Menu_Enable, _T("&Enable menu item\tAlt-E"),
351 _T("Enable or disable the last menu item"), TRUE);
352 menuMenu->Append(Menu_Menu_Check, _T("&Check menu item\tAlt-C"),
353 _T("Check or uncheck the last menu item"), TRUE);
354 menuMenu->AppendSeparator();
355 menuMenu->Append(Menu_Menu_GetInfo, _T("Get menu item in&fo\tAlt-F"),
356 _T("Show the state of the last menu item"));
357 menuMenu->AppendSeparator();
358 menuMenu->Append(Menu_Menu_FindItem, _T("Find menu item from label"),
359 _T("Find a menu item by searching for its label"));
360
361 wxMenu *testMenu = new wxMenu;
362 testMenu->Append(Menu_Test_Normal, _T("&Normal item"));
363 testMenu->AppendSeparator();
364 testMenu->AppendCheckItem(Menu_Test_Check, _T("&Check item"));
365 testMenu->AppendSeparator();
366 testMenu->AppendRadioItem(Menu_Test_Radio1, _T("Radio item &1"));
367 testMenu->AppendRadioItem(Menu_Test_Radio2, _T("Radio item &2"));
368 testMenu->AppendRadioItem(Menu_Test_Radio3, _T("Radio item &3"));
369
370 wxMenu *helpMenu = new wxMenu;
371 helpMenu->Append(Menu_Help_About, _T("&About\tF1"), _T("About menu sample"));
372
373 wxMenuBar* menuBar = new wxMenuBar( wxMB_DOCKABLE );
374
375 menuBar->Append(fileMenu, _T("&File"));
376 menuBar->Append(menubarMenu, _T("Menu&bar"));
377 menuBar->Append(menuMenu, _T("&Menu"));
378 menuBar->Append(testMenu, _T("&Test"));
379 menuBar->Append(helpMenu, _T("&Help"));
380
381 // these items should be initially checked
382 menuBar->Check(Menu_MenuBar_Toggle, TRUE);
383 menuBar->Check(Menu_MenuBar_Enable, TRUE);
384 menuBar->Check(Menu_Menu_Enable, TRUE);
385 menuBar->Check(Menu_Menu_Check, FALSE);
386
387 // associate the menu bar with the frame
388 SetMenuBar(menuBar);
389
390 // intercept all menu events and log them in this custom event handler
391 PushEventHandler(new MyEvtHandler(this));
392
393 // create the log text window
394 m_textctrl = new wxTextCtrl(this, -1, _T(""),
395 wxDefaultPosition, wxDefaultSize,
396 wxTE_MULTILINE);
397 m_textctrl->SetEditable(FALSE);
398
399 wxLog::SetTimestamp(NULL);
400 m_logOld = wxLog::SetActiveTarget(new wxLogTextCtrl(m_textctrl));
401
402 wxLogMessage(_T("Brief explanations: the commands or the \"Menu\" menu ")
403 _T("append/insert/delete items to/from the last menu.\n")
404 _T("The commands from \"Menubar\" menu work with the ")
405 _T("menubar itself.\n\n")
406 _T("Right click the band below to test popup menus.\n"));
407}
408
409MyFrame::~MyFrame()
410{
411 delete m_menu;
412
413 // delete the event handler installed in ctor
414 PopEventHandler(TRUE);
415
416 // restore old logger
417 delete wxLog::SetActiveTarget(m_logOld);
418}
419
420wxMenu *MyFrame::CreateDummyMenu(wxString *title)
421{
422 wxMenu *menu = new wxMenu;
423 menu->Append(Menu_Dummy_First, _T("&First item\tCtrl-F1"));
424 menu->AppendSeparator();
425 menu->Append(Menu_Dummy_Second, _T("&Second item\tCtrl-F2"), _T(""), TRUE);
426
427 if ( title )
428 {
429 title->Printf(wxT("Dummy menu &%u"), (unsigned)++m_countDummy);
430 }
431
432 return menu;
433}
434
435wxMenuItem *MyFrame::GetLastMenuItem() const
436{
437 wxMenuBar *menubar = GetMenuBar();
438 wxMenu *menu = menubar->GetMenu(menubar->GetMenuCount() - 1);
439
440 wxMenuItemList::Node *node = menu->GetMenuItems().GetLast();
441 if ( !node )
442 {
443 wxLogWarning(wxT("No last item in the last menu!"));
444
445 return NULL;
446 }
447 else
448 {
449 return node->GetData();
450 }
451}
452
453void MyFrame::LogMenuEvent(const wxCommandEvent& event)
454{
455 int id = event.GetId();
456 if ( !GetMenuBar()->FindItem(id) )
457 return;
458
459 wxString msg = wxString::Format(wxT("Menu command %d"), id);
460 if ( GetMenuBar()->FindItem(id)->IsCheckable() )
461 {
462 msg += wxString::Format(wxT(" (the item is currently %schecked)"),
463 event.IsChecked() ? "" : "not ");
464 }
465
466 wxLogMessage(msg);
467}
468
469// ----------------------------------------------------------------------------
470// menu callbacks
471// ----------------------------------------------------------------------------
472
473void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
474{
475 Close(TRUE);
476}
477
478void MyFrame::OnClearLog(wxCommandEvent& WXUNUSED(event))
479{
480 m_textctrl->Clear();
481}
482
483void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
484{
485