]> git.saurik.com Git - wxWidgets.git/blame - src/msw/bmpbuttn.cpp
Split some of the recent code out to make it more reusable.
[wxWidgets.git] / src / msw / bmpbuttn.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
1e6feb95 2// Name: src/msw/bmpbuttn.cpp
2bda0e17
KB
3// Purpose: wxBitmapButton
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
14f355c2 12#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
2bda0e17
KB
13#pragma implementation "bmpbuttn.h"
14#endif
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
1e6feb95 20 #pragma hdrstop
2bda0e17
KB
21#endif
22
1e6feb95
VZ
23#if wxUSE_BMPBUTTON
24
2bda0e17 25#ifndef WX_PRECOMP
10a0bdb1 26 #include "wx/bmpbuttn.h"
84f19880 27 #include "wx/log.h"
47e92c41 28 #include "wx/dcmemory.h"
2bda0e17
KB
29#endif
30
31#include "wx/msw/private.h"
d50dbf7c 32#include "wx/image.h"
2bda0e17 33
bc9fb572
JS
34// ----------------------------------------------------------------------------
35// macros
36// ----------------------------------------------------------------------------
37
38#if wxUSE_EXTENDED_RTTI
39
40WX_DEFINE_FLAGS( wxBitmapButtonStyle )
41
3ff066a4 42wxBEGIN_FLAGS( wxBitmapButtonStyle )
bc9fb572
JS
43 // new style border flags, we put them first to
44 // use them for streaming out
3ff066a4
SC
45 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
46 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
47 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
48 wxFLAGS_MEMBER(wxBORDER_RAISED)
49 wxFLAGS_MEMBER(wxBORDER_STATIC)
50 wxFLAGS_MEMBER(wxBORDER_NONE)
fcf90ee1 51
bc9fb572 52 // old style border flags
3ff066a4
SC
53 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
54 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
55 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
56 wxFLAGS_MEMBER(wxRAISED_BORDER)
57 wxFLAGS_MEMBER(wxSTATIC_BORDER)
cb0afb26 58 wxFLAGS_MEMBER(wxBORDER)
bc9fb572
JS
59
60 // standard window styles
3ff066a4
SC
61 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
62 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
63 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
64 wxFLAGS_MEMBER(wxWANTS_CHARS)
cb0afb26 65 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
3ff066a4
SC
66 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
67 wxFLAGS_MEMBER(wxVSCROLL)
68 wxFLAGS_MEMBER(wxHSCROLL)
69
70 wxFLAGS_MEMBER(wxBU_AUTODRAW)
71 wxFLAGS_MEMBER(wxBU_LEFT)
72 wxFLAGS_MEMBER(wxBU_RIGHT)
73 wxFLAGS_MEMBER(wxBU_TOP)
74 wxFLAGS_MEMBER(wxBU_BOTTOM)
75wxEND_FLAGS( wxBitmapButtonStyle )
bc9fb572
JS
76
77IMPLEMENT_DYNAMIC_CLASS_XTI(wxBitmapButton, wxButton,"wx/bmpbuttn.h")
78
3ff066a4 79wxBEGIN_PROPERTIES_TABLE(wxBitmapButton)
af498247 80 wxPROPERTY_FLAGS( WindowStyle , wxBitmapButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
3ff066a4 81wxEND_PROPERTIES_TABLE()
bc9fb572 82
3ff066a4
SC
83wxBEGIN_HANDLERS_TABLE(wxBitmapButton)
84wxEND_HANDLERS_TABLE()
bc9fb572 85
3ff066a4 86wxCONSTRUCTOR_5( wxBitmapButton , wxWindow* , Parent , wxWindowID , Id , wxBitmap , Bitmap , wxPoint , Position , wxSize , Size )
bc9fb572
JS
87
88#else
2bda0e17 89IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton, wxButton)
bc9fb572 90#endif
2bda0e17 91
a6fd0fde
VZ
92BEGIN_EVENT_TABLE(wxBitmapButton, wxBitmapButtonBase)
93 EVT_SYS_COLOUR_CHANGED(wxBitmapButton::OnSysColourChanged)
94END_EVENT_TABLE()
95
066f1b7a
SC
96/*
97TODO PROPERTIES :
98
99long "style" , wxBU_AUTODRAW
100bool "default" , 0
101bitmap "selected" ,
102bitmap "focus" ,
103bitmap "disabled" ,
104*/
105
2bda0e17
KB
106#define BUTTON_HEIGHT_FACTOR (EDIT_CONTROL_FACTOR * 1.1)
107
a265d21a
DS
108bool wxBitmapButton::Create(wxWindow *parent, wxWindowID id,
109 const wxBitmap& bitmap,
110 const wxPoint& pos,
111 const wxSize& size, long style,
112 const wxValidator& wxVALIDATOR_PARAM(validator),
113 const wxString& name)
2bda0e17 114{
a265d21a
DS
115 m_bmpNormal = bitmap;
116 SetName(name);
11b6a93b
VZ
117
118#if wxUSE_VALIDATORS
a265d21a 119 SetValidator(validator);
11b6a93b 120#endif // wxUSE_VALIDATORS
2bda0e17 121
a265d21a 122 parent->AddChild(this);
2bda0e17 123
a265d21a
DS
124 m_backgroundColour = parent->GetBackgroundColour();
125 m_foregroundColour = parent->GetForegroundColour();
126 m_windowStyle = style;
2bda0e17 127
a265d21a
DS
128 if ( style & wxBU_AUTODRAW )
129 {
130 m_marginX = wxDEFAULT_BUTTON_MARGIN;
131 m_marginY = wxDEFAULT_BUTTON_MARGIN;
132 }
2bda0e17 133
fcf90ee1 134 if (id == wxID_ANY)
a265d21a
DS
135 m_windowId = NewControlId();
136 else
137 m_windowId = id;
2bda0e17 138
a265d21a 139 long msStyle = WS_VISIBLE | WS_TABSTOP | WS_CHILD | BS_OWNERDRAW ;
f6bcfd97 140
b0766406
JS
141 if ( m_windowStyle & wxCLIP_SIBLINGS )
142 msStyle |= WS_CLIPSIBLINGS;
143
f6bcfd97
BP
144#ifdef __WIN32__
145 if(m_windowStyle & wxBU_LEFT)
146 msStyle |= BS_LEFT;
147 if(m_windowStyle & wxBU_RIGHT)
148 msStyle |= BS_RIGHT;
149 if(m_windowStyle & wxBU_TOP)
150 msStyle |= BS_TOP;
151 if(m_windowStyle & wxBU_BOTTOM)
152 msStyle |= BS_BOTTOM;
153#endif
154
a265d21a 155 m_hWnd = (WXHWND) CreateWindowEx(
42e69d6b 156 0,
223d09f6 157 wxT("BUTTON"),
fda7962d 158 wxEmptyString,
f6bcfd97 159 msStyle,
33ac7e6f 160 0, 0, 0, 0,
42e69d6b
VZ
161 GetWinHwnd(parent),
162 (HMENU)m_windowId,
163 wxGetInstance(),
164 NULL
165 );
2bda0e17 166
a265d21a
DS
167 // Subclass again for purposes of dialog editing mode
168 SubclassWin(m_hWnd);
2bda0e17 169
9f884528
RD
170 SetPosition(pos);
171 SetBestSize(size);
2bda0e17 172
a265d21a 173 return true;
2bda0e17
KB
174}
175
d50dbf7c
VZ
176bool wxBitmapButton::SetBackgroundColour(const wxColour& colour)
177{
178 if ( !wxBitmapButtonBase::SetBackgroundColour(colour) )
179 {
180 // didn't change
181 return false;
182 }
183
184 // invalidate the brush, it will be recreated the next time it's needed
185 m_brushDisabled = wxNullBrush;
186
187 return true;
188}
189
a6fd0fde
VZ
190void wxBitmapButton::OnSysColourChanged(wxSysColourChangedEvent& event)
191{
192 m_brushDisabled = wxNullBrush;
193
194 if ( !IsEnabled() )
195 {
196 // this change affects our current state
197 Refresh();
198 }
199
200 event.Skip();
201}
202
f6bcfd97
BP
203// VZ: should be at the very least less than wxDEFAULT_BUTTON_MARGIN
204#define FOCUS_MARGIN 3
205
2bda0e17
KB
206bool wxBitmapButton::MSWOnDraw(WXDRAWITEMSTRUCT *item)
207{
4676948b 208#ifndef __WXWINCE__
ba681060 209 long style = GetWindowLong((HWND) GetHWND(), GWL_STYLE);
fd3f686c
VZ
210 if (style & BS_BITMAP)
211 {
fd3f686c
VZ
212 // Let default procedure draw the bitmap, which is defined
213 // in the Windows resource.
a265d21a 214 return false;
fd3f686c 215 }
2bda0e17
KB
216#endif
217
218 LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) item;
47e92c41
GRG
219 HDC hDC = lpDIS->hDC;
220 UINT state = lpDIS->itemState;
221 bool isSelected = (state & ODS_SELECTED) != 0;
222 bool autoDraw = (GetWindowStyleFlag() & wxBU_AUTODRAW) != 0;
2bda0e17 223
47e92c41
GRG
224
225 // choose the bitmap to use depending on the button state
d9c8e68e 226 wxBitmap* bitmap;
2bda0e17 227
1e6feb95
VZ
228 if ( isSelected && m_bmpSelected.Ok() )
229 bitmap = &m_bmpSelected;
230 else if ((state & ODS_FOCUS) && m_bmpFocus.Ok())
231 bitmap = &m_bmpFocus;
232 else if ((state & ODS_DISABLED) && m_bmpDisabled.Ok())
233 bitmap = &m_bmpDisabled;
d9c8e68e 234 else
1e6feb95 235 bitmap = &m_bmpNormal;
2bda0e17 236
42e69d6b 237 if ( !bitmap->Ok() )
a265d21a 238 return false;
2bda0e17 239
47e92c41
GRG
240 // centre the bitmap in the control area
241 int x = lpDIS->rcItem.left;
242 int y = lpDIS->rcItem.top;
243 int width = lpDIS->rcItem.right - x;
244 int height = lpDIS->rcItem.bottom - y;
245 int wBmp = bitmap->GetWidth();
246 int hBmp = bitmap->GetHeight();
f6bcfd97 247
a265d21a
DS
248 int x1,y1;
249
f6bcfd97
BP
250 if(m_windowStyle & wxBU_LEFT)
251 x1 = x + (FOCUS_MARGIN+1);
252 else if(m_windowStyle & wxBU_RIGHT)
253 x1 = x + (width - wBmp) - (FOCUS_MARGIN+1);
254 else
255 x1 = x + (width - wBmp) / 2;
256
257 if(m_windowStyle & wxBU_TOP)
258 y1 = y + (FOCUS_MARGIN+1);
259 else if(m_windowStyle & wxBU_BOTTOM)
260 y1 = y + (height - hBmp) - (FOCUS_MARGIN+1);
261 else
262 y1 = y + (height - hBmp) / 2;
2bda0e17 263
47e92c41 264 if ( isSelected && autoDraw )
d9c8e68e 265 {
47e92c41
GRG
266 x1++;
267 y1++;
d9c8e68e 268 }
2bda0e17 269
47e92c41 270 // draw the face, if auto-drawing
d9c8e68e
VZ
271 if ( autoDraw )
272 {
273 DrawFace((WXHDC) hDC,
274 lpDIS->rcItem.left, lpDIS->rcItem.top,
275 lpDIS->rcItem.right, lpDIS->rcItem.bottom,
276 isSelected);
277 }
2bda0e17 278
47e92c41
GRG
279 // draw the bitmap
280 wxDC dst;
a265d21a
DS
281 dst.SetHDC((WXHDC) hDC, false);
282 dst.DrawBitmap(*bitmap, x1, y1, true);
33ac7e6f 283
47e92c41 284 // draw focus / disabled state, if auto-drawing
d9c8e68e
VZ
285 if ( (state & ODS_DISABLED) && autoDraw )
286 {
287 DrawButtonDisable((WXHDC) hDC,
288 lpDIS->rcItem.left, lpDIS->rcItem.top,
289 lpDIS->rcItem.right, lpDIS->rcItem.bottom,
a265d21a 290 true);
d9c8e68e
VZ
291 }
292 else if ( (state & ODS_FOCUS) && autoDraw )
293 {
294 DrawButtonFocus((WXHDC) hDC,
295 lpDIS->rcItem.left,
296 lpDIS->rcItem.top,
297 lpDIS->rcItem.right,
298 lpDIS->rcItem.bottom,
299 isSelected);
300 }
2bda0e17 301
a265d21a 302 return true;
2bda0e17
KB
303}
304
5ab1fa8e
GRG
305// GRG Feb/2000, support for bmp buttons with Win95/98 standard LNF
306
307#if defined(__WIN95__)
308
a265d21a
DS
309void wxBitmapButton::DrawFace( WXHDC dc, int left, int top,
310 int right, int bottom, bool sel )
2bda0e17 311{
d9c8e68e 312 HPEN oldp;
5ab1fa8e 313 HPEN penHiLight;
d9c8e68e
VZ
314 HPEN penLight;
315 HPEN penShadow;
5ab1fa8e 316 HPEN penDkShadow;
d9c8e68e 317 HBRUSH brushFace;
2bda0e17 318
5ab1fa8e
GRG
319 // create needed pens and brush
320 penHiLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DHILIGHT));
321 penLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DLIGHT));
322 penShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DSHADOW));
323 penDkShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_3DDKSHADOW));
85b43fbf
JS
324 // brushFace = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
325 // Taking the background colour fits in better with
326 // Windows XP themes.
327 brushFace = CreateSolidBrush(m_backgroundColour.m_pixel);
5ab1fa8e
GRG
328
329 // draw the rectangle
330 RECT rect;
331 rect.left = left;
332 rect.right = right;
333 rect.top = top;
334 rect.bottom = bottom;
335 FillRect((HDC) dc, &rect, brushFace);
336
337 // draw the border
338 oldp = (HPEN) SelectObject( (HDC) dc, sel? penDkShadow : penHiLight);
4676948b
JS
339
340 wxDrawLine((HDC) dc, left, top, right-1, top);
341 wxDrawLine((HDC) dc, left, top+1, left, bottom-1);
5ab1fa8e
GRG
342
343 SelectObject( (HDC) dc, sel? penShadow : penLight);
4676948b
JS
344 wxDrawLine((HDC) dc, left+1, top+1, right-2, top+1);
345 wxDrawLine((HDC) dc, left+1, top+2, left+1, bottom-2);
5ab1fa8e
GRG
346
347 SelectObject( (HDC) dc, sel? penLight : penShadow);
4676948b
JS
348 wxDrawLine((HDC) dc, left+1, bottom-2, right-1, bottom-2);
349 wxDrawLine((HDC) dc, right-2, bottom-3, right-2, top);
5ab1fa8e
GRG
350
351 SelectObject( (HDC) dc, sel? penHiLight : penDkShadow);
4676948b
JS
352 wxDrawLine((HDC) dc, left, bottom-1, right+2, bottom-1);
353 wxDrawLine((HDC) dc, right-1, bottom-2, right-1, top-1);
5ab1fa8e
GRG
354
355 // delete allocated resources
356 SelectObject((HDC) dc,oldp);
357 DeleteObject(penHiLight);
358 DeleteObject(penLight);
359 DeleteObject(penShadow);
360 DeleteObject(penDkShadow);
361 DeleteObject(brushFace);
362}
363
364#else
2bda0e17 365
a265d21a
DS
366void wxBitmapButton::DrawFace( WXHDC dc, int left, int top,
367 int right, int bottom, bool sel )
5ab1fa8e
GRG
368{
369 HPEN oldp;
370 HPEN penBorder;
371 HPEN penLight;
372 HPEN penShadow;
373 HBRUSH brushFace;
2bda0e17 374
5ab1fa8e
GRG
375 // create needed pens and brush
376 penBorder = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_WINDOWFRAME));
377 penShadow = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_BTNSHADOW));
378 penLight = CreatePen(PS_SOLID, 0, GetSysColor(COLOR_BTNHIGHLIGHT));
379 brushFace = CreateSolidBrush(COLOR_BTNFACE);
2bda0e17 380
5ab1fa8e
GRG
381 // draw the rectangle
382 RECT rect;
383 rect.left = left;
384 rect.right = right;
385 rect.top = top;
386 rect.bottom = bottom;
387 FillRect((HDC) dc, &rect, brushFace);
2bda0e17 388
5ab1fa8e
GRG
389 // draw the border
390 oldp = (HPEN) SelectObject( (HDC) dc, penBorder);
d9c8e68e
VZ
391 MoveToEx((HDC) dc,left+1,top,NULL);LineTo((HDC) dc,right-1,top);
392 MoveToEx((HDC) dc,left,top+1,NULL);LineTo((HDC) dc,left,bottom-1);
393 MoveToEx((HDC) dc,left+1,bottom-1,NULL);LineTo((HDC) dc,right-1,bottom-1);
394 MoveToEx((HDC) dc,right-1,top+1,NULL);LineTo((HDC) dc,right-1,bottom-1);
2bda0e17 395
5ab1fa8e 396 SelectObject( (HDC) dc, penShadow);
fd3f686c
VZ
397 if (sel)
398 {
5ab1fa8e
GRG
399 MoveToEx((HDC) dc,left+1 ,bottom-2 ,NULL);
400 LineTo((HDC) dc, left+1 ,top+1);
401 LineTo((HDC) dc, right-2 ,top+1);
fd3f686c
VZ
402 }
403 else
404 {
5ab1fa8e
GRG
405 MoveToEx((HDC) dc,left+1 ,bottom-2 ,NULL);
406 LineTo((HDC) dc, right-2 ,bottom-2);
407 LineTo((HDC) dc, right-2 ,top);
408
409 MoveToEx((HDC) dc,left+2 ,bottom-3 ,NULL);
410 LineTo((HDC) dc, right-3 ,bottom-3);
411 LineTo((HDC) dc, right-3 ,top+1);
412
413 SelectObject( (HDC) dc, penLight);
414
415 MoveToEx((HDC) dc,left+1 ,bottom-2 ,NULL);
416 LineTo((HDC) dc, left+1 ,top+1);
417 LineTo((HDC) dc, right-2 ,top+1);
fd3f686c 418 }
2bda0e17 419
5ab1fa8e
GRG
420 // delete allocated resources
421 SelectObject((HDC) dc,oldp);
d9c8e68e
VZ
422 DeleteObject(penBorder);
423 DeleteObject(penLight);
424 DeleteObject(penShadow);
425 DeleteObject(brushFace);
2bda0e17
KB
426}
427
5ab1fa8e
GRG
428#endif // defined(__WIN95__)
429
430
a265d21a
DS
431void wxBitmapButton::DrawButtonFocus( WXHDC dc, int left, int top, int right,
432 int bottom, bool WXUNUSED(sel) )
2bda0e17 433{
fd3f686c
VZ
434 RECT rect;
435 rect.left = left;
436 rect.top = top;
437 rect.right = right;
438 rect.bottom = bottom;
5ab1fa8e
GRG
439 InflateRect( &rect, - FOCUS_MARGIN, - FOCUS_MARGIN );
440
441 // GRG: the focus rectangle should not move when the button is pushed!
442/*
fd3f686c 443 if ( sel )
5ab1fa8e
GRG
444 OffsetRect( &rect, 1, 1 );
445*/
a265d21a 446
5ab1fa8e 447 DrawFocusRect( (HDC) dc, &rect );
2bda0e17
KB
448}
449
d50dbf7c
VZ
450void
451wxBitmapButton::DrawButtonDisable( WXHDC dc,
452 int left, int top, int right, int bottom,
453 bool with_marg )
2bda0e17 454{
d50dbf7c
VZ
455 if ( !m_brushDisabled.Ok() )
456 {
457 // draw a bitmap with two black and two background colour pixels
458 wxBitmap bmp(2, 2);
459 wxMemoryDC dc;
460 dc.SelectObject(bmp);
461 dc.SetPen(*wxBLACK_PEN);
462 dc.DrawPoint(0, 0);
463 dc.DrawPoint(1, 1);
464 dc.SetPen(GetBackgroundColour());
465 dc.DrawPoint(0, 1);
466 dc.DrawPoint(1, 0);
467
468 m_brushDisabled = wxBrush(bmp);
469 }
470
471 SelectInHDC selectBrush((HDC)dc, GetHbrushOf(m_brushDisabled));
2bda0e17 472
2b268535
VZ
473 // ROP for "dest |= pattern" operation -- as it doesn't have a standard
474 // name, give it our own
a265d21a 475 static const DWORD PATTERNPAINT = 0xFA0089UL;
d9c8e68e
VZ
476
477 if ( with_marg )
478 {
479 left += m_marginX;
480 top += m_marginY;
481 right -= 2 * m_marginX;
482 bottom -= 2 * m_marginY;
483 }
484
a265d21a 485 ::PatBlt( (HDC) dc, left, top, right, bottom, PATTERNPAINT);
2bda0e17
KB
486}
487
0655ad29
VZ
488void wxBitmapButton::SetDefault()
489{
490 wxButton::SetDefault();
491}
1e6feb95 492
c046274e
RD
493wxSize wxBitmapButton::DoGetBestSize() const
494{
9266e0ec 495 if ( m_bmpNormal.Ok() )
c046274e 496 {
9266e0ec
VZ
497 return wxSize(m_bmpNormal.GetWidth() + 2*m_marginX,
498 m_bmpNormal.GetHeight() + 2*m_marginY);
c046274e 499 }
e8153940 500
9266e0ec
VZ
501 // no idea what our best size should be, defer to the base class
502 return wxBitmapButtonBase::DoGetBestSize();
c046274e
RD
503}
504
1e6feb95 505#endif // wxUSE_BMPBUTTON
e8153940 506