~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to src/msw/anybutton.cpp

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        src/msw/anybutton.cpp
 
3
// Purpose:     wxAnyButton
 
4
// Author:      Julian Smart
 
5
// Created:     1998-01-04 (extracted from button.cpp)
 
6
// RCS-ID:      $Id: anybutton.cpp 71640 2012-06-03 19:16:59Z VZ $
 
7
// Copyright:   (c) Julian Smart
 
8
// Licence:     wxWindows licence
 
9
/////////////////////////////////////////////////////////////////////////////
 
10
 
 
11
// ============================================================================
 
12
// declarations
 
13
// ============================================================================
 
14
 
 
15
// ----------------------------------------------------------------------------
 
16
// headers
 
17
// ----------------------------------------------------------------------------
 
18
 
 
19
// For compilers that support precompilation, includes "wx.h".
 
20
#include "wx/wxprec.h"
 
21
 
 
22
#ifdef __BORLANDC__
 
23
    #pragma hdrstop
 
24
#endif
 
25
 
 
26
#ifdef wxHAS_ANY_BUTTON
 
27
 
 
28
#include "wx/anybutton.h"
 
29
 
 
30
#ifndef WX_PRECOMP
 
31
    #include "wx/app.h"
 
32
    #include "wx/brush.h"
 
33
    #include "wx/panel.h"
 
34
    #include "wx/bmpbuttn.h"
 
35
    #include "wx/settings.h"
 
36
    #include "wx/dcscreen.h"
 
37
    #include "wx/dcclient.h"
 
38
    #include "wx/toplevel.h"
 
39
    #include "wx/msw/wrapcctl.h"
 
40
    #include "wx/msw/private.h"
 
41
    #include "wx/msw/missing.h"
 
42
#endif
 
43
 
 
44
#include "wx/imaglist.h"
 
45
#include "wx/stockitem.h"
 
46
#include "wx/msw/private/button.h"
 
47
#include "wx/msw/private/dc.h"
 
48
#include "wx/private/window.h"
 
49
 
 
50
#if wxUSE_MARKUP
 
51
    #include "wx/generic/private/markuptext.h"
 
52
#endif // wxUSE_MARKUP
 
53
 
 
54
using namespace wxMSWImpl;
 
55
 
 
56
#if wxUSE_UXTHEME
 
57
    #include "wx/msw/uxtheme.h"
 
58
 
 
59
    // no need to include tmschema.h
 
60
    #ifndef BP_PUSHBUTTON
 
61
        #define BP_PUSHBUTTON 1
 
62
 
 
63
        #define PBS_NORMAL    1
 
64
        #define PBS_HOT       2
 
65
        #define PBS_PRESSED   3
 
66
        #define PBS_DISABLED  4
 
67
        #define PBS_DEFAULTED 5
 
68
 
 
69
        #define TMT_CONTENTMARGINS 3602
 
70
    #endif
 
71
 
 
72
    // provide the necessary declarations ourselves if they're missing from
 
73
    // headers
 
74
    #ifndef BCM_SETIMAGELIST
 
75
        #define BCM_SETIMAGELIST    0x1602
 
76
        #define BCM_SETTEXTMARGIN   0x1604
 
77
 
 
78
        enum
 
79
        {
 
80
            BUTTON_IMAGELIST_ALIGN_LEFT,
 
81
            BUTTON_IMAGELIST_ALIGN_RIGHT,
 
82
            BUTTON_IMAGELIST_ALIGN_TOP,
 
83
            BUTTON_IMAGELIST_ALIGN_BOTTOM
 
84
        };
 
85
 
 
86
        struct BUTTON_IMAGELIST
 
87
        {
 
88
            HIMAGELIST himl;
 
89
            RECT margin;
 
90
            UINT uAlign;
 
91
        };
 
92
    #endif
 
93
#endif // wxUSE_UXTHEME
 
94
 
 
95
#ifndef WM_THEMECHANGED
 
96
    #define WM_THEMECHANGED     0x031A
 
97
#endif
 
98
 
 
99
#ifndef ODS_NOACCEL
 
100
    #define ODS_NOACCEL         0x0100
 
101
#endif
 
102
 
 
103
#ifndef ODS_NOFOCUSRECT
 
104
    #define ODS_NOFOCUSRECT     0x0200
 
105
#endif
 
106
 
 
107
#ifndef DT_HIDEPREFIX
 
108
    #define DT_HIDEPREFIX       0x00100000
 
109
#endif
 
110
 
 
111
#if wxUSE_UXTHEME
 
112
extern wxWindowMSW *wxWindowBeingErased; // From src/msw/window.cpp
 
113
#endif // wxUSE_UXTHEME
 
114
 
 
115
// ----------------------------------------------------------------------------
 
116
// button image data
 
117
// ----------------------------------------------------------------------------
 
118
 
 
119
// we use different data classes for owner drawn buttons and for themed XP ones
 
120
 
 
121
class wxButtonImageData
 
122
{
 
123
public:
 
124
    wxButtonImageData() { }
 
125
    virtual ~wxButtonImageData() { }
 
126
 
 
127
    virtual wxBitmap GetBitmap(wxAnyButton::State which) const = 0;
 
128
    virtual void SetBitmap(const wxBitmap& bitmap, wxAnyButton::State which) = 0;
 
129
 
 
130
    virtual wxSize GetBitmapMargins() const = 0;
 
131
    virtual void SetBitmapMargins(wxCoord x, wxCoord y) = 0;
 
132
 
 
133
    virtual wxDirection GetBitmapPosition() const = 0;
 
134
    virtual void SetBitmapPosition(wxDirection dir) = 0;
 
135
 
 
136
private:
 
137
    wxDECLARE_NO_COPY_CLASS(wxButtonImageData);
 
138
};
 
139
 
 
140
namespace
 
