]> git.saurik.com Git - wxWidgets.git/blob - src/common/framecmn.cpp
Fix bug with showing hidden wxGrid lines when resizing an adjacent one.
[wxWidgets.git] / src / common / framecmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/framecmn.cpp
3 // Purpose: common (for all platforms) wxFrame functions
4 // Author: Julian Smart, Vadim Zeitlin
5 // Created: 01/02/97
6 // Id: $Id$
7 // Copyright: (c) 1998 Robert Roebling and Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #include "wx/frame.h"
27
28 #ifndef WX_PRECOMP
29 #include "wx/app.h"
30 #include "wx/menu.h"
31 #include "wx/menuitem.h"
32 #include "wx/dcclient.h"
33 #include "wx/toolbar.h"
34 #include "wx/statusbr.h"
35 #endif // WX_PRECOMP
36
37 extern WXDLLEXPORT_DATA(const char) wxFrameNameStr[] = "frame";
38 extern WXDLLEXPORT_DATA(const char) wxStatusLineNameStr[] = "status_line";
39
40 // ----------------------------------------------------------------------------
41 // event table
42 // ----------------------------------------------------------------------------
43
44 #if wxUSE_MENUS && wxUSE_STATUSBAR
45 BEGIN_EVENT_TABLE(wxFrameBase, wxTopLevelWindow)
46 EVT_MENU_OPEN(wxFrameBase::OnMenuOpen)
47 EVT_MENU_CLOSE(wxFrameBase::OnMenuClose)
48
49 EVT_MENU_HIGHLIGHT_ALL(wxFrameBase::OnMenuHighlight)
50 END_EVENT_TABLE()
51
52 #endif // wxUSE_MENUS && wxUSE_IDLEMENUUPDATES
53
54 /* static */
55 bool wxFrameBase::ShouldUpdateMenuFromIdle()
56 {
57 // Usually this is determined at compile time and is determined by whether
58 // the platform supports wxEVT_MENU_OPEN, however in wxGTK we need to also
59 // check if we're using the global menu bar as we don't get EVT_MENU_OPEN
60 // for it and need to fall back to idle time updating even if normally
61 // wxUSE_IDLEMENUUPDATES is set to 0 for wxGTK.
62 #ifdef __WXGTK20__
63 if ( wxApp::GTKIsUsingGlobalMenu() )
64 return true;
65 #endif // !__WXGTK__
66
67 return wxUSE_IDLEMENUUPDATES != 0;
68 }
69
70 // ============================================================================
71 // implementation
72 // ============================================================================
73
74 // ----------------------------------------------------------------------------
75 // XTI
76 // ----------------------------------------------------------------------------
77
78 wxDEFINE_FLAGS( wxFrameStyle )
79 wxBEGIN_FLAGS( wxFrameStyle )
80 // new style border flags, we put them first to
81 // use them for streaming out
82 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
83 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
84 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
85 wxFLAGS_MEMBER(wxBORDER_RAISED)
86 wxFLAGS_MEMBER(wxBORDER_STATIC)
87 wxFLAGS_MEMBER(wxBORDER_NONE)
88
89 // old style border flags
90 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
91 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
92 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
93 wxFLAGS_MEMBER(wxRAISED_BORDER)
94 wxFLAGS_MEMBER(wxSTATIC_BORDER)
95 wxFLAGS_MEMBER(wxBORDER)
96
97 // standard window styles
98 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
99 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
100 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
101 wxFLAGS_MEMBER(wxWANTS_CHARS)
102 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
103 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
104 wxFLAGS_MEMBER(wxVSCROLL)
105 wxFLAGS_MEMBER(wxHSCROLL)
106
107 // frame styles
108 wxFLAGS_MEMBER(wxSTAY_ON_TOP)
109 wxFLAGS_MEMBER(wxCAPTION)
110 #if WXWIN_COMPATIBILITY_2_6
111 wxFLAGS_MEMBER(wxTHICK_FRAME)
112 #endif // WXWIN_COMPATIBILITY_2_6
113 wxFLAGS_MEMBER(wxSYSTEM_MENU)
114 wxFLAGS_MEMBER(wxRESIZE_BORDER)
115 #if WXWIN_COMPATIBILITY_2_6
116 wxFLAGS_MEMBER(wxRESIZE_BOX)
117 #endif // WXWIN_COMPATIBILITY_2_6
118 wxFLAGS_MEMBER(wxCLOSE_BOX)
119 wxFLAGS_MEMBER(wxMAXIMIZE_BOX)
120 wxFLAGS_MEMBER(wxMINIMIZE_BOX)
121
122 wxFLAGS_MEMBER(wxFRAME_TOOL_WINDOW)
123 wxFLAGS_MEMBER(wxFRAME_FLOAT_ON_PARENT)
124
125 wxFLAGS_MEMBER(wxFRAME_SHAPED)
126 wxEND_FLAGS( wxFrameStyle )
127
128 wxIMPLEMENT_DYNAMIC_CLASS_XTI(wxFrame, wxTopLevelWindow, "wx/frame.h")
129
130 wxBEGIN_PROPERTIES_TABLE(wxFrame)
131 wxEVENT_PROPERTY( Menu, wxEVT_COMMAND_MENU_SELECTED, wxCommandEvent)
132
133 wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxString(), 0 /*flags*/, \
134 wxT("Helpstring"), wxT("group"))
135 wxPROPERTY_FLAGS( WindowStyle, wxFrameStyle, long, SetWindowStyleFlag, \
136 GetWindowStyleFlag, wxEMPTY_PARAMETER_VALUE, 0 /*flags*/, \
137 wxT("Helpstring"), wxT("group")) // style
138 #if wxUSE_MENUS
139 wxPROPERTY( MenuBar, wxMenuBar *, SetMenuBar, GetMenuBar, wxEMPTY_PARAMETER_VALUE, \
140 0 /*flags*/, wxT("Helpstring"), wxT("group"))
141 #endif
142 wxEND_PROPERTIES_TABLE()
143
144 wxEMPTY_HANDLERS_TABLE(wxFrame)
145
146 wxCONSTRUCTOR_6( wxFrame, wxWindow*, Parent, wxWindowID, Id, wxString, Title, \
147 wxPoint, Position, wxSize, Size, long, WindowStyle)
148
149 // ----------------------------------------------------------------------------
150 // construction/destruction
151 // ----------------------------------------------------------------------------
152
153 wxFrameBase::wxFrameBase()
154 {
155 #if wxUSE_MENUS
156 m_frameMenuBar = NULL;
157 #endif // wxUSE_MENUS
158
159 #if wxUSE_TOOLBAR
160 m_frameToolBar = NULL;
161 #endif // wxUSE_TOOLBAR
162
163 #if wxUSE_STATUSBAR
164 m_frameStatusBar = NULL;
165 #endif // wxUSE_STATUSBAR
166
167 m_statusBarPane = 0;
168 }
169
170 wxFrameBase::~wxFrameBase()
171 {
172 // this destructor is required for Darwin
173 }
174
175 wxFrame *wxFrameBase::New(wxWindow *parent,
176 wxWindowID id,
177 const wxString& title,
178 const wxPoint& pos,
179 const wxSize& size,
180 long style,
181 const wxString& name)
182 {
183 return new wxFrame(parent, id, title, pos, size, style, name);
184 }
185
186 void wxFrameBase::DeleteAllBars()
187 {
188 #if wxUSE_MENUS
189 wxDELETE(m_frameMenuBar);
190 #endif // wxUSE_MENUS
191
192 #if wxUSE_STATUSBAR
193 wxDELETE(m_frameStatusBar);
194 #endif // wxUSE_STATUSBAR
195
196 #if wxUSE_TOOLBAR
197 wxDELETE(m_frameToolBar);
198 #endif // wxUSE_TOOLBAR
199 }
200
201 bool wxFrameBase::IsOneOfBars(const wxWindow *win) const
202 {
203 #if wxUSE_MENUS
204 if ( win == GetMenuBar() )
205 return true;
206 #endif // wxUSE_MENUS
207
208 #if wxUSE_STATUSBAR
209 if ( win == GetStatusBar() )
210 return true;
211 #endif // wxUSE_STATUSBAR
212
213 #if wxUSE_TOOLBAR
214 if ( win == GetToolBar() )
215 return true;
216 #endif // wxUSE_TOOLBAR
217
218 wxUnusedVar(win);
219
220 return false;
221 }
222
223 // ----------------------------------------------------------------------------
224 // wxFrame size management: we exclude the areas taken by menu/status/toolbars
225 // from the client area, so the client area is what's really available for the
226 // frame contents
227 // ----------------------------------------------------------------------------
228
229 // get the origin of the client area in the client coordinates
230 wxPoint wxFrameBase::GetClientAreaOrigin() const
231 {
232 wxPoint pt = wxTopLevelWindow::GetClientAreaOrigin();
233
234 #if wxUSE_TOOLBAR && !defined(__WXUNIVERSAL__)
235 wxToolBar *toolbar = GetToolBar();
236 if ( toolbar && toolbar->IsShown() )
237 {
238 int w, h;
239 toolbar->GetSize(&w, &h);
240
241 if ( toolbar->GetWindowStyleFlag() & wxTB_VERTICAL )
242 {
243 pt.x += w;
244 }
245 else
246 {
247 pt.y += h;
248 }
249 }
250 #endif // wxUSE_TOOLBAR
251
252 return pt;
253 }
254
255 // ----------------------------------------------------------------------------
256 // misc
257 // ----------------------------------------------------------------------------
258
259 #if wxUSE_MENUS
260
261 bool wxFrameBase::ProcessCommand(int id)
262 {
263 wxMenuItem* const item = FindItemInMenuBar(id);
264 if ( !item )
265 return false;
266
267 return ProcessCommand(item);
268 }
269
270 bool wxFrameBase::ProcessCommand(wxMenuItem *item)
271 {
272 wxCHECK_MSG( item, false, wxS("Menu item can't be NULL") );
273
274 if (!item->IsEnabled())
275 return true;
276
277 if ((item->GetKind() == wxITEM_RADIO) && item->IsChecked() )
278 return true;
279
280 int checked;
281 if (item->IsCheckable())
282 {
283 item->Toggle();
284
285 // use the new value
286 checked = item->IsChecked();
287 }
288 else // Uncheckable item.
289 {
290 checked = -1;
291 }
292
293 wxMenu* const menu = item->GetMenu();
294 wxCHECK_MSG( menu, false, wxS("Menu item should be attached to a menu") );
295
296 return menu->SendEvent(item->GetId(), checked);
297 }
298
299 #endif // wxUSE_MENUS
300
301 // Do the UI update processing for this window. This is
302 // provided for the application to call if it wants to
303 // force a UI update, particularly for the menus and toolbar.
304 void wxFrameBase::UpdateWindowUI(long flags)
305 {
306 wxWindowBase::UpdateWindowUI(flags);
307
308 #if wxUSE_TOOLBAR
309 if (GetToolBar())
310 GetToolBar()->UpdateWindowUI(flags);
311 #endif
312
313 #if wxUSE_MENUS
314 if (GetMenuBar())
315 {
316 // If coming from an idle event, we only want to update the menus if
317 // we're in the wxUSE_IDLEMENUUPDATES configuration, otherwise they
318 // will be update when the menu is opened later
319 if ( !(flags & wxUPDATE_UI_FROMIDLE) || ShouldUpdateMenuFromIdle() )
320 DoMenuUpdates();
321 }
322 #endif // wxUSE_MENUS
323 }
324
325 // ----------------------------------------------------------------------------
326 // event handlers for status bar updates from menus
327 // ----------------------------------------------------------------------------
328
329 #if wxUSE_MENUS && wxUSE_STATUSBAR
330
331 void wxFrameBase::OnMenuHighlight(wxMenuEvent& event)
332 {
333 #if wxUSE_STATUSBAR
334 (void)ShowMenuHelp(event.GetMenuId());
335 #endif // wxUSE_STATUSBAR
336 }
337
338 void wxFrameBase::OnMenuOpen(wxMenuEvent& event)
339 {
340 if ( !ShouldUpdateMenuFromIdle() )
341 {
342 // as we didn't update the menus from idle time, do it now
343 DoMenuUpdates(event.GetMenu());
344 }
345 }
346
347 void wxFrameBase::OnMenuClose(wxMenuEvent& WXUNUSED(event))
348 {
349 DoGiveHelp(wxEmptyString, false);
350 }
351
352 #endif // wxUSE_MENUS && wxUSE_STATUSBAR
353
354 // Implement internal behaviour (menu updating on some platforms)
355 void wxFrameBase::OnInternalIdle()
356 {
357 wxTopLevelWindow::OnInternalIdle();
358
359 #if wxUSE_MENUS
360 if ( ShouldUpdateMenuFromIdle() && wxUpdateUIEvent::CanUpdate(this) )
361 DoMenuUpdates();
362 #endif
363 }
364
365 // ----------------------------------------------------------------------------
366 // status bar stuff
367 // ----------------------------------------------------------------------------
368
369 #if wxUSE_STATUSBAR
370
371 wxStatusBar* wxFrameBase::CreateStatusBar(int number,
372 long style,
373 wxWindowID id,
374 const wxString& name)
375 {
376 // the main status bar can only be created once (or else it should be
377 // deleted before calling CreateStatusBar() again)
378 wxCHECK_MSG( !m_frameStatusBar, NULL,
379 wxT("recreating status bar in wxFrame") );
380
381 SetStatusBar(OnCreateStatusBar(number, style, id, name));
382
383 return m_frameStatusBar;
384 }
385
386 wxStatusBar *wxFrameBase::OnCreateStatusBar(int number,
387 long style,
388 wxWindowID id,
389 const wxString& name)
390 {
391 wxStatusBar *statusBar = new wxStatusBar(this, id, style, name);
392
393 statusBar->SetFieldsCount(number);
394
395 return statusBar;
396 }
397
398 void wxFrameBase::SetStatusText(const wxString& text, int number)
399 {
400 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
401
402 m_frameStatusBar->SetStatusText(text, number);
403 }
404
405 void wxFrameBase::SetStatusWidths(int n, const int widths_field[] )
406 {
407 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set widths for") );
408
409 m_frameStatusBar->SetStatusWidths(n, widths_field);
410
411 PositionStatusBar();
412 }
413
414 void wxFrameBase::PushStatusText(const wxString& text, int number)
415 {
416 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
417
418 m_frameStatusBar->PushStatusText(text, number);
419 }
420
421 void wxFrameBase::PopStatusText(int number)
422 {
423 wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") );
424
425 m_frameStatusBar->PopStatusText(number);
426 }
427
428 bool wxFrameBase::ShowMenuHelp(int menuId)
429 {
430 #if wxUSE_MENUS
431 // if no help string found, we will clear the status bar text
432 //
433 // NB: wxID_NONE is used for (sub)menus themselves by wxMSW
434 wxString helpString;
435 if ( menuId != wxID_SEPARATOR && menuId != wxID_NONE )
436 {
437 const wxMenuItem * const item = FindItemInMenuBar(menuId);
438 if ( item && !item->IsSeparator() )
439 helpString = item->GetHelp();
440
441 // notice that it's ok if we don't find the item because it might
442 // belong to the popup menu, so don't assert here
443 }
444
445 DoGiveHelp(helpString, true);
446
447 return !helpString.empty();
448 #else // !wxUSE_MENUS
449 return false;
450 #endif // wxUSE_MENUS/!wxUSE_MENUS
451 }
452
453 void wxFrameBase::SetStatusBar(wxStatusBar *statBar)
454 {
455 bool hadBar = m_frameStatusBar != NULL;
456 m_frameStatusBar = statBar;
457
458 if ( (m_frameStatusBar != NULL) != hadBar )
459 {
460 PositionStatusBar();
461
462 DoLayout();
463 }
464 }
465
466 #endif // wxUSE_STATUSBAR
467
468 #if wxUSE_MENUS || wxUSE_TOOLBAR
469 void wxFrameBase::DoGiveHelp(const wxString& help, bool show)
470 {
471 #if wxUSE_STATUSBAR
472 if ( m_statusBarPane < 0 )
473 {
474 // status bar messages disabled
475 return;
476 }
477
478 wxStatusBar *statbar = GetStatusBar();
479 if ( !statbar )
480 return;
481
482 wxString text;
483 if ( show )
484 {
485 // remember the old status bar text if this is the first time we're
486 // called since the menu has been opened as we're going to overwrite it
487 // in our DoGiveHelp() and we want to restore it when the menu is
488 // closed
489 //
490 // note that it would be logical to do this in OnMenuOpen() but under
491 // MSW we get an EVT_MENU_HIGHLIGHT before EVT_MENU_OPEN, strangely
492 // enough, and so this doesn't work and instead we use the ugly trick
493 // with using special m_oldStatusText value as "menu opened" (but it is
494 // arguably better than adding yet another member variable to wxFrame
495 // on all platforms)
496 if ( m_oldStatusText.empty() )
497 {
498 m_oldStatusText = statbar->GetStatusText(m_statusBarPane);
499 if ( m_oldStatusText.empty() )
500 {
501 // use special value to prevent us from doing this the next time
502 m_oldStatusText += wxT('\0');
503 }
504 }
505
506 m_lastHelpShown =
507 text = help;
508 }
509 else // hide help, restore the original text
510 {
511 // clear the last shown help string but remember its value
512 wxString lastHelpShown;
513 lastHelpShown.swap(m_lastHelpShown);
514
515 // also clear the old status text but remember it too to restore it
516 // below
517 text.swap(m_oldStatusText);
518
519 if ( statbar->GetStatusText(m_statusBarPane) != lastHelpShown )
520 {
521 // if the text was changed with an explicit SetStatusText() call
522 // from the user code in the meanwhile, do not overwrite it with
523 // the old status bar contents -- this is almost certainly not what
524 // the user expects and would be very hard to avoid from user code
525 return;
526 }
527 }
528
529 statbar->SetStatusText(text, m_statusBarPane);
530 #else
531 wxUnusedVar(help);
532 wxUnusedVar(show);
533 #endif // wxUSE_STATUSBAR
534 }
535 #endif // wxUSE_MENUS || wxUSE_TOOLBAR
536
537
538 // ----------------------------------------------------------------------------
539 // toolbar stuff
540 // ----------------------------------------------------------------------------
541
542 #if wxUSE_TOOLBAR
543
544 wxToolBar* wxFrameBase::CreateToolBar(long style,
545 wxWindowID id,
546 const wxString& name)
547 {
548 // the main toolbar can't be recreated (unless it was explicitly deleted
549 // before)
550 wxCHECK_MSG( !m_frameToolBar, NULL,
551 wxT("recreating toolbar in wxFrame") );
552
553 if ( style == -1 )
554 {
555 // use default style
556 //
557 // NB: we don't specify the default value in the method declaration
558 // because
559 // a) this allows us to have different defaults for different
560 // platforms (even if we don't have them right now)
561 // b) we don't need to include wx/toolbar.h in the header then
562 style = wxBORDER_NONE | wxTB_HORIZONTAL | wxTB_FLAT;
563 }
564
565 SetToolBar(OnCreateToolBar(style, id, name));
566
567 return m_frameToolBar;
568 }
569
570 wxToolBar* wxFrameBase::OnCreateToolBar(long style,
571 wxWindowID id,
572 const wxString& name)
573 {
574 #if defined(__WXWINCE__) && defined(__POCKETPC__)
575 return new wxToolMenuBar(this, id,
576 wxDefaultPosition, wxDefaultSize,
577 style, name);
578 #else
579 return new wxToolBar(this, id,
580 wxDefaultPosition, wxDefaultSize,
581 style, name);
582 #endif
583 }
584
585 void wxFrameBase::SetToolBar(wxToolBar *toolbar)
586 {
587 if ( (toolbar != NULL) != (m_frameToolBar != NULL) )
588 {
589 // the toolbar visibility must have changed so we need to both position
590 // the toolbar itself (if it appeared) and to relayout the frame
591 // contents in any case
592
593 if ( toolbar )
594 {
595 // we need to assign it to m_frameToolBar for PositionToolBar() to
596 // do anything
597 m_frameToolBar = toolbar;
598 PositionToolBar();
599 }
600 //else: tricky: do not reset m_frameToolBar yet as otherwise DoLayout()
601 // wouldn't recognize the (still existing) toolbar as one of our
602 // bars and wouldn't layout the single child of the frame correctly
603
604
605 // and this is even more tricky: we want DoLayout() to recognize the
606 // old toolbar for the purpose of not counting it among our non-bar
607 // children but we don't want to reserve any more space for it so we
608 // temporarily hide it
609 if ( m_frameToolBar )
610 m_frameToolBar->Hide();
611
612 DoLayout();
613
614 if ( m_frameToolBar )
615 m_frameToolBar->Show();
616 }
617
618 // this might have been already done above but it's simpler to just always
619 // do it unconditionally instead of testing for whether we already did it
620 m_frameToolBar = toolbar;
621 }
622
623 #endif // wxUSE_TOOLBAR
624
625 // ----------------------------------------------------------------------------
626 // menus
627 // ----------------------------------------------------------------------------
628
629 #if wxUSE_MENUS
630
631 // update all menus
632 void wxFrameBase::DoMenuUpdates(wxMenu* menu)
633 {
634 if (menu)
635 {
636 wxEvtHandler* source = GetEventHandler();
637 menu->UpdateUI(source);
638 }
639 else
640 {
641 wxMenuBar* bar = GetMenuBar();
642 if (bar != NULL)
643 bar->UpdateMenus();
644 }
645 }
646
647 void wxFrameBase::DetachMenuBar()
648 {
649 if ( m_frameMenuBar )
650 {
651 m_frameMenuBar->Detach();
652 m_frameMenuBar = NULL;
653 }
654 }
655
656 void wxFrameBase::AttachMenuBar(wxMenuBar *menubar)
657 {
658 if ( menubar )
659 {
660 menubar->Attach((wxFrame *)this);
661 m_frameMenuBar = menubar;
662 }
663 }
664
665 void wxFrameBase::SetMenuBar(wxMenuBar *menubar)
666 {
667 if ( menubar == GetMenuBar() )
668 {
669 // nothing to do
670 return;
671 }
672
673 DetachMenuBar();
674
675 this->AttachMenuBar(menubar);
676 }
677
678 wxMenuItem *wxFrameBase::FindItemInMenuBar(int menuId) const
679 {
680 const wxMenuBar * const menuBar = GetMenuBar();
681
682 return menuBar ? menuBar->FindItem(menuId) : NULL;
683 }
684
685 #endif // wxUSE_MENUS