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

« back to all changes in this revision

Viewing changes to src/msw/notebook.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:        src/msw/notebook.cpp
 
3
// Purpose:     implementation of wxNotebook
 
4
// Author:      Vadim Zeitlin
 
5
// Modified by:
 
6
// Created:     11.06.98
 
7
// RCS-ID:      $Id: notebook.cpp,v 1.159.2.4 2006/02/11 15:41:24 JS Exp $
 
8
// Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
 
9
// Licence:     wxWindows licence
 
10
///////////////////////////////////////////////////////////////////////////////
 
11
 
 
12
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
 
13
#pragma implementation "notebook.h"
 
14
#endif
 
15
 
 
16
// For compilers that support precompilation, includes "wx.h".
 
17
#include "wx/wxprec.h"
 
18
 
 
19
#ifdef __BORLANDC__
 
20
    #pragma hdrstop
 
21
#endif
 
22
 
 
23
#if wxUSE_NOTEBOOK
 
24
 
 
25
// wxWidgets
 
26
#ifndef WX_PRECOMP
 
27
  #include  "wx/string.h"
 
28
  #include  "wx/dc.h"
 
29
#endif  // WX_PRECOMP
 
30
 
 
31
#include  "wx/log.h"
 
32
#include  "wx/imaglist.h"
 
33
#include  "wx/event.h"
 
34
#include  "wx/control.h"
 
35
#include  "wx/notebook.h"
 
36
#include  "wx/app.h"
 
37
#include  "wx/sysopt.h"
 
38
#include  "wx/dcclient.h"
 
39
#include  "wx/dcmemory.h"
 
40
 
 
41
#include  "wx/msw/private.h"
 
42
 
 
43
#include  <windowsx.h>
 
44
 
 
45
#include <commctrl.h>
 
46
 
 
47
#include "wx/msw/winundef.h"
 
48
 
 
49
#if wxUSE_UXTHEME
 
50
    #include "wx/msw/uxtheme.h"
 
51
#endif
 
52
 
 
53
// ----------------------------------------------------------------------------
 
54
// macros
 
55
// ----------------------------------------------------------------------------
 
56
 
 
57
// check that the page index is valid
 
58
#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount())
 
59
 
 
60
// you can set USE_NOTEBOOK_ANTIFLICKER to 0 for desktop Windows versions too
 
61
// to disable code whih results in flicker-less notebook redrawing at the
 
62
// expense of some extra GDI resource consumption
 
63
#ifdef __WXWINCE__
 
64
    // notebooks are never resized under CE anyhow
 
65
    #define USE_NOTEBOOK_ANTIFLICKER    0
 
66
#else
 
67
    #define USE_NOTEBOOK_ANTIFLICKER    1
 
68
#endif
 
69
 
 
70
// ----------------------------------------------------------------------------
 
71
// constants
 
72
// ----------------------------------------------------------------------------
 
73
 
 
74
// This is a work-around for missing defines in gcc-2.95 headers
 
75
#ifndef TCS_RIGHT
 
76
    #define TCS_RIGHT       0x0002
 
77
#endif
 
78
 
 
79
#ifndef TCS_VERTICAL
 
80
    #define TCS_VERTICAL    0x0080
 
81
#endif
 
82
 
 
83
#ifndef TCS_BOTTOM
 
84
    #define TCS_BOTTOM      TCS_RIGHT
 
85
#endif
 
86
 
 
87
// ----------------------------------------------------------------------------
 
88
// global variables
 
89
// ----------------------------------------------------------------------------
 
90
 
 
91
#if USE_NOTEBOOK_ANTIFLICKER
 
92
 
 
93
// the pointer to standard spin button wnd proc
 
94
static WXFARPROC gs_wndprocNotebookSpinBtn = (WXFARPROC)NULL;
 
95
 
 
96
// the pointer to standard tab control wnd proc
 
97
static WXFARPROC gs_wndprocNotebook = (WXFARPROC)NULL;
 
98
 
 
99
LRESULT APIENTRY _EXPORT wxNotebookWndProc(HWND hwnd,
 
100
                                           UINT message,
 
101
                                           WPARAM wParam,
 
102
                                           LPARAM lParam);
 
103
 
 
104
#endif // USE_NOTEBOOK_ANTIFLICKER
 
105
 
 
106
// ----------------------------------------------------------------------------
 
107
// event table
 
108
// ----------------------------------------------------------------------------
 
109
 
 
110
#include <wx/listimpl.cpp>
 
111
 
 
112
WX_DEFINE_LIST( wxNotebookPageInfoList ) ;
 
113
 
 
114
DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED)
 
115
DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING)
 
116
 
 
117
BEGIN_EVENT_TABLE(wxNotebook, wxControl)
 
118
    EVT_NOTEBOOK_PAGE_CHANGED(-1, wxNotebook::OnSelChange)
 
119
    EVT_SIZE(wxNotebook::OnSize)
 
120
    EVT_NAVIGATION_KEY(wxNotebook::OnNavigationKey)
 
121
 
 
122
#if USE_NOTEBOOK_ANTIFLICKER
 
123
    EVT_ERASE_BACKGROUND(wxNotebook::OnEraseBackground)
 
124
    EVT_PAINT(wxNotebook::OnPaint)
 
125
#endif // USE_NOTEBOOK_ANTIFLICKER
 
126
END_EVENT_TABLE()
 
127
 
 
128
#if wxUSE_EXTENDED_RTTI
 
129
WX_DEFINE_FLAGS( wxNotebookStyle )
 
130
 
 
131
wxBEGIN_FLAGS( wxNotebookStyle )
 
132
    // new style border flags, we put them first to
 
133
    // use them for streaming out
 
134
    wxFLAGS_MEMBER(wxBORDER_SIMPLE)
 
135
    wxFLAGS_MEMBER(wxBORDER_SUNKEN)
 
136
    wxFLAGS_MEMBER(wxBORDER_DOUBLE)
 
137
    wxFLAGS_MEMBER(wxBORDER_RAISED)
 
138
    wxFLAGS_MEMBER(wxBORDER_STATIC)
 
139
    wxFLAGS_MEMBER(wxBORDER_NONE)
 
140
 
 
141
    // old style border flags
 
142
    wxFLAGS_MEMBER(wxSIMPLE_BORDER)
 
143
    wxFLAGS_MEMBER(wxSUNKEN_BORDER)
 
144
    wxFLAGS_MEMBER(wxDOUBLE_BORDER)
 
145
    wxFLAGS_MEMBER(wxRAISED_BORDER)
 
146
    wxFLAGS_MEMBER(wxSTATIC_BORDER)
 
147
    wxFLAGS_MEMBER(wxBORDER)
 
148
 
 
149
    // standard window styles
 
150
    wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
 
151
    wxFLAGS_MEMBER(wxCLIP_CHILDREN)
 
152
    wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
 
153
    wxFLAGS_MEMBER(wxWANTS_CHARS)
 
154
    wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
 
155
    wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
 
156
    wxFLAGS_MEMBER(wxVSCROLL)
 
157
    wxFLAGS_MEMBER(wxHSCROLL)
 
158
 
 
159
    wxFLAGS_MEMBER(wxNB_FIXEDWIDTH)
 
160
    wxFLAGS_MEMBER(wxNB_LEFT)
 
161
    wxFLAGS_MEMBER(wxNB_RIGHT)
 
162
    wxFLAGS_MEMBER(wxNB_BOTTOM)
 
163
    wxFLAGS_MEMBER(wxNB_NOPAGETHEME)
 