141
{
 
142
 
 
143
// the gap between button edge and the interior area used by Windows for the
 
144
// standard buttons
 
145
const int OD_BUTTON_MARGIN = 4;
 
146
 
 
147
class wxODButtonImageData : public wxButtonImageData
 
148
{
 
149
public:
 
150
    wxODButtonImageData(wxAnyButton *btn, const wxBitmap& bitmap)
 
151
    {
 
152
        SetBitmap(bitmap, wxAnyButton::State_Normal);
 
153
        SetBitmap(bitmap.ConvertToDisabled(), wxAnyButton::State_Disabled);
 
154
 
 
155
        m_dir = wxLEFT;
 
156
 
 
157
        // we use margins when we have both bitmap and text, but when we have
 
158
        // only the bitmap it should take up the entire button area
 
159
        if ( btn->ShowsLabel() )
 
160
        {
 
161
            m_margin.x = btn->GetCharWidth();
 
162
            m_margin.y = btn->GetCharHeight() / 2;
 
163
        }
 
164
    }
 
165
 
 
166
    virtual wxBitmap GetBitmap(wxAnyButton::State which) const
 
167
    {
 
168
        return m_bitmaps[which];
 
169
    }
 
170
 
 
171
    virtual void SetBitmap(const wxBitmap& bitmap, wxAnyButton::State which)
 
172
    {
 
173
        m_bitmaps[which] = bitmap;
 
174
    }
 
175
 
 
176
    virtual wxSize GetBitmapMargins() const
 
177
    {
 
178
        return m_margin;
 
179
    }
 
180
 
 
181
    virtual void SetBitmapMargins(wxCoord x, wxCoord y)
 
182
    {
 
183
        m_margin = wxSize(x, y);
 
184
    }
 
185
 
 
186
    virtual wxDirection GetBitmapPosition() const
 
187
    {
 
188
        return m_dir;
 
189
    }
 
190
 
 
191
    virtual void SetBitmapPosition(wxDirection dir)
 
192
    {
 
193
        m_dir = dir;
 
194
    }
 
195
 
 
196
private:
 
197
    // just store the values passed to us to be able to retrieve them later
 
198
    // from the drawing code
 
199
    wxBitmap m_bitmaps[wxAnyButton::State_Max];
 
200
    wxSize m_margin;
 
201
    wxDirection m_dir;
 
202
 
 
203
    wxDECLARE_NO_COPY_CLASS(wxODButtonImageData);
 
204
};
 
205
 
 
206
#if wxUSE_UXTHEME
 
207
 
 
208
// somehow the margin is one pixel greater than the value returned by
 
209
// GetThemeMargins() call
 
210
const int XP_BUTTON_EXTRA_MARGIN = 1;
 
211
 
 
212
class wxXPButtonImageData : public wxButtonImageData
 
213
{
 
214
public:
 
215
    // we must be constructed with the size of our images as we need to create
 
216
    // the image list
 
217
    wxXPButtonImageData(wxAnyButton *btn, const wxBitmap& bitmap)
 
218
        : m_iml(bitmap.GetWidth(), bitmap.GetHeight(), true /* use mask */,
 
219
                wxAnyButton::State_Max),
 
220
          m_hwndBtn(GetHwndOf(btn))
 
221
    {
 
222
        // initialize all bitmaps except for the disabled one to normal state
 
223
        for ( int n = 0; n < wxAnyButton::State_Max; n++ )
 
224
        {
 
225
            m_iml.Add(n == wxAnyButton::State_Disabled ? bitmap.ConvertToDisabled()
 
226
                                                    : bitmap);
 
227
        }
 
228
 
 
229
        m_data.himl = GetHimagelistOf(&m_iml);
 
230
 
 
231
        // no margins by default
 
232
        m_data.margin.left =
 
233
        m_data.margin.right =
 
234
        m_data.margin.top =
 
235
        m_data.margin.bottom = 0;
 
236
 
 
237
        // use default alignment
 
238
        m_data.uAlign = BUTTON_IMAGELIST_ALIGN_LEFT;
 
239
 
 
240
        UpdateImageInfo();
 
241
    }
 
242
 
 
243
    virtual wxBitmap GetBitmap(wxAnyButton::State which) const
 
244
    {
 
245
        return m_iml.GetBitmap(which);
 
246
    }
 
247
 
 
248
    virtual void SetBitmap(const wxBitmap& bitmap, wxAnyButton::State which)
 
249
    {
 
250
        m_iml.Replace(which, bitmap);
 
251
 
 
252
        UpdateImageInfo();
 
253
    }
 
254
 
 
255
    virtual wxSize GetBitmapMargins() const
 
256
    {
 
257
        return wxSize(m_data.margin.left, m_data.margin.top);
 
258
    }
 
259
 
 
260
    virtual void SetBitmapMargins(wxCoord x, wxCoord y)
 
261
    {
 
262
        RECT& margin = m_data.margin;
 
263
        margin.left =
 
264
        margin.right = x;
 
265
        margin.top =
 
266
        margin.bottom = y;
 
267
 
 
268
        if ( !::SendMessage(m_hwndBtn, BCM_SETTEXTMARGIN, 0, (LPARAM)&margin) )
 
269
        {
 
270
            wxLogDebug("SendMessage(BCM_SETTEXTMARGIN) failed");
 
271
        }
 
272
    }
 
273
 
 
274
    virtual wxDirection GetBitmapPosition() const
 
275
    {
 
276
        switch ( m_data.uAlign )
 
277
        {
 
278
            default:
 
279
                wxFAIL_MSG( "invalid image alignment" );
 
280
                // fall through
 
281
 
 
282
            case BUTTON_IMAGELIST_ALIGN_LEFT:
 
283
                return wxLEFT;
 
284
 
 
285
            case BUTTON_IMAGELIST_ALIGN_RIGHT:
 
286
                return wxRIGHT;
 
287
 
 
288
            case BUTTON_IMAGELIST_ALIGN_TOP:
 
289
                return wxTOP;
 
290
 
 
291
            case BUTTON_IMAGELIST_ALIGN_BOTTOM:
 
292
                return wxBOTTOM;
 
293
        }
 
294
    }
 
295
 
 
296
    virtual void SetBitmapPosition(wxDirection dir)
 
297
    {
 
298
        UINT alignNew;
 
299
        switch ( dir )
 
300
        {
 
301
            default:
 
302
                wxFAIL_MSG( "invalid direction" );
 
303
                // fall through
 
304
 
 
305
            case wxLEFT:
 
306
                alignNew = BUTTON_IMAGELIST_ALIGN_LEFT;
 
307
                break;
 
308
 
 
309
            case wxRIGHT:
 
310
                alignNew = BUTTON_IMAGELIST_ALIGN_RIGHT;
 
311
                break;
 
312
 
 
313
            case wxTOP:
 
314
                alignNew = BUTTON_IMAGELIST_ALIGN_TOP;
 
315
                break;
 
316
 
 
317
            case wxBOTTOM:
 
318
                alignNew = BUTTON_IMAGELIST_ALIGN_BOTTOM;
 
319
                break;
 
320
        }
 
321
 
 
322
        if ( alignNew != m_data.uAlign )
 
323
        {
 
324
            m_data.uAlign = alignNew;
 
325
            UpdateImageInfo();
 
326
        }
 
327
    }
 
328
 
 
329
private:
 
330
    void UpdateImageInfo()
 
331
    {
 
332
        if ( !::SendMessage(m_hwndBtn, BCM_SETIMAGELIST, 0, (LPARAM)&m_data) )
 
333
        {
 
334
            wxLogDebug("SendMessage(BCM_SETIMAGELIST) failed");
 
335
        }
 
336
    }
 
337
 
 
338
    // we store image list separately to be able to use convenient wxImageList
 
339
    // methods instead of working with raw HIMAGELIST
 
340
    wxImageList m_iml;
 
341
 
 
342
    // store the rest of the data in BCM_SETIMAGELIST-friendly form
 
343
    BUTTON_IMAGELIST m_data;
 
344
 
 
345
    // the button we're associated with
 
346
    const HWND m_hwndBtn;
 
347
 
 
348
 
 
349
    wxDECLARE_NO_COPY_CLASS(wxXPButtonImageData);
 
350
};
 
351
 
 
352
#endif // wxUSE_UXTHEME
 
353
 
 
354
} // anonymous namespace
 
