1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        generic/listbkg.cpp 
   3 // Purpose:     generic implementation of wxListbook 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 2003 Vadim Zeitlin <vadim@wxwindows.org> 
   9 // Licence:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  29 #include "wx/listctrl.h" 
  30 #include "wx/statline.h" 
  31 #include "wx/listbook.h" 
  32 #include "wx/imaglist.h" 
  33 #include "wx/settings.h" 
  35 // ---------------------------------------------------------------------------- 
  37 // ---------------------------------------------------------------------------- 
  39 // margin between the list and the page, should be bigger than wxStaticLine 
  41 const wxCoord MARGIN 
= 5; 
  43 // ---------------------------------------------------------------------------- 
  44 // various wxWidgets macros 
  45 // ---------------------------------------------------------------------------- 
  47 // check that the page index is valid 
  48 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) 
  50 // ---------------------------------------------------------------------------- 
  52 // ---------------------------------------------------------------------------- 
  54 IMPLEMENT_DYNAMIC_CLASS(wxListbook
, wxControl
) 
  55 IMPLEMENT_DYNAMIC_CLASS(wxListbookEvent
, wxNotifyEvent
) 
  57 const wxEventType wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING 
= wxNewEventType(); 
  58 const wxEventType wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED 
= wxNewEventType(); 
  59 const int wxID_LISTBOOKLISTVIEW 
= wxNewId(); 
  61 BEGIN_EVENT_TABLE(wxListbook
, wxBookCtrlBase
) 
  62     EVT_SIZE(wxListbook::OnSize
) 
  63     EVT_LIST_ITEM_SELECTED(wxID_LISTBOOKLISTVIEW
, wxListbook::OnListSelected
) 
  66 // ============================================================================ 
  67 // wxListbook implementation 
  68 // ============================================================================ 
  70 // ---------------------------------------------------------------------------- 
  71 // wxListbook creation 
  72 // ---------------------------------------------------------------------------- 
  74 void wxListbook::Init() 
  77 #if wxUSE_LINE_IN_LISTBOOK 
  79 #endif // wxUSE_LINE_IN_LISTBOOK 
  80     m_selection 
