1/////////////////////////////////////////////////////////////////////////////// 2// Name: src/generic/toolbkg.cpp 3// Purpose: generic implementation of wxToolbook 4// Author: Julian Smart 5// Modified by: 6// Created: 2006-01-29 7// RCS-ID: $Id: toolbkg.cpp 44271 2007-01-21 00:52:05Z VZ $ 8// Copyright: (c) 2006 Julian Smart 9// Licence: wxWindows licence 10/////////////////////////////////////////////////////////////////////////////// 11 12// For compilers that support precompilation, includes "wx.h". 13#include "wx/wxprec.h" 14 15#ifdef __BORLANDC__ 16 #pragma hdrstop 17#endif 18 19#if wxUSE_TOOLBOOK 20 21#ifndef WX_PRECOMP 22 #include "wx/icon.h" 23 #include "wx/settings.h" 24 #include "wx/toolbar.h" 25#endif 26 27#include "wx/imaglist.h" 28#include "wx/sysopt.h" 29#include "wx/toolbook.h" 30 31#if defined(__WXMAC__) && wxUSE_TOOLBAR && wxUSE_BMPBUTTON 32#include "wx/generic/buttonbar.h" 33#endif 34 35// ---------------------------------------------------------------------------- 36// various wxWidgets macros 37// ---------------------------------------------------------------------------- 38 39// check that the page index is valid 40#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) 41 42// ---------------------------------------------------------------------------- 43// event table 44// ---------------------------------------------------------------------------- 45 46IMPLEMENT_DYNAMIC_CLASS(wxToolbook, wxBookCtrlBase) 47IMPLEMENT_DYNAMIC_CLASS(wxToolbookEvent, wxNotifyEvent) 48 49#if !WXWIN_COMPATIBILITY_EVENT_TYPES 50const wxEventType wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGING = wxNewEventType(); 51const wxEventType wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGED = wxNewEventType(); 52#endif 53 54BEGIN_EVENT_TABLE(wxToolbook, wxBookCtrlBase) 55 EVT_SIZE(wxToolbook::OnSize) 56 EVT_TOOL_RANGE(1, 50, wxToolbook::OnToolSelected) 57 EVT_IDLE(wxToolbook::OnIdle) 58END_EVENT_TABLE() 59 60// ============================================================================ 61// wxToolbook implementation 62// ============================================================================ 63 64// ---------------------------------------------------------------------------- 65// wxToolbook creation 66// ---------------------------------------------------------------------------- 67 68void wxToolbook::Init() 69{ 70 m_selection = wxNOT_FOUND; 71 m_needsRealizing = false; 72} 73 74bool wxToolbook::Create(wxWindow *parent, 75 wxWindowID id, 76 const wxPoint& pos, 77 const wxSize& size, 78 long style, 79 const wxString& name) 80{ 81 if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT ) 82 style |= wxBK_TOP; 83 84 // no border for this control 85 style &= ~wxBORDER_MASK; 86 style |= wxBORDER_NONE; 87 88 if ( !wxControl::Create(parent, id, pos, size, style, 89 wxDefaultValidator, name) ) 90 return false; 91 92 int orient = wxTB_HORIZONTAL; 93 if ( (style & (wxBK_LEFT | wxBK_RIGHT)) != 0) 94 orient = wxTB_VERTICAL; 95 96 // TODO: make more configurable 97 98#if defined(__WXMAC__) && wxUSE_TOOLBAR && wxUSE_BMPBUTTON 99 if (style & wxBK_BUTTONBAR) 100 { 101 m_bookctrl = new wxButtonToolBar 102 ( 103 this, 104 wxID_ANY, 105 wxDefaultPosition, 106 wxDefaultSize, 107 orient|wxTB_TEXT|wxTB_FLAT|wxNO_BORDER 108 ); 109 } 110 else 111#endif 112 { 113 m_bookctrl = new wxToolBar 114 ( 115 this, 116 wxID_ANY, 117 wxDefaultPosition, 118 wxDefaultSize, 119 orient|wxTB_TEXT|wxTB_FLAT|wxTB_NODIVIDER|wxNO_BORDER 120 ); 121 } 122 123 return true; 124} 125 126// ---------------------------------------------------------------------------- 127// wxToolbook geometry management 128// ---------------------------------------------------------------------------- 129 130wxSize wxToolbook::GetControllerSize() const 131{ 132 const wxSize sizeClient = GetClientSize(), 133 sizeBorder = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(), 134 sizeToolBar = GetToolBar()->GetSize() + sizeBorder; 135 136 wxSize size; 137 138 if ( IsVertical() ) 139 { 140 size.x = sizeClient.x; 141 size.y = sizeToolBar.y; 142 } 143 else // left/right aligned 144 { 145 size.x = sizeToolBar.x; 146 size.y = sizeClient.y; 147 } 148 149 return size; 150} 151 152void wxToolbook::OnSize(wxSizeEvent& event) 153{ 154 if (m_needsRealizing) 155 Realize(); 156 157 wxBookCtrlBase::OnSize(event); 158} 159 160wxSize wxToolbook::CalcSizeFromPage(const wxSize& sizePage) const 161{ 162 // we need to add the size of the list control and the border between 163 const wxSize sizeToolBar = GetControllerSize(); 164 165 wxSize size = sizePage; 166 if ( IsVertical() ) 167 { 168 size.y += sizeToolBar.y + GetInternalBorder(); 169 } 170 else // left/right aligned 171 { 172 size.x += sizeToolBar.x + GetInternalBorder(); 173 } 174 175 return size; 176} 177 178// ---------------------------------------------------------------------------- 179// accessing the pages 180// ---------------------------------------------------------------------------- 181 182bool wxToolbook::SetPageText(size_t n, const wxString& strText) 183{ 184 // Assume tool ids start from 1 185 wxToolBarToolBase* tool = GetToolBar()->FindById(n + 1); 186 if (tool) 187 { 188 tool->SetLabel(strText); 189 return true; 190 } 191 else 192 return false; 193} 194 195wxString wxToolbook::GetPageText(size_t n) const 196{ 197 wxToolBarToolBase* tool = GetToolBar()->FindById(n + 1); 198 if (tool) 199 return tool->GetLabel(); 200 else 201 return wxEmptyString; 202} 203 204int wxToolbook::GetPageImage(size_t WXUNUSED(n)) const 205{ 206 wxFAIL_MSG( _T("wxToolbook::GetPageImage() not implemented") ); 207 208 return wxNOT_FOUND; 209} 210 211bool wxToolbook::SetPageImage(size_t n, int imageId) 212{ 213 wxASSERT( GetImageList() != NULL ); 214 if (!GetImageList()) 215 return false; 216 217 wxToolBarToolBase* tool = GetToolBar()->FindById(n + 1); 218 if (tool) 219 { 220 // Find the image list index for this tool 221 wxBitmap bitmap = GetImageList()->GetBitmap(imageId); 222 tool->SetNormalBitmap(bitmap); 223 return true; 224 } 225 else 226 return false; 227} 228 229// ---------------------------------------------------------------------------- 230// image list stuff 231// ---------------------------------------------------------------------------- 232 233void wxToolbook::SetImageList(wxImageList *imageList) 234{ 235 wxBookCtrlBase::SetImageList(imageList); 236} 237 238// ---------------------------------------------------------------------------- 239// selection 240// ---------------------------------------------------------------------------- 241 242int wxToolbook::GetSelection() const 243{ 244 return m_selection; 245} 246 247wxBookCtrlBaseEvent* wxToolbook::CreatePageChangingEvent() const 248{ 249 return new wxToolbookEvent(wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGING, m_windowId); 250} 251 252void wxToolbook::MakeChangedEvent(wxBookCtrlBaseEvent &event) 253{ 254 event.SetEventType(wxEVT_COMMAND_TOOLBOOK_PAGE_CHANGED); 255} 256 257void wxToolbook::UpdateSelectedPage(size_t newsel) 258{ 259 m_selection = newsel; 260 GetToolBar()->ToggleTool(newsel + 1, true); 261} 262 263// Not part of the wxBookctrl API, but must be called in OnIdle or 264// by application to realize the toolbar and select the initial page. 265void wxToolbook::Realize() 266{ 267 if (m_needsRealizing) 268 { 269 GetToolBar()->SetToolBitmapSize(m_maxBitmapSize); 270 271 int remap = wxSystemOptions::GetOptionInt(wxT("msw.remap")); 272 wxSystemOptions::SetOption(wxT("msw.remap"), 0); 273 GetToolBar()->Realize(); 274 wxSystemOptions::SetOption(wxT("msw.remap"), remap); 275 } 276 277 m_needsRealizing = false; 278 279 if (m_selection == -1) 280 m_selection = 0; 281 282 if (GetPageCount() > 0) 283 { 284 int sel = m_selection; 285 m_selection = -1; 286 SetSelection(sel); 287 } 288 289 DoSize(); 290} 291 292int wxToolbook::HitTest(const wxPoint& pt, long *flags) const 293{ 294 int pagePos = wxNOT_FOUND; 295 296 if ( flags ) 297 *flags = wxBK_HITTEST_NOWHERE; 298 299 // convert from wxToolbook coordinates to wxToolBar ones 300 const wxToolBarBase * const tbar = GetToolBar(); 301 const wxPoint tbarPt = tbar->ScreenToClient(ClientToScreen(pt)); 302 303 // is the point over the toolbar? 304 if ( wxRect(tbar->GetSize()).Contains(tbarPt) ) 305 { 306 const wxToolBarToolBase * const 307 tool = tbar->FindToolForPosition(tbarPt.x, tbarPt.y); 308 309 if ( tool ) 310 { 311 pagePos = tbar->GetToolPos(tool->GetId()); 312 if ( flags ) 313 *flags = wxBK_HITTEST_ONICON | wxBK_HITTEST_ONLABEL; 314 } 315 } 316 else // not over the toolbar 317 { 318 if ( flags && GetPageRect().Contains(pt) ) 319 *flags |= wxBK_HITTEST_ONPAGE; 320 } 321 322 return pagePos; 323} 324 325void wxToolbook::OnIdle(wxIdleEvent& event) 326{ 327 if (m_needsRealizing) 328 Realize(); 329 event.Skip(); 330} 331 332// ---------------------------------------------------------------------------- 333// adding/removing the pages 334// ---------------------------------------------------------------------------- 335 336bool wxToolbook::InsertPage(size_t n, 337 wxWindow *page, 338 const wxString& text, 339 bool bSelect, 340 int imageId) 341{ 342 if ( !wxBookCtrlBase::InsertPage(n, page, text, bSelect, imageId) ) 343 return false; 344 345 m_needsRealizing = true; 346 347 wxASSERT(GetImageList() != NULL); 348 349 if (!GetImageList()) 350 return false; 351 352 // TODO: make sure all platforms can convert between icon and bitmap, 353 // and/or test whether the image is a bitmap or an icon. 354#ifdef __WXMAC__ 355 wxBitmap bitmap = GetImageList()->GetBitmap(imageId); 356#else 357 // On Windows, we can lose information by using GetBitmap, so extract icon instead 358 wxIcon icon = GetImageList()->GetIcon(imageId); 359 wxBitmap bitmap; 360 bitmap.CopyFromIcon(icon); 361#endif 362 363 m_maxBitmapSize.x = wxMax(bitmap.GetWidth(), m_maxBitmapSize.x); 364 m_maxBitmapSize.y = wxMax(bitmap.GetHeight(), m_maxBitmapSize.y); 365 366 GetToolBar()->SetToolBitmapSize(m_maxBitmapSize); 367 GetToolBar()->AddRadioTool(n + 1, text, bitmap, wxNullBitmap, text); 368 369 if (bSelect) 370 { 371 GetToolBar()->ToggleTool(n, true); 372 m_selection = n; 373 } 374 else 375 page->Hide(); 376 377 InvalidateBestSize(); 378 return true; 379} 380 381wxWindow *wxToolbook::DoRemovePage(size_t page) 382{ 383 const size_t page_count = GetPageCount(); 384 wxWindow *win = wxBookCtrlBase::DoRemovePage(page); 385 386 if ( win ) 387 { 388 GetToolBar()->DeleteTool(page + 1); 389 390 if (m_selection >= (int)page) 391 { 392 // force new sel valid if possible 393 int sel = m_selection - 1; 394 if (page_count == 1) 395 sel = wxNOT_FOUND; 396 else if ((page_count == 2) || (sel == -1)) 397 sel = 0; 398 399 // force sel invalid if deleting current page - don't try to hide it 400 m_selection = (m_selection == (int)page) ? wxNOT_FOUND : m_selection - 1; 401 402 if ((sel != wxNOT_FOUND) && (sel != m_selection)) 403 SetSelection(sel); 404 } 405 } 406 407 return win; 408} 409 410 411bool wxToolbook::DeleteAllPages() 412{ 413 GetToolBar()->ClearTools(); 414 return wxBookCtrlBase::DeleteAllPages(); 415} 416 417// ---------------------------------------------------------------------------- 418// wxToolbook events 419// ---------------------------------------------------------------------------- 420 421void wxToolbook::OnToolSelected(wxCommandEvent& event) 422{ 423 const int selNew = event.GetId() - 1; 424 425 if ( selNew == m_selection ) 426 { 427 // this event can only come from our own Select(m_selection) below 428 // which we call when the page change is vetoed, so we should simply 429 // ignore it 430 return; 431 } 432 433 SetSelection(selNew); 434 435 // change wasn't allowed, return to previous state 436 if (m_selection != selNew) 437 { 438 GetToolBar()->ToggleTool(m_selection, false); 439 } 440} 441 442#endif // wxUSE_TOOLBOOK 443