164
    wxFLAGS_MEMBER(wxNB_FLAT)
 
165
 
 
166
wxEND_FLAGS( wxNotebookStyle )
 
167
 
 
168
IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebook, wxControl,"wx/notebook.h")
 
169
IMPLEMENT_DYNAMIC_CLASS_XTI(wxNotebookPageInfo, wxObject , "wx/notebook.h" )
 
170
 
 
171
wxCOLLECTION_TYPE_INFO( wxNotebookPageInfo * , wxNotebookPageInfoList ) ;
 
172
 
 
173
template<> void wxCollectionToVariantArray( wxNotebookPageInfoList const &theList, wxxVariantArray &value)
 
174
{
 
175
    wxListCollectionToVariantArray<wxNotebookPageInfoList::compatibility_iterator>( theList , value ) ;
 
176
}
 
177
 
 
178
wxBEGIN_PROPERTIES_TABLE(wxNotebook)
 
179
    wxEVENT_PROPERTY( PageChanging , wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING , wxNotebookEvent )
 
180
    wxEVENT_PROPERTY( PageChanged , wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED , wxNotebookEvent )
 
181
 
 
182
    wxPROPERTY_COLLECTION( PageInfos , wxNotebookPageInfoList , wxNotebookPageInfo* , AddPageInfo , GetPageInfos , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
 
183
    wxPROPERTY_FLAGS( WindowStyle , wxNotebookStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
 
184
wxEND_PROPERTIES_TABLE()
 
185
 
 
186
wxBEGIN_HANDLERS_TABLE(wxNotebook)
 
187
wxEND_HANDLERS_TABLE()
 
188
 
 
189
wxCONSTRUCTOR_5( wxNotebook , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle)
 
190
 
 
191
 
 
192
wxBEGIN_PROPERTIES_TABLE(wxNotebookPageInfo)
 
193
    wxREADONLY_PROPERTY( Page , wxNotebookPage* , GetPage , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
 
194
    wxREADONLY_PROPERTY( Text , wxString , GetText , wxString() , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
 
195
    wxREADONLY_PROPERTY( Selected , bool , GetSelected , false, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
 
196
    wxREADONLY_PROPERTY( ImageId , int , GetImageId , -1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
 
197
wxEND_PROPERTIES_TABLE()
 
198
 
 
199
wxBEGIN_HANDLERS_TABLE(wxNotebookPageInfo)
 
200
wxEND_HANDLERS_TABLE()
 
201
 
 
202
wxCONSTRUCTOR_4( wxNotebookPageInfo , wxNotebookPage* , Page , wxString , Text , bool , Selected , int , ImageId )
 
203
 
 
204
#else
 
205
IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxControl)
 
206
IMPLEMENT_DYNAMIC_CLASS(wxNotebookPageInfo, wxObject )
 
207
#endif
 
208
IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxNotifyEvent)
 
209
 
 
210
// ============================================================================
 
211
// implementation
 
212
// ============================================================================
 
213
 
 
214
// ----------------------------------------------------------------------------
 
215
// wxNotebook construction
 
216
// ----------------------------------------------------------------------------
 
217
 
 
218
const wxNotebookPageInfoList& wxNotebook::GetPageInfos() const
 
219
{
 
220
    wxNotebookPageInfoList* list = const_cast< wxNotebookPageInfoList* >( &m_pageInfos ) ;
 
221
    WX_CLEAR_LIST( wxNotebookPageInfoList , *list ) ;
 
222
    for( size_t i = 0 ; i < GetPageCount() ; ++i )
 
223
    {
 
224
        wxNotebookPageInfo *info = new wxNotebookPageInfo() ;
 
225
        info->Create( const_cast<wxNotebook*>(this)->GetPage(i) , GetPageText(i) , GetSelection() == int(i) , GetPageImage(i) ) ;
 
226
        list->Append( info ) ;
 
227
    }
 
228
    return m_pageInfos ;
 
229
}
 
230
 
 
231
// common part of all ctors
 
232
void wxNotebook::Init()
 
233
{
 
234
  m_imageList = NULL;
 
235
  m_nSelection = -1;
 
236
 
 
237
#if wxUSE_UXTHEME
 
238
  m_hbrBackground = NULL;
 
239
#endif // wxUSE_UXTHEME
 
240
 
 
241
#if USE_NOTEBOOK_ANTIFLICKER
 
242
  m_hasSubclassedUpdown = false;
 
243
#endif // USE_NOTEBOOK_ANTIFLICKER
 
244
}
 
245
 
 
246
// default for dynamic class
 
247
wxNotebook::wxNotebook()
 
248
{
 
249
  Init();
 
250
}
 
251
 
 
252
// the same arguments as for wxControl
 
253
wxNotebook::wxNotebook(wxWindow *parent,
 
254
                       wxWindowID id,
 
255
                       const wxPoint& pos,
 
256
                       const wxSize& size,
 
257
                       long style,
 
258
                       const wxString& name)
 
259
{
 
260
  Init();
 
261
 
 
262
  Create(parent, id, pos, size, style, name);
 
263
}
 
264
 
 
265
// Create() function
 
266
bool wxNotebook::Create(wxWindow *parent,
 
267
                        wxWindowID id,
 
268
                        const wxPoint& pos,
 
269
                        const wxSize& size,
 
270
                        long style,
 
271
                        const wxString& name)
 
272
{
 
273
#ifdef __WXWINCE__
 
274
    // Not sure why, but without this style, there is no border
 
275
    // around the notebook tabs.
 
276
    if (style & wxNB_FLAT)
 
277
        style |= wxBORDER_SUNKEN;
 
278
#endif
 
279
 
 
280
#if !wxUSE_UXTHEME 
 
281
    // ComCtl32 notebook tabs simply don't work unless they're on top if we have uxtheme, we can
 
282
    // work around it later (after control creation), but if we don't have uxtheme, we have to clear
 
283
    // those styles
 
284
    const int verComCtl32 = wxApp::GetComCtl32Version();
 
285
    if ( verComCtl32 == 600 )
 
286
    {
 
287
        style &= ~(wxNB_BOTTOM | wxNB_LEFT | wxNB_RIGHT);
 
288
    }
 
289
#endif //wxUSE_UXTHEME
 
290
 
 
291
    LPCTSTR className = WC_TABCONTROL;
 
292
 
 
293
#if USE_NOTEBOOK_ANTIFLICKER
 
294
    // SysTabCtl32 class has natively CS_HREDRAW and CS_VREDRAW enabled and it
 
295
    // causes horrible flicker when resizing notebook, so get rid of it by
 
296
    // using a class without these styles (but otherwise identical to it)
 
297
    if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
 
298
    {
 
299
        static ClassRegistrar s_clsNotebook;
 
300
        if ( !s_clsNotebook.IsInitialized() )
 
301
        {
 
302
            // get a copy of standard class and modify it
 
303
            WNDCLASS wc;
 
304
 
 
305
            if ( ::GetClassInfo(NULL, WC_TABCONTROL, &wc) )
 
306
            {
 
307
                gs_wndprocNotebook =
 
308
                    wx_reinterpret_cast(WXFARPROC, wc.lpfnWndProc);
 
309
                wc.lpszClassName = wxT("_wx_SysTabCtl32");
 
310
                wc.style &= ~(CS_HREDRAW | CS_VREDRAW);
 
311
                wc.hInstance = wxGetInstance();
 
312
                wc.lpfnWndProc = wxNotebookWndProc;
 
313
                s_clsNotebook.Register(wc);
 
314
            }
 
315
            else
 
316
            {
 
317
                wxLogLastError(_T("GetClassInfoEx(SysTabCtl32)"));
 
318
            }
 
319
        }
 
320
 
 
321
        // use our custom class if available but fall back to the standard
 
322
        // notebook if we failed to register it
 
323
        if ( s_clsNotebook.IsRegistered() )
 
324
        {
 
325
            // it's ok to use c_str() here as the static s_clsNotebook object
 
326
            // has sufficiently long lifetime
 
327
            className = s_clsNotebook.GetName().c_str();
 
328
        }
 
329
    }
 
330
#endif // USE_NOTEBOOK_ANTIFLICKER
 
331
 
 
332
    if ( !CreateControl(parent, id, pos, size, style | wxTAB_TRAVERSAL,
 
333
                        wxDefaultValidator, name) )
 
334
        return false;
 
335
 
 
336
    if ( !MSWCreateControl(className, wxEmptyString, pos, size) )
 
337
        return false;
 
338
 
 
339
#if wxUSE_UXTHEME
 
340
    if ( HasFlag(wxNB_NOPAGETHEME) ||
 
341
            wxSystemOptions::IsFalse(wxT("msw.notebook.themed-background")) )
 
342
    {
 
343
        SetBackgroundColour(GetThemeBackgroundColour());
 
344
    }
 
345
    else // use themed background by default
 
346
    {
 
347
        // create backing store
 
348
        UpdateBgBrush();
 
349
    }
 
350
    
 
351
    // comctl32.dll 6.0 doesn't support non-top tabs with visual styles (the
 
352
    // control is simply not rendered correctly), so we disable themes
 
353
    // if possible, otherwise we simply clear the styles.
 
354
    // It's probably not possible to have UXTHEME without ComCtl32 6 or better, but lets
 
355
    // check it anyway.
 
356
    const int verComCtl32 = wxApp::GetComCtl32Version();
 
357
    if ( verComCtl32 == 600 ) 
 
358
    {
 
359
        // check if we use themes at all -- if we don't, we're still okay
 
360
        if ( wxUxThemeEngine::GetIfActive() && (style & (wxNB_BOTTOM|wxNB_LEFT|wxNB_RIGHT)))
 
361
        {
 
362
            wxUxThemeEngine::GetIfActive()->SetWindowTheme((HWND)this->GetHandle(), L"", L"");
 
363
            SetBackgroundColour(GetThemeBackgroundColour());    //correct the background color for the new non-themed control
 
364
        }
 
365
    }
 
366
#endif // wxUSE_UXTHEME
 
367
 
 
368
    // Undocumented hack to get flat notebook style
 
369
    // In fact, we should probably only do this in some
 
370
    // curcumstances, i.e. if we know we will have a border
 
371
    // at the bottom (the tab control doesn't draw it itself)
 
372
#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
 
373
    if (HasFlag(wxNB_FLAT))
 
374
    {
 
375
        SendMessage(GetHwnd(), CCM_SETVERSION, COMCTL32_VERSION, 0);
 
376
        if (!m_hasBgCol)
 
377
            SetBackgroundColour(*wxWHITE);
 
378
    }
 
379
#endif
 
380
    return true;
 
381
}
 
382
 
 
383
WXDWORD wxNotebook::MSWGetStyle(long style, WXDWORD *exstyle) const
 
384
{
 
385
    WXDWORD tabStyle = wxControl::MSWGetStyle(style, exstyle);
 
386
 
 
387
    tabStyle |= WS_TABSTOP | TCS_TABS;
 
388
 
 
389
    if ( style & wxNB_MULTILINE )
 
390
        tabStyle |= TCS_MULTILINE;
 
391
    if ( style & wxNB_FIXEDWIDTH )
 
392
        tabStyle |= TCS_FIXEDWIDTH;
 
393
 
 
394
    if ( style & wxNB_BOTTOM )
 
395
        tabStyle |= TCS_RIGHT;
 
396
    else if ( style & wxNB_LEFT )
 
397
        tabStyle |= TCS_VERTICAL;
 
398
    else if ( style & wxNB_RIGHT )
 
399
        tabStyle |= TCS_VERTICAL | TCS_RIGHT;
 
400
 
 
401
    // ex style
 
402
    if ( exstyle )
 
403
    {
 
404
        // note that we never want to have the default WS_EX_CLIENTEDGE style
 
405
        // as it looks too ugly for the notebooks
 
406
        *exstyle = 0;
 
407
    }
 
408
 
 
409
    return tabStyle;
 
410
}
 
411
 
 
412
wxNotebook::~wxNotebook()
 
413
{
 
414
#if wxUSE_UXTHEME
 
415
    if ( m_hbrBackground )
 
416
        ::DeleteObject((HBRUSH)m_hbrBackground);
 
417
#endif // wxUSE_UXTHEME
 
418
}
 
419
 
 
420
// ----------------------------------------------------------------------------
 
421
// wxNotebook accessors
 
422
// ----------------------------------------------------------------------------
 
423
 
 
424
size_t wxNotebook::GetPageCount() const
 
425
{
 
426
  // consistency check
 
427
  wxASSERT( (int)m_pages.Count() == TabCtrl_GetItemCount(GetHwnd()) );
 
428
 
 
429
  return m_pages.Count();
 
430
}
 
431
 
 
432
int wxNotebook::GetRowCount() const
 
433
{
 
434
  return TabCtrl_GetRowCount(GetHwnd());
 
435
}
 
436
 
 
437
int wxNotebook::SetSelection(size_t nPage)
 
438
{
 
439
  wxCHECK_MSG( IS_VALID_PAGE(nPage), wxNOT_FOUND, wxT("notebook page out of range") );
 
440
 
 
441
  if ( int(nPage) != m_nSelection )
 
442
  {
 
443
    wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, m_windowId);
 
444
    event.SetSelection(nPage);
 
445
    event.SetOldSelection(m_nSelection);
 
446
    event.SetEventObject(this);
 
447
    if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
 
448
    {
 
449
      // program allows the page change
 
450
      event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
 
451
      (void)GetEventHandler()->ProcessEvent(event);
 
452
 
 
453
      TabCtrl_SetCurSel(GetHwnd(), nPage);
 
454
    }
 
455
  }
 
456
 
 
457
  return m_nSelection;
 
458
}
 
459
 
 
460
bool wxNotebook::SetPageText(size_t nPage, const wxString& strText)
 
461
{
 
462
    wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
 
463
 
 
464
    TC_ITEM tcItem;
 
465
    tcItem.mask = TCIF_TEXT;
 
466
    tcItem.pszText = (wxChar *)strText.c_str();
 
467
 
 
468
    if ( !HasFlag(wxNB_MULTILINE) )
 
469
        return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
 
470
 
 
471
    // multiline - we need to set new page size if a line is added or removed
 
472
    int rows = GetRowCount();
 
473
    bool ret = TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
 
474
 
 
475
    if ( ret && rows != GetRowCount() )
 
476
    {
 
477
        const wxRect r = GetPageSize();
 
478
        const size_t count = m_pages.Count();
 
479
        for ( size_t page = 0; page < count; page++ )
 
480
            m_pages[page]->SetSize(r);
 
481
    }
 
482
 
 
483
    return ret;
 
484
}
 
485
 
 
486
wxString wxNotebook::GetPageText(size_t nPage) const
 
487
{
 
488
  wxCHECK_MSG( IS_VALID_PAGE(nPage), wxEmptyString, wxT("notebook page out of range") );
 
489
 
 
490
  wxChar buf[256];
 
491
  TC_ITEM tcItem;
 
492
  tcItem.mask = TCIF_TEXT;
 
493
  tcItem.pszText = buf;
 
494
  tcItem.cchTextMax = WXSIZEOF(buf);
 
495
 
 
496
  wxString str;
 
497
  if ( TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) )
 
498
    str = tcItem.pszText;
 
499
 
 
500
  return str;
 
501
}
 
502
 
 
503
int wxNotebook::GetPageImage(size_t nPage) const
 
504
{
 
505
  wxCHECK_MSG( IS_VALID_PAGE(nPage), -1, wxT("notebook page out of range") );
 
506
 
 
507
  TC_ITEM tcItem;
 
508
  tcItem.mask = TCIF_IMAGE;
 
509
 
 
510
  return TabCtrl_GetItem(GetHwnd(), nPage, &tcItem) ? tcItem.iImage : -1;
 
511
}
 
512
 
 
513
bool wxNotebook::SetPageImage(size_t nPage, int nImage)
 
514
{
 
515
  wxCHECK_MSG( IS_VALID_PAGE(nPage), false, wxT("notebook page out of range") );
 
516
 
 
517
  TC_ITEM tcItem;
 
518
  tcItem.mask = TCIF_IMAGE;
 
519
  tcItem.iImage = nImage;
 
520
 
 
521
  return TabCtrl_SetItem(GetHwnd(), nPage, &tcItem) != 0;
 
522
}
 
523
 
 
524
void wxNotebook::SetImageList(wxImageList* imageList)
 
525
{
 
526
  wxNotebookBase::SetImageList(imageList);
 
527
 
 
528
  if ( imageList )
 
529
  {
 
530
    (void) TabCtrl_SetImageList(GetHwnd(), (HIMAGELIST)imageList->GetHIMAGELIST());
 
531
  }
 
532
}
 
533
 
 
534
// ----------------------------------------------------------------------------
 
535
// wxNotebook size settings
 
536
// ----------------------------------------------------------------------------
 
537
 
 
538
wxRect wxNotebook::GetPageSize() const
 
539
{
 
540
    wxRect r;
 
541
 
 
542
    RECT rc;
 
543
    ::GetClientRect(GetHwnd(), &rc);
 
544
 
 
545
    // This check is to work around a bug in TabCtrl_AdjustRect which will
 
546
    // cause a crash on win2k or on XP with themes disabled if either
 
547
    // wxNB_MULTILINE is used or tabs are placed on a side, if the rectangle
 
548
    // is too small.
 
549
    //
 
550
    // The value of 20 is chosen arbitrarily but seems to work
 
551
    if ( rc.right > 20 && rc.bottom > 20 )
 
552
    {
 
553
        TabCtrl_AdjustRect(GetHwnd(), false, &rc);
 
554
 
 
555
        wxCopyRECTToRect(rc, r);
 
556
    }
 
557
 
 
558
    return r;
 
559
}
 
560
 
 
561
void wxNotebook::SetPageSize(const wxSize& size)
 
562
{
 
563
    // transform the page size into the notebook size
 
564
    RECT rc;
 
565
    rc.left =
 
566
    rc.top = 0;
 
567
    rc.right = size.x;
 
568
    rc.bottom = size.y;
 
569
 
 
570
    TabCtrl_AdjustRect(GetHwnd(), true, &rc);
 
571
 
 
572
    // and now set it
 
573
    SetSize(rc.right - rc.left, rc.bottom - rc.top);
 
574
}
 
575
 
 
576
void wxNotebook::SetPadding(const wxSize& padding)
 
577
{
 
578
    TabCtrl_SetPadding(GetHwnd(), padding.x, padding.y);
 
579
}
 
580
 
 
581
// Windows-only at present. Also, you must use the wxNB_FIXEDWIDTH
 
582
// style.
 
583
void wxNotebook::SetTabSize(const wxSize& sz)
 
584
{
 
585
    ::SendMessage(GetHwnd(), TCM_SETITEMSIZE, 0, MAKELPARAM(sz.x, sz.y));
 
586
}
 
587
 
 
588
wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const
 
589
{
 
590
    wxSize sizeTotal = sizePage;
 
591
 
 
592
    // We need to make getting tab size part of the wxWidgets API.
 
593
    wxSize tabSize;
 
594
    if (GetPageCount() > 0)
 
595
    {
 
596
        RECT rect;
 
597
        TabCtrl_GetItemRect((HWND) GetHWND(), 0, & rect);
 
598
        tabSize.x = rect.right - rect.left;
 
599
        tabSize.y = rect.bottom - rect.top;
 
600
    }
 
601
    if ( HasFlag(wxNB_LEFT) || HasFlag(wxNB_RIGHT) )
 
602
    {
 
603
        sizeTotal.x += tabSize.x + 7;
 
604
        sizeTotal.y += 7;
 
605
    }
 
606
    else
 
607
    {
 
608
        sizeTotal.x += 7;
 
609
        sizeTotal.y += tabSize.y + 7;
 
610
    }
 
611
 
 
612
    return sizeTotal;
 
613
}
 
614
 
 
615
void wxNotebook::AdjustPageSize(wxNotebookPage *page)
 
616
{
 
617
    wxCHECK_RET( page, _T("NULL page in wxNotebook::AdjustPageSize") );
 
618
 
 
619
    const wxRect r = GetPageSize();
 
620
    if ( !r.IsEmpty() )
 
621
    {
 
622
        page->SetSize(r);
 
623
    }
 
624
}
 
625
 
 
626
// ----------------------------------------------------------------------------
 
627
// wxNotebook operations
 
628
// ----------------------------------------------------------------------------
 
629
 
 
630
// remove one page from the notebook, without deleting
 
631
wxNotebookPage *wxNotebook::DoRemovePage(size_t nPage)
 
632
{
 
633
    wxNotebookPage *pageRemoved = wxNotebookBase::DoRemovePage(nPage);
 
634
    if ( !pageRemoved )
 
635
        return NULL;
 
636
 
 
637
    TabCtrl_DeleteItem(GetHwnd(), nPage);
 
638
 
 
639
    if ( m_pages.IsEmpty() )
 
640
    {
 
641
        // no selection any more, the notebook becamse empty
 
642
        m_nSelection = -1;
 
643
    }
 
644
    else // notebook still not empty
 
645
    {
 
646
        int selNew = TabCtrl_GetCurSel(GetHwnd());
 
647
        if (selNew != -1)
 
648
        {
 
649
            // No selection change, just refresh the current selection.
 
650
            // Because it could be that the slection index changed
 
651
            // we need to update it.
 
652
            // Note: this does not mean the selection it self changed.
 
653
            m_nSelection = selNew;
 
654
            m_pages[m_nSelection]->Refresh();
 
655
        }
 
656
        else if (int(nPage) == m_nSelection)
 
657
        {
 
658
            // The selection was deleted.
 
659
 
 
660
            // Determine new selection.
 
661
            if (m_nSelection == int(GetPageCount()))
 
662
                selNew = m_nSelection - 1;
 
663
            else
 
664
                selNew = m_nSelection;
 
665
 
 
666
            // m_nSelection must be always valid so reset it before calling
 
667
            // SetSelection()
 
668
            m_nSelection = -1;
 
669
            SetSelection(selNew);
 
670
        }
 
671
        else
 
672
        {
 
673
            wxFAIL; // Windows did not behave ok.
 
674
        }
 
675
    }
 
676
 
 
677
    return pageRemoved;
 
678
}
 
679
 
 
680
// remove all pages
 
681
bool wxNotebook::DeleteAllPages()
 
682
{
 
683
  size_t nPageCount = GetPageCount();
 
684
  size_t nPage;
 
685
  for ( nPage = 0; nPage < nPageCount; nPage++ )
 
686
    delete m_pages[nPage];
 
687
 
 
688
  m_pages.Clear();
 
689
 
 
690
  TabCtrl_DeleteAllItems(GetHwnd());
 
691
 
 
692
  m_nSelection = -1;
 
693
 
 
694
  InvalidateBestSize();
 
695
  return true;
 
696
}
 
697
 
 
698
// same as AddPage() but does it at given position
 
699
bool wxNotebook::InsertPage(size_t nPage,
 
700
                            wxNotebookPage *pPage,
 
701
                            const wxString& strText,
 
702
                            bool bSelect,
 
703
                            int imageId)
 
704
{
 
705
    wxCHECK_MSG( pPage != NULL, false, _T("NULL page in wxNotebook::InsertPage") );
 
706
    wxCHECK_MSG( IS_VALID_PAGE(nPage) || nPage == GetPageCount(), false,
 
707
                 _T("invalid index in wxNotebook::InsertPage") );
 
708
 
 
709
    wxASSERT_MSG( pPage->GetParent() == this,
 
710
                    _T("notebook pages must have notebook as parent") );
 
711
 
 
712
    // add a new tab to the control
 
713
    // ----------------------------
 
714
 
 
715
    // init all fields to 0
 
716
    TC_ITEM tcItem;
 
717
    wxZeroMemory(tcItem);
 
718
 
 
719
    // set the image, if any
 
720
    if ( imageId != -1 )
 
721
    {
 
722
        tcItem.mask |= TCIF_IMAGE;
 
723
        tcItem.iImage  = imageId;
 
724
    }
 
725
 
 
726
    // and the text
 
727
    if ( !strText.empty() )
 
728
    {
 
729
        tcItem.mask |= TCIF_TEXT;
 
730
        tcItem.pszText = (wxChar *)strText.c_str(); // const_cast
 
731
    }
 
732
 
 
733
    // hide the page: unless it is selected, it shouldn't be shown (and if it
 
734
    // is selected it will be shown later)
 
735
    HWND hwnd = GetWinHwnd(pPage);
 
736
    SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_VISIBLE);
 
737
 
 
738
    // this updates internal flag too -- otherwise it would get out of sync
 
739
    // with the real state
 
740
    pPage->Show(false);
 
741
 
 
742
 
 
743
    // fit the notebook page to the tab control's display area: this should be
 
744
    // done before adding it to the notebook or TabCtrl_InsertItem() will
 
745
    // change the notebooks size itself!
 
746
    AdjustPageSize(pPage);
 
747
 
 
748
    // finally do insert it
 
749
    if ( TabCtrl_InsertItem(GetHwnd(), nPage, &tcItem) == -1 )
 
750
    {
 
751
        wxLogError(wxT("Can't create the notebook page '%s'."), strText.c_str());
 
752
 
 
753
        return false;
 
754
    }
 
755
 
 
756
    // succeeded: save the pointer to the page
 
757
    m_pages.Insert(pPage, nPage);
 
758
 
 
759
    // we may need to adjust the size again if the notebook size changed:
 
760
    // normally this only happens for the first page we add (the tabs which
 
761
    // hadn't been there before are now shown) but for a multiline notebook it
 
762
    // can happen for any page at all as a new row could have been started
 
763
    if ( m_pages.GetCount() == 1 || HasFlag(wxNB_MULTILINE) )
 
764
    {
 
765
        AdjustPageSize(pPage);
 
766
    }
 
767
 
 
768
    // now deal with the selection
 
769
    // ---------------------------
 
770
 
 
771
    // if the inserted page is before the selected one, we must update the
 
772
    // index of the selected page
 
773
    if ( int(nPage) <= m_nSelection )
 
774
    {
 
775
        // one extra page added
 
776
        m_nSelection++;
 
777
    }
 
778
 
 
779
    // some page should be selected: either this one or the first one if there
 
780
    // is still no selection
 
781
    int selNew = -1;
 
782
    if ( bSelect )
 
783
        selNew = nPage;
 
784
    else if ( m_nSelection == -1 )
 
785
        selNew = 0;
 
786
 
 
787
    if ( selNew != -1 )
 
788
        SetSelection(selNew);
 
789
 
 
790
    InvalidateBestSize();
 
791
 
 
792
    return true;
 
793
}
 
794
 
 
795
int wxNotebook::HitTest(const wxPoint& pt, long *flags) const
 
796
{
 
797
    TC_HITTESTINFO hitTestInfo;
 
798
    hitTestInfo.pt.x = pt.x;
 
799
    hitTestInfo.pt.y = pt.y;
 
800
    int item = TabCtrl_HitTest(GetHwnd(), &hitTestInfo);
 
801
 
 
802
    if ( flags )
 
803
    {
 
804
        *flags = 0;
 
805
 
 
806
        if ((hitTestInfo.flags & TCHT_NOWHERE) == TCHT_NOWHERE)
 
807
            *flags |= wxNB_HITTEST_NOWHERE;
 
808
        if ((hitTestInfo.flags & TCHT_ONITEM) == TCHT_ONITEM)
 
809
            *flags |= wxNB_HITTEST_ONITEM;
 
810
        if ((hitTestInfo.flags & TCHT_ONITEMICON) == TCHT_ONITEMICON)
 
811
            *flags |= wxNB_HITTEST_ONICON;
 
812
        if ((hitTestInfo.flags & TCHT_ONITEMLABEL) == TCHT_ONITEMLABEL)
 
813
            *flags |= wxNB_HITTEST_ONLABEL;
 
814
    }
 
815
 
 
816
    return item;
 
817
}
 
818
 
 
819
// ----------------------------------------------------------------------------
 
820
// flicker-less notebook redraw
 
821
// ----------------------------------------------------------------------------
 
822
 
 
823
#if USE_NOTEBOOK_ANTIFLICKER
 
824
 
 
825
// wnd proc for the spin button
 
826
LRESULT APIENTRY _EXPORT wxNotebookSpinBtnWndProc(HWND hwnd,
 
827
                                                  UINT message,
 
828
                                                  WPARAM wParam,
 
829
                                                  LPARAM lParam)
 
830
{
 
831
    if ( message == WM_ERASEBKGND )
 
832
        return 0;
 
833
 
 
834
    return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebookSpinBtn,
 
835
                            hwnd, message, wParam, lParam);
 
836
}
 
