1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "toolbar.h"
19 #include "wx/toolbar.h"
22 #include <Xm/PushBG.h>
25 #include <Xm/ToggleB.h>
26 #include <Xm/ToggleBG.h>
29 #include "wx/motif/private.h"
31 #if !USE_SHARED_LIBRARY
32 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxToolBarBase
)
34 BEGIN_EVENT_TABLE(wxToolBar
, wxToolBarBase
)
38 static void wxToolButtonCallback (Widget w
, XtPointer clientData
,
40 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
41 XEvent
*event
, Boolean
*continue_to_dispatch
);
43 class wxToolBarTimer
: public wxTimer
47 virtual void Notify();
49 static Widget help_popup
;
50 static Widget buttonWidget
;
51 static wxString helpString
;
54 static wxToolBarTimer
* wxTheToolBarTimer
= (wxToolBarTimer
*) NULL
;
56 Widget
wxToolBarTimer::help_popup
= (Widget
) 0;
57 Widget
wxToolBarTimer::buttonWidget
= (Widget
) 0;
58 wxString
wxToolBarTimer::helpString
= "";
60 wxToolBar::wxToolBar():
61 m_widgets(wxKEY_INTEGER
)
69 bool wxToolBar::Create(wxWindow
*parent
, wxWindowID id
, const wxPoint
& pos
, const wxSize
& size
,
70 long style
, const wxString
& name
)
78 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
);
79 m_foregroundColour
= parent
->GetForegroundColour();
80 m_windowStyle
= style
;
84 if (parent
) parent
->AddChild(this);
86 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
88 Widget toolbar
= XtVaCreateManagedWidget("toolbar",
89 xmBulletinBoardWidgetClass
, (Widget
) parentWidget
,
92 XmNresizePolicy
, XmRESIZE_NONE
,
95 Widget toolbar = XtVaCreateManagedWidget("toolbar",
96 xmFormWidgetClass, (Widget) m_clientWidget,
97 XmNtraversalOn, False,
98 XmNhorizontalSpacing, 0,
99 XmNverticalSpacing, 0,
107 m_mainWidget
= (WXWidget
) toolbar
;
109 m_windowFont
= parent
->GetFont();
112 SetCanAddEventHandler(TRUE
);
113 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, size
.x
, size
.y
);
115 ChangeBackgroundColour();
120 wxToolBar::~wxToolBar()
122 delete wxTheToolBarTimer
;
123 wxTheToolBarTimer
= NULL
;
128 bool wxToolBar::CreateTools()
130 if (m_tools
.Number() == 0)
134 const int separatorSize
= GetToolSeparation(); // 8;
135 wxSize margins
= GetToolMargins();
136 int marginX
= margins
.x
;
137 int marginY
= margins
.y
;
139 int currentX
= marginX
;
140 int currentY
= marginY
;
142 int buttonHeight
= 0;
144 int currentSpacing
= 0;
147 Widget prevButton
= (Widget
) 0;
148 wxNode
* node
= m_tools
.First();
151 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
153 if (tool
->m_toolStyle
== wxTOOL_STYLE_SEPARATOR
)
154 currentX
+= separatorSize
;
155 else if (tool
->m_bitmap1
.Ok())
157 Widget button
= (Widget
) 0;
159 if (tool
->m_isToggle
)
161 button
= XtVaCreateWidget("toggleButton",
162 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
163 XmNx
, currentX
, XmNy
, currentY
,
164 // XmNpushButtonEnabled, True,
165 XmNmultiClick
, XmMULTICLICK_KEEP
,
166 XmNlabelType
, XmPIXMAP
,
168 XtAddCallback ((Widget
) button
, XmNvalueChangedCallback
, (XtCallbackProc
) wxToolButtonCallback
,
173 button
= XtVaCreateWidget("button",
174 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
175 XmNx
, currentX
, XmNy
, currentY
,
176 XmNpushButtonEnabled
, True
,
177 XmNmultiClick
, XmMULTICLICK_KEEP
,
178 XmNlabelType
, XmPIXMAP
,
180 XtAddCallback (button
,
181 XmNactivateCallback
, (XtCallbackProc
) wxToolButtonCallback
,
185 DoChangeBackgroundColour((WXWidget
) button
, m_backgroundColour
, TRUE
);
187 // For each button, if there is a mask, we must create
188 // a new wxBitmap that has the correct background colour
189 // for the button. Otherwise the background will just be
190 // e.g. black if a transparent XPM has been loaded.
191 wxBitmap originalBitmap
= tool
->m_bitmap1
;
193 if (tool
->m_bitmap1
.GetMask())
196 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
201 col
.SetPixel(backgroundPixel
);
203 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap1
, col
);
205 tool
->m_bitmap1
= newBitmap
;
208 // Create a selected/toggled bitmap. If there isn't a m_bitmap2,
209 // we need to create it (with a darker, selected background)
211 if (tool
->m_isToggle
)
212 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
215 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
219 col
.SetPixel(backgroundPixel
);
221 if (tool
->m_bitmap2
.Ok() && tool
->m_bitmap2
.GetMask())
224 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap2
, col
);
225 tool
->m_bitmap2
= newBitmap
;
229 // Use unselected bitmap
230 if (originalBitmap
.GetMask())
232 wxBitmap newBitmap
= wxCreateMaskedBitmap(originalBitmap
, col
);
233 tool
->m_bitmap2
= newBitmap
;
236 tool
->m_bitmap2
= tool
->m_bitmap1
;
239 Pixmap pixmap
= (Pixmap
) tool
->m_bitmap1
.GetPixmap();
240 Pixmap insensPixmap
= (Pixmap
) tool
->m_bitmap1
.GetInsensPixmap();
242 if (tool
->m_isToggle
)
245 Pixmap pixmap2
= (Pixmap
) 0;
246 Pixmap insensPixmap2
= (Pixmap
) 0;
248 // If there's a bitmap for the toggled state, use it,
249 // otherwise generate one.
250 if (tool
->m_bitmap2
.Ok())
252 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
253 insensPixmap2
= (Pixmap
) tool
->m_bitmap2
.GetInsensPixmap();
257 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
258 insensPixmap2
= XCreateInsensitivePixmap((Display
*) wxGetDisplay(), pixmap2
);
259 m_pixmaps
.Append((wxObject
*) insensPixmap2
); // Store for later deletion
261 XtVaSetValues (button
,
262 XmNindicatorOn
, False
,
263 XmNshadowThickness
, 2,
264 // XmNborderWidth, 0,
268 XmNfillOnSelect
, True
,
269 XmNlabelPixmap
, pixmap
,
270 XmNselectPixmap
, pixmap2
,
271 XmNlabelInsensitivePixmap
, insensPixmap
,
272 XmNselectInsensitivePixmap
, insensPixmap2
,
273 XmNlabelType
, XmPIXMAP
,
278 Pixmap pixmap2
= (Pixmap
) 0;
280 // If there's a bitmap for the armed state, use it,
281 // otherwise generate one.
282 if (tool
->m_bitmap2
.Ok())
284 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
288 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
292 XtVaSetValues(button
,
293 XmNlabelPixmap
, pixmap
,
294 XmNlabelInsensitivePixmap
, insensPixmap
,
295 XmNarmPixmap
, pixmap2
,
298 XtManageChild(button
);
300 Dimension width
, height
;
301 XtVaGetValues(button
, XmNwidth
, & width
, XmNheight
, & height
,
303 currentX
+= width
+ marginX
;
304 buttonHeight
= wxMax(buttonHeight
, height
);
306 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
307 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
308 m_widgets
.Append(tool
->m_index
, (wxObject
*) button
);
316 SetSize(-1, -1, currentX
, buttonHeight
+ 2*marginY
);
321 // Old version, assuming we use a form. Now we use
322 // a bulletin board, so we can create controls on the toolbar.
324 bool wxToolBar::CreateTools()
326 if (m_tools
.Number() == 0)
330 const int separatorSize
= GetToolSeparation(); // 8;
332 int currentSpacing
= 0;
335 Widget prevButton
= (Widget
) 0;
336 wxNode
* node
= m_tools
.First();
339 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
341 if (tool
->m_toolStyle
== wxTOOL_STYLE_SEPARATOR
)
342 currentSpacing
= separatorSize
;
343 else if (tool
->m_bitmap1
.Ok())
345 Widget button
= (Widget
) 0;
347 if (tool
->m_isToggle
)
349 button
= XtVaCreateManagedWidget("toggleButton",
350 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
351 XmNleftAttachment
, (prevButton
== (Widget
) 0) ? XmATTACH_FORM
: XmATTACH_WIDGET
,
352 XmNleftWidget
, (prevButton
== (Widget
) 0) ? NULL
: prevButton
,
353 XmNleftOffset
, currentSpacing
,
354 XmNtopAttachment
, XmATTACH_FORM
,
355 // XmNpushButtonEnabled, True,
356 XmNmultiClick
, XmMULTICLICK_KEEP
,
357 XmNlabelType
, XmPIXMAP
,
359 XtAddCallback ((Widget
) button
, XmNvalueChangedCallback
, (XtCallbackProc
) wxToolButtonCallback
,
364 button
= XtVaCreateManagedWidget("button",
365 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
366 XmNleftAttachment
, (prevButton
== (Widget
) 0) ? XmATTACH_FORM
: XmATTACH_WIDGET
,
367 XmNleftWidget
, (prevButton
== (Widget
) 0) ? NULL
: prevButton
,
368 XmNleftOffset
, currentSpacing
,
369 XmNtopAttachment
, XmATTACH_FORM
,
370 XmNpushButtonEnabled
, True
,
371 XmNmultiClick
, XmMULTICLICK_KEEP
,
372 XmNlabelType
, XmPIXMAP
,
374 XtAddCallback (button
,
375 XmNactivateCallback
, (XtCallbackProc
) wxToolButtonCallback
,
379 // For each button, if there is a mask, we must create
380 // a new wxBitmap that has the correct background colour
381 // for the button. Otherwise the background will just be
382 // e.g. black if a transparent XPM has been loaded.
383 wxBitmap originalBitmap
= tool
->m_bitmap1
;
385 if (tool
->m_bitmap1
.GetMask())
388 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
393 col
.SetPixel(backgroundPixel
);
395 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap1
, col
);
397 tool
->m_bitmap1
= newBitmap
;
400 // Create a selected/toggled bitmap. If there isn't a m_bitmap2,
401 // we need to create it (with a darker, selected background)
403 if (tool
->m_isToggle
)
404 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
407 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
411 col
.SetPixel(backgroundPixel
);
413 if (tool
->m_bitmap2
.Ok() && tool
->m_bitmap2
.GetMask())
416 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap2
, col
);
417 tool
->m_bitmap2
= newBitmap
;
421 // Use unselected bitmap
422 if (originalBitmap
.GetMask())
424 wxBitmap newBitmap
= wxCreateMaskedBitmap(originalBitmap
, col
);
425 tool
->m_bitmap2
= newBitmap
;
428 tool
->m_bitmap2
= tool
->m_bitmap1
;
431 Pixmap pixmap
= (Pixmap
) tool
->m_bitmap1
.GetPixmap();
432 Pixmap insensPixmap
= (Pixmap
) tool
->m_bitmap1
.GetInsensPixmap();
434 if (tool
->m_isToggle
)
437 Pixmap pixmap2
= (Pixmap
) 0;
438 Pixmap insensPixmap2
= (Pixmap
) 0;
440 // If there's a bitmap for the toggled state, use it,
441 // otherwise generate one.
442 if (tool
->m_bitmap2
.Ok())
444 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
445 insensPixmap2
= (Pixmap
) tool
->m_bitmap2
.GetInsensPixmap();
449 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
450 insensPixmap2
= XCreateInsensitivePixmap((Display
*) wxGetDisplay(), pixmap2
);
451 m_pixmaps
.Append((wxObject
*) insensPixmap2
); // Store for later deletion
453 XtVaSetValues (button
,
454 XmNindicatorOn
, False
,
455 XmNshadowThickness
, 2,
456 // XmNborderWidth, 0,
460 XmNfillOnSelect
, True
,
461 XmNlabelPixmap
, pixmap
,
462 XmNselectPixmap
, pixmap2
,
463 XmNlabelInsensitivePixmap
, insensPixmap
,
464 XmNselectInsensitivePixmap
, insensPixmap2
,
465 XmNlabelType
, XmPIXMAP
,
470 Pixmap pixmap2
= (Pixmap
) 0;
472 // If there's a bitmap for the armed state, use it,
473 // otherwise generate one.
474 if (tool
->m_bitmap2
.Ok())
476 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
480 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
484 XtVaSetValues(button
,
485 XmNlabelPixmap
, pixmap
,
486 XmNlabelInsensitivePixmap
, insensPixmap
,
487 XmNarmPixmap
, pixmap2
,
491 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
492 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
493 m_widgets
.Append(tool
->m_index
, (wxObject
*) button
);
505 void wxToolBar::SetToolBitmapSize(const wxSize
& size
)
507 // TODO not necessary?
508 m_defaultWidth
= size
.x
; m_defaultHeight
= size
.y
;
511 wxSize
wxToolBar::GetMaxSize() const
519 // The button size is bigger than the bitmap size
520 wxSize
wxToolBar::GetToolSize() const
522 // TODO not necessary?
523 return wxSize(m_defaultWidth
+ 8, m_defaultHeight
+ 7);
526 void wxToolBar::EnableTool(int toolIndex
, bool enable
)
528 wxNode
*node
= m_tools
.Find((long)toolIndex
);
531 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
532 tool
->m_enabled
= enable
;
534 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
535 if (widget
== (WXWidget
) 0)
538 XtSetSensitive((Widget
) widget
, (Boolean
) enable
);
542 void wxToolBar::ToggleTool(int toolIndex
, bool toggle
)
544 wxNode
*node
= m_tools
.Find((long)toolIndex
);
547 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
548 if (tool
->m_isToggle
)
550 tool
->m_toggleState
= toggle
;
552 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
553 if (widget
== (WXWidget
) 0)
556 XmToggleButtonSetState((Widget
) widget
, (Boolean
) toggle
, False
);
561 void wxToolBar::ClearTools()
563 wxNode
* node
= m_widgets
.First();
566 Widget button
= (Widget
) node
->Data();
567 XtDestroyWidget(button
);
573 wxToolBarBase::ClearTools();
576 void wxToolBar::DestroyPixmaps()
578 wxNode
* node
= m_pixmaps
.First();
581 Pixmap pixmap
= (Pixmap
) node
->Data();
582 XmDestroyPixmap (DefaultScreenOfDisplay ((Display
*) GetXDisplay()), pixmap
);
588 // If pushedBitmap is NULL, a reversed version of bitmap is
589 // created and used as the pushed/toggled image.
590 // If toggle is TRUE, the button toggles between the two states.
592 wxToolBarTool
*wxToolBar::AddTool(int index
, const wxBitmap
& bitmap
, const wxBitmap
& pushedBitmap
,
593 bool toggle
, long xPos
, long yPos
, wxObject
*clientData
, const wxString
& helpString1
, const wxString
& helpString2
)
595 wxToolBarTool
*tool
= new wxToolBarTool(index
, bitmap
, wxNullBitmap
, toggle
, xPos
, yPos
, helpString1
, helpString2
);
596 tool
->m_clientData
= clientData
;
601 tool
->m_x
= m_xMargin
;
606 tool
->m_y
= m_yMargin
;
608 wxSize
& size
= GetToolSize();
609 tool
->SetSize(size
.x
, size
.y
);
611 m_tools
.Append((long)index
, tool
);
615 int wxToolBar::FindIndexForWidget(WXWidget w
)
617 wxNode
* node
= m_widgets
.First();
620 WXWidget widget
= (WXWidget
) node
->Data();
622 return (int) node
->GetKeyInteger();
628 WXWidget
wxToolBar::FindWidgetForIndex(int index
)
630 wxNode
* node
= m_widgets
.Find((long) index
);
634 return (WXWidget
) node
->Data();
637 WXWidget
wxToolBar::GetTopWidget() const
642 WXWidget
wxToolBar::GetClientWidget() const
647 WXWidget
wxToolBar::GetMainWidget() const
653 void wxToolButtonCallback (Widget w
, XtPointer clientData
,
656 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
657 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
661 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
664 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
665 if (tool
->m_isToggle
)
666 tool
->m_toggleState
= toolBar
->GetToolState(index
);
668 (void) toolBar
->OnLeftClick(index
, tool
->m_toggleState
);
674 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
675 XEvent
*event
, Boolean
*continue_to_dispatch
)
677 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
678 int delayMilli
= 800;
679 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
681 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
685 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
688 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
689 wxString
str(toolBar
->GetToolShortHelp(index
));
690 if (str
.IsNull() || str
== "")
693 if (!wxTheToolBarTimer
)
694 wxTheToolBarTimer
= new wxToolBarTimer
;
696 wxToolBarTimer::buttonWidget
= w
;
697 wxToolBarTimer::helpString
= str
;
700 /************************************************************/
701 /* Popup help label */
702 /************************************************************/
703 if (event
->type
== EnterNotify
)
705 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
707 XtDestroyWidget (wxToolBarTimer::help_popup
);
708 XtPopdown (wxToolBarTimer::help_popup
);
710 wxToolBarTimer::help_popup
= (Widget
) 0;
713 wxTheToolBarTimer
->Start(delayMilli
, TRUE
);
716 /************************************************************/
717 /* Popdown help label */
718 /************************************************************/
719 else if (event
->type
== LeaveNotify
)
721 if (wxTheToolBarTimer
)
722 wxTheToolBarTimer
->Stop();
723 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
725 XtDestroyWidget (wxToolBarTimer::help_popup
);
726 XtPopdown (wxToolBarTimer::help_popup
);
728 wxToolBarTimer::help_popup
= (Widget
) 0;
733 void wxToolBarTimer::Notify()
737 /************************************************************/
738 /* Create shell without window decorations */
739 /************************************************************/
740 help_popup
= XtVaCreatePopupShell ("shell",
741 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
744 /************************************************************/
745 /* Get absolute position on display of toolbar button */
746 /************************************************************/
747 XtTranslateCoords (buttonWidget
,
752 // Move the tooltip more or less above the button
753 int yOffset
= 20; // TODO: What should be really?
755 if (y
< yOffset
) y
= 0;
757 /************************************************************/
758 /* Set the position of the help popup */
759 /************************************************************/
760 XtVaSetValues (help_popup
,
765 /************************************************************/
766 /* Create help label */
767 /************************************************************/
768 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
769 XtVaCreateManagedWidget ("help_label",
770 xmLabelWidgetClass
, help_popup
,
771 XmNlabelString
, text
,
773 XmNforeground
, XtRString
, "black",
776 XmNbackground
, XtRString
, "LightGoldenrod",
777 strlen("LightGoldenrod")+1,
781 /************************************************************/
782 /* Popup help label */
783 /************************************************************/
784 XtPopup (help_popup
, XtGrabNone
);