355
 
 
356
// ----------------------------------------------------------------------------
 
357
// macros
 
358
// ----------------------------------------------------------------------------
 
359
 
 
360
// ============================================================================
 
361
// implementation
 
362
// ============================================================================
 
363
 
 
364
// ----------------------------------------------------------------------------
 
365
// helper functions from wx/msw/private/button.h
 
366
// ----------------------------------------------------------------------------
 
367
 
 
368
void wxMSWButton::UpdateMultilineStyle(HWND hwnd, const wxString& label)
 
369
{
 
370
    // update BS_MULTILINE style depending on the new label (resetting it
 
371
    // doesn't seem to do anything very useful but it shouldn't hurt and we do
 
372
    // have to set it whenever the label becomes multi line as otherwise it
 
373
    // wouldn't be shown correctly as we don't use BS_MULTILINE when creating
 
374
    // the control unless it already has new lines in its label)
 
375
    long styleOld = ::GetWindowLong(hwnd, GWL_STYLE),
 
376
         styleNew;
 
377
    if ( label.find(wxT('\n')) != wxString::npos )
 
378
        styleNew = styleOld | BS_MULTILINE;
 
379
    else
 
380
        styleNew = styleOld & ~BS_MULTILINE;
 
381
 
 
382
    if ( styleNew != styleOld )
 
383
        ::SetWindowLong(hwnd, GWL_STYLE, styleNew);
 
384
}
 
385
 
 
386
wxSize wxMSWButton::GetFittingSize(wxWindow *win,
 
387
                                   const wxSize& sizeLabel,
 
388
                                   int flags)
 
389
{
 
390
    wxSize sizeBtn = sizeLabel;
 
391
 
 
392
    // FIXME: The numbers here are pure guesswork, no idea how should the
 
393
    //        button margins be really calculated.
 
394
    if ( flags & Size_ExactFit )
 
395
    {
 
396
        // We still need some margin or the text would be overwritten, just
 
397
        // make it as small as possible.
 
398
        sizeBtn.x += (3*win->GetCharWidth());
 
399
    }
 
400
    else
 
401
    {
 
402
        sizeBtn.x += 3*win->GetCharWidth();
 
403
        sizeBtn.y += win->GetCharHeight()/2;
 
404
    }
 
405
 
 
406
    // account for the shield UAC icon if we have it
 
407
    if ( flags & Size_AuthNeeded )
 
408
        sizeBtn.x += wxSystemSettings::GetMetric(wxSYS_SMALLICON_X);
 
409
 
 
410
    return sizeBtn;
 
411
}
 
412
 
 
413
wxSize wxMSWButton::ComputeBestFittingSize(wxControl *btn, int flags)
 
414
{
 
415
    wxClientDC dc(btn);
 
416
 
 
417
    wxSize sizeBtn;
 
418
    dc.GetMultiLineTextExtent(btn->GetLabelText(), &sizeBtn.x, &sizeBtn.y);
 
419
 
 
420
    return GetFittingSize(btn, sizeBtn, flags);
 
421
}
 
422
 
 
423
wxSize wxMSWButton::IncreaseToStdSizeAndCache(wxControl *btn, const wxSize& size)
 
424
{
 
425
    wxSize sizeBtn(size);
 
426
 
 
427
    // All buttons have at least the standard height and, unless the user
 
428
    // explicitly wants them to be as small as possible and used wxBU_EXACTFIT
 
429
    // style to indicate this, of at least the standard width too.
 
430
    //
 
431
    // Notice that we really want to make all buttons equally high, otherwise
 
432
    // they look ugly and the existing code using wxBU_EXACTFIT only uses it to
 
433
    // control width and not height.
 
434
 
 
435
    // The 50x14 button size is documented in the "Recommended sizing and
 
436
    // spacing" section of MSDN layout article.
 
437
    //
 
438
    // Note that we intentionally don't use GetDefaultSize() here, because
 
439
    // it's inexact -- dialog units depend on this dialog's font.
 
440
    const wxSize sizeDef = btn->ConvertDialogToPixels(wxSize(50, 14));
 
441
    if ( !btn->HasFlag(wxBU_EXACTFIT) )
 
442
    {
 
443
        if ( sizeBtn.x < sizeDef.x )
 
444
            sizeBtn.x = sizeDef.x;
 
445
    }
 
446
    if ( sizeBtn.y < sizeDef.y )
 
447
        sizeBtn.y = sizeDef.y;
 
448
 
 
449
    btn->CacheBestSize(sizeBtn);
 
450
 
 
451
    return sizeBtn;
 
452
}
 
453
 
 
454
// ----------------------------------------------------------------------------
 
455
// creation/destruction
 
456
// ----------------------------------------------------------------------------
 
457
 
 
458
wxAnyButton::~wxAnyButton()
 
459
{
 
460
    delete m_imageData;
 
461
#if wxUSE_MARKUP
 
462
    delete m_markupText;
 
463
#endif // wxUSE_MARKUP
 
464
}
 
465
 
 
466
void wxAnyButton::SetLabel(const wxString& label)
 
467
{
 
468
    wxMSWButton::UpdateMultilineStyle(GetHwnd(), label);
 
469
 
 
470
    wxAnyButtonBase::SetLabel(label);
 
471
 
 
472
#if wxUSE_MARKUP
 
473
    // If we have a plain text label, we shouldn't be using markup any longer.
 
474
    if ( m_markupText )
 
475
    {
 
476
        delete m_markupText;
 
477
        m_markupText = NULL;
 
478
 
 
479
        // Unfortunately we don't really know whether we can reset the button
 
480
        // to be non-owner-drawn or not: if we had made it owner-drawn just
 
481
        // because of a call to SetLabelMarkup(), we could, but not if there
 
482
        // were [also] calls to Set{Fore,Back}groundColour(). If it's really a
 
483
        // problem to have button remain owner-drawn forever just because it
 
484
        // had markup label once, we should record the reason for our current
 
485
        // owner-drawnness and check it here.
 
486
    }
 
487
#endif // wxUSE_MARKUP
 
488
}
 
