~ubuntu-dev/wxwidgets2.6/upstream-debian

« back to all changes in this revision

Viewing changes to src/msw/tbar95.cpp

  • Committer: Daniel T Chen
  • Date: 2006-06-26 10:15:11 UTC
  • Revision ID: crimsun@ubuntu.com-20060626101511-a4436cec4c6d9b35
ImportĀ DebianĀ 2.6.3.2.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        msw/tbar95.cpp
 
3
// Purpose:     wxToolBar
 
4
// Author:      Julian Smart
 
5
// Modified by:
 
6
// Created:     04/01/98
 
7
// RCS-ID:      $Id: tbar95.cpp,v 1.157.2.8 2006/04/01 18:16:17 JS Exp $
 
8
// Copyright:   (c) Julian Smart
 
9
// Licence:     wxWindows licence
 
10
/////////////////////////////////////////////////////////////////////////////
 
11
 
 
12
// ============================================================================
 
13
// declarations
 
14
// ============================================================================
 
15
 
 
16
// ----------------------------------------------------------------------------
 
17
// headers
 
18
// ----------------------------------------------------------------------------
 
19
 
 
20
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
 
21
    #pragma implementation "tbar95.h"
 
22
#endif
 
23
 
 
24
// For compilers that support precompilation, includes "wx.h".
 
25
#include "wx/wxprec.h"
 
26
 
 
27
#ifdef __BORLANDC__
 
28
    #pragma hdrstop
 
29
#endif
 
30
 
 
31
#ifndef WX_PRECOMP
 
32
    #include "wx/frame.h"
 
33
    #include "wx/log.h"
 
34
    #include "wx/intl.h"
 
35
    #include "wx/dynarray.h"
 
36
    #include "wx/settings.h"
 
37
    #include "wx/bitmap.h"
 
38
    #include "wx/dcmemory.h"
 
39
    #include "wx/control.h"
 
40
#endif
 
41
 
 
42
#if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE && !defined(__SMARTPHONE__)
 
43
 
 
44
#include "wx/toolbar.h"
 
45
#include "wx/sysopt.h"
 
46
#include "wx/image.h"
 
47
 
 
48
#include "wx/msw/private.h"
 
49
 
 
50
#if wxUSE_UXTHEME
 
51
#include "wx/msw/uxtheme.h"
 
52
#endif
 
53
 
 
54
// include <commctrl.h> "properly"
 
55
#include "wx/msw/wrapcctl.h"
 
56
 
 
57
#include "wx/app.h"         // for GetComCtl32Version
 
58
 
 
59
// ----------------------------------------------------------------------------
 
60
// constants
 
61
// ----------------------------------------------------------------------------
 
62
 
 
63
// these standard constants are not always defined in compilers headers
 
64
 
 
65
// Styles
 
66
#ifndef TBSTYLE_FLAT
 
67
    #define TBSTYLE_LIST            0x1000
 
68
    #define TBSTYLE_FLAT            0x0800
 
69
#endif
 
70
 
 
71
#ifndef TBSTYLE_TRANSPARENT
 
72
    #define TBSTYLE_TRANSPARENT     0x8000
 
73
#endif
 
74
 
 
75
#ifndef TBSTYLE_TOOLTIPS
 
76
    #define TBSTYLE_TOOLTIPS        0x0100
 
77
#endif
 
78
 
 
79
// Messages
 
80
#ifndef TB_GETSTYLE
 
81
    #define TB_SETSTYLE             (WM_USER + 56)
 
82
    #define TB_GETSTYLE             (WM_USER + 57)
 
83
#endif
 
84
 
 
85
#ifndef TB_HITTEST
 
86
    #define TB_HITTEST              (WM_USER + 69)
 
87
#endif
 
88
 
 
89
#ifndef TB_GETMAXSIZE
 
90
    #define TB_GETMAXSIZE           (WM_USER + 83)
 
91
#endif
 
92
 
 
93
// these values correspond to those used by comctl32.dll
 
94
#define DEFAULTBITMAPX   16
 
95
#define DEFAULTBITMAPY   15
 
96
 
 
97
// ----------------------------------------------------------------------------
 
98
// wxWin macros
 
99
// ----------------------------------------------------------------------------
 
100
 
 
101
IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl)
 
102
 
 
103
/*
 
104
    TOOLBAR PROPERTIES
 
105
        tool
 
106
            bitmap
 
107
            bitmap2
 
108
            tooltip
 
109
            longhelp
 
110
            radio (bool)
 
111
            toggle (bool)
 
112
        separator
 
113
        style ( wxNO_BORDER | wxTB_HORIZONTAL)
 
114
        bitmapsize
 
115
        margins
 
116
        packing
 
117
        separation
 
118
 
 
119
        dontattachtoframe
 
120
*/
 
121
 
 
122
BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
 
123
    EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent)
 
124
    EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged)
 
125
    EVT_ERASE_BACKGROUND(wxToolBar::OnEraseBackground)
 
126
END_EVENT_TABLE()
 
127
 
 
128
// ----------------------------------------------------------------------------
 
129
// private classes
 
130
// ----------------------------------------------------------------------------
 
131
 
 
132
class wxToolBarTool : public wxToolBarToolBase
 
133
{
 
134
public:
 
135
    wxToolBarTool(wxToolBar *tbar,
 
136
                  int id,
 
137
                  const wxString& label,
 
138
                  const wxBitmap& bmpNormal,
 
139
                  const wxBitmap& bmpDisabled,
 
140
                  wxItemKind kind,
 
141
                  wxObject *clientData,
 
142
                  const wxString& shortHelp,
 
143
                  const wxString& longHelp)
 
144
        : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind,
 
145
                            clientData, shortHelp, longHelp)
 
146
    {
 
147
        m_nSepCount = 0;
 
148
    }
 
149
 
 
150
    wxToolBarTool(wxToolBar *tbar, wxControl *control)
 
151
        : wxToolBarToolBase(tbar, control)
 
152
    {
 
153
        m_nSepCount = 1;
 
154
    }
 
155
 
 
156
    virtual void SetLabel(const wxString& label)
 
157
    {
 
158
        if ( label == m_label )
 
159
            return;
 
160
 
 
161
        wxToolBarToolBase::SetLabel(label);
 
162
 
 
163
        // we need to update the label shown in the toolbar because it has a
 
164
        // pointer to the internal buffer of the old label
 
165
        //
 
166
        // TODO: use TB_SETBUTTONINFO
 
167
    }
 
168
 
 
169
    // set/get the number of separators which we use to cover the space used by
 
170
    // a control in the toolbar
 
171
    void SetSeparatorsCount(size_t count) { m_nSepCount = count; }
 
172
    size_t GetSeparatorsCount() const { return m_nSepCount; }
 
173
 
 
174
private:
 
175
    size_t m_nSepCount;
 
176
 
 
177
    DECLARE_NO_COPY_CLASS(wxToolBarTool)
 
178
};
 
179
 
 
180
 
 
181
// ============================================================================
 
182
// implementation
 
183
// ============================================================================
 
184
 
 
185
// ----------------------------------------------------------------------------
 
186
// wxToolBarTool
 
187
// ----------------------------------------------------------------------------
 
188
 
 
189
wxToolBarToolBase *wxToolBar::CreateTool(int id,
 
190
                                         const wxString& label,
 
191
                                         const wxBitmap& bmpNormal,
 
192
                                         const wxBitmap& bmpDisabled,
 
193
                                         wxItemKind kind,
 
194
                                         wxObject *clientData,
 
195
                                         const wxString& shortHelp,
 
196
                                         const wxString& longHelp)
 
197
{
 
198
    return new wxToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind,
 
199
                             clientData, shortHelp, longHelp);
 
200
}
 
201
 
 
202
wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
 
203
{
 
204
    return new wxToolBarTool(this, control);
 
205
}
 
206
 
 
207
// ----------------------------------------------------------------------------
 
208
// wxToolBar construction
 
209
// ----------------------------------------------------------------------------
 
210
 
 
211
void wxToolBar::Init()
 
212
{
 
213
    m_hBitmap = 0;
 
214
    m_disabledImgList = NULL;
 
215
 
 
216
    m_nButtons = 0;
 
217
 
 
218
    m_defaultWidth = DEFAULTBITMAPX;
 
219
    m_defaultHeight = DEFAULTBITMAPY;
 
220
 
 
221
    m_pInTool = 0;
 
222
}
 
