1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wxMenuButton
3 // Purpose: A button with a dropdown wxMenu
4 // Author: John Labenski
5 // Modified by:
6 // Created: 11/05/2002
7 // RCS-ID:
8 // Copyright: (c) John Labenki
9 // Licence: wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "menubtn.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/control.h"
25 #include "wx/menu.h"
26 #include "wx/settings.h"
27 #include "wx/bitmap.h"
28 #include "wx/pen.h"
29 #include "wx/dc.h"
30 #endif // WX_PRECOMP
31
32 #include <wx/tglbtn.h>
33 #include <wx/dcclient.h>
34 #include <wx/timer.h>
35 #include <wx/image.h>
36
37 #include "menubtn.h"
38
39
40
41 // ==========================================================================
42 // wxCustomButton
43 // ==========================================================================
IMPLEMENT_DYNAMIC_CLASS(wxCustomButton,wxControl)44 IMPLEMENT_DYNAMIC_CLASS( wxCustomButton, wxControl )
45
46 BEGIN_EVENT_TABLE(wxCustomButton,wxControl)
47 EVT_MOUSE_EVENTS ( wxCustomButton::OnMouseEvents )
48 EVT_PAINT ( wxCustomButton::OnPaint )
49 EVT_SIZE ( wxCustomButton::OnSize )
50 END_EVENT_TABLE()
51
52 wxCustomButton::~wxCustomButton()
53 {
54 if (HasCapture()) ReleaseMouse();
55 if (m_timer) delete m_timer;
56 }
57
Init()58 void wxCustomButton::Init()
59 {
60 m_focused = FALSE;
61 m_labelMargin = wxSize(4,4);
62 m_bitmapMargin = wxSize(2,2);
63 m_down = 0;
64 m_timer = NULL;
65 m_eventType = 0;
66 m_button_style = wxCUSTBUT_TOGGLE|wxCUSTBUT_BOTTOM;
67 }
68
Create(wxWindow * parent,wxWindowID id,const wxString & label,const wxBitmap & bitmap,const wxPoint & pos,const wxSize & size,long style,const wxValidator & val,const wxString & name)69 bool wxCustomButton::Create(wxWindow* parent, wxWindowID id,
70 const wxString& label, const wxBitmap &bitmap,
71 const wxPoint& pos, const wxSize& size,
72 long style, const wxValidator& val,
73 const wxString& name)
74 {
75 if (!wxControl::Create(parent,id,pos,size,wxNO_BORDER|wxCLIP_CHILDREN,val,name))
76 return FALSE;
77
78 wxControl::SetLabel(label);
79 wxControl::SetBackgroundColour(parent->GetBackgroundColour());
80 wxControl::SetForegroundColour(parent->GetForegroundColour());
81 wxControl::SetFont(parent->GetFont());
82
83 if (bitmap.Ok()) m_bmpLabel = bitmap;
84
85 if (!SetButtonStyle(style)) return FALSE;
86
87 wxSize bestSize = DoGetBestSize();
88 SetSize(wxSize(size.x<0 ? bestSize.x:size.x, size.y<0 ? bestSize.y:size.y));
89 #if (wxMINOR_VERSION<8)
90 SetBestSize(GetSize());
91 #else
92 SetInitialSize(GetSize());
93 #endif
94
95 CalcLayout(TRUE);
96 return TRUE;
97 }
98
SetValue(bool depressed)99 void wxCustomButton::SetValue(bool depressed)
100 {
101 wxCHECK_RET(!(m_button_style & wxCUSTBUT_NOTOGGLE), wxT("can't set button state"));
102 m_down = depressed ? 1 : 0;
103 Refresh(FALSE);
104 }
105
SetButtonStyle(long style)106 bool wxCustomButton::SetButtonStyle(long style)
107 {
108 int n_styles = 0;
109 if ((style & wxCUSTBUT_LEFT) != 0) n_styles++;
110 if ((style & wxCUSTBUT_RIGHT) != 0) n_styles++;
111 if ((style & wxCUSTBUT_TOP) != 0) n_styles++;
112 if ((style & wxCUSTBUT_BOTTOM) != 0) n_styles++;
113 wxCHECK_MSG(n_styles < 2, FALSE, wxT("Only one wxCustomButton label position allowed"));
114
115 n_styles = 0;
116 if ((style & wxCUSTBUT_NOTOGGLE) != 0) n_styles++;
117 if ((style & wxCUSTBUT_BUTTON) != 0) n_styles++;
118 if ((style & wxCUSTBUT_TOGGLE) != 0) n_styles++;
119 if ((style & wxCUSTBUT_BUT_DCLICK_TOG) != 0) n_styles++;
120 if ((style & wxCUSTBUT_TOG_DCLICK_BUT) != 0) n_styles++;
121 wxCHECK_MSG(n_styles < 2, FALSE, wxT("Only one wxCustomButton style allowed"));
122
123 m_button_style = style;
124
125 if ((m_button_style & wxCUSTBUT_BUTTON) != 0)
126 m_down = 0;
127
128 CalcLayout(TRUE);
129 return TRUE;
130 }
131
SetLabel(const wxString & label)132 void wxCustomButton::SetLabel( const wxString &label )
133 {
134 wxControl::SetLabel(label);
135 CalcLayout(TRUE);
136 }
137
138 // sequence of events in GTK is up, dclick, up.
139
OnMouseEvents(wxMouseEvent & event)140 void wxCustomButton::OnMouseEvents(wxMouseEvent& event)
141 {
142 if (m_button_style & wxCUSTBUT_NOTOGGLE) return;
143
144 if (event.LeftDown() || event.RightDown())
145 {
146 if (!HasCapture())
147 CaptureMouse(); // keep depressed until up
148
149 m_down++;
150 Redraw();
151 }
152 else if (event.LeftDClick() || event.RightDClick())
153 {
154 m_down++; // GTK eats second down event
155 Redraw();
156 }
157 else if (event.LeftUp())
158 {
159 if (HasCapture())
160 ReleaseMouse();
161
162 m_eventType = wxEVT_LEFT_UP;
163
164 #if (wxMINOR_VERSION<8)
165 if (wxRect(wxPoint(0,0), GetSize()).Inside(event.GetPosition()))
166 #else
167 if (wxRect(wxPoint(0,0), GetSize()).Contains(event.GetPosition()))
168 #endif
169 {
170 if ((m_button_style & wxCUSTBUT_BUTTON) && (m_down > 0))
171 {
172 m_down = 0;
173 Redraw();
174 SendEvent();
175 return;
176 }
177 else
178 {
179 if (!m_timer)
180 {
181 m_timer = new wxTimer(this, m_down+1);
182 m_timer->Start(200, TRUE);
183 }
184 else
185 {
186 m_eventType = wxEVT_LEFT_DCLICK;
187 }
188
189 if ((m_button_style & wxCUSTBUT_TOGGLE) &&
190 (m_button_style & wxCUSTBUT_TOG_DCLICK_BUT)) m_down++;
191 }
192 }
193
194 Redraw();
195 }
196 else if (event.RightUp())
197 {
198 if (HasCapture())
199 ReleaseMouse();
200
201 m_eventType = wxEVT_RIGHT_UP;
202
203 #if (wxMINOR_VERSION<8)
204 if (wxRect(wxPoint(0,0), GetSize()).Inside(event.GetPosition()))
205 #else
206 if (wxRect(wxPoint(0,0), GetSize()).Contains(event.GetPosition()))
207 #endif
208 {
209 if ((m_button_style & wxCUSTBUT_BUTTON) && (m_down > 0))
210 {
211 m_down = 0;
212 Redraw();
213 SendEvent();
214 return;
215 }
216 else
217 {
218 m_down++;
219
220 if (!m_timer)
221 {
222 m_timer = new wxTimer(this, m_down);
223 m_timer->Start(250, TRUE);
224 }
225 else
226 {
227 m_eventType = wxEVT_RIGHT_DCLICK;
228 }
229 }
230 }
231
232 Redraw();
233 }
234 else if (event.Entering())
235 {
236 m_focused = TRUE;
237 if ((event.LeftIsDown() || event.RightIsDown()) && HasCapture())
238 m_down++;
239
240 Redraw();
241 }
242 else if (event.Leaving())
243 {
244 m_focused = FALSE;
245 if ((event.LeftIsDown() || event.RightIsDown()) && HasCapture())
246 m_down--;
247
248 Redraw();
249 }
250 }
251
252
253
SendEvent()254 void wxCustomButton::SendEvent()
255 {
256 if (((m_button_style & wxCUSTBUT_TOGGLE) && (m_eventType == wxEVT_LEFT_UP)) ||
257 ((m_button_style & wxCUSTBUT_BUT_DCLICK_TOG) && (m_eventType == wxEVT_LEFT_DCLICK)) ||
258 ((m_button_style & wxCUSTBUT_TOG_DCLICK_BUT) && (m_eventType == wxEVT_LEFT_UP)))
259 {
260 wxCommandEvent eventOut(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, GetId());
261 eventOut.SetInt(m_down%2 ? 1 : 0);
262 eventOut.SetExtraLong(m_eventType);
263 eventOut.SetEventObject(this);
264 GetEventHandler()->ProcessEvent(eventOut);
265 }
266 else
267 {
268 wxCommandEvent eventOut(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
269 eventOut.SetInt(0);
270 eventOut.SetExtraLong(m_eventType);
271 eventOut.SetEventObject(this);
272 GetEventHandler()->ProcessEvent(eventOut);
273 }
274 }
275
CreateBitmapDisabled(const wxBitmap & bitmap) const276 wxBitmap wxCustomButton::CreateBitmapDisabled(const wxBitmap &bitmap) const
277 {
278 wxCHECK_MSG(bitmap.Ok(), wxNullBitmap, wxT("invalid bitmap"));
279
280 unsigned char br = GetBackgroundColour().Red();
281 unsigned char bg = GetBackgroundColour().Green();
282 unsigned char bb = GetBackgroundColour().Blue();
283
284 wxImage image = bitmap.ConvertToImage();
285 int pos, width = image.GetWidth(), height = image.GetHeight();
286 unsigned char *img_data = image.GetData();
287
288 for (int j=0; j<height; j++)
289 {
290 for (int i=j%2; i<width; i+=2)
291 {
292 pos = (j*width+i)*3;
293 img_data[pos ] = br;
294 img_data[pos+1] = bg;
295 img_data[pos+2] = bb;
296 }
297 }
298
299 return wxBitmap(image);
300 }
301
SetBitmapLabel(const wxBitmap & bitmap)302 void wxCustomButton::SetBitmapLabel(const wxBitmap& bitmap)
303 {
304 m_bmpLabel = bitmap;
305 CalcLayout(TRUE);
306 }
307
OnPaint(wxPaintEvent & WXUNUSED (event))308 void wxCustomButton::OnPaint(wxPaintEvent& WXUNUSED(event))
309 {
310 wxPaintDC dc(this);
311 Paint(dc);
312 }
313
Redraw()314 void wxCustomButton::Redraw()
315 {
316 wxClientDC dc(this);
317 Paint(dc);
318 }
319
Paint(wxDC & dc)320 void wxCustomButton::Paint( wxDC &dc )
321 {
322 #if (wxMINOR_VERSION<8)
323 dc.BeginDrawing();
324 #endif
325
326 int w, h;
327 GetSize(&w,&h);
328
329 wxColour foreColour = GetForegroundColour();
330 wxColour backColour = GetBackgroundColour();
331
332 if (m_focused)
333 {
334 backColour.Set( wxMin(backColour.Red() + 20, 255),
335 wxMin(backColour.Green() + 20, 255),
336 wxMin(backColour.Blue() + 20, 255) );
337 }
338
339 wxBitmap bitmap;
340
341 if (IsEnabled())
342 {
343 if (GetValue() && m_bmpSelected.Ok())
344 bitmap = m_bmpSelected;
345 else if (m_focused && m_bmpFocus.Ok())
346 bitmap = m_bmpFocus;
347 else if (m_bmpLabel.Ok())
348 bitmap = m_bmpLabel;
349 }
350 else
351 {
352 // try to create disabled if it doesn't exist
353 if (!m_bmpDisabled.Ok() && m_bmpLabel.Ok())
354 m_bmpDisabled = CreateBitmapDisabled(m_bmpLabel);
355
356 if (m_bmpDisabled.Ok())
357 bitmap = m_bmpDisabled;
358 else if (m_bmpLabel.Ok())
359 bitmap = m_bmpLabel;
360
361 foreColour = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
362 }
363
364 wxBrush brush(backColour, wxSOLID);
365 dc.SetBackground(brush);
366 dc.SetBrush(brush);
367 dc.SetPen(*wxTRANSPARENT_PEN);
368
369 dc.DrawRectangle(0, 0, w, h);
370
371 if (bitmap.Ok())
372 dc.DrawBitmap(bitmap, m_bitmapPos.x, m_bitmapPos.y, TRUE );
373
374 if (!GetLabel().IsEmpty())
375 {
376 dc.SetFont(GetFont());
377 dc.SetTextBackground(backColour);
378 dc.SetTextForeground(foreColour);
379 dc.DrawText(GetLabel(), m_labelPos.x, m_labelPos.y);
380 }
381
382 if (GetValue()) // draw sunken border
383 {
384 dc.SetPen(*wxGREY_PEN);
385 dc.DrawLine(0,h-1,0,0);
386 dc.DrawLine(0,0,w,0);
387 dc.SetPen(*wxWHITE_PEN);
388 dc.DrawLine(w-1,1,w-1,h-1);
389 dc.DrawLine(w-1,h-1,0,h-1);
390 dc.SetPen(*wxBLACK_PEN);
391 dc.DrawLine(1,h-2,1,1);
392 dc.DrawLine(1,1,w-1,1);
393 }
394 else if (((m_button_style & wxCUSTBUT_FLAT) == 0) || m_focused) // draw raised border
395 {
396 dc.SetPen(*wxWHITE_PEN);
397 dc.DrawLine(0,h-2,0,0);
398 dc.DrawLine(0,0,w-1,0);
399 dc.SetPen(*wxBLACK_PEN);
400 dc.DrawLine(w-1,0,w-1,h-1);
401 dc.DrawLine(w-1,h-1,-1,h-1);
402 dc.SetPen(*wxGREY_PEN);
403 dc.DrawLine(2,h-2,w-2,h-2);
404 dc.DrawLine(w-2,h-2,w-2,1);
405 }
406
407 dc.SetBackground(wxNullBrush);
408 dc.SetBrush(wxNullBrush);
409 dc.SetPen(wxNullPen);
410 #if (wxMINOR_VERSION<8)
411 dc.EndDrawing();
412 #endif
413 }
414
OnSize(wxSizeEvent & event)415 void wxCustomButton::OnSize( wxSizeEvent &event )
416 {
417 CalcLayout(TRUE);
418 event.Skip();
419 }
420
SetMargins(const wxSize & margin,bool fit)421 void wxCustomButton::SetMargins(const wxSize &margin, bool fit)
422 {
423 m_labelMargin = margin;
424 m_bitmapMargin = margin;
425 CalcLayout(TRUE);
426 if (fit) SetSize(DoGetBestSize());
427 }
SetLabelMargin(const wxSize & margin,bool fit)428 void wxCustomButton::SetLabelMargin(const wxSize &margin, bool fit)
429 {
430 m_labelMargin = margin;
431 CalcLayout(TRUE);
432 if (fit) SetSize(DoGetBestSize());
433 }
SetBitmapMargin(const wxSize & margin,bool fit)434 void wxCustomButton::SetBitmapMargin(const wxSize &margin, bool fit)
435 {
436 m_bitmapMargin = margin;
437 CalcLayout(TRUE);
438 if (fit) SetSize(DoGetBestSize());
439 }
440
DoGetBestSize() const441 wxSize wxCustomButton::DoGetBestSize() const
442 {
443 int lw=0, lh=0;
444 int bw=0, bh=0;
445 bool has_bitmap = FALSE;
446 bool has_label = FALSE;
447
448 if (!GetLabel().IsEmpty())
449 {
450 GetTextExtent(GetLabel(), &lw, &lh);
451 lw += 2*m_labelMargin.x;
452 lh += 2*m_labelMargin.y;
453 has_label = TRUE;
454 }
455 if (m_bmpLabel.Ok())
456 {
457 bw = m_bmpLabel.GetWidth() + 2*m_bitmapMargin.x;
458 bh = m_bmpLabel.GetHeight() + 2*m_bitmapMargin.y;
459 has_bitmap = TRUE;
460 }
461
462 if ((m_button_style & wxCUSTBUT_LEFT) || (m_button_style & wxCUSTBUT_RIGHT))
463 {
464 int h = bh > lh ? bh : lh;
465 if (has_bitmap && has_label) lw -= wxMin(m_labelMargin.x, m_bitmapMargin.x);
466 return wxSize(lw+bw, h);
467 }
468
469 int w = bw > lw ? bw : lw;
470 if (has_bitmap && has_label) lh -= wxMin(m_labelMargin.y, m_bitmapMargin.y);
471 return wxSize(w, lh+bh);
472 }
473
CalcLayout(bool refresh)474 void wxCustomButton::CalcLayout(bool refresh)
475 {
476 int w, h;
477 GetSize(&w,&h);
478
479 int bw = 0, bh = 0;
480 int lw = 0, lh = 0;
481
482 if (m_bmpLabel.Ok()) // assume they're all the same size
483 {
484 bw = m_bmpLabel.GetWidth();
485 bh = m_bmpLabel.GetHeight();
486 }
487 wxString label = GetLabel();
488 if (!label.IsEmpty())
489 {
490 GetTextExtent(label, &lw, &lh);
491 }
492
493 // Center the label or bitmap if only one or the other
494 if (!m_bmpLabel.Ok())
495 {
496 m_bitmapPos = wxPoint(0,0);
497 m_labelPos = wxPoint((w-lw)/2, (h-lh)/2);
498 }
499 else if (label.IsEmpty())
500 {
501 m_bitmapPos = wxPoint((w-bw)/2, (h-bh)/2);
502 m_labelPos = wxPoint(0,0);
503 }
504 else if (m_button_style & wxCUSTBUT_LEFT)
505 {
506 int mid_margin = wxMax(m_labelMargin.x, m_bitmapMargin.x);
507 m_labelPos = wxPoint((w - (bw+lw+m_labelMargin.x+m_bitmapMargin.x+mid_margin))/2 + m_labelMargin.x, (h - lh)/2);
508 m_bitmapPos = wxPoint(m_labelPos.x + lw + mid_margin, (h - bh)/2);
509 }
510 else if (m_button_style & wxCUSTBUT_RIGHT)
511 {
512 int mid_margin = wxMax(m_labelMargin.x, m_bitmapMargin.x);
513 m_bitmapPos = wxPoint((w - (bw+lw+m_labelMargin.x+m_bitmapMargin.x+mid_margin))/2 + m_bitmapMargin.x, (h - bh)/2);
514 m_labelPos = wxPoint(m_bitmapPos.x + bw + mid_margin, (h - lh)/2);
515 }
516 else if (m_button_style & wxCUSTBUT_TOP)
517 {
518 int mid_margin = wxMax(m_labelMargin.y, m_bitmapMargin.y);
519 m_labelPos = wxPoint((w - lw)/2, (h - (bh+lh+m_labelMargin.y+m_bitmapMargin.y+mid_margin))/2 + m_labelMargin.y);
520 m_bitmapPos = wxPoint((w - bw)/2, m_labelPos.y + lh + mid_margin);
521 }
522 else // if (m_button_style & wxCUSTBUT_BOTTOM) DEFAULT
523 {
524 int mid_margin = wxMax(m_labelMargin.y, m_bitmapMargin.y);
525 m_bitmapPos = wxPoint((w - bw)/2, (h - (bh+lh+m_labelMargin.y+m_bitmapMargin.y+mid_margin))/2 + m_bitmapMargin.y);
526 m_labelPos = wxPoint((w - lw)/2, m_bitmapPos.y + bh + mid_margin);
527 }
528
529 if (refresh) Refresh(FALSE);
530 }
531
532
533 /* XPM */
534 static const char *down_arrow_xpm_data[] = {
535 /* columns rows colors chars-per-pixel */
536 "5 3 2 1",
537 " c None",
538 "a c Black",
539 /* pixels */
540 "aaaaa",
541 " aaa ",
542 " a "
543 };
544
545 static wxBitmap s_dropdownBitmap; // all buttons share the same bitmap
546
547 enum
548 {
549 IDD_DROPDOWN_BUTTON = 100
550 };
551
552 //-----------------------------------------------------------------------------
553 // wxMenuButtonEvents
554 //-----------------------------------------------------------------------------
555
556 DEFINE_LOCAL_EVENT_TYPE(wxEVT_MENUBUTTON_OPEN)
557
558 // ==========================================================================
559 // MenuDropButton
560 // ==========================================================================
561
562 class MenuDropButton : public wxCustomButton
563 {
564 public:
MenuDropButton(wxWindow * parent,wxWindowID id,long style)565 MenuDropButton( wxWindow *parent, wxWindowID id, long style) : wxCustomButton()
566 {
567 if (!s_dropdownBitmap.Ok())
568 s_dropdownBitmap = wxBitmap(down_arrow_xpm_data);
569
570 Create( parent, id, wxEmptyString, s_dropdownBitmap, wxDefaultPosition,
571 wxSize(wxMENUBUTTON_DROP_WIDTH, wxMENUBUTTON_DROP_HEIGHT), style);
572 }
573
Paint(wxDC & dc)574 virtual void Paint( wxDC &dc )
575 {
576 wxCustomButton *labelBut = ((wxMenuButton*)GetParent())->GetLabelButton();
577
578 // pretend that both buttons have focus (for flat style)
579 if (labelBut)
580 {
581 wxPoint p = GetParent()->ScreenToClient(wxGetMousePosition());
582
583 #if (wxMINOR_VERSION<8)
584 if (GetRect().Inside(p) || labelBut->GetRect().Inside(p))
585 #else
586 if (GetRect().Contains(p) || labelBut->GetRect().Contains(p))
587 #endif
588 {
589 m_focused = TRUE;
590
591 if (!labelBut->GetFocused())
592 labelBut->SetFocused(TRUE);
593 }
594 else
595 {
596 m_focused = FALSE;
597
598 if (labelBut->GetFocused())
599 labelBut->SetFocused(FALSE);
600 }
601 }
602
603 wxCustomButton::Paint(dc);
604 }
605 };
606
607 // ==========================================================================
608 // MenuLabelButton
609 // ==========================================================================
610
611 class MenuLabelButton : public wxCustomButton
612 {
613 public:
MenuLabelButton(wxWindow * parent,wxWindowID id,const wxString & label,const wxBitmap & bitmap,long style)614 MenuLabelButton( wxWindow* parent, wxWindowID id,
615 const wxString &label,
616 const wxBitmap &bitmap,
617 long style ) : wxCustomButton()
618 {
619 Create(parent, id, label, bitmap, wxDefaultPosition, wxDefaultSize, style);
620 }
621
Paint(wxDC & dc)622 virtual void Paint( wxDC &dc )
623 {
624 wxCustomButton *dropBut = ((wxMenuButton*)GetParent())->GetDropDownButton();
625
626 // pretend that both buttons have focus (for flat style)
627 if (dropBut)
628 {
629 wxPoint p = GetParent()->ScreenToClient(wxGetMousePosition());
630
631 #if (wxMINOR_VERSION<8)
632 if (GetRect().Inside(p) || dropBut->GetRect().Inside(p))
633 #else
634 if (GetRect().Contains(p) || dropBut->GetRect().Contains(p))
635 #endif
636 {
637 m_focused = TRUE;
638
639 if (!dropBut->GetFocused())
640 dropBut->SetFocused(TRUE);
641 }
642 else
643 {
644 m_focused = FALSE;
645
646 if (dropBut->GetFocused())
647 dropBut->SetFocused(FALSE);
648 }
649 }
650
651 wxCustomButton::Paint(dc);
652 }
653 };
654
655 // ==========================================================================
656 // wxMenuButton
657 // ==========================================================================
658
IMPLEMENT_DYNAMIC_CLASS(wxMenuButton,wxControl)659 IMPLEMENT_DYNAMIC_CLASS( wxMenuButton, wxControl )
660
661 BEGIN_EVENT_TABLE(wxMenuButton,wxControl)
662 EVT_BUTTON(wxID_ANY, wxMenuButton::OnButton)
663
664 #ifdef __WXMSW__
665 EVT_MENU(wxID_ANY, wxMenuButton::OnMenu)
666 #endif
667 END_EVENT_TABLE()
668
669 wxMenuButton::~wxMenuButton()
670 {
671 AssignMenu(NULL, TRUE);
672 }
673
Init()674 void wxMenuButton::Init()
675 {
676 m_labelButton = NULL;
677 m_dropdownButton = NULL;
678 m_menu = NULL;
679 m_menu_static = FALSE;
680 m_style = 0;
681 }
682
Create(wxWindow * parent,wxWindowID id,const wxString & label,const wxBitmap & bitmap,const wxPoint & pos,const wxSize & size,long style,const wxValidator & val,const wxString & name)683 bool wxMenuButton::Create( wxWindow* parent, wxWindowID id,
684 const wxString &label,
685 const wxBitmap &bitmap,
686 const wxPoint& pos,
687 const wxSize& size,
688 long style,
689 const wxValidator& val,
690 const wxString& name)
691 {
692 m_style = style;
693
694 long flat = style & wxMENUBUT_FLAT;
695
696 wxControl::Create(parent,id,pos,size,wxNO_BORDER|wxCLIP_CHILDREN,val,name);
697 wxControl::SetLabel(label);
698 SetBackgroundColour(parent->GetBackgroundColour());
699 SetForegroundColour(parent->GetForegroundColour());
700 SetFont(parent->GetFont());
701
702 m_labelButton = new MenuLabelButton(this, id, label, bitmap, wxCUSTBUT_BUTTON|flat);
703 m_dropdownButton = new MenuDropButton(this, IDD_DROPDOWN_BUTTON, wxCUSTBUT_BUTTON|flat);
704
705 wxSize bestSize = DoGetBestSize();
706 SetSize( wxSize(size.x < 0 ? bestSize.x : size.x,
707 size.y < 0 ? bestSize.y : size.y) );
708
709 #if (wxMINOR_VERSION<8)
710 SetBestSize(GetSize());
711 #else
712 SetInitialSize(GetSize());
713 #endif
714
715 return TRUE;
716 }
717
718 #ifdef __WXMSW__
719 // FIXME - I think there was a patch to fix this
OnMenu(wxCommandEvent & event)720 void wxMenuButton::OnMenu( wxCommandEvent &event )
721 {
722 event.Skip();
723 wxMenuItem *mi = m_menu->FindItem(event.GetId());
724 if (mi && (mi->GetKind() == wxITEM_RADIO))
725 m_menu->Check(event.GetId(), TRUE);
726 }
727 #endif // __WXMSW__
728
OnButton(wxCommandEvent & event)729 void wxMenuButton::OnButton( wxCommandEvent &event)
730 {
731 int win_id = event.GetId();
732
733 if (win_id == IDD_DROPDOWN_BUTTON)
734 {
735 wxNotifyEvent mevent(wxEVT_MENUBUTTON_OPEN, GetId());
736 mevent.SetEventObject(this);
737 if (GetEventHandler()->ProcessEvent(mevent) && !mevent.IsAllowed())
738 return;
739
740 if (!m_menu)
741 return;
742
743 PopupMenu(m_menu, wxPoint(0, GetSize().y));
744
745 m_labelButton->Refresh(FALSE);
746 m_dropdownButton->Refresh(FALSE);
747 }
748 else if (win_id == m_labelButton->GetId())
749 {
750
751 wxCommandEvent cevent(wxEVT_COMMAND_MENU_SELECTED, win_id);
752 cevent.SetEventObject(this);
753 cevent.SetId(win_id);
754 GetParent()->GetEventHandler()->ProcessEvent(cevent);
755
756 if (!m_menu) return;
757
758 const wxMenuItemList &items = m_menu->GetMenuItems();
759 int first_radio_id = -1;
760 int checked_id = -1;
761 bool check_next = FALSE;
762
763 // find the next available radio item to check
764 for (wxMenuItemList::Node *node = items.GetFirst(); node; node = node->GetNext())
765 {
766 wxMenuItem *mi = (wxMenuItem*)node->GetData();
767 if (mi && (mi->GetKind() == wxITEM_RADIO))
768 {
769 if (first_radio_id == -1)
770 first_radio_id = mi->GetId();
771
772 if (check_next)
773 {
774 check_next = FALSE;
775 checked_id = mi->GetId();
776 break;
777 }
778 else if (mi->IsChecked())
779 check_next = TRUE;
780 }
781 }
782 // the last item was checked, go back to the first
783 if (check_next && (first_radio_id != -1))
784 checked_id = first_radio_id;
785
786 if (checked_id != -1)
787 {
788 m_menu->Check(checked_id, TRUE);
789
790 wxCommandEvent mevent( wxEVT_COMMAND_MENU_SELECTED, checked_id);
791 mevent.SetEventObject( m_menu );
792 mevent.SetInt(1);
793 GetEventHandler()->ProcessEvent(mevent);
794 }
795 }
796 }
797
GetSelection() const798 int wxMenuButton::GetSelection() const
799 {
800 wxCHECK_MSG(m_menu != NULL, wxNOT_FOUND, wxT("No attached menu in wxMenuButton::GetSelection"));
801
802 const wxMenuItemList &items = m_menu->GetMenuItems();
803
804 for (wxMenuItemList::Node *node = items.GetFirst(); node; node = node->GetNext())
805 {
806 wxMenuItem *mi = (wxMenuItem*)node->GetData();
807 if (mi && (mi->GetKind() == wxITEM_RADIO))
808 {
809 if (mi->IsChecked())
810 return mi->GetId();
811 }
812 }
813
814 return wxNOT_FOUND;
815 }
816
AssignMenu(wxMenu * menu,bool static_menu)817 void wxMenuButton::AssignMenu(wxMenu *menu, bool static_menu)
818 {
819 if (!m_menu_static && m_menu)
820 delete m_menu;
821
822 m_menu = menu;
823 m_menu_static = static_menu;
824 }
825
SetToolTip(const wxString & tip)826 void wxMenuButton::SetToolTip(const wxString &tip)
827 {
828 wxWindow::SetToolTip(tip);
829 ((wxWindow*)m_labelButton)->SetToolTip(tip);
830 ((wxWindow*)m_dropdownButton)->SetToolTip(tip);
831 }
SetToolTip(wxToolTip * tip)832 void wxMenuButton::SetToolTip(wxToolTip *tip)
833 {
834 wxWindow::SetToolTip(tip);
835 ((wxWindow*)m_labelButton)->SetToolTip(tip);
836 ((wxWindow*)m_dropdownButton)->SetToolTip(tip);
837 }
838
DoSetSize(int x,int y,int width,int height,int sizeFlags)839 void wxMenuButton::DoSetSize(int x, int y, int width, int height, int sizeFlags)
840 {
841 wxSize curSize( GetSize() );
842 wxSize bestSize( DoGetBestSize() );
843
844 if (width == -1)
845 width = curSize.GetWidth();
846 if (width < 10)
847 width = bestSize.GetWidth();
848
849 if (height == -1)
850 height = curSize.GetHeight();
851 if (height < 5)
852 height = bestSize.GetHeight();
853
854 wxWindow::DoSetSize(x, y, width, height, sizeFlags);
855
856 if (m_labelButton)
857 m_labelButton->SetSize(0, 0, width - wxMENUBUTTON_DROP_WIDTH, height);
858 if (m_dropdownButton)
859 m_dropdownButton->SetSize(width-wxMENUBUTTON_DROP_WIDTH, 0, wxMENUBUTTON_DROP_WIDTH, height);
860 }
861
DoGetBestSize()862 wxSize wxMenuButton::DoGetBestSize()
863 {
864 if (!m_labelButton || !m_dropdownButton)
865 return wxSize(wxMENUBUTTON_DROP_WIDTH+wxMENUBUTTON_DROP_HEIGHT, wxMENUBUTTON_DROP_HEIGHT);
866
867 wxSize size = m_labelButton->GetBestSize();
868 size.x += wxMENUBUTTON_DROP_WIDTH;
869 return size;
870 }
871