489
 
 
490
// ----------------------------------------------------------------------------
 
491
// size management including autosizing
 
492
// ----------------------------------------------------------------------------
 
493
 
 
494
void wxAnyButton::AdjustForBitmapSize(wxSize &size) const
 
495
{
 
496
    wxCHECK_RET( m_imageData, wxT("shouldn't be called if no image") );
 
497
 
 
498
    // account for the bitmap size
 
499
    const wxSize sizeBmp = m_imageData->GetBitmap(State_Normal).GetSize();
 
500
    const wxDirection dirBmp = m_imageData->GetBitmapPosition();
 
501
    if ( dirBmp == wxLEFT || dirBmp == wxRIGHT )
 
502
    {
 
503
        size.x += sizeBmp.x;
 
504
        if ( sizeBmp.y > size.y )
 
505
            size.y = sizeBmp.y;
 
506
    }
 
507
    else // bitmap on top/below the text
 
508
    {
 
509
        size.y += sizeBmp.y;
 
510
        if ( sizeBmp.x > size.x )
 
511
            size.x = sizeBmp.x;
 
512
    }
 
513
 
 
514
    // account for the user-specified margins
 
515
    size += 2*m_imageData->GetBitmapMargins();
 
516
 
 
517
    // and also for the margins we always add internally (unless we have no
 
518
    // border at all in which case the button has exactly the same size as
 
519
    // bitmap and so no margins should be used)
 
520
    if ( !HasFlag(wxBORDER_NONE) )
 
521
    {
 
522
        int marginH = 0,
 
523
            marginV = 0;
 
524
#if wxUSE_UXTHEME
 
525
        if ( wxUxThemeEngine::GetIfActive() )
 
526
        {
 
527
            wxUxThemeHandle theme(const_cast<wxAnyButton *>(this), L"BUTTON");
 
528
 
 
529
            MARGINS margins;
 
530
            wxUxThemeEngine::Get()->GetThemeMargins(theme, NULL,
 
531
                                                    BP_PUSHBUTTON,
 
532
                                                    PBS_NORMAL,
 
533
                                                    TMT_CONTENTMARGINS,
 
534
                                                    NULL,
 
535
                                                    &margins);
 
536
 
 
537
            // XP doesn't draw themed buttons correctly when the client
 
538
            // area is smaller than 8x8 - enforce this minimum size for
 
539
            // small bitmaps
 
540
            size.IncTo(wxSize(8, 8));
 
541
 
 
542
            marginH = margins.cxLeftWidth + margins.cxRightWidth
 
543
                        + 2*XP_BUTTON_EXTRA_MARGIN;
 
544
            marginV = margins.cyTopHeight + margins.cyBottomHeight
 
545
                        + 2*XP_BUTTON_EXTRA_MARGIN;
 
546
        }
 
547
        else
 
548
#endif // wxUSE_UXTHEME
 
549
        {
 
550
            marginH =
 
551
            marginV = OD_BUTTON_MARGIN;
 
552
        }
 
553
 
 
554
        size.IncBy(marginH, marginV);
 
555
    }
 
556
}
 
557
 
 
558
wxSize wxAnyButton::DoGetBestSize() const
 
559
{
 
560
    wxAnyButton * const self = const_cast<wxAnyButton *>(this);
 
561
 
 
562
    wxSize size;
 
563
 
 
564
    // Account for the text part if we have it.
 
565
    if ( ShowsLabel() )
 
566
    {
 
567
        int flags = 0;
 
568
        if ( HasFlag(wxBU_EXACTFIT) )
 
569
            flags |= wxMSWButton::Size_ExactFit;
 
570
        if ( DoGetAuthNeeded() )
 
571
            flags |= wxMSWButton::Size_AuthNeeded;
 
572
 
 
573
#if wxUSE_MARKUP
 
574
        if ( m_markupText )
 
575
        {
 
576
            wxClientDC dc(self);
 
577
            size = wxMSWButton::GetFittingSize(self,
 
578
                                               m_markupText->Measure(dc),
 
579
                                               flags);
 
580
        }
 
581
        else // Normal plain text (but possibly multiline) label.
 
582
#endif // wxUSE_MARKUP
 
583
        {
 
584
            size = wxMSWButton::ComputeBestFittingSize(self, flags);
 
585
        }
 
586
    }
 
587
 
 
588
    if ( m_imageData )
 
589
        AdjustForBitmapSize(size);
 
590
 
 
591
    return wxMSWButton::IncreaseToStdSizeAndCache(self, size);
 
592
}
 
593
 
 
594
// ----------------------------------------------------------------------------
 
595
// event/message handlers
 
596
// ----------------------------------------------------------------------------
 
597
 
 
598
WXLRESULT wxAnyButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
 
599
{
 
600
    if ( nMsg == WM_LBUTTONDBLCLK )
 
601
    {
 
602
        // emulate a click event to force an owner-drawn button to change its
 
603
        // appearance - without this, it won't do it
 
604
        (void)wxControl::MSWWindowProc(WM_LBUTTONDOWN, wParam, lParam);
 
605
 
 
606
        // and continue with processing the message normally as well
 
607
    }
 
608
#if wxUSE_UXTHEME
 
609
    else if ( nMsg == WM_THEMECHANGED )
 
610
    {
 
611
        // need to recalculate the best size here
 
612
        // as the theme size might have changed
 
613
        InvalidateBestSize();
 
614
    }
 
615
#endif // wxUSE_UXTHEME
 
616
    // must use m_mouseInWindow here instead of IsMouseInWindow()
 
617
    // since we need to know the first time the mouse enters the window
 
618
    // and IsMouseInWindow() would return true in this case
 
619
    else if ( (nMsg == WM_MOUSEMOVE && !m_mouseInWindow) ||
 
620
                nMsg == WM_MOUSELEAVE )
 
621
    {
 
622
        if (
 
623
                IsEnabled() &&
 
624
                (
 
625
#if wxUSE_UXTHEME
 
626
                wxUxThemeEngine::GetIfActive() ||
 
627
#endif // wxUSE_UXTHEME
 
628
                 (m_imageData && m_imageData->GetBitmap(State_Current).IsOk())
 
629
                )
 
630
           )
 
631
        {
 
632
            Refresh();
 
633
        }
 
634
    }
 
635
 
 
636
    // let the base class do all real processing
 
637
    return wxControl::MSWWindowProc(nMsg, wParam, lParam);
 
638
}
 
639
 
 
640
// ----------------------------------------------------------------------------
 
641
// button images
 
642
// ----------------------------------------------------------------------------
 
643
 
 
644
wxBitmap wxAnyButton::DoGetBitmap(State which) const
 
645
{
 
646
    return m_imageData ? m_imageData->GetBitmap(which) : wxBitmap();
 
647
}
 