223
 
 
224
bool wxToolBar::Create(wxWindow *parent,
 
225
                       wxWindowID id,
 
226
                       const wxPoint& pos,
 
227
                       const wxSize& size,
 
228
                       long style,
 
229
                       const wxString& name)
 
230
{
 
231
    // common initialisation
 
232
    if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) )
 
233
        return false;
 
234
 
 
235
    // MSW-specific initialisation
 
236
    if ( !MSWCreateToolbar(pos, size) )
 
237
        return false;
 
238
 
 
239
    wxSetCCUnicodeFormat(GetHwnd());
 
240
 
 
241
    // set up the colors and fonts
 
242
    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
 
243
    SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
 
244
 
 
245
    // workaround for flat toolbar on Windows XP classic style: we have to set
 
246
    // the style after creating the control, doing it at creation time doesn't
 
247
    // work
 
248
#if wxUSE_UXTHEME
 
249
    if ( style & wxTB_FLAT )
 
250
    {
 
251
        LRESULT style = ::SendMessage(GetHwnd(), TB_GETSTYLE, 0, 0L);
 
252
 
 
253
        if ( !(style & TBSTYLE_FLAT) )
 
254
        {
 
255
            ::SendMessage(GetHwnd(), TB_SETSTYLE, 0, style | TBSTYLE_FLAT);
 
256
        }
 
257
    }
 
258
#endif // wxUSE_UXTHEME
 
259
 
 
260
    return true;
 
261
}
 
262
 
 
263
bool wxToolBar::MSWCreateToolbar(const wxPoint& pos, const wxSize& size)
 
264
{
 
265
    if ( !MSWCreateControl(TOOLBARCLASSNAME, wxEmptyString, pos, size) )
 
266
        return false;
 
267
 
 
268
    // toolbar-specific post initialisation
 
269
    ::SendMessage(GetHwnd(), TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
 
270
 
 
271
    return true;
 
272
}
 
273
 
 
274
void wxToolBar::Recreate()
 
275
{
 
276
    const HWND hwndOld = GetHwnd();
 
277
    if ( !hwndOld )
 
278
    {
 
279
        // we haven't been created yet, no need to recreate
 
280
        return;
 
281
    }
 
282
 
 
283
    // get the position and size before unsubclassing the old toolbar
 
284
    const wxPoint pos = GetPosition();
 
285
    const wxSize size = GetSize();
 
286
 
 
287
    UnsubclassWin();
 
288
 
 
289
    if ( !MSWCreateToolbar(pos, size) )
 
290
    {
 
291
        // what can we do?
 
292
        wxFAIL_MSG( _T("recreating the toolbar failed") );
 
293
 
 
294
        return;
 
295
    }
 
296
 
 
297
    // reparent all our children under the new toolbar
 
298
    for ( wxWindowList::compatibility_iterator node = m_children.GetFirst();
 
299
          node;
 
300
          node = node->GetNext() )
 
301
    {
 
302
        wxWindow *win = node->GetData();
 
303
        if ( !win->IsTopLevel() )
 
304
            ::SetParent(GetHwndOf(win), GetHwnd());
 
305
    }
 
306
 
 
307
    // only destroy the old toolbar now -- after all the children had been
 
308
    // reparented
 
309
    ::DestroyWindow(hwndOld);
 
310
 
 
311
    // it is for the old bitmap control and can't be used with the new one
 
312
    if ( m_hBitmap )
 
313
    {
 
314
        ::DeleteObject((HBITMAP) m_hBitmap);
 
315
        m_hBitmap = 0;
 
316
    }
 
317
 
 
318
    if ( m_disabledImgList )
 
319
    {
 
320
        delete m_disabledImgList;
 
321
        m_disabledImgList = NULL;
 
322
    }
 
323
 
 
324
    Realize();
 
325
}
 
326
 
 
327
wxToolBar::~wxToolBar()
 
328
{
 
329
    // we must refresh the frame size when the toolbar is deleted but the frame
 
330
    // is not - otherwise toolbar leaves a hole in the place it used to occupy
 
331
    wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
 
332
    if ( frame && !frame->IsBeingDeleted() )
 
333
    {
 
334
        frame->SendSizeEvent();
 
335
    }
 
336
 
 
337
    if ( m_hBitmap )
 
338
    {
 
339
        ::DeleteObject((HBITMAP) m_hBitmap);
 
340
    }
 
341
 
 
342
    delete m_disabledImgList;
 
343
}
 
344
 
 
345
wxSize wxToolBar::DoGetBestSize() const
 
346
{
 
347
    wxSize sizeBest;
 
348
 
 
349
    SIZE size;
 
350
    if ( !::SendMessage(GetHwnd(), TB_GETMAXSIZE, 0, (LPARAM)&size) )
 
351
    {
 
352
        // maybe an old (< 0x400) Windows version? try to approximate the
 
353
        // toolbar size ourselves
 
354
        sizeBest = GetToolSize();
 
355
        sizeBest.y += 2 * ::GetSystemMetrics(SM_CYBORDER); // Add borders
 
356
        sizeBest.x *= GetToolsCount();
 
357
 
 
358
        // reverse horz and vertical components if necessary
 
359
        if ( HasFlag(wxTB_VERTICAL) )
 
360
        {
 
361
            int t = sizeBest.x;
 
362
            sizeBest.x = sizeBest.y;
 
363
            sizeBest.y = t;
 
364
        }
 
365
    }
 
366
    else
 
367
    {
 
368
        sizeBest.x = size.cx;
 
369
        sizeBest.y = size.cy;
 
370
    }
 
371
 
 
372
    CacheBestSize(sizeBest);
 
373
    return sizeBest;
 
374
}
 
375
 
 
376
WXDWORD wxToolBar::MSWGetStyle(long style, WXDWORD *exstyle) const
 
377
{
 
378
    // toolbars never have border, giving one to them results in broken
 
379
    // appearance
 
380
    WXDWORD msStyle = wxControl::MSWGetStyle
 
381
                      (
 
382
                        (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle
 
383
                      );
 
384
 
 
385
    // always include this one, it never hurts and setting it later only if we
 
386
    // do have tooltips wouldn't work
 
387
    msStyle |= TBSTYLE_TOOLTIPS;
 
388
 
 
389
    if ( style & (wxTB_FLAT | wxTB_HORZ_LAYOUT) )
 
390
    {
 
391
        // static as it doesn't change during the program lifetime
 
392
        static int s_verComCtl = wxApp::GetComCtl32Version();
 
393
 
 
394
        // comctl32.dll 4.00 doesn't support the flat toolbars and using this
 
395
        // style with 6.00 (part of Windows XP) leads to the toolbar with
 
396
        // incorrect background colour - and not using it still results in the
 
397
        // correct (flat) toolbar, so don't use it there
 
398
        if ( s_verComCtl > 400 && s_verComCtl < 600 )
 
399
        {
 
400
            msStyle |= TBSTYLE_FLAT | TBSTYLE_TRANSPARENT;
 
401
        }
 
402
 
 
403
        if ( s_verComCtl >= 470 && style & wxTB_HORZ_LAYOUT )
 
404
        {
 
405
            msStyle |= TBSTYLE_LIST;
 
406
        }
 
407
    }
 
408
 
 
409
    if ( style & wxTB_NODIVIDER )
 
410
        msStyle |= CCS_NODIVIDER;
 
411
 
 
412
    if ( style & wxTB_NOALIGN )
 
413
        msStyle |= CCS_NOPARENTALIGN;
 
414
 
 
415
    if ( style & wxTB_VERTICAL )
 
416
        msStyle |= CCS_VERT;
 
417
 
 
418
    return msStyle;
 
419
}
 
420
 
 
421
// ----------------------------------------------------------------------------
 
422
// adding/removing tools
 
423
// ----------------------------------------------------------------------------
 
424
 
 
425
bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
 
426
{
 
427
    // nothing special to do here - we really create the toolbar buttons in
 
428
    // Realize() later
 
429
    tool->Attach(this);
 
430
 
 
431
    InvalidateBestSize();
 
432
    return true;
 
433
}
 
434
 
 
435
bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool)
 
436
{
 
437
    // the main difficulty we have here is with the controls in the toolbars:
 
438
    // as we (sometimes) use several separators to cover up the space used by
 
439
    // them, the indices are not the same for us and the toolbar
 
440
 
 
441
    // first determine the position of the first button to delete: it may be
 
442
    // different from pos if we use several separators to cover the space used
 
443
    // by a control
 
444
    wxToolBarToolsList::compatibility_iterator node;
 
445
    for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
 
446
    {
 
447
        wxToolBarToolBase *tool2 = node->GetData();
 
448
        if ( tool2 == tool )
 
449
        {
 
450
            // let node point to the next node in the list
 
451
            node = node->GetNext();
 
452
 
 
453
            break;
 
454
        }
 
455
 
 
456
        if ( tool2->IsControl() )
 
457
        {
 
458
            pos += ((wxToolBarTool *)tool2)->GetSeparatorsCount() - 1;
 
459
        }
 
460
    }
 
461
 
 
462
    // now determine the number of buttons to delete and the area taken by them
 
463
    size_t nButtonsToDelete = 1;
 
464
 
 
465
    // get the size of the button we're going to delete
 
466
    RECT r;
 
467
    if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT, pos, (LPARAM)&r) )
 
