Steps towards implementing native-style, non-top-level toolbars on Mac
[wxWidgets.git] / src / generic / buttonbar.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/buttonbar.cpp
3 // Purpose: wxButtonToolBar implementation
4 // Author: Julian Smart, after Robert Roebling, Vadim Zeitlin, SciTech
5 // Modified by:
6 // Created: 2006-04-13
7 // Id: $Id$
8 // Copyright: (c) Julian Smart, Robert Roebling, Vadim Zeitlin,
9 // SciTech Software, Inc.
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 // ============================================================================
14 // declarations
15 // ============================================================================
16
17 // ----------------------------------------------------------------------------
18 // headers
19 // ----------------------------------------------------------------------------
20
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23
24 #ifdef __BORLANDC__
25 #pragma hdrstop
26 #endif
27
28 #if wxUSE_TOOLBAR && wxUSE_BMPBUTTON
29
30 #ifndef WX_PRECOMP
31 #include "wx/utils.h"
32 #include "wx/app.h"
33 #endif
34
35 #include "wx/generic/buttonbar.h"
36 #include "wx/frame.h"
37 #include "wx/image.h"
38 #include "wx/log.h"
39
40 // ----------------------------------------------------------------------------
41 // wxButtonToolBarTool: our implementation of wxToolBarToolBase
42 // ----------------------------------------------------------------------------
43
44 class WXDLLEXPORT wxButtonToolBarTool : public wxToolBarToolBase
45 {
46 public:
47 wxButtonToolBarTool(wxButtonToolBar *tbar,
48 int id,
49 const wxString& label,
50 const wxBitmap& bmpNormal,
51 const wxBitmap& bmpDisabled,
52 wxItemKind kind,
53 wxObject *clientData,
54 const wxString& shortHelp,
55 const wxString& longHelp)
56 : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind,
57 clientData, shortHelp, longHelp)
58 {
59 m_x = m_y = wxDefaultCoord;
60 m_width =
61 m_height = 0;
62
63 m_button = NULL;
64 }
65
66 wxButtonToolBarTool(wxButtonToolBar *tbar, wxControl *control)
67 : wxToolBarToolBase(tbar, control)
68 {
69 m_x = m_y = wxDefaultCoord;
70 m_width =
71 m_height = 0;
72 m_button = NULL;
73 }
74
75 wxBitmapButton* GetButton() const { return m_button; }
76 void SetButton(wxBitmapButton* button) { m_button = button; }
77
78 public:
79 // the tool position (for controls)
80 wxCoord m_x;
81 wxCoord m_y;
82 wxCoord m_width;
83 wxCoord m_height;
84
85 private:
86 // the control representing the button
87 wxBitmapButton* m_button;
88 };
89
90 // ============================================================================
91 // wxButtonToolBar implementation
92 // ============================================================================
93
94 IMPLEMENT_DYNAMIC_CLASS(wxButtonToolBar, wxControl)
95
96 BEGIN_EVENT_TABLE(wxButtonToolBar, wxControl)
97 EVT_BUTTON(wxID_ANY, wxButtonToolBar::OnCommand)
98 END_EVENT_TABLE()
99
100 // ----------------------------------------------------------------------------
101 // wxButtonToolBar creation
102 // ----------------------------------------------------------------------------
103
104 void wxButtonToolBar::Init()
105 {
106 // no tools yet
107 m_needsLayout = false;
108
109 // unknown widths for the tools and separators
110 m_widthSeparator = wxDefaultCoord;
111
112 m_maxWidth =
113 m_maxHeight = 0;
114 }
115
116 bool wxButtonToolBar::Create(wxWindow *parent,
117 wxWindowID id,
118 const wxPoint& pos,
119 const wxSize& size,
120 long style,
121 const wxString& name)
122 {
123 if ( !wxToolBarBase::Create(parent, id, pos, size, style,
124 wxDefaultValidator, name) )
125 {
126 return false;
127 }
128
129 return true;
130 }
131
132 wxButtonToolBar::~wxButtonToolBar()
133 {
134 }
135
136 // ----------------------------------------------------------------------------
137 // wxButtonToolBar tool-related methods
138 // ----------------------------------------------------------------------------
139
140 wxToolBarToolBase *wxButtonToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
141 {
142 // check the "other" direction first: it must be inside the toolbar or we
143 // don't risk finding anything
144 if ( IsVertical() )
145 {
146 if ( x < 0 || x > m_maxWidth )
147 return NULL;
148
149 // we always use x, even for a vertical toolbar, this makes the code
150 // below simpler
151 x = y;
152 }
153 else // horizontal
154 {
155 if ( y < 0 || y > m_maxHeight )
156 return NULL;
157 }
158
159 for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
160 node;
161 node = node->GetNext() )
162 {
163 wxButtonToolBarTool *tool = (wxButtonToolBarTool*) node->GetData();
164 wxRect rectTool = GetToolRect(tool);
165
166 wxCoord startTool, endTool;
167 GetRectLimits(rectTool, &startTool, &endTool);
168
169 if ( x >= startTool && x <= endTool )
170 {
171 // don't return the separators from here, they don't accept any
172 // input anyhow
173 return tool->IsSeparator() ? NULL : tool;
174 }
175 }
176
177 return NULL;
178 }
179
180 void wxButtonToolBar::GetRectLimits(const wxRect& rect,
181 wxCoord *start,
182 wxCoord *end) const
183 {
184 wxCHECK_RET( start && end, _T("NULL pointer in GetRectLimits") );
185
186 if ( IsVertical() )
187 {
188 *start = rect.GetTop();
189 *end = rect.GetBottom();
190 }
191 else // horizontal
192 {
193 *start = rect.GetLeft();
194 *end = rect.GetRight();
195 }
196 }
197
198
199 void wxButtonToolBar::SetToolShortHelp(int id, const wxString& help)
200 {
201 wxToolBarToolBase *tool = FindById(id);
202
203 wxCHECK_RET( tool, _T("SetToolShortHelp: no such tool") );
204
205 // TODO: set tooltip/short help
206 tool->SetShortHelp(help);
207 }
208
209 bool wxButtonToolBar::DoInsertTool(size_t WXUNUSED(pos),
210 wxToolBarToolBase * WXUNUSED(tool))
211 {
212 return true;
213 }
214
215 bool wxButtonToolBar::DoDeleteTool(size_t WXUNUSED(pos),
216 wxToolBarToolBase * WXUNUSED(tool))
217 {
218 // TODO
219 return true;
220 }
221
222 void wxButtonToolBar::DoEnableTool(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(enable))
223 {
224 // TODO
225 }
226
227 void wxButtonToolBar::DoToggleTool(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
228 {
229 // TODO
230 }
231
232 void wxButtonToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
233 {
234 // TODO
235 }
236
237 wxToolBarToolBase *wxButtonToolBar::CreateTool(int id,
238 const wxString& label,
239 const wxBitmap& bmpNormal,
240 const wxBitmap& bmpDisabled,
241 wxItemKind kind,
242 wxObject *clientData,
243 const wxString& shortHelp,
244 const wxString& longHelp)
245 {
246 return new wxButtonToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind,
247 clientData, shortHelp, longHelp);
248 }
249
250 wxToolBarToolBase *wxButtonToolBar::CreateTool(wxControl *control)
251 {
252 return new wxButtonToolBarTool(this, control);
253 }
254
255 // ----------------------------------------------------------------------------
256 // wxButtonToolBar geometry
257 // ----------------------------------------------------------------------------
258
259 wxRect wxButtonToolBar::GetToolRect(wxToolBarToolBase *toolBase) const
260 {
261 const wxButtonToolBarTool *tool = (wxButtonToolBarTool *)toolBase;
262
263 wxRect rect;
264
265 wxCHECK_MSG( tool, rect, _T("GetToolRect: NULL tool") );
266
267 // ensure that we always have the valid tool position
268 if ( m_needsLayout )
269 {
270 wxConstCast(this, wxButtonToolBar)->DoLayout();
271 }
272
273 rect.x = tool->m_x - m_xMargin;
274 rect.y = tool->m_y - m_yMargin;
275
276 if ( IsVertical() )
277 {
278 if (tool->IsButton())
279 {
280 rect.width = m_defaultWidth;
281 rect.height = m_defaultHeight;
282 if (tool->GetButton())
283 rect.SetSize(tool->GetButton()->GetSize());
284 }
285 else if (tool->IsSeparator())
286 {
287 rect.width = m_defaultWidth;
288 rect.height = m_widthSeparator;
289 }
290 else // control
291 {
292 rect.width = tool->m_width;
293 rect.height = tool->m_height;
294 }
295 }
296 else // horizontal
297 {
298 if (tool->IsButton())
299 {
300 rect.width = m_defaultWidth;
301 rect.height = m_defaultHeight;
302 if (tool->GetButton())
303 rect.SetSize(tool->GetButton()->GetSize());
304 }
305 else if (tool->IsSeparator())
306 {
307 rect.width = m_widthSeparator;
308 rect.height = m_defaultHeight;
309 }
310 else // control
311 {
312 rect.width = tool->m_width;
313 rect.height = tool->m_height;
314 }
315 }
316
317 rect.width += 2*m_xMargin;
318 rect.height += 2*m_yMargin;
319
320 return rect;
321 }
322
323 bool wxButtonToolBar::Realize()
324 {
325 if ( !wxToolBarBase::Realize() )
326 return false;
327
328 m_needsLayout = true;
329 DoLayout();
330
331 SetBestSize(wxSize(m_maxWidth, m_maxHeight));
332
333 return true;
334 }
335
336 void wxButtonToolBar::DoLayout()
337 {
338 m_needsLayout = false;
339
340 wxCoord x = m_xMargin,
341 y = m_yMargin;
342
343 int maxHeight = 0;
344
345 const wxCoord widthTool = IsVertical() ? m_defaultHeight : m_defaultWidth;
346 wxCoord margin = IsVertical() ? m_xMargin : m_yMargin;
347 wxCoord *pCur = IsVertical() ? &y : &x;
348
349 // calculate the positions of all elements
350 for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
351 node;
352 node = node->GetNext() )
353 {
354 wxButtonToolBarTool *tool = (wxButtonToolBarTool *) node->GetData();
355
356 tool->m_x = x;
357 tool->m_y = y;
358
359 if (tool->IsButton())
360 {
361 if (!tool->GetButton())
362 {
363 wxBitmapButton* bmpButton = new wxBitmapButton(this, tool->GetId(), tool->GetNormalBitmap(), wxPoint(tool->m_x, tool->m_y), wxDefaultSize,
364 wxBU_AUTODRAW);
365
366 tool->SetButton(bmpButton);
367 }
368 else
369 {
370 tool->GetButton()->Move(wxPoint(tool->m_x, tool->m_y));
371 }
372
373 int w = widthTool;
374 if (tool->GetButton())
375 {
376 wxSize sz = tool->GetButton()->GetSize();
377 w = sz.x;
378
379 maxHeight = wxMax(maxHeight, sz.y);
380 }
381
382 *pCur += (w + GetToolPacking());
383 }
384 else if (tool->IsSeparator())
385 {
386 *pCur += m_widthSeparator;
387 }
388 else if (!IsVertical()) // horizontal control
389 {
390 wxControl *control = tool->GetControl();
391 wxSize size = control->GetSize();
392 tool->m_y += (m_defaultHeight - size.y)/2;
393 tool->m_width = size.x;
394 tool->m_height = size.y;
395
396 *pCur += tool->m_width;
397
398 maxHeight = wxMax(maxHeight, size.y);
399 }
400 *pCur += margin;
401 }
402
403 // calculate the total toolbar size
404 m_maxWidth = x + 2*m_xMargin;
405 m_maxHeight = maxHeight + 2*m_yMargin;
406 }
407
408 wxSize wxButtonToolBar::DoGetBestClientSize() const
409 {
410 return wxSize(m_maxWidth, m_maxHeight);
411 }
412
413 // receives button commands
414 void wxButtonToolBar::OnCommand(wxCommandEvent& event)
415 {
416 wxButtonToolBarTool* tool = (wxButtonToolBarTool*) FindById(event.GetId());
417 if (!tool)
418 {
419 event.Skip();
420 return;
421 }
422
423 // TODO: handle toggle items
424 OnLeftClick(event.GetId(), false);
425 }
426
427 #endif // wxUSE_TOOLBAR && wxUSE_BMPBUTTON
428