648
 
 
649
void wxAnyButton::DoSetBitmap(const wxBitmap& bitmap, State which)
 
650
{
 
651
#if wxUSE_UXTHEME
 
652
    wxXPButtonImageData *oldData = NULL;
 
653
#endif // wxUSE_UXTHEME
 
654
 
 
655
    // Check if we already had bitmaps of different size.
 
656
    if ( m_imageData &&
 
657
          bitmap.GetSize() != m_imageData->GetBitmap(State_Normal).GetSize() )
 
658
    {
 
659
        wxASSERT_MSG( (which == State_Normal) || bitmap.IsNull(),
 
660
                      "Must set normal bitmap with the new size first" );
 
661
 
 
662
#if wxUSE_UXTHEME
 
663
        if ( ShowsLabel() && wxUxThemeEngine::GetIfActive() )
 
664
        {
 
665
            // We can't change the size of the images stored in wxImageList
 
666
            // in wxXPButtonImageData::m_iml so force recreating it below but
 
667
            // keep the current data to copy its values into the new one.
 
668
            oldData = static_cast<wxXPButtonImageData *>(m_imageData);
 
669
            m_imageData = NULL;
 
670
        }
 
671
#endif // wxUSE_UXTHEME
 
672
        //else: wxODButtonImageData doesn't require anything special
 
673
    }
 
674
 
 
675
    // allocate the image data when the first bitmap is set
 
676
    if ( !m_imageData )
 
677
    {
 
678
#if wxUSE_UXTHEME
 
679
        // using image list doesn't work correctly if we don't have any label
 
680
        // (even if we use BUTTON_IMAGELIST_ALIGN_CENTER alignment and
 
681
        // BS_BITMAP style), at least under Windows 2003 so use owner drawn
 
682
        // strategy for bitmap-only buttons
 
683
        if ( ShowsLabel() && wxUxThemeEngine::GetIfActive() )
 
684
        {
 
685
            m_imageData = new wxXPButtonImageData(this, bitmap);
 
686
 
 
687
            if ( oldData )
 
688
            {
 
689
                // Preserve the old values in case the user changed them.
 
690
                m_imageData->SetBitmapPosition(oldData->GetBitmapPosition());
 
691
 
 
692
                const wxSize oldMargins = oldData->GetBitmapMargins();
 
693
                m_imageData->SetBitmapMargins(oldMargins.x, oldMargins.y);
 
694
 
 
695
                // No need to preserve the bitmaps though as they were of wrong
 
696
                // size anyhow.
 
697
 
 
698
                delete oldData;
 
699
            }
 
700
        }
 
701
        else
 
702
#endif // wxUSE_UXTHEME
 
703
        {
 
704
            m_imageData = new wxODButtonImageData(this, bitmap);
 
705
            MakeOwnerDrawn();
 
706
        }
 
707
    }
 
708
    else
 
709
    {
 
710
        m_imageData->SetBitmap(bitmap, which);
 
711
    }
 
712
 
 
713
    // it should be enough to only invalidate the best size when the normal
 
714
    // bitmap changes as all bitmaps assigned to the button should be of the
 
715
    // same size anyhow
 
716
    if ( which == State_Normal )
 
717
        InvalidateBestSize();
 
718
 
 
719
    Refresh();
 
720
}
 
721
 
 
722
wxSize wxAnyButton::DoGetBitmapMargins() const
 
723
{
 
724
    return m_imageData ? m_imageData->GetBitmapMargins() : wxSize(0, 0);
 
725
}
 
726
 
 
727
void wxAnyButton::DoSetBitmapMargins(wxCoord x, wxCoord y)
 
728
{
 
729
    wxCHECK_RET( m_imageData, "SetBitmap() must be called first" );
 
730
 
 
731
    m_imageData->SetBitmapMargins(x, y);
 
732
    InvalidateBestSize();
 
733
}
 
734
 
 
735
void wxAnyButton::DoSetBitmapPosition(wxDirection dir)
 
736
{
 
737
    wxCHECK_RET( m_imageData, "SetBitmap() must be called first" );
 
738
 
 
739
    m_imageData->SetBitmapPosition(dir);
 
740
    InvalidateBestSize();
 
741
}
 
742
 
 
743
// ----------------------------------------------------------------------------
 
744
// markup support
 
745
// ----------------------------------------------------------------------------
 
746
 
 
747
#if wxUSE_MARKUP
 
748
 
 
749
bool wxAnyButton::DoSetLabelMarkup(const wxString& markup)
 
750
{
 
751
    if ( !wxAnyButtonBase::DoSetLabelMarkup(markup) )
 
752
        return false;
 
753
 
 
754
    if ( !m_markupText )
 
755
    {
 
756
        m_markupText = new wxMarkupText(markup);
 
757
        MakeOwnerDrawn();
 
758
    }
 
759
    else
 
760
    {
 
761
        // We are already owner-drawn so just update the text.
 
762
        m_markupText->SetMarkup(markup);
 
763
    }
 
764
 
 
765
    Refresh();
 
766
 
 
767
    return true;
 
768
}
 
769
 
 
770
#endif // wxUSE_MARKUP
 
771
 
 
772
// ----------------------------------------------------------------------------
 
773
// owner-drawn buttons support
 
774
// ----------------------------------------------------------------------------
 
775
 
 
776
// drawing helpers
 
777
namespace
 