468
    {
 
469
        wxLogLastError(_T("TB_GETITEMRECT"));
 
470
    }
 
471
 
 
472
    int width = r.right - r.left;
 
473
 
 
474
    if ( tool->IsControl() )
 
475
    {
 
476
        nButtonsToDelete = ((wxToolBarTool *)tool)->GetSeparatorsCount();
 
477
        width *= nButtonsToDelete;
 
478
        tool->GetControl()->Destroy();
 
479
    }
 
480
 
 
481
    // do delete all buttons
 
482
    m_nButtons -= nButtonsToDelete;
 
483
    while ( nButtonsToDelete-- > 0 )
 
484
    {
 
485
        if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, pos, 0) )
 
486
        {
 
487
            wxLogLastError(wxT("TB_DELETEBUTTON"));
 
488
 
 
489
            return false;
 
490
        }
 
491
    }
 
492
 
 
493
    tool->Detach();
 
494
 
 
495
    // and finally reposition all the controls after this button (the toolbar
 
496
    // takes care of all normal items)
 
497
    for ( /* node -> first after deleted */ ; node; node = node->GetNext() )
 
498
    {
 
499
        wxToolBarToolBase *tool2 = node->GetData();
 
500
        if ( tool2->IsControl() )
 
501
        {
 
502
            int x;
 
503
            wxControl *control = tool2->GetControl();
 
504
            control->GetPosition(&x, NULL);
 
505
            control->Move(x - width, wxDefaultCoord);
 
506
        }
 
507
    }
 
508
 
 
509
    InvalidateBestSize();
 
510
    return true;
 
511
}
 
512
 
 
513
void wxToolBar::CreateDisabledImageList()
 
514
{
 
515
    // as we can't use disabled image list with older versions of comctl32.dll,
 
516
    // don't even bother creating it
 
517
    if ( wxTheApp->GetComCtl32Version() >= 470 )
 
518
    {
 
519
        // search for the first disabled button img in the toolbar, if any
 
520
        for ( wxToolBarToolsList::compatibility_iterator
 
521
                node = m_tools.GetFirst(); node; node = node->GetNext() )
 
522
        {
 
523
            wxToolBarToolBase *tool = node->GetData();
 
524
            wxBitmap bmpDisabled = tool->GetDisabledBitmap();
 
525
            if ( bmpDisabled.Ok() )
 
526
            {
 
527
                m_disabledImgList = new wxImageList
 
528
                                        (
 
529
                                            m_defaultWidth,
 
530
                                            m_defaultHeight,
 
531
                                            bmpDisabled.GetMask() != NULL,
 
532
                                            GetToolsCount()
 
533
                                        );
 
534
                return;
 
535
            }
 
536
        }
 
537
 
 
538
        // we don't have any disabled bitmaps
 
539
    }
 
540
 
 
541
    m_disabledImgList = NULL;
 
542
}
 
543
 
 
544
bool wxToolBar::Realize()
 
545
{
 
546
    const size_t nTools = GetToolsCount();
 
547
    if ( nTools == 0 )
 
548
    {
 
549
        // nothing to do
 
550
        return true;
 
551
    }
 
552
 
 
553
    const bool isVertical = HasFlag(wxTB_VERTICAL);
 
554
 
 
555
    bool doRemap, doRemapBg, doTransparent;
 
556
#ifdef __WXWINCE__
 
557
    doRemapBg = false;
 
558
    doRemap = false;
 
559
    doTransparent = false;
 
560
#else
 
561
    if (wxSystemOptions::GetOptionInt(wxT("msw.remap")) == 2)
 
562
    {
 
563
        doRemapBg = doRemap = false;
 
564
        doTransparent = true;
 
565
    }
 
566
    else
 
567
    {   doRemap = !wxSystemOptions::HasOption(wxT("msw.remap"))
 
568
            || wxSystemOptions::GetOptionInt(wxT("msw.remap")) == 1;
 
569
        doRemapBg = !doRemap;
 
570
        doTransparent = false;
 
571
    }
 
572
#endif
 
573
 
 
574
    // delete all old buttons, if any
 
575
    for ( size_t pos = 0; pos < m_nButtons; pos++ )
 
576
    {
 
577
        if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, 0, 0) )
 
578
        {
 
579
            wxLogDebug(wxT("TB_DELETEBUTTON failed"));
 
580
        }
 
581
    }
 
582
 
 
583
    // First, add the bitmap: we use one bitmap for all toolbar buttons
 
584
    // ----------------------------------------------------------------
 
585
 
 
586
    wxToolBarToolsList::compatibility_iterator node;
 
587
    int bitmapId = 0;
 
588
 
 
589
    wxSize sizeBmp;
 
590
    if ( HasFlag(wxTB_NOICONS) )
 
591
    {
 
592
        // no icons, don't leave space for them
 
593
        sizeBmp.x =
 
594
        sizeBmp.y = 0;
 
595
    }
 
596
    else // do show icons
 
