Set/get for internal border in book based controls.
[wxWidgets.git] / src / generic / choicbkg.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: generic/choicbkg.cpp
3 // Purpose: generic implementation of wxChoicebook
4 // Author: Vadim Zeitlin
5 // Modified by: Wlodzimierz ABX Skiba from generic/listbkg.cpp
6 // Created: 15.09.04
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin, Wlodzimierz Skiba
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_CHOICEBOOK
28
29 #include "wx/choice.h"
30 #include "wx/choicebk.h"
31 #include "wx/imaglist.h"
32 #include "wx/settings.h"
33
34 // ----------------------------------------------------------------------------
35 // various wxWidgets macros
36 // ----------------------------------------------------------------------------
37
38 // check that the page index is valid
39 #define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount())
40
41 // ----------------------------------------------------------------------------
42 // event table
43 // ----------------------------------------------------------------------------
44
45 IMPLEMENT_DYNAMIC_CLASS(wxChoicebook, wxControl)
46 IMPLEMENT_DYNAMIC_CLASS(wxChoicebookEvent, wxNotifyEvent)
47
48 const wxEventType wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGING = wxNewEventType();
49 const wxEventType wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGED = wxNewEventType();
50 const int wxID_CHOICEBOOKCHOICE = wxNewId();
51
52 BEGIN_EVENT_TABLE(wxChoicebook, wxBookCtrlBase)
53 EVT_SIZE(wxChoicebook::OnSize)
54 EVT_CHOICE(wxID_CHOICEBOOKCHOICE, wxChoicebook::OnChoiceSelected)
55 END_EVENT_TABLE()
56
57 // ============================================================================
58 // wxChoicebook implementation
59 // ============================================================================
60
61 // ----------------------------------------------------------------------------
62 // wxChoicebook creation
63 // ----------------------------------------------------------------------------
64
65 void wxChoicebook::Init()
66 {
67 m_choice = NULL;
68 m_selection = wxNOT_FOUND;
69 }
70
71 bool
72 wxChoicebook::Create(wxWindow *parent,
73 wxWindowID id,
74 const wxPoint& pos,
75 const wxSize& size,
76 long style,
77 const wxString& name)
78 {
79 if ( (style & wxCHB_ALIGN_MASK) == wxCHB_DEFAULT )
80 {
81 style |= wxCHB_TOP;
82 }
83
84 // no border for this control, it doesn't look nice together with
85 // wxChoice border
86 style &= ~wxBORDER_MASK;
87 style |= wxBORDER_NONE;
88
89 if ( !wxControl::Create(parent, id, pos, size, style,
90 wxDefaultValidator, name) )
91 return false;
92
93 m_choice = new wxChoice
94 (
95 this,
96 wxID_CHOICEBOOKCHOICE,
97 wxDefaultPosition,
98 wxDefaultSize
99 );
100
101 return true;
102 }
103
104 // ----------------------------------------------------------------------------
105 // wxChoicebook geometry management
106 // ----------------------------------------------------------------------------
107
108 wxSize wxChoicebook::GetChoiceSize() const
109 {
110 const wxSize sizeClient = GetClientSize(),
111 sizeChoice = m_choice->GetBestFittingSize();
112
113 wxSize size;
114 if ( IsVertical() )
115 {
116 size.x = sizeClient.x;
117 size.y = sizeChoice.y;
118 }
119 else // left/right aligned
120 {
121 size.x = sizeChoice.x;
122 size.y = sizeClient.y;
123 }
124
125 return size;
126 }
127
128 wxRect wxChoicebook::GetPageRect() const
129 {
130 const wxSize sizeChoice = m_choice->GetBestFittingSize();
131
132 wxPoint pt;
133 wxRect rectPage(pt, GetClientSize());
134 switch ( GetWindowStyle() & wxCHB_ALIGN_MASK )
135 {
136 default:
137 wxFAIL_MSG( _T("unexpected wxChoicebook alignment") );
138 // fall through
139
140 case wxCHB_TOP:
141 rectPage.y = sizeChoice.y + GetInternalBorder();
142 // fall through
143
144 case wxCHB_BOTTOM:
145 rectPage.height -= sizeChoice.y + GetInternalBorder();
146 break;
147
148 case wxCHB_LEFT:
149 rectPage.x = sizeChoice.x + GetInternalBorder();
150 // fall through
151
152 case wxCHB_RIGHT:
153 rectPage.width -= sizeChoice.x + GetInternalBorder();
154 break;
155 }
156
157 return rectPage;
158 }
159
160 void wxChoicebook::OnSize(wxSizeEvent& event)
161 {
162 event.Skip();
163
164 if ( !m_choice )
165 {
166 // we're not fully created yet
167 return;
168 }
169
170 // resize the choice control and the page area to fit inside our new size
171 const wxSize sizeClient = GetClientSize(),
172 sizeChoice = GetChoiceSize();
173
174 wxPoint posChoice;
175 switch ( GetWindowStyle() & wxCHB_ALIGN_MASK )
176 {
177 default:
178 wxFAIL_MSG( _T("unexpected wxChoicebook alignment") );
179 // fall through
180
181 case wxCHB_TOP:
182 case wxCHB_LEFT:
183 // posChoice is already ok
184 break;
185
186 case wxCHB_BOTTOM:
187 posChoice.y = sizeClient.y - sizeChoice.y;
188 break;
189
190 case wxCHB_RIGHT:
191 posChoice.x = sizeClient.x - sizeChoice.x;
192 break;
193 }
194
195 m_choice->Move(posChoice);
196 m_choice->SetSize(sizeChoice);
197
198 // resize the currently shown page
199 if ( m_selection != wxNOT_FOUND )
200 {
201 wxWindow *page = m_pages[m_selection];
202 wxCHECK_RET( page, _T("NULL page in wxChoicebook?") );
203 page->SetSize(GetPageRect());
204 }
205 }
206
207 wxSize wxChoicebook::CalcSizeFromPage(const wxSize& sizePage) const
208 {
209 // we need to add the size of the choice control and the border between
210 const wxSize sizeChoice = GetChoiceSize();
211
212 wxSize size = sizePage;
213 if ( IsVertical() )
214 {
215 size.y += sizeChoice.y + GetInternalBorder();
216 }
217 else // left/right aligned
218 {
219 size.x += sizeChoice.x + GetInternalBorder();
220 }
221
222 return size;
223 }
224
225
226 // ----------------------------------------------------------------------------
227 // accessing the pages
228 // ----------------------------------------------------------------------------
229
230 bool wxChoicebook::SetPageText(size_t n, const wxString& strText)
231 {
232 m_choice->SetString(n, strText);
233
234 return true;
235 }
236
237 wxString wxChoicebook::GetPageText(size_t n) const
238 {
239 return m_choice->GetString(n);
240 }
241
242 int wxChoicebook::GetPageImage(size_t WXUNUSED(n)) const
243 {
244 wxFAIL_MSG( _T("wxChoicebook::GetPageImage() not implemented") );
245
246 return wxNOT_FOUND;
247 }
248
249 bool wxChoicebook::SetPageImage(size_t WXUNUSED(n), int WXUNUSED(imageId))
250 {
251 wxFAIL_MSG( _T("wxChoicebook::SetPageImage() not implemented") );
252
253 return false;
254 }
255
256 // ----------------------------------------------------------------------------
257 // image list stuff
258 // ----------------------------------------------------------------------------
259
260 void wxChoicebook::SetImageList(wxImageList *imageList)
261 {
262 // TODO: can be implemented in form of static bitmap near choice control
263
264 wxBookCtrlBase::SetImageList(imageList);
265 }
266
267 // ----------------------------------------------------------------------------
268 // selection
269 // ----------------------------------------------------------------------------
270
271 int wxChoicebook::GetSelection() const
272 {
273 return m_selection;
274 }
275
276 int wxChoicebook::SetSelection(size_t n)
277 {
278 wxCHECK_MSG( IS_VALID_PAGE(n), wxNOT_FOUND,
279 wxT("invalid page index in wxChoicebook::SetSelection()") );
280
281 const int oldSel = m_selection;
282
283 if ( int(n) != m_selection )
284 {
285 wxChoicebookEvent event(wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGING, m_windowId);
286 event.SetSelection(n);
287 event.SetOldSelection(m_selection);
288 event.SetEventObject(this);
289 if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
290 {
291 if ( m_selection != wxNOT_FOUND )
292 m_pages[m_selection]->Hide();
293
294 wxWindow *page = m_pages[n];
295 page->SetSize(GetPageRect());
296 page->Show();
297
298 // change m_selection now to ignore the selection change event
299 m_selection = n;
300 m_choice->Select(n);
301
302 // program allows the page change
303 event.SetEventType(wxEVT_COMMAND_CHOICEBOOK_PAGE_CHANGED);
304 (void)GetEventHandler()->ProcessEvent(event);
305 }
306 }
307
308 return oldSel;
309 }
310
311 // ----------------------------------------------------------------------------
312 // adding/removing the pages
313 // ----------------------------------------------------------------------------
314
315 bool
316 wxChoicebook::InsertPage(size_t n,
317 wxWindow *page,
318 const wxString& text,
319 bool bSelect,
320 int imageId)
321 {
322 if ( !wxBookCtrlBase::InsertPage(n, page, text, bSelect, imageId) )
323 return false;
324
325 m_choice->Insert(text, n);
326
327 // if the inserted page is before the selected one, we must update the
328 // index of the selected page
329 if ( int(n) <= m_selection )
330 {
331 // one extra page added
332 m_selection++;
333 m_choice->Select(m_selection);
334 }
335
336 // some page should be selected: either this one or the first one if there
337 // is still no selection
338 int selNew = wxNOT_FOUND;
339 if ( bSelect )
340 selNew = n;
341 else if ( m_selection == wxNOT_FOUND )
342 selNew = 0;
343
344 if ( selNew != m_selection )
345 page->Hide();
346
347 if ( selNew != wxNOT_FOUND )
348 SetSelection(selNew);
349
350 InvalidateBestSize();
351 return true;
352 }
353
354 wxWindow *wxChoicebook::DoRemovePage(size_t page)
355 {
356 const size_t page_count = GetPageCount();
357 wxWindow *win = wxBookCtrlBase::DoRemovePage(page);
358
359 if ( win )
360 {
361 m_choice->Delete(page);
362
363 if (m_selection >= (int)page)
364 {
365 // force new sel valid if possible
366 int sel = m_selection - 1;
367 if (page_count == 1)
368 sel = wxNOT_FOUND;
369 else if ((page_count == 2) || (sel == -1))
370 sel = 0;
371
372 // force sel invalid if deleting current page - don't try to hide it
373 m_selection = (m_selection == (int)page) ? wxNOT_FOUND : m_selection - 1;
374
375 if ((sel != wxNOT_FOUND) && (sel != m_selection))
376 SetSelection(sel);
377 }
378 }
379
380 return win;
381 }
382
383
384 bool wxChoicebook::DeleteAllPages()
385 {
386 m_choice->Clear();
387 return wxBookCtrlBase::DeleteAllPages();
388 }
389
390 // ----------------------------------------------------------------------------
391 // wxChoicebook events
392 // ----------------------------------------------------------------------------
393
394 void wxChoicebook::OnChoiceSelected(wxCommandEvent& eventChoice)
395 {
396 const int selNew = eventChoice.GetSelection();
397
398 if ( selNew == m_selection )
399 {
400 // this event can only come from our own Select(m_selection) below
401 // which we call when the page change is vetoed, so we should simply
402 // ignore it
403 return;
404 }
405
406 SetSelection(selNew);
407
408 // change wasn't allowed, return to previous state
409 if (m_selection != selNew)
410 m_choice->Select(m_selection);
411 }
412
413 #endif // wxUSE_CHOICEBOOK