]> git.saurik.com Git - wxWidgets.git/blob - src/common/tbarbase.cpp
fix button double click handling (should be treated the same as single click)
[wxWidgets.git] / src / common / tbarbase.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/tbarbase.cpp
3 // Purpose: wxToolBarBase implementation
4 // Author: Julian Smart
5 // Modified by: VZ at 11.12.99 (wxScrollableToolBar splitted off)
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "tbarbase.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_TOOLBAR
32
33 #ifndef WX_PRECOMP
34 #include "wx/control.h"
35 #endif
36
37 #include "wx/frame.h"
38 #include "wx/image.h"
39 #include "wx/settings.h"
40
41 #include "wx/tbarbase.h"
42
43 // ----------------------------------------------------------------------------
44 // wxWindows macros
45 // ----------------------------------------------------------------------------
46
47 IMPLEMENT_CLASS(wxToolBarBase, wxControl)
48
49 BEGIN_EVENT_TABLE(wxToolBarBase, wxControl)
50 EVT_IDLE(wxToolBarBase::OnIdle)
51 END_EVENT_TABLE()
52
53 #include "wx/listimpl.cpp"
54
55 WX_DEFINE_LIST(wxToolBarToolsList);
56
57 // ============================================================================
58 // implementation
59 // ============================================================================
60
61 // ----------------------------------------------------------------------------
62 // wxToolBarToolBase
63 // ----------------------------------------------------------------------------
64
65 bool wxToolBarToolBase::Enable(bool enable)
66 {
67 if ( m_enabled == enable )
68 return FALSE;
69
70 m_enabled = enable;
71
72 return TRUE;
73 }
74
75 bool wxToolBarToolBase::Toggle(bool toggle)
76 {
77 wxASSERT_MSG( m_isToggle, _T("can't toggle this tool") );
78
79 if ( m_toggled == toggle )
80 return FALSE;
81
82 m_toggled = toggle;
83
84 return TRUE;
85 }
86
87 bool wxToolBarToolBase::SetToggle(bool toggle)
88 {
89 if ( m_isToggle == toggle )
90 return FALSE;
91
92 m_isToggle = toggle;
93
94 return TRUE;
95 }
96
97 bool wxToolBarToolBase::SetShortHelp(const wxString& help)
98 {
99 if ( m_shortHelpString == help )
100 return FALSE;
101
102 m_shortHelpString = help;
103
104 return TRUE;
105 }
106
107 bool wxToolBarToolBase::SetLongHelp(const wxString& help)
108 {
109 if ( m_longHelpString == help )
110 return FALSE;
111
112 m_longHelpString = help;
113
114 return TRUE;
115 }
116
117 wxToolBarToolBase::~wxToolBarToolBase()
118 {
119 }
120
121 // ----------------------------------------------------------------------------
122 // wxToolBarBase adding/deleting items
123 // ----------------------------------------------------------------------------
124
125 wxToolBarBase::wxToolBarBase()
126 {
127 // the list owns the pointers
128 m_tools.DeleteContents(TRUE);
129
130 m_xMargin = m_yMargin = 0;
131
132 m_maxRows = m_maxCols = 0;
133 }
134
135 wxToolBarToolBase *wxToolBarBase::AddTool(int id,
136 const wxBitmap& bitmap,
137 const wxBitmap& pushedBitmap,
138 bool toggle,
139 wxCoord WXUNUSED(xPos),
140 wxCoord WXUNUSED(yPos),
141 wxObject *clientData,
142 const wxString& helpString1,
143 const wxString& helpString2)
144 {
145 return InsertTool(GetToolsCount(), id, bitmap, pushedBitmap,
146 toggle, clientData, helpString1, helpString2);
147 }
148
149 wxToolBarToolBase *wxToolBarBase::InsertTool(size_t pos,
150 int id,
151 const wxBitmap& bitmap,
152 const wxBitmap& pushedBitmap,
153 bool toggle,
154 wxObject *clientData,
155 const wxString& helpString1,
156 const wxString& helpString2)
157 {
158 wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL,
159 _T("invalid position in wxToolBar::InsertTool()") );
160
161 wxToolBarToolBase *tool = CreateTool(id, bitmap, pushedBitmap, toggle,
162 clientData, helpString1, helpString2);
163
164 if ( !tool || !DoInsertTool(pos, tool) )
165 {
166 delete tool;
167
168 return NULL;
169 }
170
171 m_tools.Insert(pos, tool);
172
173 return tool;
174 }
175
176 wxToolBarToolBase *wxToolBarBase::AddControl(wxControl *control)
177 {
178 return InsertControl(GetToolsCount(), control);
179 }
180
181 wxToolBarToolBase *wxToolBarBase::InsertControl(size_t pos, wxControl *control)
182 {
183 wxCHECK_MSG( control, (wxToolBarToolBase *)NULL,
184 _T("toolbar: can't insert NULL control") );
185
186 wxCHECK_MSG( control->GetParent() == this, (wxToolBarToolBase *)NULL,
187 _T("control must have toolbar as parent") );
188
189 wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL,
190 _T("invalid position in wxToolBar::InsertControl()") );
191
192 wxToolBarToolBase *tool = CreateTool(control);
193
194 if ( !tool || !DoInsertTool(pos, tool) )
195 {
196 delete tool;
197
198 return NULL;
199 }
200
201 m_tools.Insert(pos, tool);
202
203 return tool;
204 }
205
206 wxToolBarToolBase *wxToolBarBase::AddSeparator()
207 {
208 return InsertSeparator(GetToolsCount());
209 }
210
211 wxToolBarToolBase *wxToolBarBase::InsertSeparator(size_t pos)
212 {
213 wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL,
214 _T("invalid position in wxToolBar::InsertSeparator()") );
215
216 wxToolBarToolBase *tool = CreateTool(wxID_SEPARATOR,
217 wxNullBitmap, wxNullBitmap,
218 FALSE, (wxObject *)NULL,
219 wxEmptyString, wxEmptyString);
220
221 if ( !tool || !DoInsertTool(pos, tool) )
222 {
223 delete tool;
224
225 return NULL;
226 }
227
228 m_tools.Insert(pos, tool);
229
230 return tool;
231 }
232
233 wxToolBarToolBase *wxToolBarBase::RemoveTool(int id)
234 {
235 size_t pos = 0;
236 wxToolBarToolsList::Node *node;
237 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
238 {
239 if ( node->GetData()->GetId() == id )
240 break;
241
242 pos++;
243 }
244
245 if ( !node )
246 {
247 // don't give any error messages - sometimes we might call RemoveTool()
248 // without knowing whether the tool is or not in the toolbar
249 return (wxToolBarToolBase *)NULL;
250 }
251
252 wxToolBarToolBase *tool = node->GetData();
253 if ( !DoDeleteTool(pos, tool) )
254 {
255 return (wxToolBarToolBase *)NULL;
256 }
257
258 // the node would delete the data, so set it to NULL to avoid this
259 node->SetData(NULL);
260
261 m_tools.DeleteNode(node);
262
263 return tool;
264 }
265
266 bool wxToolBarBase::DeleteToolByPos(size_t pos)
267 {
268 wxCHECK_MSG( pos < GetToolsCount(), FALSE,
269 _T("invalid position in wxToolBar::DeleteToolByPos()") );
270
271 wxToolBarToolsList::Node *node = m_tools.Item(pos);
272
273 if ( !DoDeleteTool(pos, node->GetData()) )
274 {
275 return FALSE;
276 }
277
278 m_tools.DeleteNode(node);
279
280 return TRUE;
281 }
282
283 bool wxToolBarBase::DeleteTool(int id)
284 {
285 size_t pos = 0;
286 wxToolBarToolsList::Node *node;
287 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
288 {
289 if ( node->GetData()->GetId() == id )
290 break;
291
292 pos++;
293 }
294
295 if ( !node || !DoDeleteTool(pos, node->GetData()) )
296 {
297 return FALSE;
298 }
299
300 m_tools.DeleteNode(node);
301
302 return TRUE;
303 }
304
305 wxToolBarToolBase *wxToolBarBase::FindById(int id) const
306 {
307 wxToolBarToolBase *tool = (wxToolBarToolBase *)NULL;
308
309 for ( wxToolBarToolsList::Node *node = m_tools.GetFirst();
310 node;
311 node = node->GetNext() )
312 {
313 tool = node->GetData();
314 if ( tool->GetId() == id )
315 {
316 // found
317 break;
318 }
319
320 tool = NULL;
321 }
322
323 return tool;
324 }
325
326 void wxToolBarBase::ClearTools()
327 {
328 m_tools.Clear();
329 }
330
331 bool wxToolBarBase::Realize()
332 {
333 return TRUE;
334 }
335
336 wxToolBarBase::~wxToolBarBase()
337 {
338 }
339
340 // ----------------------------------------------------------------------------
341 // wxToolBarBase tools state
342 // ----------------------------------------------------------------------------
343
344 void wxToolBarBase::EnableTool(int id, bool enable)
345 {
346 wxToolBarToolBase *tool = FindById(id);
347 if ( tool )
348 {
349 if ( tool->Enable(enable) )
350 {
351 DoEnableTool(tool, enable);
352 }
353 }
354 }
355
356 void wxToolBarBase::ToggleTool(int id, bool toggle)
357 {
358 wxToolBarToolBase *tool = FindById(id);
359 if ( tool && tool->CanBeToggled() )
360 {
361 if ( tool->Toggle(toggle) )
362 {
363 DoToggleTool(tool, toggle);
364 }
365 }
366 }
367
368 void wxToolBarBase::SetToggle(int id, bool toggle)
369 {
370 wxToolBarToolBase *tool = FindById(id);
371 if ( tool )
372 {
373 if ( tool->SetToggle(toggle) )
374 {
375 DoSetToggle(tool, toggle);
376 }
377 }
378 }
379
380 void wxToolBarBase::SetToolShortHelp(int id, const wxString& help)
381 {
382 wxToolBarToolBase *tool = FindById(id);
383 if ( tool )
384 {
385 (void)tool->SetShortHelp(help);
386 }
387 }
388
389 void wxToolBarBase::SetToolLongHelp(int id, const wxString& help)
390 {
391 wxToolBarToolBase *tool = FindById(id);
392 if ( tool )
393 {
394 (void)tool->SetLongHelp(help);
395 }
396 }
397
398 wxObject *wxToolBarBase::GetToolClientData(int id) const
399 {
400 wxToolBarToolBase *tool = FindById(id);
401
402 return tool ? tool->GetClientData() : (wxObject *)NULL;
403 }
404
405 void wxToolBarBase::SetToolClientData(int id, wxObject *clientData)
406 {
407 wxToolBarToolBase *tool = FindById(id);
408
409 wxCHECK_RET( tool, _T("no such tool in wxToolBar::SetToolClientData") );
410
411 tool->SetClientData(clientData);
412 }
413
414 bool wxToolBarBase::GetToolState(int id) const
415 {
416 wxToolBarToolBase *tool = FindById(id);
417 wxCHECK_MSG( tool, FALSE, _T("no such tool") );
418
419 return tool->IsToggled();
420 }
421
422 bool wxToolBarBase::GetToolEnabled(int id) const
423 {
424 wxToolBarToolBase *tool = FindById(id);
425 wxCHECK_MSG( tool, FALSE, _T("no such tool") );
426
427 return tool->IsEnabled();
428 }
429
430 wxString wxToolBarBase::GetToolShortHelp(int id) const
431 {
432 wxToolBarToolBase *tool = FindById(id);
433 wxCHECK_MSG( tool, _T(""), _T("no such tool") );
434
435 return tool->GetShortHelp();
436 }
437
438 wxString wxToolBarBase::GetToolLongHelp(int id) const
439 {
440 wxToolBarToolBase *tool = FindById(id);
441 wxCHECK_MSG( tool, _T(""), _T("no such tool") );
442
443 return tool->GetLongHelp();
444 }
445
446 // ----------------------------------------------------------------------------
447 // wxToolBarBase geometry
448 // ----------------------------------------------------------------------------
449
450 void wxToolBarBase::SetMargins(int x, int y)
451 {
452 m_xMargin = x;
453 m_yMargin = y;
454 }
455
456 void wxToolBarBase::SetRows(int WXUNUSED(nRows))
457 {
458 // nothing
459 }
460
461 // ----------------------------------------------------------------------------
462 // event processing
463 // ----------------------------------------------------------------------------
464
465 // Only allow toggle if returns TRUE
466 bool wxToolBarBase::OnLeftClick(int id, bool toggleDown)
467 {
468 wxCommandEvent event(wxEVT_COMMAND_TOOL_CLICKED, id);
469 event.SetEventObject(this);
470
471 // we use SetInt() to make wxCommandEvent::IsChecked() return toggleDown
472 event.SetInt((int)toggleDown);
473
474 // and SetExtraLong() for backwards compatibility
475 event.SetExtraLong((long)toggleDown);
476
477 // Send events to this toolbar instead (and thence up the window hierarchy)
478 GetEventHandler()->ProcessEvent(event);
479
480 return TRUE;
481 }
482
483 // Call when right button down.
484 void wxToolBarBase::OnRightClick(int id,
485 long WXUNUSED(x),
486 long WXUNUSED(y))
487 {
488 wxCommandEvent event(wxEVT_COMMAND_TOOL_RCLICKED, id);
489 event.SetEventObject(this);
490 event.SetInt(id);
491
492 GetEventHandler()->ProcessEvent(event);
493 }
494
495 // Called when the mouse cursor enters a tool bitmap (no button pressed).
496 // Argument is -1 if mouse is exiting the toolbar.
497 // Note that for this event, the id of the window is used,
498 // and the integer parameter of wxCommandEvent is used to retrieve
499 // the tool id.
500 void wxToolBarBase::OnMouseEnter(int id)
501 {
502 wxCommandEvent event(wxEVT_COMMAND_TOOL_ENTER, GetId());
503 event.SetEventObject(this);
504 event.SetInt(id);
505
506 (void)GetEventHandler()->ProcessEvent(event);
507
508 wxToolBarToolBase *tool = FindById(id);
509 if ( !tool || !tool->GetLongHelp() )
510 return;
511
512 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
513 if ( !frame )
514 return;
515
516 frame->SetStatusText(tool->GetLongHelp());
517 }
518
519 // ----------------------------------------------------------------------------
520 // UI updates
521 // ----------------------------------------------------------------------------
522
523 void wxToolBarBase::OnIdle(wxIdleEvent& event)
524 {
525 DoToolbarUpdates();
526
527 event.Skip();
528 }
529
530 // Do the toolbar button updates (check for EVT_UPDATE_UI handlers)
531 void wxToolBarBase::DoToolbarUpdates()
532 {
533 wxWindow* parent = this;
534 while (parent->GetParent())
535 parent = parent->GetParent();
536
537 #ifdef __WXMSW__
538 wxWindow* focusWin = wxFindFocusDescendant(parent);
539 #else
540 wxWindow* focusWin = (wxWindow*) NULL;
541 #endif
542
543 wxEvtHandler* evtHandler = focusWin ? focusWin->GetEventHandler() : GetEventHandler() ;
544
545 for ( wxToolBarToolsList::Node* node = m_tools.GetFirst();
546 node;
547 node = node->GetNext() )
548 {
549 int id = node->GetData()->GetId();
550
551 wxUpdateUIEvent event(id);
552 event.SetEventObject(this);
553
554 if ( evtHandler->ProcessEvent(event) )
555 {
556 if ( event.GetSetEnabled() )
557 EnableTool(id, event.GetEnabled());
558 if ( event.GetSetChecked() )
559 ToggleTool(id, event.GetChecked());
560 #if 0
561 if ( event.GetSetText() )
562 // Set tooltip?
563 #endif // 0
564 }
565 }
566 }
567
568 // Helper function, used by wxCreateGreyedImage
569
570 static void wxGreyOutImage( const wxImage& src,
571 wxImage& dest,
572 const wxColour& darkCol,
573 const wxColour& lightCol,
574 const wxColour& bgCol )
575 {
576 // Second attempt, just making things monochrome
577 int width = src.GetWidth();
578 int height = src.GetHeight();
579
580 int redCur, greenCur, blueCur;
581 for ( int x = 0; x < width; x++ )
582 {
583 for ( int y = 1; y < height; y++ )
584 {
585 redCur = src.GetRed(x, y);
586 greenCur = src.GetGreen(x, y);
587 blueCur = src.GetBlue(x, y);
588
589 // Change light things to the background colour
590 if ( redCur >= (lightCol.Red() - 50) && greenCur >= (lightCol.Green() - 50) && blueCur >= (lightCol.Blue() - 50) )
591 {
592 dest.SetRGB(x,y, bgCol.Red(), bgCol.Green(), bgCol.Blue());
593 }
594 else if ( redCur == bgCol.Red() && greenCur == bgCol.Green() && blueCur == bgCol.Blue() )
595 {
596 // Leave the background colour as-is
597 // dest.SetRGB(x,y, bgCol.Red(), bgCol.Green(), bgCol.Blue());
598 }
599 else // if ( redCur <= darkCol.Red() && greenCur <= darkCol.Green() && blueCur <= darkCol.Blue() )
600 {
601 // Change dark things to really dark
602 dest.SetRGB(x,y, darkCol.Red(), darkCol.Green(), darkCol.Blue());
603 }
604 }
605 }
606 }
607
608 /*
609 * Make a greyed-out image suitable for disabled buttons.
610 * This code is adapted from wxNewBitmapButton in FL.
611 */
612
613 bool wxCreateGreyedImage(const wxImage& in, wxImage& out)
614 {
615 out = in.Copy();
616
617 // assuming the pixels along the edges are of the background color
618 wxColour bgCol(in.GetRed(0, 0), in.GetGreen(0, 0), in.GetBlue(0, 0));
619
620 wxColour darkCol = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW) ;
621 wxColour lightCol = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT) ;
622
623 wxGreyOutImage(in, out, darkCol, lightCol, bgCol);
624
625 return TRUE;
626 }
627
628 #endif // wxUSE_TOOLBAR