597
    {
 
598
        // if we already have a bitmap, we'll replace the existing one --
 
599
        // otherwise we'll install a new one
 
600
        HBITMAP oldToolBarBitmap = (HBITMAP)m_hBitmap;
 
601
 
 
602
        sizeBmp.x = m_defaultWidth;
 
603
        sizeBmp.y = m_defaultHeight;
 
604
 
 
605
        const wxCoord totalBitmapWidth  = m_defaultWidth *
 
606
                                          wx_truncate_cast(wxCoord, nTools),
 
607
                      totalBitmapHeight = m_defaultHeight;
 
608
 
 
609
        // Create a bitmap and copy all the tool bitmaps to it
 
610
        wxMemoryDC dcAllButtons;
 
611
        wxBitmap bitmap(totalBitmapWidth, totalBitmapHeight);
 
612
        dcAllButtons.SelectObject(bitmap);
 
613
#ifdef __WXWINCE__
 
614
        dcAllButtons.SetBackground(wxBrush(wxColour(192,192,192)));
 
615
#else
 
616
        if (doTransparent)
 
617
            dcAllButtons.SetBackground(*wxTRANSPARENT_BRUSH);
 
618
        else
 
619
            dcAllButtons.SetBackground(wxBrush(GetBackgroundColour()));
 
620
#endif
 
621
        dcAllButtons.Clear();
 
622
 
 
623
        m_hBitmap = bitmap.GetHBITMAP();
 
624
        HBITMAP hBitmap = (HBITMAP)m_hBitmap;
 
625
 
 
626
#ifndef __WXWINCE__
 
627
        if (doRemapBg)
 
628
        {
 
629
            dcAllButtons.SelectObject(wxNullBitmap);
 
630
 
 
631
            // Even if we're not remapping the bitmap
 
632
            // content, we still have to remap the background.
 
633
            hBitmap = (HBITMAP)MapBitmap((WXHBITMAP) hBitmap,
 
634
                totalBitmapWidth, totalBitmapHeight);
 
635
 
 
636
            dcAllButtons.SelectObject(bitmap);
 
637
 
 
638
 
 
639
        }
 
640
#endif // !__WXWINCE__
 
641
 
 
642
        // the button position
 
643
        wxCoord x = 0;
 
644
 
 
645
        // the number of buttons (not separators)
 
646
        int nButtons = 0;
 
647
 
 
648
        CreateDisabledImageList();
 
649
        for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
 
650
        {
 
651
            wxToolBarToolBase *tool = node->GetData();
 
652
            if ( tool->IsButton() )
 
653
            {
 
654
                const wxBitmap& bmp = tool->GetNormalBitmap();
 
655
 
 
656
                const int w = bmp.GetWidth();
 
657
                const int h = bmp.GetHeight();
 
658
 
 
659
                if ( bmp.Ok() )
 
660
                {
 
661
                    int xOffset = wxMax(0, (m_defaultWidth - w)/2);
 
662
                    int yOffset = wxMax(0, (m_defaultHeight - h)/2);
 
663
 
 
664
                    // notice the last parameter: do use mask
 
665
                    dcAllButtons.DrawBitmap(bmp, x + xOffset, yOffset, true);
 
666
                }
 
667
                else
 
668
                {
 
669
                    wxFAIL_MSG( _T("invalid tool button bitmap") );
 
670
                }
 
671
 
 
672
                // also deal with disabled bitmap if we want to use them
 
673
                if ( m_disabledImgList )
 
674
                {
 
675
                    wxBitmap bmpDisabled = tool->GetDisabledBitmap();
 
676
#if wxUSE_IMAGE && wxUSE_WXDIB
 
677
                    if ( !bmpDisabled.Ok() )
 
678
                    {
 
679
                        // no disabled bitmap specified but we still need to
 
680
                        // fill the space in the image list with something, so
 
681
                        // we grey out the normal bitmap
 
682
                        wxImage imgGreyed;
 
683
                        wxCreateGreyedImage(bmp.ConvertToImage(), imgGreyed);
 
684
 
 
685
                        // we need to have light grey background colour for
 
686
                        // MapBitmap() to work correctly
 
687
                        for ( int y = 0; y < h; y++ )
 
688
                        {
 
689
                            for ( int x = 0; x < w; x++ )
 
690
                            {
 
691
                                if ( imgGreyed.IsTransparent(x, y) )
 
692
                                    imgGreyed.SetRGB(x, y,
 
693
                                                     wxLIGHT_GREY->Red(),
 
694
                                                     wxLIGHT_GREY->Green(),
 
695
                                                     wxLIGHT_GREY->Blue());
 
696
                            }
 
697
                        }
 
698
 
 
699
                        bmpDisabled = wxBitmap(imgGreyed);
 
700
                    }
 
701
#endif // wxUSE_IMAGE
 
702
 
 
703
                    MapBitmap(bmpDisabled.GetHBITMAP(), w, h);
 
704
 
 
705
                    m_disabledImgList->Add(bmpDisabled);
 
706
                }
 
707
 
 
708
                // still inc width and number of buttons because otherwise the
 
709
                // subsequent buttons will all be shifted which is rather confusing
 
710
                // (and like this you'd see immediately which bitmap was bad)
 
711
                x += m_defaultWidth;
 
712
                nButtons++;
 
713
            }
 
714
        }
 
715
 
 
716
        dcAllButtons.SelectObject(wxNullBitmap);
 
717
 
 
718
        // don't delete this HBITMAP!
 
719
        bitmap.SetHBITMAP(0);
 
720
 
 
721
        if (doRemap)
 
722
        {
 
723
            // Map to system colours
 
724
            hBitmap = (HBITMAP)MapBitmap((WXHBITMAP) hBitmap,
 
725
                totalBitmapWidth, totalBitmapHeight);
 
726
 
 
727
 
 
728
        }
 
729
 
 
730
        bool addBitmap = true;
 
731
 
 
732
        if ( oldToolBarBitmap )
 
733
        {
 
734
#ifdef TB_REPLACEBITMAP
 
735
            if ( wxApp::GetComCtl32Version() >= 400 )
 
736
            {
 
737
                TBREPLACEBITMAP replaceBitmap;
 
738
                replaceBitmap.hInstOld = NULL;
 
739
                replaceBitmap.hInstNew = NULL;
 
740
                replaceBitmap.nIDOld = (UINT) oldToolBarBitmap;
 
741
                replaceBitmap.nIDNew = (UINT) hBitmap;
 
742
                replaceBitmap.nButtons = nButtons;
 
743
                if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP,
 
744
                                    0, (LPARAM) &replaceBitmap) )
 
745
                {
 
746
                    wxFAIL_MSG(wxT("Could not replace the old bitmap"));
 
747
                }
 
748
 
 
749
                ::DeleteObject(oldToolBarBitmap);
 
750
 
 
751
                // already done
 
752
                addBitmap = false;
 
753
            }
 
754
            else
 
755
#endif // TB_REPLACEBITMAP
 
756
            {
 
757
                // we can't replace the old bitmap, so we will add another one
 
758
                // (awfully inefficient, but what else to do?) and shift the bitmap
 
759
                // indices accordingly
 
760
                addBitmap = true;
 
761
 
 
762
                bitmapId = m_nButtons;
 
763
            }
 
764
        }
 
765
 
 
766
        if ( addBitmap ) // no old bitmap or we can't replace it
 
767
        {
 
768
            TBADDBITMAP addBitmap;
 
769
            addBitmap.hInst = 0;
 
770
            addBitmap.nID = (UINT) hBitmap;
 
771
            if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP,
 
772
                               (WPARAM) nButtons, (LPARAM)&addBitmap) == -1 )
 
773
            {
 
774
                wxFAIL_MSG(wxT("Could not add bitmap to toolbar"));
 
775
            }
 
776
        }
 
777
 
 
778
        if ( m_disabledImgList )
 
779
        {
 
780
            HIMAGELIST oldImageList = (HIMAGELIST)
 
781
                ::SendMessage(GetHwnd(),
 
782
                              TB_SETDISABLEDIMAGELIST,
 
783
                              0,
 
784
                              (LPARAM)GetHimagelistOf(m_disabledImgList));
 
785
 
 
786
            // delete previous image list if any
 
787
            if ( oldImageList )
 
788
                ::DeleteObject( oldImageList );
 
789
        }
 
790
    }
 
791
 
 
792
    // don't call SetToolBitmapSize() as we don't want to change the values of
 
793
    // m_defaultWidth/Height
 
794
    if ( !::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0,
 
795
                        MAKELONG(sizeBmp.x, sizeBmp.y)) )
 
796
    {
 
797
        wxLogLastError(_T("TB_SETBITMAPSIZE"));
 
798
    }
 
799
 
 
800
    // Next add the buttons and separators
 
801
    // -----------------------------------
 
802
 
 
803
    TBBUTTON *buttons = new TBBUTTON[nTools];
 
804
 
 
805
    // this array will hold the indices of all controls in the toolbar
 
806
    wxArrayInt controlIds;
 
807
 
 
808
    bool lastWasRadio = false;
 
809
    int i = 0;
 
810
    for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
 
811
    {
 
812
        wxToolBarToolBase *tool = node->GetData();
 
813
 
 
814
        // don't add separators to the vertical toolbar with old comctl32.dll
 
815
        // versions as they didn't handle this properly
 
816
        if ( isVertical && tool->IsSeparator() &&
 
817
                wxApp::GetComCtl32Version() <= 472 )
 
818
        {
 
819
            continue;
 
820
        }
 
821
 
 
822
 
 
823
        TBBUTTON& button = buttons[i];
 
824
 
 
825
        wxZeroMemory(button);
 
826
 
 
827
        bool isRadio = false;
 
828
        switch ( tool->GetStyle() )
 
829
        {
 
830
            case wxTOOL_STYLE_CONTROL:
 
831
                button.idCommand = tool->GetId();
 
832
                // fall through: create just a separator too
 
833
 
 
834
            case wxTOOL_STYLE_SEPARATOR:
 
835
                button.fsState = TBSTATE_ENABLED;
 
836
                button.fsStyle = TBSTYLE_SEP;
 
837
                break;
 
838
 
 
839
            case wxTOOL_STYLE_BUTTON:
 
840
                if ( !HasFlag(wxTB_NOICONS) )
 
841
                    button.iBitmap = bitmapId;
 
842
 
 
843
                if ( HasFlag(wxTB_TEXT) )
 
844
                {
 
845
                    const wxString& label = tool->GetLabel();
 
846
                    if ( !label.empty() )
 
847
                    {
 
848
                        button.iString = (int)label.c_str();
 
849
                    }
 
850
                }
 
851
 
 
852
                button.idCommand = tool->GetId();
 
853
 
 
854
                if ( tool->IsEnabled() )
 
855
                    button.fsState |= TBSTATE_ENABLED;
 
856
                if ( tool->IsToggled() )
 
857
                    button.fsState |= TBSTATE_CHECKED;
 
858
 
 
859
                switch ( tool->GetKind() )
 
860
                {
 
861
                    case wxITEM_RADIO:
 
862
                        button.fsStyle = TBSTYLE_CHECKGROUP;
 
863
 
 
864
                        if ( !lastWasRadio )
 
865
                        {
 
866
                            // the first item in the radio group is checked by
 
867
                            // default to be consistent with wxGTK and the menu
 
868
                            // radio items
 
869
                            button.fsState |= TBSTATE_CHECKED;
 
870
 
 
871
                            if (tool->Toggle(true))
 
872
                            {
 
873
                                DoToggleTool(tool, true);
 
874
                            }
 
875
                        }
 
876
                        else if (tool->IsToggled())
 
877
                        {
 
878
                            wxToolBarToolsList::compatibility_iterator nodePrev = node->GetPrevious();
 
879
                            int prevIndex = i - 1;
 
880
                            while ( nodePrev )
 
881
                            {
 
882
                                TBBUTTON& prevButton = buttons[prevIndex];
 
883
                                wxToolBarToolBase *tool = nodePrev->GetData();
 
884
                                if ( !tool->IsButton() || tool->GetKind() != wxITEM_RADIO )
 
885
                                    break;
 
886
 
 
887
                                if ( tool->Toggle(false) )
 
888
                                {
 
889
                                    DoToggleTool(tool, false);
 
890
                                }
 
891
                                prevButton.fsState = TBSTATE_ENABLED;
 
892
                                nodePrev = nodePrev->GetPrevious();
 
893
                                prevIndex--;
 
894
                            }
 
895
                        }
 
896
 
 
897
                        isRadio = true;
 
898
                        break;
 
899
 
 
900
                    case wxITEM_CHECK:
 
901
                        button.fsStyle = TBSTYLE_CHECK;
 
902
                        break;
 
903
 
 
904
                    default:
 
905
                        wxFAIL_MSG( _T("unexpected toolbar button kind") );
 
906
                        // fall through
 
907
 
 
908
                    case wxITEM_NORMAL:
 
909
                        button.fsStyle = TBSTYLE_BUTTON;
 
910
                }
 
911
 
 
912
                bitmapId++;
 
913
                break;
 
914
        }
 
915
 
 
916
        lastWasRadio = isRadio;
 
917
 
 
918
        i++;
 
919
    }
 