778
{
 
779
 
 
780
// return the button state using both the ODS_XXX flags specified in state
 
781
// parameter and the current button state
 
782
wxAnyButton::State GetButtonState(wxAnyButton *btn, UINT state)
 
783
{
 
784
    if ( state & ODS_DISABLED )
 
785
        return wxAnyButton::State_Disabled;
 
786
 
 
787
    if ( state & ODS_SELECTED )
 
788
        return wxAnyButton::State_Pressed;
 
789
 
 
790
    if ( btn->HasCapture() || btn->IsMouseInWindow() )
 
791
        return wxAnyButton::State_Current;
 
792
 
 
793
    if ( state & ODS_FOCUS )
 
794
        return wxAnyButton::State_Focused;
 
795
 
 
796
    return btn->GetNormalState();
 
797
}
 
798
 
 
799
void DrawButtonText(HDC hdc,
 
800
                    RECT *pRect,
 
801
                    wxAnyButton *btn,
 
802
                    int flags)
 
803
{
 
804
    const wxString text = btn->GetLabel();
 
805
 
 
806
    if ( text.find(wxT('\n')) != wxString::npos )
 
807
    {
 
808
        // draw multiline label
 
809
 
 
810
        // center text horizontally in any case
 
811
        flags |= DT_CENTER;
 
812
 
 
813
        // first we need to compute its bounding rect
 
814
        RECT rc;
 
815
        ::CopyRect(&rc, pRect);
 
816
        ::DrawText(hdc, text.t_str(), text.length(), &rc,
 
817
                   DT_CENTER | DT_CALCRECT);
 
818
 
 
819
        // now center this rect inside the entire button area
 
820
        const LONG w = rc.right - rc.left;
 
821
        const LONG h = rc.bottom - rc.top;
 
822
        rc.left = pRect->left + (pRect->right - pRect->left)/2 - w/2;
 
823
        rc.right = rc.left+w;
 
824
        rc.top = pRect->top + (pRect->bottom - pRect->top)/2 - h/2;
 
825
        rc.bottom = rc.top+h;
 
826
 
 
827
        ::DrawText(hdc, text.t_str(), text.length(), &rc, flags);
 
828
    }
 
829
    else // single line label
 
830
    {
 
831
        // translate wx button flags to alignment flags for DrawText()
 
832
        if ( btn->HasFlag(wxBU_RIGHT) )
 
833
        {
 
834
            flags |= DT_RIGHT;
 
835
        }
 
836
        else if ( !btn->HasFlag(wxBU_LEFT) )
 
837
        {
 
838
            flags |= DT_CENTER;
 
839
        }
 
840
        //else: DT_LEFT is the default anyhow (and its value is 0 too)
 
841
 
 
842
        if ( btn->HasFlag(wxBU_BOTTOM) )
 
843
        {
 
844
            flags |= DT_BOTTOM;
 
845
        }
 
846
        else if ( !btn->HasFlag(wxBU_TOP) )
 
847
        {
 
848
            flags |= DT_VCENTER;
 
849
        }
 
850
        //else: as above, DT_TOP is the default
 
851
 
 
852
        // notice that we must have DT_SINGLELINE for vertical alignment flags
 
853
        // to work
 
854
        ::DrawText(hdc, text.t_str(), text.length(), pRect,
 
855
                   flags | DT_SINGLELINE );
 
856
    }
 
857
}
 
858
 
 
859
void DrawRect(HDC hdc, const RECT& r)
 
860
{
 
861
    wxDrawLine(hdc, r.left, r.top, r.right, r.top);
 
862
    wxDrawLine(hdc, r.right, r.top, r.right, r.bottom);
 
863
    wxDrawLine(hdc, r.right, r.bottom, r.left, r.bottom);
 
864
    wxDrawLine(hdc, r.left, r.bottom, r.left, r.top);
 
865
}
 
866
 
 
867
/*
 
868
   The button frame looks like this normally:
 
869
 
 
870
   WWWWWWWWWWWWWWWWWWB
 
871
   WHHHHHHHHHHHHHHHHGB  W = white       (HILIGHT)
 
872
   WH               GB  H = light grey  (LIGHT)
 
873
   WH               GB  G = dark grey   (SHADOW)
 
874
   WH               GB  B = black       (DKSHADOW)
 
875
   WH               GB
 
876
   WGGGGGGGGGGGGGGGGGB
 
877
   BBBBBBBBBBBBBBBBBBB
 
878
 
 
879
   When the button is selected, the button becomes like this (the total button
 
880
   size doesn't change):
 
881
 
 
882
   BBBBBBBBBBBBBBBBBBB
 
883
   BWWWWWWWWWWWWWWWWBB
 
884
   BWHHHHHHHHHHHHHHGBB
 
885
   BWH             GBB
 
886
   BWH             GBB
 
887
   BWGGGGGGGGGGGGGGGBB
 
888
   BBBBBBBBBBBBBBBBBBB
 
889
   BBBBBBBBBBBBBBBBBBB
 
890
 
 
891
   When the button is pushed (while selected) it is like:
 
892
 
 
893
   BBBBBBBBBBBBBBBBBBB
 
894
   BGGGGGGGGGGGGGGGGGB
 
895
   BG               GB
 
896
   BG               GB
 
897
   BG               GB
 
898
   BG               GB
 
899
   BGGGGGGGGGGGGGGGGGB
 
900
   BBBBBBBBBBBBBBBBBBB
 
901
*/
 
902
void DrawButtonFrame(HDC hdc, RECT& rectBtn,
 
903
                     bool selected, bool pushed)
 
904
{
 
905
    RECT r;
 
906
    CopyRect(&r, &rectBtn);
 
907
 
 
908
    AutoHPEN hpenBlack(GetSysColor(COLOR_3DDKSHADOW)),
 
909
             hpenGrey(GetSysColor(COLOR_3DSHADOW)),
 
910
             hpenLightGr(GetSysColor(COLOR_3DLIGHT)),
 
911
             hpenWhite(GetSysColor(COLOR_3DHILIGHT));
 
912
 
 
913
    SelectInHDC selectPen(hdc, hpenBlack);
 
914
 
 
915
    r.right--;
 
916
    r.bottom--;
 
917
 
 
918
    if ( pushed )
 
919
    {
 
920
        DrawRect(hdc, r);
 
921
 
 
922
        (void)SelectObject(hdc, hpenGrey);
 
923
        ::InflateRect(&r, -1, -1);
 
924
 
 
925
        DrawRect(hdc, r);
 
926
    }
 
927
    else // !pushed
 
928
    {
 
929
        if ( selected )
 
930
        {
 
931
            DrawRect(hdc, r);
 
932
 
 
933
            ::InflateRect(&r, -1, -1);
 
934
        }
 
935
 
 
936
        wxDrawLine(hdc, r.left, r.bottom, r.right, r.bottom);
 
937
        wxDrawLine(hdc, r.right, r.bottom, r.right, r.top - 1);
 
938
 
 
939
        (void)SelectObject(hdc, hpenWhite);
 
940
        wxDrawLine(hdc, r.left, r.bottom - 1, r.left, r.top);
 
941
        wxDrawLine(hdc, r.left, r.top, r.right, r.top);
 
942
 
 
943
        (void)SelectObject(hdc, hpenLightGr);
 
944
        wxDrawLine(hdc, r.left + 1, r.bottom - 2, r.left + 1, r.top + 1);
 
945
        wxDrawLine(hdc, r.left + 1, r.top + 1, r.right - 1, r.top + 1);
 
946
 
 
947
        (void)SelectObject(hdc, hpenGrey);
 
948
        wxDrawLine(hdc, r.left + 1, r.bottom - 1, r.right - 1, r.bottom - 1);
 
949
        wxDrawLine(hdc, r.right - 1, r.bottom - 1, r.right - 1, r.top);
 
950
    }
 
951
 
 
952
    InflateRect(&rectBtn, -OD_BUTTON_MARGIN, -OD_BUTTON_MARGIN);
 
953
}
 
954
 
 
955
#if wxUSE_UXTHEME
 
956
void DrawXPBackground(wxAnyButton *button, HDC hdc, RECT& rectBtn, UINT state)
 
957
{
 
958
    wxUxThemeHandle theme(button, L"BUTTON");
 
959
 
 
960
    // this array is indexed by wxAnyButton::State values and so must be kept in
 
961
    // sync with it
 
962
    static const int uxStates[] =
 
963
    {
 
964
        PBS_NORMAL, PBS_HOT, PBS_PRESSED, PBS_DISABLED, PBS_DEFAULTED
 
965
    };
 
966
 
 
967
    int iState = uxStates[GetButtonState(button, state)];
 
968
 
 
969
    wxUxThemeEngine * const engine = wxUxThemeEngine::Get();
 
970
 
 
971
    // draw parent background if needed
 
972
    if ( engine->IsThemeBackgroundPartiallyTransparent
 
973
                 (
 
974
                    theme,
 
975
                    BP_PUSHBUTTON,
 
976
                    iState
 
977
                 ) )
 
978
    {
 
979
        // Set this button as the one whose background is being erased: this
 
980
        // allows our WM_ERASEBKGND handler used by DrawThemeParentBackground()
 
981
        // to correctly align the background brush with this window instead of
 
982
        // the parent window to which WM_ERASEBKGND is sent. Notice that this
 
983
        // doesn't work with custom user-defined EVT_ERASE_BACKGROUND handlers
 
984
        // as they won't be aligned but unfortunately all the attempts to fix
 
985
        // it by shifting DC origin before calling DrawThemeParentBackground()
 
986
        // failed to work so we at least do this, even though this is far from
 
987
        // being the perfect solution.
 
988
        wxWindowBeingErased = button;
 
989
 
 
990
        engine->DrawThemeParentBackground(GetHwndOf(button), hdc, &rectBtn);
 
991
 
 
992
        wxWindowBeingErased = NULL;
 
993
    }
 
994
 
 
995
    // draw background
 
996
    engine->DrawThemeBackground(theme, hdc, BP_PUSHBUTTON, iState,
 
997
                                &rectBtn, NULL);
 
998
 
 
999
    // calculate content area margins
 
1000
    MARGINS margins;
 
1001
    engine->GetThemeMargins(theme, hdc, BP_PUSHBUTTON, iState,
 
1002
                            TMT_CONTENTMARGINS, &rectBtn, &margins);
 
1003
    ::InflateRect(&rectBtn, -margins.cxLeftWidth, -margins.cyTopHeight);
 
1004
    ::InflateRect(&rectBtn, -XP_BUTTON_EXTRA_MARGIN, -XP_BUTTON_EXTRA_MARGIN);
 
1005
 
 
1006
    if ( button->UseBgCol() )
 
1007
    {
 
1008
        COLORREF colBg = wxColourToRGB(button->GetBackgroundColour());
 
1009
        AutoHBRUSH hbrushBackground(colBg);
 
1010
 
 
1011
        // don't overwrite the focus rect
 
1012
        RECT rectClient;
 
1013
        ::CopyRect(&rectClient, &rectBtn);
 
1014
        ::InflateRect(&rectClient, -1, -1);
 
1015
        FillRect(hdc, &rectClient, hbrushBackground);
 
1016
    }
 
1017
}
 
1018
#endif // wxUSE_UXTHEME
 
1019
 
 
1020
} // anonymous namespace
 