837
 
 
838
LRESULT APIENTRY _EXPORT wxNotebookWndProc(HWND hwnd,
 
839
                                           UINT message,
 
840
                                           WPARAM wParam,
 
841
                                           LPARAM lParam)
 
842
{
 
843
    return ::CallWindowProc(CASTWNDPROC gs_wndprocNotebook,
 
844
                            hwnd, message, wParam, lParam);
 
845
}
 
846
 
 
847
 
 
848
 
 
849
void wxNotebook::OnEraseBackground(wxEraseEvent& WXUNUSED(event))
 
850
{
 
851
    // do nothing here
 
852
}
 
853
 
 
854
void wxNotebook::OnPaint(wxPaintEvent& WXUNUSED(event))
 
855
{
 
856
    wxPaintDC dc(this);
 
857
    wxMemoryDC memdc;
 
858
    RECT rc;
 
859
    ::GetClientRect(GetHwnd(), &rc);
 
860
    wxBitmap bmp(rc.right, rc.bottom);
 
861
    memdc.SelectObject(bmp);
 
862
 
 
863
    // if there is no special brush just use the solid background colour
 
864
#if wxUSE_UXTHEME
 
865
    HBRUSH hbr = (HBRUSH)m_hbrBackground;
 
866
#else
 
867
    HBRUSH hbr = 0;
 
868
#endif    
 
869
    wxBrush brush;
 
870
    if ( !hbr )
 
871
    {
 
872
        brush = wxBrush(GetBackgroundColour());
 
873
        hbr = GetHbrushOf(brush);
 
874
    }
 
875
 
 
876
    ::FillRect(GetHdcOf(memdc), &rc, hbr);
 
877
 
 
878
    MSWDefWindowProc(WM_PAINT, (WPARAM)memdc.GetHDC(), 0);
 
879
 
 
880
    dc.Blit(0, 0, rc.right, rc.bottom, &memdc, 0, 0);
 
881
}
 