920
 
 
921
    if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS, (WPARAM)i, (LPARAM)buttons) )
 
922
    {
 
923
        wxLogLastError(wxT("TB_ADDBUTTONS"));
 
924
    }
 
925
 
 
926
    delete [] buttons;
 
927
 
 
928
    // Deal with the controls finally
 
929
    // ------------------------------
 
930
 
 
931
    // adjust the controls size to fit nicely in the toolbar
 
932
    int y = 0;
 
933
    size_t index = 0;
 
934
    for ( node = m_tools.GetFirst(); node; node = node->GetNext(), index++ )
 
935
    {
 
936
        wxToolBarToolBase *tool = node->GetData();
 
937
 
 
938
        // we calculate the running y coord for vertical toolbars so we need to
 
939
        // get the items size for all items but for the horizontal ones we
 
940
        // don't need to deal with the non controls
 
941
        bool isControl = tool->IsControl();
 
942
        if ( !isControl && !isVertical )
 
943
            continue;
 
944
 
 
945
        // note that we use TB_GETITEMRECT and not TB_GETRECT because the
 
946
        // latter only appeared in v4.70 of comctl32.dll
 
947
        RECT r;
 
948
        if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT,
 
949
                            index, (LPARAM)(LPRECT)&r) )
 
950
        {
 
951
            wxLogLastError(wxT("TB_GETITEMRECT"));
 
952
        }
 
953
 
 
954
        if ( !isControl )
 
955
        {
 
956
            // can only be control if isVertical
 
957
            y += r.bottom - r.top;
 
958
 
 
959
            continue;
 
960
        }
 
961
 
 
962
        wxControl *control = tool->GetControl();
 
963
 
 
964
        wxSize size = control->GetSize();
 
965
 
 
966
        // the position of the leftmost controls corner
 
967
        int left = wxDefaultCoord;
 
968
 
 
969
        // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+
 
970
#ifdef TB_SETBUTTONINFO
 
971
        // available in headers, now check whether it is available now
 
972
        // (during run-time)
 
973
        if ( wxApp::GetComCtl32Version() >= 471 )
 
974
        {
 
975
            // set the (underlying) separators width to be that of the
 
976
            // control
 
977
            TBBUTTONINFO tbbi;
 
978
            tbbi.cbSize = sizeof(tbbi);
 
979
            tbbi.dwMask = TBIF_SIZE;
 
980
            tbbi.cx = (WORD)size.x;
 
981
            if ( !::SendMessage(GetHwnd(), TB_SETBUTTONINFO,
 
982
                                tool->GetId(), (LPARAM)&tbbi) )
 
983
            {
 
984
                // the id is probably invalid?
 
985
                wxLogLastError(wxT("TB_SETBUTTONINFO"));
 
986
            }
 
987
        }
 
988
        else
 
989
#endif // comctl32.dll 4.71
 
990
        // TB_SETBUTTONINFO unavailable
 
991
        {
 
992
            // try adding several separators to fit the controls width
 
993
            int widthSep = r.right - r.left;
 
994
            left = r.left;
 
995
 
 
996
            TBBUTTON tbb;
 
997
            wxZeroMemory(tbb);
 
998
            tbb.idCommand = 0;
 
999
            tbb.fsState = TBSTATE_ENABLED;
 
1000
            tbb.fsStyle = TBSTYLE_SEP;
 
1001
 
 
1002
            size_t nSeparators = size.x / widthSep;
 
1003
            for ( size_t nSep = 0; nSep < nSeparators; nSep++ )
 
1004
            {
 
1005
                if ( !::SendMessage(GetHwnd(), TB_INSERTBUTTON,
 
1006
                                    index, (LPARAM)&tbb) )
 
1007
                {
 
1008
                    wxLogLastError(wxT("TB_INSERTBUTTON"));
 
1009
                }
 
1010
 
 
1011
                index++;
 
1012
            }
 
1013
 
 
1014
            // remember the number of separators we used - we'd have to
 
1015
            // delete all of them later
 
1016
            ((wxToolBarTool *)tool)->SetSeparatorsCount(nSeparators);
 
1017
 
 
1018
            // adjust the controls width to exactly cover the separators
 
1019
            control->SetSize((nSeparators + 1)*widthSep, wxDefaultCoord);
 
1020
        }
 
1021
 
 
1022
        // position the control itself correctly vertically
 
1023
        int height = r.bottom - r.top;
 
1024
        int diff = height - size.y;
 
1025
        if ( diff < 0 )
 
1026
        {
 
1027
            // the control is too high, resize to fit
 
1028
            control->SetSize(wxDefaultCoord, height - 2);
 
1029
 
 
1030
            diff = 2;
 
1031
        }
 
1032
 
 
1033
        int top;
 
1034
        if ( isVertical )
 
1035
        {
 
1036
            left = 0;
 
1037
            top = y;
 
1038
 
 
1039
            y += height + 2*GetMargins().y;
 
1040
        }
 
1041
        else // horizontal toolbar
 
1042
        {
 
1043
            if ( left == wxDefaultCoord )
 
1044
                left = r.left;
 
1045
 
 
1046
            top = r.top;
 
1047
        }
 
1048
 
 
1049
        control->Move(left, top + (diff + 1) / 2);
 
1050
    }
 
1051
 
 
1052
    // the max index is the "real" number of buttons - i.e. counting even the
 
1053
    // separators which we added just for aligning the controls
 
1054
    m_nButtons = index;
 
1055
 
 
1056
    if ( !isVertical )
 
1057
    {
 
1058
        if ( m_maxRows == 0 )
 
1059
        {
 
1060
            // if not set yet, only one row
 
1061
            SetRows(1);
 
1062
        }
 
1063
    }
 
1064
    else if ( m_nButtons > 0 ) // vertical non empty toolbar
 
1065
    {
 
1066
        if ( m_maxRows == 0 )
 
1067
        {
 
1068
            // if not set yet, have one column
 
1069
            SetRows(m_nButtons);
 
1070
        }
 
1071
    }
 
1072
 
 
1073
    InvalidateBestSize();
 
1074
    UpdateSize();
 
1075
 
 
1076
    return true;
 
1077
}
 
1078
 
 
1079
// ----------------------------------------------------------------------------
 
1080
// message handlers
 
1081
// ----------------------------------------------------------------------------
 
1082
 
 
1083
bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id)
 