1021
 
 
1022
// ----------------------------------------------------------------------------
 
1023
// owner drawn buttons support
 
1024
// ----------------------------------------------------------------------------
 
1025
 
 
1026
void wxAnyButton::MakeOwnerDrawn()
 
1027
{
 
1028
    if ( !IsOwnerDrawn() )
 
1029
    {
 
1030
        // make it so
 
1031
        // note that BS_OWNERDRAW is not independent from other style bits
 
1032
        long style = GetWindowLong(GetHwnd(), GWL_STYLE);
 
1033
        style &= ~(BS_3STATE | BS_AUTO3STATE | BS_AUTOCHECKBOX | BS_AUTORADIOBUTTON | BS_CHECKBOX | BS_DEFPUSHBUTTON | BS_GROUPBOX | BS_PUSHBUTTON | BS_RADIOBUTTON | BS_PUSHLIKE);
 
1034
        style |= BS_OWNERDRAW;
 
1035
        SetWindowLong(GetHwnd(), GWL_STYLE, style);
 
1036
    }
 
1037
}
 
1038
 
 
1039
bool wxAnyButton::IsOwnerDrawn() const
 
1040
{
 
1041
    long style = GetWindowLong(GetHwnd(), GWL_STYLE);
 
1042
    return ( (style & BS_OWNERDRAW) == BS_OWNERDRAW );
 
1043
}
 
1044
 
 
1045
bool wxAnyButton::SetBackgroundColour(const wxColour &colour)
 
1046
{
 
1047
    if ( !wxControl::SetBackgroundColour(colour) )
 
1048
    {
 
1049
        // nothing to do
 
1050
        return false;
 
1051
    }
 
1052
 
 
1053
    MakeOwnerDrawn();
 
1054
 
 
1055
    Refresh();
 
1056
 
 
1057
    return true;
 
1058
}
 
1059
 
 
1060
bool wxAnyButton::SetForegroundColour(const wxColour &colour)
 
1061
{
 
1062
    if ( !wxControl::SetForegroundColour(colour) )
 
1063
    {
 
1064
        // nothing to do
 
1065
        return false;
 
1066
    }
 
1067
 
 
1068
    MakeOwnerDrawn();
 
1069
 
 
1070
    Refresh();
 
1071
 
 
1072
    return true;
 
1073
}
 
1074
 
 
1075
bool wxAnyButton::MSWOnDraw(WXDRAWITEMSTRUCT *wxdis)
 