882
 
 
883
#endif // USE_NOTEBOOK_ANTIFLICKER
 
884
 
 
885
// ----------------------------------------------------------------------------
 
886
// wxNotebook callbacks
 
887
// ----------------------------------------------------------------------------
 
888
 
 
889
void wxNotebook::OnSize(wxSizeEvent& event)
 
890
{
 
891
    if ( GetPageCount() == 0 )
 
892
    {
 
893
        // Prevents droppings on resize, but does cause some flicker
 
894
        // when there are no pages.
 
895
        Refresh();
 
896
        event.Skip();
 
897
        return;
 
898
    }
 
899
#ifndef __WXWINCE__
 
900
    else
 
901
    {
 
902
        // Without this, we can sometimes get droppings at the edges
 
903
        // of a notebook, for example a notebook in a splitter window.
 
904
        // This needs to be reconciled with the RefreshRect calls
 
905
        // at the end of this function, which weren't enough to prevent
 
906
        // the droppings.
 
907
 
 
908
        wxSize sz = GetClientSize();
 
909
 
 
910
        // Refresh right side
 
911
        wxRect rect(sz.x-4, 0, 4, sz.y);
 
912
        RefreshRect(rect);
 
913
 
 
914
        // Refresh bottom side
 
915
        rect = wxRect(0, sz.y-4, sz.x, 4);
 
916
        RefreshRect(rect);
 
917
 
 
918
        // Refresh left side
 
919
        rect = wxRect(0, 0, 4, sz.y);
 
920
        RefreshRect(rect);
 
921
    }
 
922
#endif // !__WXWINCE__
 
923
 
 
924
    // fit all the notebook pages to the tab control's display area
 
925
 
 
926
    RECT rc;
 
927
    rc.left = rc.top = 0;
 
928
    GetSize((int *)&rc.right, (int *)&rc.bottom);
 
929
 
 
930
    // save the total size, we'll use it below
 
931
    int widthNbook = rc.right - rc.left,
 
932
        heightNbook = rc.bottom - rc.top;
 
933
 
 
934
    // there seems to be a bug in the implementation of TabCtrl_AdjustRect(): it
 
935
    // returns completely false values for multiline tab controls after the tabs
 
936
    // are added but before getting the first WM_SIZE (off by ~50 pixels, see
 
937
    //
 
938
    // http://sf.net/tracker/index.php?func=detail&aid=645323&group_id=9863&atid=109863
 
939
    //
 
940
    // and the only work around I could find was this ugly hack... without it
 
941
    // simply toggling the "multiline" checkbox in the notebook sample resulted
 
942
    // in a noticeable page displacement
 
943
    if ( HasFlag(wxNB_MULTILINE) )
 
944
    {
 
945
        // avoid an infinite recursion: we get another notification too!
 
946
        static bool s_isInOnSize = false;
 
947
 
 
948
        if ( !s_isInOnSize )
 
949
        {
 
950
            s_isInOnSize = true;
 
951
            SendMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED,
 
952
                    MAKELPARAM(rc.right, rc.bottom));
 
953
            s_isInOnSize = false;
 
954
        }
 
955
    }
 