1084
{
 
1085
    wxToolBarToolBase *tool = FindById((int)id);
 
1086
    if ( !tool )
 
1087
        return false;
 
1088
 
 
1089
    bool toggled = false; // just to suppress warnings
 
1090
 
 
1091
    if ( tool->CanBeToggled() )
 
1092
    {
 
1093
        LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0);
 
1094
        toggled = (state & TBSTATE_CHECKED) != 0;
 
1095
 
 
1096
        // ignore the event when a radio button is released, as this doesn't
 
1097
        // seem to happen at all, and is handled otherwise
 
1098
        if ( tool->GetKind() == wxITEM_RADIO && !toggled )
 
1099
            return true;
 
1100
 
 
1101
        tool->Toggle(toggled);
 
1102
        UnToggleRadioGroup(tool);
 
1103
    }
 
1104
 
 
1105
    // OnLeftClick() can veto the button state change - for buttons which
 
1106
    // may be toggled only, of couse
 
1107
    if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() )
 
1108
    {
 
1109
        // revert back
 
1110
        tool->Toggle(!toggled);
 
1111
 
 
1112
        ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(!toggled, 0));
 
1113
    }
 
1114
 
 
1115
    return true;
 
1116
}
 
1117
 
 
1118
bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl),
 
1119
                            WXLPARAM lParam,
 
1120
                            WXLPARAM *WXUNUSED(result))
 
1121
{
 
1122
#if wxUSE_TOOLTIPS
 
1123
    // First check if this applies to us
 
1124
    NMHDR *hdr = (NMHDR *)lParam;
 
1125
 
 
1126
    // the tooltips control created by the toolbar is sometimes Unicode, even
 
1127
    // in an ANSI application - this seems to be a bug in comctl32.dll v5
 
1128
    UINT code = hdr->code;
 
1129
    if ( (code != (UINT) TTN_NEEDTEXTA) && (code != (UINT) TTN_NEEDTEXTW) )
 
1130
        return false;
 
1131
 
 
1132
    HWND toolTipWnd = (HWND)::SendMessage((HWND)GetHWND(), TB_GETTOOLTIPS, 0, 0);
 
1133
    if ( toolTipWnd != hdr->hwndFrom )
 
1134
        return false;
 
1135
 
 
1136
    LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
 
1137
    int id = (int)ttText->hdr.idFrom;
 
1138
 
 
1139
    wxToolBarToolBase *tool = FindById(id);
 
1140
    if ( !tool )
 
1141
        return false;
 
1142
 
 
1143
    return HandleTooltipNotify(code, lParam, tool->GetShortHelp());
 
1144
#else
 
1145
    wxUnusedVar(lParam);
 
1146
 
 
1147
    return false;
 
1148
#endif
 
1149
}
 
1150
 
 
1151
// ----------------------------------------------------------------------------
 
1152
// toolbar geometry
 
1153
// ----------------------------------------------------------------------------
 
1154
 
 
1155
void wxToolBar::SetToolBitmapSize(const wxSize& size)
 
1156
{
 
1157
    wxToolBarBase::SetToolBitmapSize(size);
 
1158
 
 
1159
    ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0, MAKELONG(size.x, size.y));
 
1160
}
 
1161
 
 
1162
void wxToolBar::SetRows(int nRows)
 
1163
{
 
1164
    if ( nRows == m_maxRows )
 
1165
    {
 
1166
        // avoid resizing the frame uselessly
 
1167
        return;
 
1168
    }
 
1169
 
 
1170
    // TRUE in wParam means to create at least as many rows, FALSE -
 
1171
    // at most as many
 
1172
    RECT rect;
 
1173
    ::SendMessage(GetHwnd(), TB_SETROWS,
 
1174
                  MAKEWPARAM(nRows, !(GetWindowStyle() & wxTB_VERTICAL)),
 
1175
                  (LPARAM) &rect);
 
1176
 
 
1177
    m_maxRows = nRows;
 
1178
 
 
1179
    UpdateSize();
 
1180
}
 
1181
 
 
1182
// The button size is bigger than the bitmap size
 
1183
wxSize wxToolBar::GetToolSize() const
 
1184
{
 
1185
    // TB_GETBUTTONSIZE is supported from version 4.70
 
1186
#if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 ) \
 
1187
    && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) ) \
 
1188
    && !defined (__DIGITALMARS__)
 
1189
    if ( wxApp::GetComCtl32Version() >= 470 )
 
1190
    {
 
1191
        DWORD dw = ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE, 0, 0);
 
1192
 
 
1193
        return wxSize(LOWORD(dw), HIWORD(dw));
 
1194
    }
 
1195
    else
 
1196
#endif // comctl32.dll 4.70+
 
1197
    {
 
1198
        // defaults
 
1199
        return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
 
1200
    }
 
1201
}
 
1202
 
 
1203
static
 
1204
wxToolBarToolBase *GetItemSkippingDummySpacers(const wxToolBarToolsList& tools,
 
1205
                                               size_t index )
 
1206
{
 
1207
    wxToolBarToolsList::compatibility_iterator current = tools.GetFirst();
 
1208
 
 
1209
    for ( ; current ; current = current->GetNext() )
 
1210
    {
 
1211
        if ( index == 0 )
 
1212
            return current->GetData();
 
1213
 
 
1214
        wxToolBarTool *tool = (wxToolBarTool *)current->GetData();
 
1215
        size_t separators = tool->GetSeparatorsCount();
 
1216
 
 
1217
        // if it is a normal button, sepcount == 0, so skip 1 item (the button)
 
1218
        // otherwise, skip as many items as the separator count, plus the
 
1219
        // control itself
 
1220
        index -= separators ? separators + 1 : 1;
 
1221
    }
 
1222
 
 
1223
    return 0;
 
1224
}
 
1225
 
 
1226
wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
 
1227
{
 
1228
    POINT pt;
 
1229
    pt.x = x;
 
1230
    pt.y = y;
 
1231
    int index = (int)::SendMessage(GetHwnd(), TB_HITTEST, 0, (LPARAM)&pt);
 
1232
    // MBN: when the point ( x, y ) is close to the toolbar border
 
1233
    //      TB_HITTEST returns m_nButtons ( not -1 )
 
1234
    if ( index < 0 || (size_t)index >= m_nButtons )
 
1235
    {
 
1236
        // it's a separator or there is no tool at all there
 
1237
        return (wxToolBarToolBase *)NULL;
 
1238
    }
 
1239
 
 
1240
    // when TB_SETBUTTONINFO is available (both during compile- and run-time),
 
1241
    // we don't use the dummy separators hack
 
1242
#ifdef TB_SETBUTTONINFO
 
1243
    if ( wxApp::GetComCtl32Version() >= 471 )
 
1244
    {
 
1245
        return m_tools.Item((size_t)index)->GetData();
 
1246
    }
 
1247
    else
 
1248
#endif // TB_SETBUTTONINFO
 
1249
    {
 
1250
        return GetItemSkippingDummySpacers( m_tools, (size_t) index );
 
1251
    }
 
1252
}
 
1253
 
 
1254
void wxToolBar::UpdateSize()
 
1255
{
 
1256
    wxPoint pos = GetPosition();
 
1257
    ::SendMessage(GetHwnd(), TB_AUTOSIZE, 0, 0);
 
1258
    if (pos != GetPosition())
 
1259
        Move(pos);
 
1260
 
 
1261
    // In case Realize is called after the initial display (IOW the programmer
 
1262
    // may have rebuilt the toolbar) give the frame the option of resizing the
 
1263
    // toolbar to full width again, but only if the parent is a frame and the
 
1264
    // toolbar is managed by the frame.  Otherwise assume that some other
 
1265
    // layout mechanism is controlling the toolbar size and leave it alone.
 
1266
    wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
 
1267
    if ( frame && frame->GetToolBar() == this )
 
1268
    {
 
1269
        frame->SendSizeEvent();
 
1270
    }
 
1271
}
 
1272
 
 
1273
// ----------------------------------------------------------------------------
 
1274
// toolbar styles
 
1275
// ---------------------------------------------------------------------------
 
1276
 
 
1277
void wxToolBar::SetWindowStyleFlag(long style)
 
1278
{
 
1279
    // the style bits whose changes force us to recreate the toolbar
 
1280
    static const long MASK_NEEDS_RECREATE = wxTB_TEXT | wxTB_NOICONS;
 
1281
 
 
1282
    const long styleOld = GetWindowStyle();
 
1283
 
 
1284
    wxToolBarBase::SetWindowStyleFlag(style);
 
1285
 
 
1286
    // don't recreate an empty toolbar: not only this is unnecessary, but it is
 
1287
    // also fatal as we'd then try to recreate the toolbar when it's just being
 
1288
    // created
 
1289
    if ( GetToolsCount() &&
 
1290
            (style & MASK_NEEDS_RECREATE) != (styleOld & MASK_NEEDS_RECREATE) )
 
1291
    {
 
1292
        // to remove the text labels, simply re-realizing the toolbar is enough
 
1293
        // but I don't know of any way to add the text to an existing toolbar
 
1294
        // other than by recreating it entirely
 
1295
        Recreate();
 
1296
    }
 
1297
}
 
