]> git.saurik.com Git - wxWidgets.git/blob - src/msw/bmpbuttn.cpp
Add room for the scrollbar
[wxWidgets.git] / src / msw / bmpbuttn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/bmpbuttn.cpp
3 // Purpose: wxBitmapButton
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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__
20 #pragma hdrstop
21 #endif
22
23 #if wxUSE_BMPBUTTON
24
25 #ifndef WX_PRECOMP
26 #include "wx/bmpbuttn.h"
27 #include "wx/log.h"
28 #include "wx/dcmemory.h"
29 #endif
30
31 #include "wx/msw/private.h"
32 #include "wx/image.h"
33
34 // ----------------------------------------------------------------------------
35 // macros
36 // ----------------------------------------------------------------------------
37
38 #if wxUSE_EXTENDED_RTTI
39
40 WX_DEFINE_FLAGS( wxBitmapButtonStyle )
41
42 wxBEGIN_FLAGS( wxBitmapButtonStyle )
43 // new style border flags, we put them first to
44 // use them for streaming out
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)
51
52 // old style border flags
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)
58 wxFLAGS_MEMBER(wxBORDER)
59
60 // standard window styles
61 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
62 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
63 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
64 wxFLAGS_MEMBER(wxWANTS_CHARS)
65 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
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)
75 wxEND_FLAGS( wxBitmapButtonStyle )
76
77 IMPLEMENT_DYNAMIC_CLASS_XTI(wxBitmapButton, wxButton,"wx/bmpbuttn.h")
78
79 wxBEGIN_PROPERTIES_TABLE(wxBitmapButton)
80 wxPROPERTY_FLAGS( WindowStyle , wxBitmapButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
81 wxEND_PROPERTIES_TABLE()
82
83 wxBEGIN_HANDLERS_TABLE(wxBitmapButton)
84 wxEND_HANDLERS_TABLE()
85
86 wxCONSTRUCTOR_5( wxBitmapButton , wxWindow* , Parent , wxWindowID , Id , wxBitmap , Bitmap , wxPoint , Position , wxSize , Size )
87
88 #else
89 IMPLEMENT_DYNAMIC_CLASS(wxBitmapButton, wxButton)
90 #endif
91
92 BEGIN_EVENT_TABLE(wxBitmapButton, wxBitmapButtonBase)
93 EVT_SYS_COLOUR_CHANGED(wxBitmapButton::OnSysColourChanged)
94 END_EVENT_TABLE()
95
96 /*
97 TODO PROPERTIES :
98
99 long "style" , wxBU_AUTODRAW
100 bool "default" , 0
101 bitmap "selected" ,
102 bitmap "focus" ,
103 bitmap "disabled" ,
104 */
105
106 #define BUTTON_HEIGHT_FACTOR (EDIT_CONTROL_FACTOR * 1.1)
107
108 bool 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)
114 {
115 m_bmpNormal = bitmap;
116 SetName(name);
117
118 #if wxUSE_VALIDATORS
119 SetValidator(validator);
120 #endif // wxUSE_VALIDATORS
121
122 parent->AddChild(this);
123
124 m_backgroundColour = parent->GetBackgroundColour();
125 m_foregroundColour = parent->GetForegroundColour();
126 m_windowStyle = style;
127
128 if ( style & wxBU_AUTODRAW )
129 {
130 m_marginX = wxDEFAULT_BUTTON_MARGIN;
131 m_marginY = wxDEFAULT_BUTTON_MARGIN;
132 }
133
134 if (id == wxID_ANY)
135 m_windowId = NewControlId();
136 else
137 m_windowId = id;
138
139 long msStyle = WS_VISIBLE | WS_TABSTOP | WS_CHILD | BS_OWNERDRAW ;
140
141 if ( m_windowStyle & wxCLIP_SIBLINGS )
142 msStyle |= WS_CLIPSIBLINGS;
143
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
155 m_hWnd = (WXHWND) CreateWindowEx(
156 0,
157 wxT("BUTTON"),
158 wxEmptyString,
159 msStyle,
160 0, 0, 0, 0,
161 GetWinHwnd(parent),
162 (HMENU)m_windowId,
163 wxGetInstance(),
164 NULL
165 );
166
167 // Subclass again for purposes of dialog editing mode
168 SubclassWin(m_hWnd);
169
170 SetPosition(pos);
171 SetBestSize(size);
172
173 return true;
174 }
175
176 bool 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
190 void 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
203 // VZ: should be at the very least less than wxDEFAULT_BUTTON_MARGIN
204 #define FOCUS_MARGIN 3
205
206 bool wxBitmapButton::MSWOnDraw(WXDRAWITEMSTRUCT *item)
207 {
208 #ifndef __WXWINCE__
209 long style = GetWindowLong((HWND) GetHWND(), GWL_STYLE);
210 if (style & BS_BITMAP)
211 {
212 // Let default procedure draw the bitmap, which is defined
213 // in the Windows resource.
214 return false;
215 }
216 #endif
217
218 LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT) item;
219 HDC hDC = lpDIS->hDC;
220 UINT state = lpDIS->itemState;
221 bool isSelected = (state & ODS_SELECTED) != 0;
222 bool autoDraw = (GetWindowStyleFlag() & wxBU_AUTODRAW) != 0;
223
224
225 // choose the bitmap to use depending on the button state
226 wxBitmap* bitmap;
227
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;
234 else
235 bitmap = &m_bmpNormal;
236
237 if ( !bitmap->Ok() )
238 return false;
239
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();
247
248 int x1,y1;
249
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;
263
264 if ( isSelected && autoDraw )
265 {
266 x1++;
267 y1++;
268 }
269
270 // draw the face, if auto-drawing
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 }
278
279 // draw the bitmap
280 wxDC dst;
281 dst.SetHDC((WXHDC) hDC, false);
282 dst.DrawBitmap(*bitmap, x1, y1, true);
283
284 // draw focus / disabled state, if auto-drawing
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,
290 true);
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 }
301
302 return true;
303 }
304
305 // GRG Feb/2000, support for bmp buttons with Win95/98 standard LNF
306
307 #if defined(__WIN95__)
308
309 void wxBitmapButton::DrawFace( WXHDC dc, int left, int top,
310 int right, int bottom, bool sel )
311 {
312 HPEN oldp;
313 HPEN penHiLight;
314 HPEN penLight;
315 HPEN penShadow;
316 HPEN penDkShadow;
317 HBRUSH brushFace;
318
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));
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);
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);
339
340 wxDrawLine((HDC) dc, left, top, right-1, top);
341 wxDrawLine((HDC) dc, left, top+1, left, bottom-1);
342
343 SelectObject( (HDC) dc, sel? penShadow : penLight);
344 wxDrawLine((HDC) dc, left+1, top+1, right-2, top+1);
345 wxDrawLine((HDC) dc, left+1, top+2, left+1, bottom-2);
346
347 SelectObject( (HDC) dc, sel? penLight : penShadow);
348 wxDrawLine((HDC) dc, left+1, bottom-2, right-1, bottom-2);
349 wxDrawLine((HDC) dc, right-2, bottom-3, right-2, top);
350
351 SelectObject( (HDC) dc, sel? penHiLight : penDkShadow);
352 wxDrawLine((HDC) dc, left, bottom-1, right+2, bottom-1);
353 wxDrawLine((HDC) dc, right-1, bottom-2, right-1, top-1);
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
365
366 void wxBitmapButton::DrawFace( WXHDC dc, int left, int top,
367 int right, int bottom, bool sel )
368 {
369 HPEN oldp;
370 HPEN penBorder;
371 HPEN penLight;
372 HPEN penShadow;
373 HBRUSH brushFace;
374
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);
380
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);
388
389 // draw the border
390 oldp = (HPEN) SelectObject( (HDC) dc, penBorder);
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);
395
396 SelectObject( (HDC) dc, penShadow);
397 if (sel)
398 {
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);
402 }
403 else
404 {
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);
418 }
419
420 // delete allocated resources
421 SelectObject((HDC) dc,oldp);
422 DeleteObject(penBorder);
423 DeleteObject(penLight);
424 DeleteObject(penShadow);
425 DeleteObject(brushFace);
426 }
427
428 #endif // defined(__WIN95__)
429
430
431 void wxBitmapButton::DrawButtonFocus( WXHDC dc, int left, int top, int right,
432 int bottom, bool WXUNUSED(sel) )
433 {
434 RECT rect;
435 rect.left = left;
436 rect.top = top;
437 rect.right = right;
438 rect.bottom = bottom;
439 InflateRect( &rect, - FOCUS_MARGIN, - FOCUS_MARGIN );
440
441 // GRG: the focus rectangle should not move when the button is pushed!
442 /*
443 if ( sel )
444 OffsetRect( &rect, 1, 1 );
445 */
446
447 DrawFocusRect( (HDC) dc, &rect );
448 }
449
450 void
451 wxBitmapButton::DrawButtonDisable( WXHDC dc,
452 int left, int top, int right, int bottom,
453 bool with_marg )
454 {
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));
472
473 // ROP for "dest |= pattern" operation -- as it doesn't have a standard
474 // name, give it our own
475 static const DWORD PATTERNPAINT = 0xFA0089UL;
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
485 ::PatBlt( (HDC) dc, left, top, right, bottom, PATTERNPAINT);
486 }
487
488 void wxBitmapButton::SetDefault()
489 {
490 wxButton::SetDefault();
491 }
492
493 wxSize wxBitmapButton::DoGetBestSize() const
494 {
495 if ( m_bmpNormal.Ok() )
496 {
497 return wxSize(m_bmpNormal.GetWidth() + 2*m_marginX,
498 m_bmpNormal.GetHeight() + 2*m_marginY);
499 }
500
501 // no idea what our best size should be, defer to the base class
502 return wxBitmapButtonBase::DoGetBestSize();
503 }
504
505 #endif // wxUSE_BMPBUTTON
506