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