Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SplitButton.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
13 /* This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This software is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  * General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public
24  * License along with this software. If not, see
25  * <http://www.gnu.org/licenses/>.
26  *
27  */
28 
29 #include "SplitButton.h"
30 #include <wx/event.h>
31 #include <wx/renderer.h>
32 #include <algorithm>
33 
34 bool SplitButton::Create(wxWindow* parent, wxWindowID id, const wxString& label, const wxPoint& pos, const wxSize& size, const wxString& name)
35 {
36  if (!wxPanel::Create(parent, id, pos, size, wxBORDER_NONE | wxTAB_TRAVERSAL))
37  {
38  return false;
39  }
40  m_label = label;
41 
42  if (size == wxDefaultSize)
43  {
44  UpdateMinSize();
45  }
46 
47  Bind(wxEVT_PAINT, &SplitButton::OnPaint, this);
48  Bind(wxEVT_LEFT_UP, &SplitButton::OnLeftButtonUp, this);
49  Bind(wxEVT_LEFT_DOWN, &SplitButton::OnLeftButtonDown, this);
50  Bind(wxEVT_KILL_FOCUS, &SplitButton::OnKillFocus, this);
51  Bind(wxEVT_LEAVE_WINDOW, &SplitButton::OnMouseLeave, this);
52  Bind(wxEVT_ENTER_WINDOW, &SplitButton::OnMouseEnter, this);
53 
54  m_dropDownMenu = new wxMenu();
55  return true;
56 }
57 
59 {
60  delete m_dropDownMenu;
61  m_dropDownMenu = nullptr;
62 }
63 
65 {
66  return m_dropDownMenu;
67 }
68 
69 void SplitButton::OnKillFocus(wxFocusEvent& event)
70 {
71  m_stateButton = 0;
72  m_stateMenu = 0;
73  Refresh();
74 
75  event.Skip();
76 }
77 
78 void SplitButton::OnMouseLeave(wxMouseEvent& event)
79 {
80  m_stateButton = 0;
81  m_stateMenu = 0;
82  Refresh();
83 
84  event.Skip();
85 }
86 
87 void SplitButton::OnMouseEnter(wxMouseEvent& event)
88 {
89  m_stateButton = wxCONTROL_CURRENT;
90  m_stateMenu = wxCONTROL_CURRENT;
91  Refresh();
92 
93  event.Skip();
94 }
95 
96 void SplitButton::OnLeftButtonUp(wxMouseEvent& event)
97 {
98  m_stateButton = 0;
99  m_stateMenu = 0;
100 
101  Refresh();
102 
103  int x = -1;
104  int y = -1;
105  event.GetPosition(&x, &y);
106 
107  if (x < (GetSize().GetWidth() - m_arrowButtonWidth))
108  {
109  wxEvtHandler* pEventHandler = GetEventHandler();
110  wxASSERT(pEventHandler);
111 
112  pEventHandler->CallAfter([=]()
113  {
114  wxCommandEvent evt(wxEVT_BUTTON, this->GetId());
115  evt.SetEventObject(this);
116  GetEventHandler()->ProcessEvent(evt);
117  });
118  }
119 
120  event.Skip();
121 }
122 
123 void SplitButton::OnLeftButtonDown(wxMouseEvent& event)
124 {
125  int x = -1;
126  int y = -1;
127  event.GetPosition(&x, &y);
128 
129  if (x >= (GetSize().GetWidth() - m_arrowButtonWidth))
130  {
131  m_stateButton = 0;
132  m_stateMenu = wxCONTROL_PRESSED;
133  Refresh();
134 
135  wxSize size = GetSize();
136  wxPoint position;
137  position.x = 0;
138  position.y = size.GetHeight();
139  // draw menu only when menu is assigned and has items
140  if (m_dropDownMenu && m_dropDownMenu->GetMenuItemCount() > 0)
141  {
142  PopupMenu(m_dropDownMenu, position);
143  };
144 
145  m_stateMenu = 0;
146  Refresh();
147  }
148  else
149  {
150  m_stateButton = wxCONTROL_PRESSED;
151  m_stateMenu = wxCONTROL_PRESSED;
152  Refresh();
153  }
154 
155  event.Skip();
156 }
157 
158 void SplitButton::OnPaint(wxPaintEvent& WXUNUSED(event))
159 {
160  wxPaintDC dc(this);
161  wxSize size = GetSize();
162  const int width = size.GetWidth() - m_arrowButtonWidth;
163 
164  // Draw first part of button
165  wxRect r1;
166  r1.x = 0;
167  r1.y = 0;
168  r1.width = width + 2;
169  r1.height = size.GetHeight();
170 
171  wxRendererNative::Get().DrawPushButton(this, dc, r1, m_stateButton);
172  dc.SetTextForeground(wxSystemSettings::GetColour(m_IsEnabled ? wxSYS_COLOUR_BTNTEXT : wxSYS_COLOUR_GRAYTEXT));
173  // draw label and bitmap
174  if (HasBitmap())
175  {
176  dc.DrawLabel(m_label, m_bitmap, r1, wxALIGN_CENTER);
177  }
178  else
179  {
180  dc.DrawLabel(m_label, r1, wxALIGN_CENTER);
181  };
182 
183  // Draw second part of button
184  wxRect r2;
185  r2.x = width - 2;
186  r2.y = 0;
187  r2.width = m_arrowButtonWidth;
188  r2.height = size.GetHeight();
189 
190  wxRendererNative::Get().DrawPushButton(this, dc, r2, m_stateMenu);
191  wxRendererNative::Get().DrawDropArrow(this, dc, r2, m_stateMenu);
192 }
193 
195 {
196  return m_bitmap.IsOk() && m_bitmap.GetWidth() > 0 && m_bitmap.GetHeight() > 0;
197 }
198 
200 {
201  wxSize size = wxButton::GetDefaultSize();
202  wxSize textSize = GetTextExtent(m_label);
203  // add size of drop down button
204  textSize.SetWidth(textSize.GetWidth() + m_arrowButtonWidth + 20);
205  wxSize bitmapSize;
206  if (HasBitmap())
207  {
208  bitmapSize = m_bitmap.GetSize();
209 #ifdef __WXMSW__
210  // add some border to match the size of other buttons
211  bitmapSize.IncBy(0, 8);
212 #endif
213  };
214  size.SetWidth(std::max(size.GetWidth(), bitmapSize.GetWidth() + textSize.GetWidth()));
215  size.SetHeight(std::max(size.GetHeight(), std::max(bitmapSize.GetHeight(), textSize.GetHeight())));
216 #ifdef __WXGTK__
217  // add a little border to match to other buttons
218  size.SetHeight(size.GetHeight() + 7);
219 #endif
220  SetMinSize(size);
221  InvalidateBestSize();
222 }
223 
224 bool SplitButton::Enable(bool enable)
225 {
226  m_IsEnabled = enable;
227  wxPanel::Enable(m_IsEnabled);
228 
229  if (m_IsEnabled)
230  {
231  m_stateButton = 0;
232  m_stateMenu = 0;
233 }
234  else
235  {
236  m_stateButton = wxCONTROL_DISABLED;
237  m_stateMenu = wxCONTROL_DISABLED;
238  }
239  Refresh();
240  return enable;
241 }
242 
243 wxBitmap SplitButton::GetBitmap() const
244 {
245  if (HasBitmap())
246  {
247  return m_bitmap;
248  };
249  return wxNullBitmap;
250 }
251 
252 void SplitButton::SetBitmap(const wxBitmap& bitmap)
253 {
254  m_bitmap = bitmap;
255  // update minimum size
256  UpdateMinSize();
257 }
258 
259 wxMenu* SplitButton::LoadMenu(const wxString& name)
260 {
261  delete m_dropDownMenu;
262  m_dropDownMenu = wxXmlResource::Get()->LoadMenu(name);
263  return m_dropDownMenu;
264 }
265 
266 void SplitButton::SetLabel(const wxString& label)
267 {
268  m_label = label;
269  UpdateMinSize();
270 }
271 
272 wxString SplitButton::GetLabel() const
273 {
274  return m_label;
275 }
276 
278 {
279  AddWindowStyles();
280 }
281 
283 {
284  XRC_MAKE_INSTANCE(control, SplitButton)
285  control->Create(m_parentAsWindow, GetID(), GetText(wxT("label")), GetPosition(), GetSize(), GetName());
286  if (GetParamNode("bitmap"))
287  {
288  control->SetBitmap(GetBitmap("bitmap", wxART_BUTTON));
289  };
290 
291  SetupWindow(control);
292  return control;
293 }
294 
295 bool SplitButtonXmlHandler::CanHandle(wxXmlNode *node)
296 {
297  return IsOfClass(node, wxT("SplitButton"));
298 }
299 
300 IMPLEMENT_DYNAMIC_CLASS(SplitButtonXmlHandler, wxXmlResourceHandler)
wxString GetLabel() const
return the label of the button
virtual wxObject * DoCreateResource()
void OnLeftButtonUp(wxMouseEvent &event)
handle left mouse button on button and drop down button
Definition: SplitButton.cpp:96
int m_stateButton
Definition: SplitButton.h:84
void OnPaint(wxPaintEvent &WXUNUSED(event))
paint handler to draw to the button
xrc handler for split button
Definition: SplitButton.h:94
wxBitmap m_bitmap
Definition: SplitButton.h:90
void OnMouseEnter(wxMouseEvent &event)
Definition: SplitButton.cpp:87
wxMenu * GetSplitButtonMenu()
returns a pointer to the drop down menu
Definition: SplitButton.cpp:64
bool HasBitmap() const
return true if buttons has a bitmap assigned
void OnMouseLeave(wxMouseEvent &event)
Definition: SplitButton.cpp:78
bool m_IsEnabled
Definition: SplitButton.h:86
wxMenu * LoadMenu(const wxString &name)
loads the drop down menu from the XRC ressource
IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow, wxWindow)
virtual bool CanHandle(wxXmlNode *node)
void OnKillFocus(wxFocusEvent &event)
some event handler to mimic default mouse over behaviour
Definition: SplitButton.cpp:69
int m_stateMenu
Definition: SplitButton.h:85
void SetBitmap(const wxBitmap &bitmap)
sets bitmap and direction
const int m_arrowButtonWidth
Definition: SplitButton.h:87
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &label=wxEmptyString, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, const wxString &name=wxT("splitbutton"))
for two-step creation
Definition: SplitButton.cpp:34
bool Enable(bool enable=true) override
enable or disable the control
wxMenu * m_dropDownMenu
Definition: SplitButton.h:89
static T max(T x, T y)
Definition: svm.cpp:65
void OnLeftButtonDown(wxMouseEvent &event)
void SetLabel(const wxString &label)
set the label string
wxBitmap GetBitmap() const
returns the currently active bitmap
wxString m_label
Definition: SplitButton.h:88
void UpdateMinSize()
update the internal size calculation