1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/anybutton.cpp
3 // Purpose: wxAnyButton
4 // Author: Vadim Zeitlin
5 // Created: 2014-03-26 (extracted from button.cpp and tglbtn.cpp)
6 // Copyright: (c) 2014
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13
14
15 #ifndef WX_PRECOMP
16 #include "wx/dcclient.h"
17 #endif
18
19 #include "wx/univ/renderer.h"
20 #include "wx/univ/theme.h"
21 #include "wx/univ/colschem.h"
22
23 // ============================================================================
24 // implementation
25 // ============================================================================
26
27
Press()28 void wxAnyButton::Press()
29 {
30 if ( !m_isPressed )
31 {
32 m_isPressed = true;
33
34 Refresh();
35 }
36 }
37
Release()38 void wxAnyButton::Release()
39 {
40 if ( m_isPressed )
41 {
42 m_isPressed = false;
43
44 Refresh();
45 }
46 }
47
Toggle()48 void wxAnyButton::Toggle()
49 {
50 if ( m_isPressed )
51 Release();
52 else
53 Press();
54
55 if ( !m_isPressed )
56 {
57 // releasing button after it had been pressed generates a click event
58 Click();
59 }
60 Refresh();
61 }
62
PerformAction(const wxControlAction & action,long numArg,const wxString & strArg)63 bool wxAnyButton::PerformAction(const wxControlAction& action,
64 long numArg,
65 const wxString& strArg)
66 {
67 if ( action == wxACTION_BUTTON_TOGGLE )
68 Toggle();
69 else if ( action == wxACTION_BUTTON_CLICK )
70 Click();
71 else if ( action == wxACTION_BUTTON_PRESS )
72 Press();
73 else if ( action == wxACTION_BUTTON_RELEASE )
74 Release();
75 else
76 return wxControl::PerformAction(action, numArg, strArg);
77
78 return true;
79 }
80
81 /* static */
GetStdInputHandler(wxInputHandler * handlerDef)82 wxInputHandler *wxAnyButton::GetStdInputHandler(wxInputHandler *handlerDef)
83 {
84 static wxStdAnyButtonInputHandler s_handlerBtn(handlerDef);
85
86 return &s_handlerBtn;
87 }
88
89 // ----------------------------------------------------------------------------
90 // size management
91 // ----------------------------------------------------------------------------
92
DoGetBestClientSize() const93 wxSize wxAnyButton::DoGetBestClientSize() const
94 {
95 wxClientDC dc(wxConstCast(this, wxAnyButton));
96 wxCoord width, height;
97 dc.GetMultiLineTextExtent(GetLabel(), &width, &height);
98
99 if ( m_bitmap.IsOk() )
100 {
101 // allocate extra space for the bitmap
102 wxCoord heightBmp = m_bitmap.GetHeight() + 2*m_marginBmpY;
103 if ( height < heightBmp )
104 height = heightBmp;
105
106 width += m_bitmap.GetWidth() + 2*m_marginBmpX;
107 }
108
109 // The default size should not be adjusted, so the code is moved into the
110 // renderer. This is conceptual wrong but currently the only solution.
111 // (Otto Wyss, Patch 664399)
112
113 /*
114 // for compatibility with other ports, the buttons default size is never
115 // less than the standard one, but not when display not PDAs.
116 if (wxSystemSettings::GetScreenType() > wxSYS_SCREEN_PDA)
117 {
118 if ( !(GetWindowStyle() & wxBU_EXACTFIT) )
119 {
120 wxSize szDef = GetDefaultSize();
121 if ( width < szDef.x )
122 width = szDef.x;
123 }
124 }
125 */
126 return wxSize(width, height);
127 }
128
129 // ----------------------------------------------------------------------------
130 // drawing
131 // ----------------------------------------------------------------------------
132
DoDraw(wxControlRenderer * renderer)133 void wxAnyButton::DoDraw(wxControlRenderer *renderer)
134 {
135 if ( !(GetWindowStyle() & wxBORDER_NONE) )
136 {
137 renderer->DrawButtonBorder();
138 }
139
140 renderer->DrawButtonLabel(m_bitmap, m_marginBmpX, m_marginBmpY);
141 }
142
DoDrawBackground(wxDC & dc)143 bool wxAnyButton::DoDrawBackground(wxDC& dc)
144 {
145 wxRect rect;
146 wxSize size = GetSize();
147 rect.width = size.x;
148 rect.height = size.y;
149
150 if ( GetBackgroundBitmap().IsOk() )
151 {
152 // get the bitmap and the flags
153 int alignment;
154 wxStretch stretch;
155 wxBitmap bmp = GetBackgroundBitmap(&alignment, &stretch);
156 wxControlRenderer::DrawBitmap(dc, bmp, rect, alignment, stretch);
157 }
158 else
159 {
160 m_renderer->DrawButtonSurface(dc, wxTHEME_BG_COLOUR(this),
161 rect, GetStateFlags());
162 }
163
164 return true;
165 }
166
167 // ============================================================================
168 // wxStdAnyButtonInputHandler
169 // ============================================================================
170
wxStdAnyButtonInputHandler(wxInputHandler * handler)171 wxStdAnyButtonInputHandler::wxStdAnyButtonInputHandler(wxInputHandler *handler)
172 : wxStdInputHandler(handler)
173 {
174 m_winCapture = NULL;
175 m_winHasMouse = false;
176 }
177
HandleKey(wxInputConsumer * consumer,const wxKeyEvent & event,bool pressed)178 bool wxStdAnyButtonInputHandler::HandleKey(wxInputConsumer *consumer,
179 const wxKeyEvent& event,
180 bool pressed)
181 {
182 int keycode = event.GetKeyCode();
183 if ( keycode == WXK_SPACE || keycode == WXK_RETURN )
184 {
185 consumer->PerformAction(wxACTION_BUTTON_TOGGLE);
186
187 return true;
188 }
189
190 return wxStdInputHandler::HandleKey(consumer, event, pressed);
191 }
192
HandleMouse(wxInputConsumer * consumer,const wxMouseEvent & event)193 bool wxStdAnyButtonInputHandler::HandleMouse(wxInputConsumer *consumer,
194 const wxMouseEvent& event)
195 {
196 // the button has 2 states: pressed and normal with the following
197 // transitions between them:
198 //
199 // normal -> left down -> capture mouse and go to pressed state
200 // pressed -> left up inside -> generate click -> go to normal
201 // outside ------------------>
202 //
203 // the other mouse buttons are ignored
204 if ( event.Button(1) )
205 {
206 if ( event.LeftDown() || event.LeftDClick() )
207 {
208 m_winCapture = consumer->GetInputWindow();
209 m_winCapture->CaptureMouse();
210 m_winHasMouse = true;
211
212 consumer->PerformAction(wxACTION_BUTTON_PRESS);
213
214 return true;
215 }
216 else if ( event.LeftUp() )
217 {
218 if ( m_winCapture )
219 {
220 m_winCapture->ReleaseMouse();
221 m_winCapture = NULL;
222 }
223
224 if ( m_winHasMouse )
225 {
226 // this will generate a click event
227 consumer->PerformAction(wxACTION_BUTTON_TOGGLE);
228
229 return true;
230 }
231 //else: the mouse was released outside the window, this doesn't
232 // count as a click
233 }
234 //else: don't do anything special about the double click
235 }
236
237 return wxStdInputHandler::HandleMouse(consumer, event);
238 }
239
HandleMouseMove(wxInputConsumer * consumer,const wxMouseEvent & event)240 bool wxStdAnyButtonInputHandler::HandleMouseMove(wxInputConsumer *consumer,
241 const wxMouseEvent& event)
242 {
243 // we only have to do something when the mouse leaves/enters the pressed
244 // button and don't care about the other ones
245 if ( event.GetEventObject() == m_winCapture )
246 {
247 // leaving the button should remove its pressed state
248 if ( event.Leaving() )
249 {
250 // remember that the mouse is now outside
251 m_winHasMouse = false;
252
253 // we do have a pressed button, so release it
254 consumer->GetInputWindow()->SetCurrent(false);
255 consumer->PerformAction(wxACTION_BUTTON_RELEASE);
256
257 return true;
258 }
259 // and entering it back should make it pressed again if it had been
260 // pressed
261 else if ( event.Entering() )
262 {
263 // the mouse is (back) inside the button
264 m_winHasMouse = true;
265
266 // we did have a pressed button which we released when leaving the
267 // window, press it again
268 consumer->GetInputWindow()->SetCurrent(true);
269 consumer->PerformAction(wxACTION_BUTTON_PRESS);
270
271 return true;
272 }
273 }
274
275 return wxStdInputHandler::HandleMouseMove(consumer, event);
276 }
277
HandleFocus(wxInputConsumer * WXUNUSED (consumer),const wxFocusEvent & WXUNUSED (event))278 bool wxStdAnyButtonInputHandler::HandleFocus(wxInputConsumer * WXUNUSED(consumer),
279 const wxFocusEvent& WXUNUSED(event))
280 {
281 // buttons change appearance when they get/lose focus, so return true to
282 // refresh
283 return true;
284 }
285
HandleActivation(wxInputConsumer * consumer,bool WXUNUSED (activated))286 bool wxStdAnyButtonInputHandler::HandleActivation(wxInputConsumer *consumer,
287 bool WXUNUSED(activated))
288 {
289 // the default button changes appearance when the app is [de]activated, so
290 // return true to refresh
291 return wxStaticCast(consumer->GetInputWindow(), wxAnyButton)->IsDefault();
292 }
293