1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "toolbar.h"
19 #include "wx/motif/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 // For each button, if there is a mask, we must create
186 // a new wxBitmap that has the correct background colour
187 // for the button. Otherwise the background will just be
188 // e.g. black if a transparent XPM has been loaded.
189 wxBitmap originalBitmap
= tool
->m_bitmap1
;
191 if (tool
->m_bitmap1
.GetMask())
194 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
199 col
.SetPixel(backgroundPixel
);
201 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap1
, col
);
203 tool
->m_bitmap1
= newBitmap
;
206 // Create a selected/toggled bitmap. If there isn't a m_bitmap2,
207 // we need to create it (with a darker, selected background)
209 if (tool
->m_isToggle
)
210 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
213 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
217 col
.SetPixel(backgroundPixel
);
219 if (tool
->m_bitmap2
.Ok() && tool
->m_bitmap2
.GetMask())
222 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap2
, col
);
223 tool
->m_bitmap2
= newBitmap
;
227 // Use unselected bitmap
228 if (originalBitmap
.GetMask())
230 wxBitmap newBitmap
= wxCreateMaskedBitmap(originalBitmap
, col
);
231 tool
->m_bitmap2
= newBitmap
;
234 tool
->m_bitmap2
= tool
->m_bitmap1
;
237 Pixmap pixmap
= (Pixmap
) tool
->m_bitmap1
.GetPixmap();
238 Pixmap insensPixmap
= (Pixmap
) tool
->m_bitmap1
.GetInsensPixmap();
240 if (tool
->m_isToggle
)
243 Pixmap pixmap2
= (Pixmap
) 0;
244 Pixmap insensPixmap2
= (Pixmap
) 0;
246 // If there's a bitmap for the toggled state, use it,
247 // otherwise generate one.
248 if (tool
->m_bitmap2
.Ok())
250 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
251 insensPixmap2
= (Pixmap
) tool
->m_bitmap2
.GetInsensPixmap();
255 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
256 insensPixmap2
= XCreateInsensitivePixmap((Display
*) wxGetDisplay(), pixmap2
);
257 m_pixmaps
.Append((wxObject
*) insensPixmap2
); // Store for later deletion
259 XtVaSetValues (button
,
260 XmNindicatorOn
, False
,
261 XmNshadowThickness
, 2,
262 // XmNborderWidth, 0,
266 XmNfillOnSelect
, True
,
267 XmNlabelPixmap
, pixmap
,
268 XmNselectPixmap
, pixmap2
,
269 XmNlabelInsensitivePixmap
, insensPixmap
,
270 XmNselectInsensitivePixmap
, insensPixmap2
,
271 XmNlabelType
, XmPIXMAP
,
276 Pixmap pixmap2
= (Pixmap
) 0;
278 // If there's a bitmap for the armed state, use it,
279 // otherwise generate one.
280 if (tool
->m_bitmap2
.Ok())
282 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
286 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
290 XtVaSetValues(button
,
291 XmNlabelPixmap
, pixmap
,
292 XmNlabelInsensitivePixmap
, insensPixmap
,
293 XmNarmPixmap
, pixmap2
,
296 XtManageChild(button
);
298 Dimension width
, height
;
299 XtVaGetValues(button
, XmNwidth
, & width
, XmNheight
, & height
,
301 currentX
+= width
+ marginX
;
302 buttonHeight
= wxMax(buttonHeight
, height
);
304 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
305 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
306 m_widgets
.Append(tool
->m_index
, (wxObject
*) button
);
314 SetSize(-1, -1, currentX
, buttonHeight
+ 2*marginY
);
319 // Old version, assuming we use a form. Now we use
320 // a bulletin board, so we can create controls on the toolbar.
322 bool wxToolBar::CreateTools()
324 if (m_tools
.Number() == 0)
328 const int separatorSize
= GetToolSeparation(); // 8;
330 int currentSpacing
= 0;
333 Widget prevButton
= (Widget
) 0;
334 wxNode
* node
= m_tools
.First();
337 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
339 if (tool
->m_toolStyle
== wxTOOL_STYLE_SEPARATOR
)
340 currentSpacing
= separatorSize
;
341 else if (tool
->m_bitmap1
.Ok())
343 Widget button
= (Widget
) 0;
345 if (tool
->m_isToggle
)
347 button
= XtVaCreateManagedWidget("toggleButton",
348 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
349 XmNleftAttachment
, (prevButton
== (Widget
) 0) ? XmATTACH_FORM
: XmATTACH_WIDGET
,
350 XmNleftWidget
, (prevButton
== (Widget
) 0) ? NULL
: prevButton
,
351 XmNleftOffset
, currentSpacing
,
352 XmNtopAttachment
, XmATTACH_FORM
,
353 // XmNpushButtonEnabled, True,
354 XmNmultiClick
, XmMULTICLICK_KEEP
,
355 XmNlabelType
, XmPIXMAP
,
357 XtAddCallback ((Widget
) button
, XmNvalueChangedCallback
, (XtCallbackProc
) wxToolButtonCallback
,
362 button
= XtVaCreateManagedWidget("button",
363 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
364 XmNleftAttachment
, (prevButton
== (Widget
) 0) ? XmATTACH_FORM
: XmATTACH_WIDGET
,
365 XmNleftWidget
, (prevButton
== (Widget
) 0) ? NULL
: prevButton
,
366 XmNleftOffset
, currentSpacing
,
367 XmNtopAttachment
, XmATTACH_FORM
,
368 XmNpushButtonEnabled
, True
,
369 XmNmultiClick
, XmMULTICLICK_KEEP
,
370 XmNlabelType
, XmPIXMAP
,
372 XtAddCallback (button
,
373 XmNactivateCallback
, (XtCallbackProc
) wxToolButtonCallback
,
377 // For each button, if there is a mask, we must create
378 // a new wxBitmap that has the correct background colour
379 // for the button. Otherwise the background will just be
380 // e.g. black if a transparent XPM has been loaded.
381 wxBitmap originalBitmap
= tool
->m_bitmap1
;
383 if (tool
->m_bitmap1
.GetMask())
386 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
391 col
.SetPixel(backgroundPixel
);
393 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap1
, col
);
395 tool
->m_bitmap1
= newBitmap
;
398 // Create a selected/toggled bitmap. If there isn't a m_bitmap2,
399 // we need to create it (with a darker, selected background)
401 if (tool
->m_isToggle
)
402 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
405 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
409 col
.SetPixel(backgroundPixel
);
411 if (tool
->m_bitmap2
.Ok() && tool
->m_bitmap2
.GetMask())
414 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap2
, col
);
415 tool
->m_bitmap2
= newBitmap
;
419 // Use unselected bitmap
420 if (originalBitmap
.GetMask())
422 wxBitmap newBitmap
= wxCreateMaskedBitmap(originalBitmap
, col
);
423 tool
->m_bitmap2
= newBitmap
;
426 tool
->m_bitmap2
= tool
->m_bitmap1
;
429 Pixmap pixmap
= (Pixmap
) tool
->m_bitmap1
.GetPixmap();
430 Pixmap insensPixmap
= (Pixmap
) tool
->m_bitmap1
.GetInsensPixmap();
432 if (tool
->m_isToggle
)
435 Pixmap pixmap2
= (Pixmap
) 0;
436 Pixmap insensPixmap2
= (Pixmap
) 0;
438 // If there's a bitmap for the toggled state, use it,
439 // otherwise generate one.
440 if (tool
->m_bitmap2
.Ok())
442 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
443 insensPixmap2
= (Pixmap
) tool
->m_bitmap2
.GetInsensPixmap();
447 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
448 insensPixmap2
= XCreateInsensitivePixmap((Display
*) wxGetDisplay(), pixmap2
);
449 m_pixmaps
.Append((wxObject
*) insensPixmap2
); // Store for later deletion
451 XtVaSetValues (button
,
452 XmNindicatorOn
, False
,
453 XmNshadowThickness
, 2,
454 // XmNborderWidth, 0,
458 XmNfillOnSelect
, True
,
459 XmNlabelPixmap
, pixmap
,
460 XmNselectPixmap
, pixmap2
,
461 XmNlabelInsensitivePixmap
, insensPixmap
,
462 XmNselectInsensitivePixmap
, insensPixmap2
,
463 XmNlabelType
, XmPIXMAP
,
468 Pixmap pixmap2
= (Pixmap
) 0;
470 // If there's a bitmap for the armed state, use it,
471 // otherwise generate one.
472 if (tool
->m_bitmap2
.Ok())
474 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
478 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
482 XtVaSetValues(button
,
483 XmNlabelPixmap
, pixmap
,
484 XmNlabelInsensitivePixmap
, insensPixmap
,
485 XmNarmPixmap
, pixmap2
,
489 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
490 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
491 m_widgets
.Append(tool
->m_index
, (wxObject
*) button
);
503 void wxToolBar::SetToolBitmapSize(const wxSize
& size
)
505 // TODO not necessary?
506 m_defaultWidth
= size
.x
; m_defaultHeight
= size
.y
;
509 wxSize
wxToolBar::GetMaxSize() const
517 // The button size is bigger than the bitmap size
518 wxSize
wxToolBar::GetToolSize() const
520 // TODO not necessary?
521 return wxSize(m_defaultWidth
+ 8, m_defaultHeight
+ 7);
524 void wxToolBar::EnableTool(int toolIndex
, bool enable
)
526 wxNode
*node
= m_tools
.Find((long)toolIndex
);
529 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
530 tool
->m_enabled
= enable
;
532 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
533 if (widget
== (WXWidget
) 0)
536 XtSetSensitive((Widget
) widget
, (Boolean
) enable
);
540 void wxToolBar::ToggleTool(int toolIndex
, bool toggle
)
542 wxNode
*node
= m_tools
.Find((long)toolIndex
);
545 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
546 if (tool
->m_isToggle
)
548 tool
->m_toggleState
= toggle
;
550 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
551 if (widget
== (WXWidget
) 0)
554 XmToggleButtonSetState((Widget
) widget
, (Boolean
) toggle
, False
);
559 void wxToolBar::ClearTools()
561 wxNode
* node
= m_widgets
.First();
564 Widget button
= (Widget
) node
->Data();
565 XtDestroyWidget(button
);
571 wxToolBarBase::ClearTools();
574 void wxToolBar::DestroyPixmaps()
576 wxNode
* node
= m_pixmaps
.First();
579 Pixmap pixmap
= (Pixmap
) node
->Data();
580 XmDestroyPixmap (DefaultScreenOfDisplay ((Display
*) GetXDisplay()), pixmap
);
586 // If pushedBitmap is NULL, a reversed version of bitmap is
587 // created and used as the pushed/toggled image.
588 // If toggle is TRUE, the button toggles between the two states.
590 wxToolBarTool
*wxToolBar::AddTool(int index
, const wxBitmap
& bitmap
, const wxBitmap
& pushedBitmap
,
591 bool toggle
, long xPos
, long yPos
, wxObject
*clientData
, const wxString
& helpString1
, const wxString
& helpString2
)
593 wxToolBarTool
*tool
= new wxToolBarTool(index
, bitmap
, wxNullBitmap
, toggle
, xPos
, yPos
, helpString1
, helpString2
);
594 tool
->m_clientData
= clientData
;
599 tool
->m_x
= m_xMargin
;
604 tool
->m_y
= m_yMargin
;
606 tool
->SetSize(GetDefaultButtonWidth(), GetDefaultButtonHeight());
608 m_tools
.Append((long)index
, tool
);
612 int wxToolBar::FindIndexForWidget(WXWidget w
)
614 wxNode
* node
= m_widgets
.First();
617 WXWidget widget
= (WXWidget
) node
->Data();
619 return (int) node
->GetKeyInteger();
625 WXWidget
wxToolBar::FindWidgetForIndex(int index
)
627 wxNode
* node
= m_widgets
.Find((long) index
);
631 return (WXWidget
) node
->Data();
634 WXWidget
wxToolBar::GetTopWidget() const
639 WXWidget
wxToolBar::GetClientWidget() const
644 WXWidget
wxToolBar::GetMainWidget() const
650 void wxToolButtonCallback (Widget w
, XtPointer clientData
,
653 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
654 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
658 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
661 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
662 if (tool
->m_isToggle
)
663 tool
->m_toggleState
= toolBar
->GetToolState(index
);
665 (void) toolBar
->OnLeftClick(index
, tool
->m_toggleState
);
671 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
672 XEvent
*event
, Boolean
*continue_to_dispatch
)
674 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
675 int delayMilli
= 800;
676 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
678 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
682 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
685 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
686 wxString
str(toolBar
->GetToolShortHelp(index
));
687 if (str
.IsNull() || str
== "")
690 if (!wxTheToolBarTimer
)
691 wxTheToolBarTimer
= new wxToolBarTimer
;
693 wxToolBarTimer::buttonWidget
= w
;
694 wxToolBarTimer::helpString
= str
;
697 /************************************************************/
698 /* Popup help label */
699 /************************************************************/
700 if (event
->type
== EnterNotify
)
702 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
704 XtDestroyWidget (wxToolBarTimer::help_popup
);
705 XtPopdown (wxToolBarTimer::help_popup
);
707 wxToolBarTimer::help_popup
= (Widget
) 0;
710 wxTheToolBarTimer
->Start(delayMilli
, TRUE
);
713 /************************************************************/
714 /* Popdown help label */
715 /************************************************************/
716 else if (event
->type
== LeaveNotify
)
718 if (wxTheToolBarTimer
)
719 wxTheToolBarTimer
->Stop();
720 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
722 XtDestroyWidget (wxToolBarTimer::help_popup
);
723 XtPopdown (wxToolBarTimer::help_popup
);
725 wxToolBarTimer::help_popup
= (Widget
) 0;
730 void wxToolBarTimer::Notify()
734 /************************************************************/
735 /* Create shell without window decorations */
736 /************************************************************/
737 help_popup
= XtVaCreatePopupShell ("shell",
738 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
741 /************************************************************/
742 /* Get absolute position on display of toolbar button */
743 /************************************************************/
744 XtTranslateCoords (buttonWidget
,
749 // Move the tooltip more or less above the button
750 int yOffset
= 20; // TODO: What should be really?
752 if (y
< yOffset
) y
= 0;
754 /************************************************************/
755 /* Set the position of the help popup */
756 /************************************************************/
757 XtVaSetValues (help_popup
,
762 /************************************************************/
763 /* Create help label */
764 /************************************************************/
765 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
766 XtVaCreateManagedWidget ("help_label",
767 xmLabelWidgetClass
, help_popup
,
768 XmNlabelString
, text
,
770 XmNforeground
, XtRString
, "black",
773 XmNbackground
, XtRString
, "LightGoldenrod",
774 strlen("LightGoldenrod")+1,
778 /************************************************************/
779 /* Popup help label */
780 /************************************************************/
781 XtPopup (help_popup
, XtGrabNone
);