1298
 
 
1299
// ----------------------------------------------------------------------------
 
1300
// tool state
 
1301
// ----------------------------------------------------------------------------
 
1302
 
 
1303
void wxToolBar::DoEnableTool(wxToolBarToolBase *tool, bool enable)
 
1304
{
 
1305
    ::SendMessage(GetHwnd(), TB_ENABLEBUTTON,
 
1306
                  (WPARAM)tool->GetId(), (LPARAM)MAKELONG(enable, 0));
 
1307
}
 
1308
 
 
1309
void wxToolBar::DoToggleTool(wxToolBarToolBase *tool, bool toggle)
 
1310
{
 
1311
    ::SendMessage(GetHwnd(), TB_CHECKBUTTON,
 
1312
                  (WPARAM)tool->GetId(), (LPARAM)MAKELONG(toggle, 0));
 
1313
}
 
1314
 
 
1315
void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
 
1316
{
 
1317
    // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or
 
1318
    //     without, so we really need to delete the button and recreate it here
 
1319
    wxFAIL_MSG( _T("not implemented") );
 
1320
}
 
1321
 
 
1322
// ----------------------------------------------------------------------------
 
1323
// event handlers
 
1324
// ----------------------------------------------------------------------------
 
1325
 
 
1326
// Responds to colour changes, and passes event on to children.
 
1327
void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent& event)
 
1328
{
 
1329
    wxRGBToColour(m_backgroundColour, ::GetSysColor(COLOR_BTNFACE));
 
1330
 
 
1331
    // Remap the buttons
 
1332
    Realize();
 
1333
 
 
1334
    // Relayout the toolbar
 
1335
    int nrows = m_maxRows;
 
1336
    m_maxRows = 0;      // otherwise SetRows() wouldn't do anything
 
1337
    SetRows(nrows);
 
1338
 
 
1339
    Refresh();
 
1340
 
 
1341
    // let the event propagate further
 
1342
    event.Skip();
 
1343
}
 
1344
 
 
1345
void wxToolBar::OnMouseEvent(wxMouseEvent& event)
 
1346
{
 
1347
    if (event.Leaving() && m_pInTool)
 
1348
    {
 
1349
        OnMouseEnter( -1 );
 
1350
        event.Skip();
 
1351
        return;
 
1352
    }
 
1353
 
 
1354
    if ( event.RightDown() )
 
1355
    {
 
1356
        // find the tool under the mouse
 
1357
        wxCoord x,y;
 
1358
        event.GetPosition(&x, &y);
 
1359
 
 
1360
        wxToolBarToolBase *tool = FindToolForPosition(x, y);
 
1361
        OnRightClick(tool ? tool->GetId() : -1, x, y);
 
1362
    }
 
1363
    else
 
1364
    {
 
1365
        event.Skip();
 
1366
    }
 
1367
}
 
1368
 
 
1369
// This handler is required to allow the toolbar to be set to a non-default
 
1370
// colour: for example, when it must blend in with a notebook page.
 
1371
void wxToolBar::OnEraseBackground(wxEraseEvent& event)
 
1372
{
 
1373
    wxColour bgCol = GetBackgroundColour();
 
1374
    if (!bgCol.Ok())
 
1375
    {
 
1376
        event.Skip();
 
1377
        return;
 
1378
    }
 
1379
 
 
1380
    // notice that this 'dumb' implementation may cause flicker for some of the
 
1381
    // controls in which case they should intercept wxEraseEvent and process it
 
1382
    // themselves somehow
 
1383
 
 
1384
    RECT rect;
 
1385
    ::GetClientRect(GetHwnd(), &rect);
 
1386
 
 
1387
    HBRUSH hBrush = ::CreateSolidBrush(wxColourToRGB(bgCol));
 
1388
 
 
1389
    HDC hdc = GetHdcOf((*event.GetDC()));
 
1390
 
 
1391
#ifndef __WXWINCE__
 
1392
    int mode = ::SetMapMode(hdc, MM_TEXT);
 
1393
#endif
 
1394
 
 
1395
    ::FillRect(hdc, &rect, hBrush);
 
1396
    ::DeleteObject(hBrush);
 
1397
 
 
1398
#ifndef __WXWINCE__
 
1399
    ::SetMapMode(hdc, mode);
 
1400
#endif
 
1401
}
 
1402
 
 
1403
bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
 
1404
{
 
1405
    // calculate our minor dimension ourselves - we're confusing the standard
 
1406
    // logic (TB_AUTOSIZE) with our horizontal toolbars and other hacks
 
1407
    RECT r;
 
1408
    if ( ::SendMessage(GetHwnd(), TB_GETITEMRECT, 0, (LPARAM)&r) )
 
1409
    {
 
1410
        int w, h;
 
1411
 
 
1412
        if ( GetWindowStyle() & wxTB_VERTICAL )
 
1413
        {
 
1414
            w = r.right - r.left;
 
1415
            if ( m_maxRows )
 
1416
            {
 
1417
                w *= (m_nButtons + m_maxRows - 1)/m_maxRows;
 
1418
            }
 
1419
            h = HIWORD(lParam);
 
1420
        }
 
1421
        else
 
1422
        {
 
1423
            w = LOWORD(lParam);
 
1424
            if (HasFlag( wxTB_FLAT ))
 
1425
                h = r.bottom - r.top - 3;
 
1426
            else
 
1427
                h = r.bottom - r.top;
 
1428
            if ( m_maxRows )
 
1429
            {
 
1430
                // FIXME: hardcoded separator line height...
 
1431
                h += HasFlag(wxTB_NODIVIDER) ? 4 : 6;
 
1432
                h *= m_maxRows;
 
1433
            }
 
1434
        }
 
1435
 
 
1436
        if ( MAKELPARAM(w, h) != lParam )
 
1437
        {
 
1438
            // size really changed
 
1439
            SetSize(w, h);
 
1440
        }
 
1441
 
 
1442
        // message processed
 
1443
        return true;
 
1444
    }
 
1445
 
 
1446
    return false;
 
1447
}
 
1448
 
 
1449
bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam)
 
1450
{
 
1451
    // erase any dummy separators which we used for aligning the controls if
 
1452
    // any here
 
1453
 
 
1454
    // first of all, do we have any controls at all?
 
1455
    wxToolBarToolsList::compatibility_iterator node;
 
1456
    for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
 
1457
    {
 
1458
        if ( node->GetData()->IsControl() )
 
1459
            break;
 
1460
    }
 
1461
 
 
1462
    if ( !node )
 
1463
    {
 
1464
        // no controls, nothing to erase
 
1465
        return false;
 
1466
    }
 
1467
 
 
1468
    // prepare the DC on which we'll be drawing
 
1469
    wxClientDC dc(this);
 
1470
    dc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID));
 
1471
    dc.SetPen(*wxTRANSPARENT_PEN);
 
1472
 
 
1473
    RECT r;
 
1474
    if ( !::GetUpdateRect(GetHwnd(), &r, FALSE) )
 
1475
    {
 
1476
        // nothing to redraw anyhow
 
1477
        return false;
 
1478
    }
 
1479
 
 
1480
    wxRect rectUpdate;
 
1481
    wxCopyRECTToRect(r, rectUpdate);
 
1482
 
 
1483
    dc.SetClippingRegion(rectUpdate);
 
1484
 
 
1485
    // draw the toolbar tools, separators &c normally
 
1486
    wxControl::MSWWindowProc(WM_PAINT, wParam, lParam);
 
1487
 
 
1488
    // for each control in the toolbar find all the separators intersecting it
 
1489
    // and erase them
 
1490
    //
 
1491
    // NB: this is really the only way to do it as we don't know if a separator
 
1492
    //     corresponds to a control (i.e. is a dummy one) or a real one
 
1493
    //     otherwise
 
1494
    for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
 