956
 
 
957
#if wxUSE_UXTHEME
 
958
    // background bitmap size has changed, update the brush using it too
 
959
    UpdateBgBrush();
 
960
#endif // wxUSE_UXTHEME
 
961
 
 
962
    TabCtrl_AdjustRect(GetHwnd(), false, &rc);
 
963
 
 
964
    int width = rc.right - rc.left,
 
965
        height = rc.bottom - rc.top;
 
966
    size_t nCount = m_pages.Count();
 
967
    for ( size_t nPage = 0; nPage < nCount; nPage++ ) {
 
968
        wxNotebookPage *pPage = m_pages[nPage];
 
969
        pPage->SetSize(rc.left, rc.top, width, height);
 
970
    }
 
971
 
 
972
 
 
973
    // unless we had already repainted everything, we now need to refresh
 
974
    if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
 
975
    {
 
976
        // invalidate areas not covered by pages
 
977
        RefreshRect(wxRect(0, 0, widthNbook, rc.top), false);
 
978
        RefreshRect(wxRect(0, rc.top, rc.left, height), false);
 
979
        RefreshRect(wxRect(0, rc.bottom, widthNbook, heightNbook - rc.bottom),
 
980
                    false);
 
981
        RefreshRect(wxRect(rc.right, rc.top, widthNbook - rc.right, height),
 
982
                    false);
 
983
    }
 