1076
{
 
1077
    LPDRAWITEMSTRUCT lpDIS = (LPDRAWITEMSTRUCT)wxdis;
 
1078
    HDC hdc = lpDIS->hDC;
 
1079
 
 
1080
    UINT state = lpDIS->itemState;
 
1081
    switch ( GetButtonState(this, state) )
 
1082
    {
 
1083
        case State_Disabled:
 
1084
            state |= ODS_DISABLED;
 
1085
            break;
 
1086
        case State_Pressed:
 
1087
            state |= ODS_SELECTED;
 
1088
            break;
 
1089
        case State_Focused:
 
1090
            state |= ODS_FOCUS;
 
1091
            break;
 
1092
        default:
 
1093
            break;
 
1094
    }
 
1095
 
 
1096
    bool pushed = (SendMessage(GetHwnd(), BM_GETSTATE, 0, 0) & BST_PUSHED) != 0;
 
1097
 
 
1098
    RECT rectBtn;
 
1099
    CopyRect(&rectBtn, &lpDIS->rcItem);
 
1100
 
 
1101
    // draw the button background
 
1102
    if ( !HasFlag(wxBORDER_NONE) )
 
1103
    {
 
1104
#if wxUSE_UXTHEME
 
1105
        if ( wxUxThemeEngine::GetIfActive() )
 
1106
        {
 
1107
            DrawXPBackground(this, hdc, rectBtn, state);
 
1108
        }
 
1109
        else
 
1110
#endif // wxUSE_UXTHEME
 
1111
        {
 
1112
            COLORREF colBg = wxColourToRGB(GetBackgroundColour());
 
1113
 
 
1114
            // first, draw the background
 
1115
            AutoHBRUSH hbrushBackground(colBg);
 
1116
            FillRect(hdc, &rectBtn, hbrushBackground);
 
1117
 
 
1118
            // draw the border for the current state
 
1119
            bool selected = (state & ODS_SELECTED) != 0;
 
1120
            if ( !selected )
 
1121
            {
 
1122
                wxTopLevelWindow *
 
1123
                    tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
 
1124
                if ( tlw )
 
1125
                {
 
1126
                    selected = tlw->GetDefaultItem() == this;
 
1127
                }
 
1128
            }
 
1129
 
 
1130
            DrawButtonFrame(hdc, rectBtn, selected, pushed);
 
1131
        }
 
1132
 
 
1133
        // draw the focus rectangle if we need it
 
1134
        if ( (state & ODS_FOCUS) && !(state & ODS_NOFOCUSRECT) )
 
1135
        {
 
1136
            DrawFocusRect(hdc, &rectBtn);
 
1137
 
 
1138
#if wxUSE_UXTHEME
 
1139
            if ( !wxUxThemeEngine::GetIfActive() )
 
1140
#endif // wxUSE_UXTHEME
 
1141
            {
 
1142
                if ( pushed )
 
1143
                {
 
1144
                    // the label is shifted by 1 pixel to create "pushed" effect
 
1145
                    OffsetRect(&rectBtn, 1, 1);
 
1146
                }
 
1147
            }
 
1148
        }
 
1149
    }
 
1150
 
 
1151
 
 
1152
    // draw the image, if any
 
1153
    if ( m_imageData )
 
1154
    {
 
1155
        wxBitmap bmp = m_imageData->GetBitmap(GetButtonState(this, state));
 
1156
        if ( !bmp.IsOk() )
 
1157
            bmp = m_imageData->GetBitmap(State_Normal);
 
1158
 
 
1159
        const wxSize sizeBmp = bmp.GetSize();
 
1160
        const wxSize margin = m_imageData->GetBitmapMargins();
 
1161
        const wxSize sizeBmpWithMargins(sizeBmp + 2*margin);
 
1162
        wxRect rectButton(wxRectFromRECT(rectBtn));
 
1163
 
 
1164
        // for simplicity, we start with centred rectangle and then move it to
 
1165
        // the appropriate edge
 
1166
        wxRect rectBitmap = wxRect(sizeBmp).CentreIn(rectButton);
 
1167
 
 
1168
        // move bitmap only if we have a label, otherwise keep it centered
 
1169
        if ( ShowsLabel() )
 
1170
        {
 
1171
            switch ( m_imageData->GetBitmapPosition() )
 
1172
            {
 
1173
                default:
 
1174
                    wxFAIL_MSG( "invalid direction" );
 
1175
                    // fall through
 
1176
 
 
1177
                case wxLEFT:
 
1178
                    rectBitmap.x = rectButton.x + margin.x;
 
1179
                    rectButton.x += sizeBmpWithMargins.x;
 
1180
                    rectButton.width -= sizeBmpWithMargins.x;
 
1181
                    break;
 
1182
 
 
1183
                case wxRIGHT:
 
1184
                    rectBitmap.x = rectButton.GetRight() - sizeBmp.x - margin.x;
 
1185
                    rectButton.width -= sizeBmpWithMargins.x;
 
1186
                    break;
 
1187
 
 
1188
                case wxTOP:
 
1189
                    rectBitmap.y = rectButton.y + margin.y;
 
1190
                    rectButton.y += sizeBmpWithMargins.y;
 
1191
                    rectButton.height -= sizeBmpWithMargins.y;
 
1192
                    break;
 
1193
 
 
1194
                case wxBOTTOM:
 
1195
                    rectBitmap.y = rectButton.GetBottom() - sizeBmp.y - margin.y;
 
1196
                    rectButton.height -= sizeBmpWithMargins.y;
 
1197
                    break;
 
1198
            }
 
1199
        }
 
1200
 
 
1201
        wxDCTemp dst((WXHDC)hdc);
 
1202
        dst.DrawBitmap(bmp, rectBitmap.GetPosition(), true);
 
1203
 
 
1204
        wxCopyRectToRECT(rectButton, rectBtn);
 
1205
    }
 
1206
 
 
1207
 
 
1208
    // finally draw the label
 
1209
    if ( ShowsLabel() )
 
1210
    {
 
1211
        COLORREF colFg = state & ODS_DISABLED
 
1212
                            ? ::GetSysColor(COLOR_GRAYTEXT)
 
1213
                            : wxColourToRGB(GetForegroundColour());
 
1214
 
 
1215
        wxTextColoursChanger changeFg(hdc, colFg, CLR_INVALID);
 
1216
        wxBkModeChanger changeBkMode(hdc, wxBRUSHSTYLE_TRANSPARENT);
 
1217
 
 
1218
#if wxUSE_MARKUP
 
1219
        if ( m_markupText )
 
1220
        {
 
1221
            wxDCTemp dc((WXHDC)hdc);
 
1222
            dc.SetTextForeground(wxColour(colFg));
 
1223
            dc.SetFont(GetFont());
 
1224
 
 
1225
            m_markupText->Render(dc, wxRectFromRECT(rectBtn),
 
1226
                                 state & ODS_NOACCEL
 
1227
                                    ? wxMarkupText::Render_Default
 
1228
                                    : wxMarkupText::Render_ShowAccels);
 
1229
        }
 
1230
        else // Plain text label
 
1231
#endif // wxUSE_MARKUP
 
1232
        {
 
1233
            // notice that DT_HIDEPREFIX doesn't work on old (pre-Windows 2000)
 
1234
            // systems but by happy coincidence ODS_NOACCEL is not used under
 
1235
            // them neither so DT_HIDEPREFIX should never be used there
 
1236
            DrawButtonText(hdc, &rectBtn, this,
 
1237
                           state & ODS_NOACCEL ? DT_HIDEPREFIX : 0);
 
1238
        }
 
1239
    }
 
1240
 
 
1241
    return true;
 
1242
}
 
1243
 
 
1244
#endif // wxHAS_ANY_BUTTON