]> git.saurik.com Git - wxWidgets.git/blob - utils/framelayout/src/newbmpbtn.cpp
Made font/color fixes right for windows
[wxWidgets.git] / utils / framelayout / src / newbmpbtn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: No names yet.
3 // Purpose: Contrib. demo
4 // Author: Aleksandras Gluchovas
5 // Modified by:
6 // Created: ??/09/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Aleksandras Gluchovas
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "newbmpbtn.cpp"
14 #pragma interface "newbmpbtn.cpp"
15 #endif
16
17 // For compilers that support precompilation, includes "wx/wx.h".
18 #include "wx/wxprec.h"
19
20 /*
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24 */
25
26 #ifndef WX_PRECOMP
27 #include "wx/wx.h"
28 #endif
29
30 #include "newbmpbtn.h"
31 #include "wx/utils.h" // import wxMin,wxMax macros
32
33 ///////////// button-label rendering helpers //////////////////
34
35 static int* create_array( int width, int height, int fill = 0 )
36 {
37 int* array = new int[width*height];
38
39 int len = width*height;
40 for( int i = 0; i != len; ++i ) array[i] = fill;
41
42 return array;
43 }
44
45 #define GET_ELEM(array,x,y) (array[width*(y)+(x)])
46
47 #define MIN_COLOR_DIFF 10
48
49 #define IS_IN_ARRAY(x,y) ( (x) < width && (y) < height && (x) >= 0 && (y) >= 0 )
50
51 #define GET_RED(col) col & 0xFF
52 #define GET_GREEN(col) (col >> 8) & 0xFF
53 #define GET_BLUE(col) (col >> 16) & 0xFF
54
55 #define MAKE_INT_COLOR(red,green,blue) ( (red) | \
56 ( ( (green) << 8 ) & 0xFF00 ) | \
57 ( ( (blue) << 16) & 0xFF0000) \
58 )
59
60 #define IS_GREATER(col1,col2) ( ( (GET_RED(col1) ) > (GET_RED(col2) ) + MIN_COLOR_DIFF ) && \
61 ( (GET_GREEN(col1)) > (GET_GREEN(col2)) + MIN_COLOR_DIFF ) && \
62 ( (GET_BLUE(col1) ) > (GET_BLUE(col2) ) + MIN_COLOR_DIFF ) \
63 )
64
65 #define MASK_BG 0
66 #define MASK_DARK 1
67 #define MASK_LIGHT 2
68
69 // helper function, used internally
70
71 static void gray_out_pixmap( int* src, int* dest, int width, int height )
72 {
73 // assuming the pixels along the edges are of the background color
74 int bgCol = GET_ELEM(src,0,0);
75
76 int x = 0;
77 int y = 1;
78
79 do
80 {
81 int cur = GET_ELEM(src,x,y);
82
83 int r = GET_RED(cur);
84 int g = GET_GREEN(cur);
85 int b = GET_BLUE(cur);
86
87 if ( IS_IN_ARRAY(x-1,y-1) )
88 {
89 int upperElem = GET_ELEM(src,x-1,y-1);
90
91 // if the upper element is lighter than current
92 if ( IS_GREATER(upperElem,cur) )
93 {
94 GET_ELEM(dest,x,y) = MASK_DARK;
95 }
96 else
97 // if the current element is ligher than the upper
98 if ( IS_GREATER(cur,upperElem) )
99 {
100 GET_ELEM(dest,x,y) = MASK_LIGHT;
101 }
102 else
103 {
104 if ( GET_ELEM(dest,x-1,y-1) == MASK_LIGHT )
105
106 GET_ELEM(dest,x,y) = MASK_BG;
107
108 if ( GET_ELEM(dest,x-1,y-1 ) == MASK_DARK )
109
110 GET_ELEM(dest,x,y) = MASK_DARK;
111 else
112 GET_ELEM(dest,x,y) = MASK_BG;
113 }
114 }
115
116 // go zig-zag
117
118 if ( IS_IN_ARRAY(x+1,y-1) )
119 {
120 ++x;--y;
121 }
122 else
123 {
124 while( IS_IN_ARRAY(x-1,y+1) )
125 {
126 --x;++y;
127 }
128
129 if ( IS_IN_ARRAY(x,y+1) )
130 {
131 ++y; continue;
132 }
133 else
134 {
135 if ( IS_IN_ARRAY(x+1,y) )
136 {
137 ++x; continue;
138 }
139 else break;
140 }
141 }
142
143 } while(1);
144 }
145
146 // alg. for making the image look "grayed" (e.g. disabled button)
147 // NOTE:: used GetPixel(), which is Windows-Only!
148
149 void greay_out_image_on_dc( wxDC& dc, int width, int height )
150 {
151 // assuming the pixels along the edges are of the background color
152 wxColour bgCol;
153 dc.GetPixel( 0, 0, &bgCol );
154
155 wxPen darkPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW),1, wxSOLID );
156 wxPen lightPen( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHIGHLIGHT),1, wxSOLID );
157 wxPen bgPen ( bgCol, 1, wxSOLID );
158
159 int* src = create_array( width, height, MASK_BG );
160 int* dest = create_array( width, height, MASK_BG );
161
162 int y = 0;
163 for( y = 0; y != height; ++y )
164
165 for( int x = 0; x != width; ++x )
166 {
167 wxColour col;
168 dc.GetPixel( x,y, &col );
169
170 int r = col.Red(),
171 g = col.Green(),
172 b = col.Blue();
173
174 int o = MAKE_INT_COLOR( r,g,b );
175
176 GET_ELEM(src,x,y) = MAKE_INT_COLOR( col.Red(), col.Green(), col.Blue() );
177 }
178
179 gray_out_pixmap( src, dest, width, height );
180
181 for( y = 0; y != height; ++y )
182
183 for( int x = 0; x != width; ++x )
184 {
185 int mask = GET_ELEM(dest,x,y);
186
187 switch (mask)
188 {
189 case MASK_BG : { dc.SetPen( bgPen );
190 dc.DrawPoint( x,y ); break;
191 }
192 case MASK_DARK : { dc.SetPen( darkPen );
193 dc.DrawPoint( x,y ); break;
194 }
195 case MASK_LIGHT : { dc.SetPen( lightPen );
196 dc.DrawPoint( x,y ); break;
197 }
198 default : break;
199 }
200 }
201
202 delete [] src;
203 delete [] dest;
204 }
205
206 ///////////////////////////////
207
208 /***** Impelementation for class wxNewBitmapButton *****/
209
210 IMPLEMENT_DYNAMIC_CLASS(wxNewBitmapButton, wxPanel)
211
212 BEGIN_EVENT_TABLE( wxNewBitmapButton, wxPanel )
213
214 EVT_LEFT_DOWN( wxNewBitmapButton::OnLButtonDown )
215 EVT_LEFT_UP ( wxNewBitmapButton::OnLButtonUp )
216 EVT_MOTION ( wxNewBitmapButton::OnMouseMove )
217
218 EVT_SIZE ( wxNewBitmapButton::OnSize )
219 EVT_PAINT( wxNewBitmapButton::OnPaint )
220
221 //EVT_KILL_FOCUS( wxNewBitmapButton::OnKillFocus )
222
223 EVT_ERASE_BACKGROUND( wxNewBitmapButton::OnEraseBackground )
224
225 END_EVENT_TABLE()
226
227 wxNewBitmapButton::wxNewBitmapButton( const wxBitmap& labelBitmap,
228 const wxString& labelText,
229 int alignText,
230 bool isFlat,
231 int firedEventType,
232 int marginX,
233 int marginY,
234 int textToLabelGap,
235 bool isSticky)
236 : mpDepressedImg( NULL ),
237 mpPressedImg ( NULL ),
238 mpDisabledImg ( NULL ),
239 mpFocusedImg ( NULL ),
240
241 mMarginX( marginX ),
242 mMarginY( marginY ),
243 mTextAlignment( alignText ),
244 mIsFlat( isFlat ),
245
246 mIsPressed ( FALSE ),
247 mDragStarted ( FALSE ),
248 mPrevPressedState( FALSE ),
249 mTextToLabelGap ( textToLabelGap ),
250
251 mBlackPen( wxColour( 0, 0, 0), 1, wxSOLID ),
252 mDarkPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID ),
253 mGrayPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE), 1, wxSOLID ),
254 mLightPen( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHIGHLIGHT), 1, wxSOLID ),
255
256 mFiredEventType( firedEventType ),
257 mIsSticky( isSticky ),
258 mIsCreated( FALSE ),
259 mSizeIsSet( FALSE ),
260
261 mHasFocusedBmp( FALSE ),
262 mIsInFocus( FALSE ),
263
264 mDepressedBmp( labelBitmap ),
265 mLabelText( labelText ),
266 mImageFileType( -1 )
267 {
268 }
269
270 wxNewBitmapButton::wxNewBitmapButton( const wxString& bitmapFileName,
271 const int bitmapFileType,
272 const wxString& labelText,
273 int alignText,
274 bool isFlat,
275 int firedEventType,
276 int marginX,
277 int marginY,
278 int textToLabelGap,
279 bool isSticky)
280
281 : mpDepressedImg( NULL ),
282 mpPressedImg ( NULL ),
283 mpDisabledImg ( NULL ),
284 mpFocusedImg ( NULL ),
285
286 mMarginX( 2 ),
287 mMarginY( 2 ),
288 mTextAlignment( alignText ),
289 mIsFlat( isFlat ),
290
291 mIsPressed ( FALSE ),
292 mDragStarted ( FALSE ),
293 mPrevPressedState( FALSE ),
294 mTextToLabelGap ( 2 ),
295
296 mBlackPen( wxColour( 0, 0, 0), 1, wxSOLID ),
297 mDarkPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID ),
298 mGrayPen ( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE), 1, wxSOLID ),
299 mLightPen( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DHIGHLIGHT), 1, wxSOLID ),
300
301 mFiredEventType( wxEVT_COMMAND_MENU_SELECTED ),
302 mIsSticky( FALSE ),
303 mIsCreated( FALSE ),
304 mSizeIsSet( FALSE ),
305
306 mHasFocusedBmp( FALSE ),
307 mIsInFocus( FALSE ),
308
309 mLabelText( labelText ),
310 mImageFileName( bitmapFileName ),
311 mImageFileType( bitmapFileType )
312 {
313 //mDepressedBmp.LoadFile( bitmapFileName, bitmapFileType );
314 }
315
316 wxNewBitmapButton::~wxNewBitmapButton(void)
317 {
318 DestroyLabels();
319 }
320
321 void wxNewBitmapButton::DrawShade( int outerLevel,
322 wxDC& dc,
323 wxPen& upperLeftSidePen,
324 wxPen& lowerRightSidePen )
325 {
326 wxBitmap* pBmp = GetStateLabel();
327
328 int x = mMarginX - (outerLevel + 1);
329 int y = mMarginY - (outerLevel + 1);
330
331 int height = pBmp->GetHeight() + (outerLevel + 1)*2 - 1;
332 int width = pBmp->GetWidth() + (outerLevel + 1)*2 - 1;
333
334 dc.SetPen( upperLeftSidePen );
335 dc.DrawLine( x,y, x + width, y );
336 dc.DrawLine( x,y, x, y + height );
337
338 dc.SetPen( lowerRightSidePen );
339 dc.DrawLine( x + width, y, x + width, y + height + 1 );
340 dc.DrawLine( x, y + height, x + width, y + height );
341 }
342
343 void wxNewBitmapButton::DestroyLabels()
344 {
345 if ( mpDepressedImg ) delete mpDepressedImg;
346 if ( mpPressedImg ) delete mpPressedImg;
347 if ( mpDisabledImg ) delete mpDisabledImg;
348 if ( mpFocusedImg ) delete mpFocusedImg;
349
350 mpDepressedImg = NULL;
351 mpPressedImg = NULL;
352 mpDisabledImg = NULL;
353 mpFocusedImg = NULL;
354 }
355
356 wxBitmap* wxNewBitmapButton::GetStateLabel()
357 {
358 if ( IsEnabled() )
359 {
360 if ( mIsPressed )
361 {
362 return mpPressedImg;
363 }
364 else
365 {
366 if ( mIsInFocus )
367 {
368 if ( mHasFocusedBmp )
369
370 return mpFocusedImg;
371 else
372 return mpDepressedImg;
373 }
374 else
375 return mpDepressedImg;
376 }
377 }
378 else
379 return mpDisabledImg;
380 }
381
382 void wxNewBitmapButton::RenderLabelImage( wxBitmap*& destBmp, wxBitmap* srcBmp,
383 bool isEnabled, bool isPressed )
384 {
385 if ( destBmp != 0 ) return;
386
387 // render lables on-demand
388
389 wxMemoryDC srcDc;
390 srcDc.SelectObject( *srcBmp );
391
392 bool hasText = ( mTextAlignment != NB_NO_TEXT ) &&
393 ( mLabelText.length() != 0 );
394
395 bool hasImage = (mTextAlignment != NB_NO_IMAGE);
396
397 wxSize destDim;
398 wxPoint txtPos;
399 wxPoint imgPos;
400
401 if ( hasText )
402 {
403 long txtWidth, txtHeight;
404
405 srcDc.SetFont( wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT) );
406 srcDc.GetTextExtent( mLabelText, &txtWidth, &txtHeight );
407
408 if ( mTextAlignment == NB_ALIGN_TEXT_RIGHT )
409 {
410 destDim.x = srcBmp->GetWidth() + 2*mTextToLabelGap + txtWidth;
411
412 destDim.y =
413 wxMax( srcBmp->GetHeight(), txtHeight );
414
415 txtPos.x = srcBmp->GetWidth() + mTextToLabelGap;
416 txtPos.y = (destDim.y - txtHeight)/2;
417 imgPos.x = 0;
418 imgPos.y = (destDim.y - srcBmp->GetHeight())/2;
419 }
420 else
421 if ( mTextAlignment == NB_ALIGN_TEXT_BOTTOM )
422 {
423 destDim.x =
424 wxMax( srcBmp->GetWidth(), txtWidth );
425
426 destDim.y = srcBmp->GetHeight() + mTextToLabelGap + txtHeight;
427
428 txtPos.x = (destDim.x - txtWidth)/2;
429 txtPos.y = srcBmp->GetHeight() + mTextToLabelGap;
430 imgPos.x = (destDim.x - srcBmp->GetWidth())/2;
431 imgPos.y = 0;
432 }
433 else wxASSERT(0);// unsupported alignment type
434 }
435 else
436 {
437 imgPos.x = 0;
438 imgPos.y = 0;
439 destDim.x = srcBmp->GetWidth();
440 destDim.y = srcBmp->GetHeight();
441 }
442
443 destBmp = new wxBitmap( int(destDim.x), int(destDim.y) );
444
445 wxMemoryDC destDc;
446 destDc.SelectObject( *destBmp );
447
448 wxBrush grayBrush( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_3DFACE), wxSOLID );
449 wxPen nullPen( wxColour(0,0,0), 1, wxTRANSPARENT );
450
451 destDc.SetBrush( grayBrush );
452 destDc.SetPen( nullPen );
453
454 destDc.DrawRectangle( 0,0, destDim.x+1, destDim.y+1 );
455
456 if ( isPressed )
457 {
458 ++imgPos.x; ++imgPos.y;
459 ++txtPos.x; ++txtPos.y;
460 }
461
462 if ( hasImage )
463 {
464 destDc.Blit( imgPos.x, imgPos.y,
465 srcBmp->GetWidth()+1,
466 srcBmp->GetHeight()+1,
467 &srcDc, 0,0, wxCOPY,TRUE );
468 }
469
470 if ( hasText )
471 {
472 wxWindow* pTopWnd = this;
473
474 do
475 {
476 wxWindow* pParent = pTopWnd->GetParent();
477
478 if ( pParent == 0 ) break;
479
480 pTopWnd = pParent;
481 } while(1);
482
483 destDc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT) );
484
485 // Should be wxSYS_COLOUR_BTNTEXT, but gtk gives white?
486 destDc.SetTextForeground( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT) );
487 destDc.SetTextBackground( wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE) );
488
489 destDc.DrawText( mLabelText, txtPos.x, txtPos.y );
490 }
491
492 if ( !isEnabled )
493
494 greay_out_image_on_dc( destDc, destDim.x, destDim.y );
495
496 // adjust button size to fit the new dimensions of the label
497 if ( !mSizeIsSet && 0 )
498 {
499 mSizeIsSet = TRUE;
500 SetSize( -1,-1,
501 destBmp->GetWidth() + mMarginX*2,
502 destBmp->GetHeight() + mMarginY*2, 0
503 );
504 }
505 }
506
507 void wxNewBitmapButton::RenderLabelImages()
508 {
509 if ( !mIsCreated ) return;
510
511 if ( !IsEnabled() )
512 {
513 RenderLabelImage( mpDisabledImg, &mDepressedBmp, FALSE );
514 }
515 else
516
517 if ( mIsPressed )
518
519 RenderLabelImage( mpPressedImg, &mDepressedBmp, TRUE, TRUE );
520 else
521 {
522 if ( mIsInFocus )
523 {
524 if ( mHasFocusedBmp )
525
526 RenderLabelImage( mpFocusedImg, &mFocusedBmp, TRUE, FALSE );
527 else
528 RenderLabelImage( mpDepressedImg, &mDepressedBmp, TRUE, FALSE );
529 }
530 else
531 RenderLabelImage( mpDepressedImg, &mDepressedBmp, TRUE, FALSE );
532 }
533 }
534
535 void wxNewBitmapButton::DrawDecorations( wxDC& dc )
536 {
537 if ( mIsFlat )
538 {
539 DrawShade( 1, dc, mGrayPen, mGrayPen );
540
541 if ( mIsInFocus )
542 {
543 if ( mIsPressed )
544
545 DrawShade( 0, dc, mDarkPen, mLightPen );
546 else
547 DrawShade( 0, dc, mLightPen, mDarkPen );
548 }
549 else
550 DrawShade( 0, dc, mGrayPen, mGrayPen );
551 }
552 else
553 {
554 if ( mIsPressed )
555 {
556 DrawShade( 0, dc, mDarkPen, mGrayPen );
557 DrawShade( 1, dc, mBlackPen, mLightPen );
558 }
559 else
560 {
561 DrawShade( 0, dc, mGrayPen, mDarkPen );
562 DrawShade( 1, dc, mLightPen, mBlackPen );
563 }
564 }
565 }
566
567 void wxNewBitmapButton::SetLabel(const wxBitmap& labelBitmap,
568 const wxString& labelText )
569 {
570 DestroyLabels();
571
572 mLabelText = labelText;
573 mDepressedBmp = labelBitmap;
574
575 RenderLabelImages();
576 }
577
578 void wxNewBitmapButton::SetAlignments( int alignText,
579 int marginX,
580 int marginY,
581 int textToLabelGap)
582 {
583 DestroyLabels();
584
585 mMarginX = marginX;
586 mMarginY = marginY;
587 mTextAlignment = alignText;
588 mTextToLabelGap = textToLabelGap;
589
590 RenderLabelImages();
591 }
592
593 // event handlers
594
595 void wxNewBitmapButton::OnLButtonDown( wxMouseEvent& event )
596 {
597 mPrevPressedState = FALSE;
598 mDragStarted = TRUE;
599 mIsPressed = TRUE;
600 Refresh();
601
602 if ( !mIsInFocus )
603
604 CaptureMouse();
605 }
606
607 void wxNewBitmapButton::OnLButtonUp( wxMouseEvent& event )
608 {
609 if ( !mDragStarted ) return;
610
611 mDragStarted = FALSE;
612 mIsPressed = FALSE;
613 mIsInFocus = FALSE;
614 Refresh();
615
616 ReleaseMouse();
617
618 if ( IsInWindow( event.m_x, event.m_y ) )
619 {
620 // fire event, if mouse was released
621 // within the bounds of button
622 wxCommandEvent cmd( mFiredEventType, GetId() );
623 GetParent()->ProcessEvent( cmd );
624 }
625 }
626
627 bool wxNewBitmapButton::IsInWindow( int x, int y )
628 {
629 int width, height;
630 GetSize( &width, &height );
631
632 return ( x >= 0 && y >= 0 &&
633 x < width &&
634 y < height );
635 }
636
637 void wxNewBitmapButton::OnMouseMove( wxMouseEvent& event )
638 {
639 if ( !mIsInFocus && IsInWindow( event.m_x, event.m_y ) )
640 {
641 if ( !mDragStarted )
642 CaptureMouse();
643
644 mIsInFocus = TRUE;
645 }
646 else
647 if ( mIsInFocus && !IsInWindow( event.m_x, event.m_y ) )
648 {
649 mIsInFocus = FALSE;
650
651 if ( !mDragStarted )
652 ReleaseMouse();
653 }
654
655 if ( mDragStarted )
656 {
657 if ( IsInWindow( event.m_x, event.m_y ) )
658
659 mIsPressed = TRUE;
660 else
661 mIsPressed = FALSE;
662
663 if ( mIsPressed != mPrevPressedState )
664
665 Refresh();
666
667 mPrevPressedState = mIsPressed;
668 }
669
670 // FOR NOW::
671 Refresh();
672 }
673
674 void wxNewBitmapButton::OnSize( wxSizeEvent& event )
675 {
676 //Reshape();
677 }
678
679 void wxNewBitmapButton::Reshape( )
680 {
681 bool wasCreated = mIsCreated;
682 mIsCreated = TRUE;
683
684 if ( !wasCreated )
685 {
686 // in the case of loading button from stream, check if we
687 // have non-empty image-file name, load if possible
688
689 if ( mImageFileName != "" )
690 {
691 mDepressedBmp.LoadFile( mImageFileName, mImageFileType );
692
693 //wxMessageBox("Image Loaded!!!");
694 }
695
696 RenderLabelImages();
697
698 wxBitmap* pCurImg = GetStateLabel();
699
700 int w = pCurImg->GetWidth(),
701 h = pCurImg->GetHeight();
702
703 SetSize( 0,0, w + mMarginX*2, h + mMarginY*2 , 0 );
704 }
705 }
706
707 void wxNewBitmapButton::DrawLabel( wxDC& dc )
708 {
709 wxBitmap* pCurBmp = GetStateLabel();
710
711 if ( pCurBmp == NULL )
712 {
713 wxSizeEvent evt;
714 OnSize( evt ); // fake it up!
715
716 RenderLabelImages();
717 pCurBmp = GetStateLabel();
718 }
719
720 wxMemoryDC mdc;
721 mdc.SelectObject( *pCurBmp );
722
723 dc.Blit( mMarginX, mMarginY,
724 pCurBmp->GetWidth(),
725 pCurBmp->GetHeight(),
726 &mdc, 0,0, wxCOPY
727 );
728
729 mdc.SelectObject( wxNullBitmap );
730 }
731
732 void wxNewBitmapButton::OnPaint( wxPaintEvent& event )
733 {
734 wxPaintDC dc(this);
735
736 // first, make sure images for current state are prepared
737 RenderLabelImages();
738
739 DrawLabel( dc );
740
741 DrawDecorations( dc );
742 }
743
744 void wxNewBitmapButton::OnEraseBackground( wxEraseEvent& event )
745 {
746 // do nothing
747 }
748
749 void wxNewBitmapButton::OnKillFocus( wxFocusEvent& event )
750 {
751 // useless
752
753 wxMessageBox("kill-focus for button!");
754 }
755