984
 
 
985
#if USE_NOTEBOOK_ANTIFLICKER
 
986
    // subclass the spin control used by the notebook to scroll pages to
 
987
    // prevent it from flickering on resize
 
988
    if ( !m_hasSubclassedUpdown )
 
989
    {
 
990
        // iterate over all child windows to find spin button
 
991
        for ( HWND child = ::GetWindow(GetHwnd(), GW_CHILD);
 
992
              child;
 
993
              child = ::GetWindow(child, GW_HWNDNEXT) )
 
994
        {
 
995
            wxWindow *childWindow = wxFindWinFromHandle((WXHWND)child);
 
996
 
 
997
            // see if it exists, if no wxWindow found then assume it's the spin
 
998
            // btn
 
999
            if ( !childWindow )
 
1000
            {
 
1001
                // subclass the spin button to override WM_ERASEBKGND
 
1002
                if ( !gs_wndprocNotebookSpinBtn )
 
1003
                    gs_wndprocNotebookSpinBtn = (WXFARPROC)wxGetWindowProc(child);
 
1004
 
 
1005
                wxSetWindowProc(child, wxNotebookSpinBtnWndProc);
 
1006
                m_hasSubclassedUpdown = true;
 
1007
                break;
 
1008
            }
 
1009
        }
 
1010
    }
 
1011
#endif // USE_NOTEBOOK_ANTIFLICKER
 
1012
 
 
1013
    event.Skip();
 
1014
}
 
1015
 
 
1016
void wxNotebook::OnSelChange(wxNotebookEvent& event)
 