= wxNOT_FOUND
; 
  84 wxListbook::Create(wxWindow 
*parent
, 
  91     if ( (style 
& wxLB_ALIGN_MASK
) == wxLB_DEFAULT 
) 
  97 #endif // __WXMAC__/!__WXMAC__ 
 100     // no border for this control, it doesn't look nice together with 
 102     style 
&= ~wxBORDER_MASK
; 
 103     style 
|= wxBORDER_NONE
; 
 105     if ( !wxControl::Create(parent
, id
, pos
, size
, style
, 
 106                             wxDefaultValidator
, name
) ) 
 109     m_list 
= new wxListView
 
 112                     wxID_LISTBOOKLISTVIEW
, 
 115                     wxLC_ICON 
| wxLC_SINGLE_SEL 
| 
 116                         (IsVertical() ? wxLC_ALIGN_LEFT 
: wxLC_ALIGN_TOP
) 
 119 #if wxUSE_LINE_IN_LISTBOOK 
 120     m_line 
= new wxStaticLine
 
 126                     IsVertical() ? wxLI_HORIZONTAL 
: wxLI_VERTICAL
 
 128 #endif // wxUSE_LINE_IN_LISTBOOK 
 131     // On XP with themes enabled the GetViewRect used in GetListSize to 
 132     // determine the space needed for the list view will incorrectly return 
 133     // (0,0,0,0) the first time.  So send a pending event so OnSize will be 
 134     // called again after the window is ready to go.  Technically we don't 
 135     // need to do this on non-XP windows, but if things are already sized 
 136     // correctly then nothing changes and so there is no harm. 
 138     GetEventHandler()->AddPendingEvent(evt
); 
 143 // ---------------------------------------------------------------------------- 
 144 // wxListbook geometry management 
 145 // ---------------------------------------------------------------------------- 
 147 wxSize 
wxListbook::GetListSize() const 
 149     const wxSize sizeClient 
= GetClientSize(), 
 150                  sizeBorder 
= m_list
->GetSize() - m_list
->GetClientSize(), 
 151                  sizeList 
= m_list
->GetViewRect().GetSize() + sizeBorder
; 
 156         size
.x 
= sizeClient
.x
; 
 159     else // left/right aligned 
 162         size
.y 
= sizeClient
.y
; 
 168 wxRect 
wxListbook::GetPageRect() const 
 170     const wxSize sizeList 
= m_list
->GetSize(); 
 173     wxRect 
rectPage(pt
, GetClientSize()); 
 174     switch ( GetWindowStyle() & wxLB_ALIGN_MASK 
) 
 177             wxFAIL_MSG( _T("unexpected wxListbook alignment") ); 
 181             rectPage
.y 
= sizeList
.y 
+ MARGIN
; 
 185             rectPage
.height 
-= sizeList
.y 
+ MARGIN
; 
 189             rectPage
.x 
= sizeList
.x 
+ MARGIN
; 
 193             rectPage
.width 
-= sizeList
.x 
+ MARGIN
; 
 200 void wxListbook::OnSize(wxSizeEvent
& event
) 
 206         // we're not fully created yet 
 210     // arrange the icons before calling SetClientSize(), otherwise it wouldn't 
 211     // account for the scrollbars the list control might need and, at least 
 212     // under MSW, we'd finish with an ugly looking list control with both 
 213     // vertical and horizontal scrollbar (with one of them being added because 
 214     // the other one is not accounted for in client size computations) 
 217     // resize the list control and the page area to fit inside our new size 
 218     const wxSize sizeClient 
= GetClientSize(), 
 219                  sizeBorder 
= m_list
->GetSize() - m_list
->GetClientSize(), 
 220                  sizeList 
= GetListSize(); 
 222     m_list
->SetClientSize( sizeList
.x 
- sizeBorder
.x
, sizeList
.y 
- sizeBorder
.y 
); 
 224     const wxSize sizeNew 
= m_list
->GetSize(); 
 226     switch ( GetWindowStyle() & wxLB_ALIGN_MASK 
) 
 229             wxFAIL_MSG( _T("unexpected wxListbook alignment") ); 
 234             // posList is already ok 
 238             posList
.y 
= sizeClient
.y 
- sizeNew
.y
; 
 242             posList
.x 
= sizeClient
.x 
- sizeNew
.x
; 
 246     if ( m_list
->GetPosition() != posList 
) 
 247         m_list
->Move(posList
); 
 249 #if wxUSE_LINE_IN_LISTBOOK 
 252         wxRect 
rectLine(sizeClient
); 
 254         switch ( GetWindowStyle() & wxLB_ALIGN_MASK 
) 
 257                 rectLine
.y 
= sizeNew
.y 
+ 1; 
 258                 rectLine
.height 
= MARGIN 
- 2; 
 262                 rectLine
.height 
= MARGIN 
- 2; 
 263                 rectLine
.y 
= sizeClient
.y 
- sizeNew
.y 
- rectLine
.height
; 
 267                 rectLine
.x 
= sizeNew
.x 
+ 1; 
 268                 rectLine
.width 
= MARGIN 
- 2; 
 272                 rectLine
.width 
= MARGIN 
- 2; 
 273                 rectLine
.x 
= sizeClient
.x 
- sizeNew
.x 
- rectLine
.width
; 
 277         m_line
->SetSize(rectLine
); 
 279 #endif // wxUSE_LINE_IN_LISTBOOK 
 281     // resize the currently shown page 
 282     if (m_selection 
!= wxNOT_FOUND 
) 
 284         wxWindow 
*page 
= m_pages
[m_selection
]; 
 285         wxCHECK_RET( page
, _T("NULL page in wxListbook?") ); 
 286         page
->SetSize(GetPageRect()); 
 290 wxSize 
wxListbook::CalcSizeFromPage(const wxSize
& sizePage
) const 
 292     // we need to add the size of the list control and the margin 
 293     const wxSize sizeList 
= GetListSize(); 
 295     wxSize size 
= sizePage
; 
 298         size
.y 
+= sizeList
.y 
+ MARGIN
; 
 300     else // left/right aligned 
 302         size
.x 
+= sizeList
.x 
+ MARGIN
; 
 309 // ---------------------------------------------------------------------------- 
 310 // accessing the pages 
 311 // ---------------------------------------------------------------------------- 
 313 bool wxListbook::SetPageText(size_t n
, const wxString
& strText
) 
 315     m_list
->SetItemText(n
, strText
); 
 320 wxString 
wxListbook::GetPageText(size_t n
) const 
 322     return m_list
->GetItemText(n
); 
 325 int wxListbook::GetPageImage(size_t WXUNUSED(n
)) const 
 327     wxFAIL_MSG( _T("wxListbook::GetPageImage() not implemented") ); 
 332 bool wxListbook::SetPageImage(size_t n
, int imageId
) 
 334     return m_list
->SetItemImage(n
, imageId
); 
 337 // ---------------------------------------------------------------------------- 
 339 // ---------------------------------------------------------------------------- 
 341 void wxListbook::SetImageList(wxImageList 
*imageList
) 
 343     m_list
->SetImageList(imageList
, wxIMAGE_LIST_NORMAL
); 
 345     wxBookCtrlBase::SetImageList(imageList
); 
 348 // ---------------------------------------------------------------------------- 
 350 // ---------------------------------------------------------------------------- 
 352 int wxListbook::GetSelection() const 
 357 int wxListbook::SetSelection(size_t n
) 
 359     wxCHECK_MSG( IS_VALID_PAGE(n
), wxNOT_FOUND
, 
 360                  wxT("invalid page index in wxListbook::SetSelection()") ); 
 362     const int oldSel 
= m_selection
; 
 364     if ( int(n
) != m_selection 
) 
 366         wxListbookEvent 
event(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGING
, m_windowId
); 
 367         event
.SetSelection(n
); 
 368         event
.SetOldSelection(m_selection
); 
 369         event
.SetEventObject(this); 
 370         if ( !GetEventHandler()->ProcessEvent(event
) || event
.IsAllowed() ) 
 372             if ( m_selection 
!= wxNOT_FOUND 
) 
 373                 m_pages
[m_selection
]->Hide(); 
 375             wxWindow 
*page 
= m_pages
[n
]; 
 376             page
->SetSize(GetPageRect()); 
 379             // change m_selection now to ignore the selection change event 
 384             // program allows the page change 
 385             event
.SetEventType(wxEVT_COMMAND_LISTBOOK_PAGE_CHANGED
); 
 386             (void)GetEventHandler()->ProcessEvent(event
); 
 393 // ---------------------------------------------------------------------------- 
 394 // adding/removing the pages 
 395 // ---------------------------------------------------------------------------- 
 398 wxListbook::InsertPage(size_t n
, 
 400                        const wxString
& text
, 
 404     if ( !wxBookCtrlBase::InsertPage(n
, page
, text
, bSelect
, imageId
) ) 
 407     m_list
->InsertItem(n
, text
, imageId
); 
 409     // if the inserted page is before the selected one, we must update the 
 410     // index of the selected page 
 411     if ( int(n
) <= m_selection 
) 
 413         // one extra page added 
 415         m_list
->Select(m_selection
); 
 416         m_list
->Focus(m_selection
); 
 419     // some page should be selected: either this one or the first one if there 
 420     // is still no selection 
 424     else if ( m_selection 
== -1 ) 
 427     if ( selNew 
!= m_selection 
) 
 431         SetSelection(selNew
); 
 433     InvalidateBestSize(); 
 438 wxWindow 
*wxListbook::DoRemovePage(size_t page
) 
 440     const size_t page_count 
= GetPageCount(); 
 441     wxWindow 
*win 
= wxBookCtrlBase::DoRemovePage(page
); 
 445         m_list
->DeleteItem(page
); 
 447         if (m_selection 
>= (int)page
) 
 449             // force new sel valid if possible 
 450             int sel 
= m_selection 
- 1; 
 453             else if ((page_count 
== 2) || (sel 
== -1)) 
 456             // force sel invalid if deleting current page - don't try to hide it 
 457             m_selection 
= (m_selection 
== (int)page
) ? wxNOT_FOUND 
: m_selection 
- 1; 
 459             if ((sel 
!= wxNOT_FOUND
) && (sel 
!= m_selection
)) 
 470 bool wxListbook::DeleteAllPages() 
 472     m_list
->DeleteAllItems(); 
 473     return wxBookCtrlBase::DeleteAllPages(); 
 476 // ---------------------------------------------------------------------------- 
 478 // ---------------------------------------------------------------------------- 
 480 void wxListbook::OnListSelected(wxListEvent
& eventList
) 
 482     const int selNew 
= eventList
.GetIndex(); 
 484     if ( selNew 
== m_selection 
) 
 486         // this event can only come from our own Select(m_selection) below 
 487         // which we call when the page change is vetoed, so we should simply 
 492     SetSelection(selNew
); 
 494     // change wasn't allowed, return to previous state 
 495     if (m_selection 
!= selNew
) 
 497         m_list
->Select(m_selection
); 
 498         m_list
->Focus(m_selection
); 
 502 #endif // wxUSE_LISTBOOK