1495
    {
 
1496
        wxToolBarToolBase *tool = node->GetData();
 
1497
        if ( tool->IsControl() )
 
1498
        {
 
1499
            // get the control rect in our client coords
 
1500
            wxControl *control = tool->GetControl();
 
1501
            wxRect rectCtrl = control->GetRect();
 
1502
 
 
1503
            // iterate over all buttons
 
1504
            TBBUTTON tbb;
 
1505
            int count = ::SendMessage(GetHwnd(), TB_BUTTONCOUNT, 0, 0);
 
1506
            for ( int n = 0; n < count; n++ )
 
1507
            {
 
1508
                // is it a separator?
 
1509
                if ( !::SendMessage(GetHwnd(), TB_GETBUTTON,
 
1510
                                    n, (LPARAM)&tbb) )
 
1511
                {
 
1512
                    wxLogDebug(_T("TB_GETBUTTON failed?"));
 
1513
 
 
1514
                    continue;
 
1515
                }
 
1516
 
 
1517
                if ( tbb.fsStyle != TBSTYLE_SEP )
 
1518
                    continue;
 
1519
 
 
1520
                // get the bounding rect of the separator
 
1521
                RECT r;
 
1522
                if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT,
 
1523
                                    n, (LPARAM)&r) )
 
1524
                {
 
1525
                    wxLogDebug(_T("TB_GETITEMRECT failed?"));
 
1526
 
 
1527
                    continue;
 
1528
                }
 
1529
 
 
1530
                // does it intersect the control?
 
1531
                wxRect rectItem;
 
1532
                wxCopyRECTToRect(r, rectItem);
 
1533
                if ( rectCtrl.Intersects(rectItem) )
 
1534
                {
 
1535
                    // yes, do erase it!
 
1536
                    dc.DrawRectangle(rectItem);
 
1537
 
 
1538
                    // Necessary in case we use a no-paint-on-size
 
1539
                    // style in the parent: the controls can disappear
 
1540
                    control->Refresh(false);
 
1541
                }
 
1542
            }
 
1543
        }
 
1544
    }
 
1545
 
 
1546
    return true;
 
1547
}
 
1548
 
 
1549
void wxToolBar::HandleMouseMove(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
 
1550
{
 
1551
    wxCoord x = GET_X_LPARAM(lParam),
 
1552
            y = GET_Y_LPARAM(lParam);
 
1553
    wxToolBarToolBase* tool = FindToolForPosition( x, y );
 
1554
 
 
1555
    // cursor left current tool
 
1556
    if( tool != m_pInTool && !tool )
 
1557
    {
 
1558
        m_pInTool = 0;
 
1559
        OnMouseEnter( -1 );
 
1560
    }
 
1561
 
 
1562
    // cursor entered a tool
 
1563
    if( tool != m_pInTool && tool )
 
1564
    {
 
1565
        m_pInTool = tool;
 
1566
        OnMouseEnter( tool->GetId() );
 
1567
    }
 
1568
}
 
1569
 
 
1570
WXLRESULT wxToolBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
 
1571
{
 
1572
    switch ( nMsg )
 
1573
    {
 
1574
        case WM_MOUSEMOVE:
 
1575
            // we don't handle mouse moves, so always pass the message to
 
1576
            // wxControl::MSWWindowProc (HandleMouseMove just calls OnMouseEnter)
 
1577
            HandleMouseMove(wParam, lParam);
 
1578
            break;
 
1579
 
 
1580
        case WM_SIZE:
 
1581
            if ( HandleSize(wParam, lParam) )
 
1582
                return 0;
 
1583
            break;
 
1584
 
 
1585
#ifndef __WXWINCE__
 
1586
        case WM_PAINT:
 
1587
            if ( HandlePaint(wParam, lParam) )
 
1588
                return 0;
 
1589
#endif
 
1590
    }
 
1591
 
 
1592
    return wxControl::MSWWindowProc(nMsg, wParam, lParam);
 
1593
}
 
1594
 
 
1595
// ----------------------------------------------------------------------------
 
1596
// private functions
 
1597
// ----------------------------------------------------------------------------
 
1598
 
 
1599
WXHBITMAP wxToolBar::MapBitmap(WXHBITMAP bitmap, int width, int height)
 
1600
{
 
1601
    MemoryHDC hdcMem;
 
1602
 
 
1603
    if ( !hdcMem )
 
1604
    {
 
1605
        wxLogLastError(_T("CreateCompatibleDC"));
 
1606
 
 
1607
        return bitmap;
 
1608
    }
 
1609
 
 
1610
    SelectInHDC bmpInHDC(hdcMem, (HBITMAP)bitmap);
 
1611
 
 
1612
    if ( !bmpInHDC )
 
1613
    {
 
1614
        wxLogLastError(_T("SelectObject"));
 
1615
 
 
1616
        return bitmap;
 
1617
    }
 
1618
 
 
1619
    wxCOLORMAP *cmap = wxGetStdColourMap();
 
1620
 
 
1621
    for ( int i = 0; i < width; i++ )
 
1622
    {
 
1623
        for ( int j = 0; j < height; j++ )
 
1624
        {
 
1625
            COLORREF pixel = ::GetPixel(hdcMem, i, j);
 
1626
 
 
1627
            for ( size_t k = 0; k < wxSTD_COL_MAX; k++ )
 
1628
            {
 
1629
                COLORREF col = cmap[k].from;
 
1630
                if ( abs(GetRValue(pixel) - GetRValue(col)) < 10 &&
 
1631
                     abs(GetGValue(pixel) - GetGValue(col)) < 10 &&
 
1632
                     abs(GetBValue(pixel) - GetBValue(col)) < 10 )
 
1633
                {
 
1634
                    ::SetPixel(hdcMem, i, j, cmap[k].to);
 
1635
                    break;
 
1636
                }
 
1637
            }
 
1638
        }
 
1639
    }
 
1640
 
 
1641
    return bitmap;
 
1642
 
 
1643
    // VZ: I leave here my attempts to map the bitmap to the system colours
 
1644
    //     faster by using BitBlt() even though it's broken currently - but
 
1645
    //     maybe someone else can finish it? It should be faster than iterating
 
1646
    //     over all pixels...
 
1647
#if 0
 
1648
    MemoryHDC hdcMask, hdcDst;
 
1649
    if ( !hdcMask || !hdcDst )
 
1650
    {
 
1651
        wxLogLastError(_T("CreateCompatibleDC"));
 
1652
 
 
1653
        return bitmap;
 
1654
    }
 
1655
 
 
1656
    // create the target bitmap
 
1657
    HBITMAP hbmpDst = ::CreateCompatibleBitmap(hdcDst, width, height);
 
1658
    if ( !hbmpDst )
 
1659
    {
 
1660
        wxLogLastError(_T("CreateCompatibleBitmap"));
 
1661
 
 
1662
        return bitmap;
 
1663
    }
 
1664
 
 
1665
    // create the monochrome mask bitmap
 
1666
    HBITMAP hbmpMask = ::CreateBitmap(width, height, 1, 1, 0);
 
1667
    if ( !hbmpMask )
 
1668
    {
 
1669
        wxLogLastError(_T("CreateBitmap(mono)"));
 
1670
 
 
1671
        ::DeleteObject(hbmpDst);
 
1672
 
 
1673
        return bitmap;
 
1674
    }
 
1675
 
 
1676
    SelectInHDC bmpInDst(hdcDst, hbmpDst),
 
1677
                bmpInMask(hdcMask, hbmpMask);
 
1678
 
 
1679
    // for each colour:
 
1680
    for ( n = 0; n < NUM_OF_MAPPED_COLOURS; n++ )
 
1681
    {
 
1682
        // create the mask for this colour
 
1683
        ::SetBkColor(hdcMem, ColorMap[n].from);
 
1684
        ::BitBlt(hdcMask, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
 
1685
 
 
1686
        // replace this colour with the target one in the dst bitmap
 
1687
        HBRUSH hbr = ::CreateSolidBrush(ColorMap[n].to);
 
1688
        HGDIOBJ hbrOld = ::SelectObject(hdcDst, hbr);
 
1689
 
 
1690
        ::MaskBlt(hdcDst, 0, 0, width, height,
 
1691
                  hdcMem, 0, 0,
 
1692
                  hbmpMask, 0, 0,
 
1693
                  MAKEROP4(PATCOPY, SRCCOPY));
 
1694
 
 
1695
        (void)::SelectObject(hdcDst, hbrOld);
 
1696
        ::DeleteObject(hbr);
 
1697
    }
 
1698
 
 
1699
    ::DeleteObject((HBITMAP)bitmap);
 
1700
 
 
1701
    return (WXHBITMAP)hbmpDst;
 
1702
#endif // 0
 
1703
}
 
1704
 
 
1705
#endif // wxUSE_TOOLBAR && Win95
 
1706