1017
{
 
1018
  // is it our tab control?
 
1019
  if ( event.GetEventObject() == this )
 
1020
  {
 
1021
      int sel = event.GetOldSelection();
 
1022
      if ( sel != -1 )
 
1023
        m_pages[sel]->Show(false);
 
1024
 
 
1025
      sel = event.GetSelection();
 
1026
      if ( sel != -1 )
 
1027
      {
 
1028
        wxNotebookPage *pPage = m_pages[sel];
 
1029
        pPage->Show(true);
 
1030
 
 
1031
        // As per bug report:
 
1032
        // http://sourceforge.net/tracker/index.php?func=detail&aid=1150659&group_id=9863&atid=109863,
 
1033
        // we should not set the page focus (and thereby the focus for
 
1034
        // a child window) since it erroneously selects radio button controls and also
 
1035
        // breaks keyboard handling for a notebook's scroll buttons. So
 
1036
        // we always focus the notebook and not the page.
 
1037
        SetFocus();
 
1038
 
 
1039
      }
 
1040
      else // no pages in the notebook, give the focus to itself
 
1041
      {
 
1042
          SetFocus();
 
1043
      }
 
1044
 
 
1045
      m_nSelection = sel;
 
1046
  }
 
1047
 
 
1048
  // we want to give others a chance to process this message as well
 
1049
  event.Skip();
 
1050
}
 
1051
 
 
1052
bool wxNotebook::MSWTranslateMessage(WXMSG *wxmsg)
 
1053
{
 
1054
    const MSG * const msg = (MSG *)wxmsg;
 
1055
 
 
1056
    // intercept TAB, CTRL+TAB and CTRL+SHIFT+TAB for processing by wxNotebook.
 
1057
    // TAB will be passed to the currently selected page, CTRL+TAB and
 
1058
    // CTRL+SHIFT+TAB will be processed by the notebook itself. do not
 
1059
    // intercept SHIFT+TAB. This goes to the parent of the notebook which will
 
1060
    // process it.
 
1061
    if ( msg->message == WM_KEYDOWN && msg->wParam == VK_TAB &&
 
1062
            msg->hwnd == GetHwnd() &&
 
1063
                (wxIsCtrlDown() || !wxIsShiftDown()) )
 
1064
    {
 
1065
        return MSWProcessMessage(wxmsg);
 
1066
    }
 
1067
 
 
1068
    return false;
 
1069
}
 
1070
 
 
1071
void wxNotebook::OnNavigationKey(wxNavigationKeyEvent& event)
 
1072
{
 
1073
    if ( event.IsWindowChange() ) {
 
1074
        // change pages
 
1075
        AdvanceSelection(event.GetDirection());
 
1076
    }
 
1077
    else {
 
1078
        // we get this event in 3 cases
 
1079
        //
 
1080
        // a) one of our pages might have generated it because the user TABbed
 
1081
        // out from it in which case we should propagate the event upwards and
 
1082
        // our parent will take care of setting the focus to prev/next sibling
 
1083
        //
 
1084
        // or
 
1085
        //
 
1086
        // b) the parent panel wants to give the focus to us so that we
 
1087
        // forward it to our selected page. We can't deal with this in
 
1088
        // OnSetFocus() because we don't know which direction the focus came
 
1089
        // from in this case and so can't choose between setting the focus to
 
1090
        // first or last panel child
 
1091
        //
 
1092
        // or
 
1093
        //
 
1094
        // c) we ourselves (see MSWTranslateMessage) generated the event
 
1095
        //
 
1096
        wxWindow * const parent = GetParent();
 
1097
 
 
1098
        // the wxObject* casts are required to avoid MinGW GCC 2.95.3 ICE
 
1099
        const bool isFromParent = event.GetEventObject() == (wxObject*) parent;
 
1100
        const bool isFromSelf = event.GetEventObject() == (wxObject*) this;
 
1101
 
 
1102
        if ( isFromParent || isFromSelf )
 
1103
        {
 
1104
            // no, it doesn't come from child, case (b) or (c): forward to a
 
1105
            // page but only if direction is backwards (TAB) or from ourselves,
 
1106
            if ( m_nSelection != -1 &&
 
1107
                    (!event.GetDirection() || isFromSelf) )
 
1108
            {
 
1109
                // so that the page knows that the event comes from it's parent
 
1110
                // and is being propagated downwards
 
1111
                event.SetEventObject(this);
 
1112
 
 
1113
                wxWindow *page = m_pages[m_nSelection];
 
1114
                if ( !page->GetEventHandler()->ProcessEvent(event) )
 
1115
                {
 
1116
                    page->SetFocus();
 
1117
                }
 
1118
                //else: page manages focus inside it itself
 
1119
            }
 
1120
            else // otherwise set the focus to the notebook itself
 
1121
            {
 
1122
                SetFocus();
 
1123
            }
 
1124
        }
 
1125
        else
 
1126
        {
 
1127
            // it comes from our child, case (a), pass to the parent, but only
 
1128
            // if the direction is forwards. Otherwise set the focus to the
 
1129
            // notebook itself. The notebook is always the 'first' control of a
 
1130
            // page.
 
1131
            if ( !event.GetDirection() )
 
1132
            {
 
1133
                SetFocus();
 
1134
            }
 
1135
            else if ( parent )
 
1136
            {
 
1137
                event.SetCurrentFocus(this);
 
1138
                parent->GetEventHandler()->ProcessEvent(event);
 
1139
            }
 
1140
        }
 
1141
    }
 
1142
}
 
1143
 
 
1144
#if wxUSE_UXTHEME
 
1145
 
 
1146
bool wxNotebook::DoDrawBackground(WXHDC hDC, wxWindow *child)
 
1147
{
 
1148
    wxUxThemeHandle theme(child ? child : this, L"TAB");
 
1149
    if ( !theme )
 
1150
        return false;
 
1151
 
 
1152
    // get the notebook client rect (we're not interested in drawing tabs
 
1153
    // themselves)
 
1154
    wxRect r = GetPageSize();
 
1155
    if ( r.IsEmpty() )
 
1156
        return false;
 
1157
 
 
1158
    RECT rc;
 
1159
    wxCopyRectToRECT(r, rc);
 
1160
 
 
1161
    // map rect to the coords of the window we're drawing in
 
1162
    if ( child )
 
1163
        ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
 
1164
 
 
1165
    // we have the content area (page size), but we need to draw all of the
 
1166
    // background for it to be aligned correctly
 
1167
    wxUxThemeEngine::Get()->GetThemeBackgroundExtent
 
1168
                            (
 
1169
                                theme,
 
1170
                                (HDC) hDC,
 
1171
                                9 /* TABP_PANE */,
 
1172
                                0,
 
1173
                                &rc,
 
1174
                                &rc
 
1175
                            );
 
1176
    wxUxThemeEngine::Get()->DrawThemeBackground
 
1177
                            (
 
1178
                                theme,
 
1179
                                (HDC) hDC,
 
1180
                                9 /* TABP_PANE */,
 
1181
                                0,
 
1182
                                &rc,
 
1183
                                NULL
 
1184
                            );
 
1185
 
 
1186
    return true;
 
1187
}
 
1188
 
 
1189
WXHBRUSH wxNotebook::QueryBgBitmap()
 
1190
{
 
1191
    wxRect r = GetPageSize();
 
1192
    if ( r.IsEmpty() )
 
1193
        return 0;
 
1194
 
 
1195
    WindowHDC hDC(GetHwnd());
 
1196
    MemoryHDC hDCMem(hDC);
 
1197
    CompatibleBitmap hBmp(hDC, r.x + r.width, r.y + r.height);
 
1198
 
 
1199
    SelectInHDC selectBmp(hDCMem, hBmp);
 
1200
 
 
1201
    if ( !DoDrawBackground((WXHDC)(HDC)hDCMem) )
 
1202
        return 0;
 
1203
 
 
1204
    return (WXHBRUSH)::CreatePatternBrush(hBmp);
 
1205
}
 
1206
 
 
1207
void wxNotebook::UpdateBgBrush()
 
1208
{
 
1209
    if ( m_hbrBackground )
 
1210
        ::DeleteObject((HBRUSH)m_hbrBackground);
 
1211
 
 
1212
    if ( !m_hasBgCol && wxUxThemeEngine::GetIfActive() )
 
1213
    {
 
1214
        m_hbrBackground = QueryBgBitmap();
 
1215
    }
 
1216
    else // no themes or we've got user-defined solid colour
 
1217
    {
 
1218
        m_hbrBackground = NULL;
 
1219
    }
 
1220
}
 
1221
 
 
1222
WXHBRUSH wxNotebook::MSWGetBgBrushForChild(WXHDC hDC, WXHWND hWnd)
 
1223
{
 
1224
    if ( m_hbrBackground )
 
1225
    {
 
1226
        // before drawing with the background brush, we need to position it
 
1227
        // correctly
 
1228
        RECT rc;
 
1229
        ::GetWindowRect((HWND)hWnd, &rc);
 
1230
 
 
1231
        ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
 
1232
 
 
1233
        if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
 
1234
        {
 
1235
            wxLogLastError(_T("SetBrushOrgEx(notebook bg brush)"));
 
1236
        }
 
1237
 
 
1238
        return m_hbrBackground;
 
1239
    }
 
1240
 
 
1241
    return wxNotebookBase::MSWGetBgBrushForChild(hDC, hWnd);
 
1242
}
 
1243
 
 
1244
bool wxNotebook::MSWPrintChild(WXHDC hDC, wxWindow *child)
 
1245
{
 
1246
    // solid background colour overrides themed background drawing
 
1247
    if ( !UseBgCol() && DoDrawBackground(hDC, child) )
 
1248
        return true;
 
1249
 
 
1250
    // If we're using a solid colour (for example if we've switched off
 
1251
    // theming for this notebook), paint it
 
1252
    if (UseBgCol())
 
1253
    {
 
1254
        wxRect r = GetPageSize();
 
1255
        if ( r.IsEmpty() )
 
1256
            return false;
 
1257
 
 
1258
        RECT rc;
 
1259
        wxCopyRectToRECT(r, rc);
 
1260
 
 
1261
        // map rect to the coords of the window we're drawing in
 
1262
        if ( child )
 
1263
            ::MapWindowPoints(GetHwnd(), GetHwndOf(child), (POINT *)&rc, 2);
 
1264
 
 
1265
        wxBrush brush(GetBackgroundColour());
 
1266
        HBRUSH hbr = GetHbrushOf(brush);
 
1267
 
 
1268
        ::FillRect((HDC) hDC, &rc, hbr);
 
1269
 
 
1270
        return true;
 
1271
    }
 
1272
 
 
1273
    return wxNotebookBase::MSWPrintChild(hDC, child);
 
1274
}
 
1275
 
 
1276
#endif // wxUSE_UXTHEME
 
1277
 
 
1278
// Windows only: attempts to get colour for UX theme page background
 
1279
wxColour wxNotebook::GetThemeBackgroundColour() const
 
1280
{
 
1281
#if wxUSE_UXTHEME
 
1282
    if (wxUxThemeEngine::Get())
 
1283
    {
 
1284
        wxUxThemeHandle hTheme((wxNotebook*) this, L"TAB");
 
1285
        if (hTheme)
 
1286
        {
 
1287
            // This is total guesswork.
 
1288
            // See PlatformSDK\Include\Tmschema.h for values
 
1289
            COLORREF themeColor;
 
1290
            wxUxThemeEngine::Get()->GetThemeColor(
 
1291
                                        hTheme,
 
1292
                                        10 /* TABP_BODY */,
 
1293
                                        1 /* NORMAL */,
 
1294
                                        3821 /* FILLCOLORHINT */,
 
1295
                                        &themeColor);
 
1296
 
 
1297
            /*
 
1298
            [DS] Workaround for WindowBlinds:
 
1299
            Some themes return a near black theme color using FILLCOLORHINT,
 
1300
            this makes notebook pages have an ugly black background and makes
 
1301
            text (usually black) unreadable. Retry again with FILLCOLOR.
 
1302
 
 
1303
            This workaround potentially breaks appearance of some themes,
 
1304
            but in practice it already fixes some themes.
 
1305
            */
 
1306
            if (themeColor == 1)
 
1307
            {
 
1308
                wxUxThemeEngine::Get()->GetThemeColor(
 
1309
                                            hTheme,
 
1310
                                            10 /* TABP_BODY */,
 
1311
                                            1 /* NORMAL */,
 
1312
                                            3802 /* FILLCOLOR */,
 
1313
                                            &themeColor);
 
1314
            }
 
1315
 
 
1316
            return wxRGBToColour(themeColor);
 
1317
        }
 
1318
    }
 
1319
#endif // wxUSE_UXTHEME
 
1320
 
 
1321
    return GetBackgroundColour();
 
1322
}
 
1323
 
 
1324
// ----------------------------------------------------------------------------
 
1325
// wxNotebook base class virtuals
 
1326
// ----------------------------------------------------------------------------
 
1327
 
 
1328
#if wxUSE_CONSTRAINTS
 
1329
 
 
1330
// override these 2 functions to do nothing: everything is done in OnSize
 
1331
 
 
1332
void wxNotebook::SetConstraintSizes(bool WXUNUSED(recurse))
 
1333
{
 
1334
  // don't set the sizes of the pages - their correct size is not yet known
 
1335
  wxControl::SetConstraintSizes(false);
 
1336
}
 
1337
 
 
1338
bool wxNotebook::DoPhase(int WXUNUSED(nPhase))
 
1339
{
 
1340
  return true;
 
1341
}
 
1342
 
 
1343
#endif // wxUSE_CONSTRAINTS
 
1344
 
 
1345
// ----------------------------------------------------------------------------
 
1346
// wxNotebook Windows message handlers
 
1347
// ----------------------------------------------------------------------------
 
1348
 
 
1349
bool wxNotebook::MSWOnScroll(int orientation, WXWORD nSBCode,
 
1350
                             WXWORD pos, WXHWND control)
 
1351
{
 
1352
    // don't generate EVT_SCROLLWIN events for the WM_SCROLLs coming from the
 
1353
    // up-down control
 
1354
    if ( control )
 
1355
        return false;
 
1356
 
 
1357
    return wxNotebookBase::MSWOnScroll(orientation, nSBCode, pos, control);
 
1358
}
 
1359
 
 
1360
bool wxNotebook::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM* result)
 
1361
{
 
1362
  wxNotebookEvent event(wxEVT_NULL, m_windowId);
 
1363
 
 
1364
  NMHDR* hdr = (NMHDR *)lParam;
 
1365
  switch ( hdr->code ) {
 
1366
    case TCN_SELCHANGE:
 
1367
      event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED);
 
1368
      break;
 
1369
 
 
1370
    case TCN_SELCHANGING:
 
1371
      event.SetEventType(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING);
 
1372
      break;
 
1373
 
 
1374
    default:
 
1375
      return wxControl::MSWOnNotify(idCtrl, lParam, result);
 
1376
  }
 
1377
 
 
1378
  event.SetSelection(TabCtrl_GetCurSel(GetHwnd()));
 
1379
  event.SetOldSelection(m_nSelection);
 
1380
  event.SetEventObject(this);
 
1381
  event.SetInt(idCtrl);
 
1382
 
 
1383
  bool processed = GetEventHandler()->ProcessEvent(event);
 
1384
  *result = !event.IsAllowed();
 
1385
  return processed;
 
1386
}
 
1387
 
 
1388
#endif // wxUSE_NOTEBOOK