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
)
79 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
);
80 m_foregroundColour
= parent
->GetForegroundColour();
81 m_windowStyle
= style
;
85 if (parent
) parent
->AddChild(this);
87 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
89 Widget toolbar
= XtVaCreateManagedWidget("toolbar",
90 xmBulletinBoardWidgetClass
, (Widget
) parentWidget
,
93 XmNresizePolicy
, XmRESIZE_NONE
,
96 Widget toolbar = XtVaCreateManagedWidget("toolbar",
97 xmFormWidgetClass, (Widget) m_clientWidget,
98 XmNtraversalOn, False,
99 XmNhorizontalSpacing, 0,
100 XmNverticalSpacing, 0,
108 m_mainWidget
= (WXWidget
) toolbar
;
110 m_font
= parent
->GetFont();
113 SetCanAddEventHandler(TRUE
);
114 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, size
.x
, size
.y
);
116 ChangeBackgroundColour();
121 wxToolBar::~wxToolBar()
123 delete wxTheToolBarTimer
;
124 wxTheToolBarTimer
= NULL
;
129 bool wxToolBar::CreateTools()
131 if (m_tools
.Number() == 0)
135 const int separatorSize
= GetToolSeparation(); // 8;
136 wxSize margins
= GetToolMargins();
137 int marginX
= margins
.x
;
138 int marginY
= margins
.y
;
140 int currentX
= marginX
;
141 int currentY
= marginY
;
143 int buttonHeight
= 0;
145 int currentSpacing
= 0;
148 Widget prevButton
= (Widget
) 0;
149 wxNode
* node
= m_tools
.First();
152 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
154 if (tool
->m_toolStyle
== wxTOOL_STYLE_SEPARATOR
)
155 currentX
+= separatorSize
;
156 else if (tool
->m_bitmap1
.Ok())
158 Widget button
= (Widget
) 0;
160 if (tool
->m_isToggle
)
162 button
= XtVaCreateWidget("toggleButton",
163 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
164 XmNx
, currentX
, XmNy
, currentY
,
165 // XmNpushButtonEnabled, True,
166 XmNmultiClick
, XmMULTICLICK_KEEP
,
167 XmNlabelType
, XmPIXMAP
,
169 XtAddCallback ((Widget
) button
, XmNvalueChangedCallback
, (XtCallbackProc
) wxToolButtonCallback
,
172 XtVaSetValues ((Widget
) button
,
173 XmNselectColor
, m_backgroundColour
.AllocColour(XtDisplay((Widget
) button
)),
178 button
= XtVaCreateWidget("button",
179 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
180 XmNx
, currentX
, XmNy
, currentY
,
181 XmNpushButtonEnabled
, True
,
182 XmNmultiClick
, XmMULTICLICK_KEEP
,
183 XmNlabelType
, XmPIXMAP
,
185 XtAddCallback (button
,
186 XmNactivateCallback
, (XtCallbackProc
) wxToolButtonCallback
,
190 DoChangeBackgroundColour((WXWidget
) button
, m_backgroundColour
, TRUE
);
192 // For each button, if there is a mask, we must create
193 // a new wxBitmap that has the correct background colour
194 // for the button. Otherwise the background will just be
195 // e.g. black if a transparent XPM has been loaded.
196 wxBitmap originalBitmap
= tool
->m_bitmap1
;
198 if (tool
->m_bitmap1
.GetMask())
201 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
206 col
.SetPixel(backgroundPixel
);
208 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap1
, col
);
210 tool
->m_bitmap1
= newBitmap
;
213 // Create a selected/toggled bitmap. If there isn't a m_bitmap2,
214 // we need to create it (with a darker, selected background)
216 if (tool
->m_isToggle
)
217 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
220 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
224 col
.SetPixel(backgroundPixel
);
226 if (tool
->m_bitmap2
.Ok() && tool
->m_bitmap2
.GetMask())
229 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap2
, col
);
230 tool
->m_bitmap2
= newBitmap
;
234 // Use unselected bitmap
235 if (originalBitmap
.GetMask())
237 wxBitmap newBitmap
= wxCreateMaskedBitmap(originalBitmap
, col
);
238 tool
->m_bitmap2
= newBitmap
;
241 tool
->m_bitmap2
= tool
->m_bitmap1
;
244 Pixmap pixmap
= (Pixmap
) tool
->m_bitmap1
.GetPixmap();
245 Pixmap insensPixmap
= (Pixmap
) tool
->m_bitmap1
.GetInsensPixmap();
247 if (tool
->m_isToggle
)
250 Pixmap pixmap2
= (Pixmap
) 0;
251 Pixmap insensPixmap2
= (Pixmap
) 0;
253 // If there's a bitmap for the toggled state, use it,
254 // otherwise generate one.
255 if (tool
->m_bitmap2
.Ok())
257 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
258 insensPixmap2
= (Pixmap
) tool
->m_bitmap2
.GetInsensPixmap();
262 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
263 insensPixmap2
= XCreateInsensitivePixmap((Display
*) wxGetDisplay(), pixmap2
);
264 m_pixmaps
.Append((wxObject
*) insensPixmap2
); // Store for later deletion
266 XtVaSetValues (button
,
267 XmNindicatorOn
, False
,
268 XmNshadowThickness
, 2,
269 // XmNborderWidth, 0,
273 XmNfillOnSelect
, True
,
274 XmNlabelPixmap
, pixmap
,
275 XmNselectPixmap
, pixmap2
,
276 XmNlabelInsensitivePixmap
, insensPixmap
,
277 XmNselectInsensitivePixmap
, insensPixmap2
,
278 XmNlabelType
, XmPIXMAP
,
283 Pixmap pixmap2
= (Pixmap
) 0;
285 // If there's a bitmap for the armed state, use it,
286 // otherwise generate one.
287 if (tool
->m_bitmap2
.Ok())
289 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
293 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
297 XtVaSetValues(button
,
298 XmNlabelPixmap
, pixmap
,
299 XmNlabelInsensitivePixmap
, insensPixmap
,
300 XmNarmPixmap
, pixmap2
,
303 XtManageChild(button
);
305 Dimension width
, height
;
306 XtVaGetValues(button
, XmNwidth
, & width
, XmNheight
, & height
,
308 currentX
+= width
+ marginX
;
309 buttonHeight
= wxMax(buttonHeight
, height
);
311 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
312 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
313 m_widgets
.Append(tool
->m_index
, (wxObject
*) button
);
321 SetSize(-1, -1, currentX
, buttonHeight
+ 2*marginY
);
326 void wxToolBar::SetToolBitmapSize(const wxSize
& size
)
328 // TODO not necessary?
329 m_defaultWidth
= size
.x
; m_defaultHeight
= size
.y
;
332 wxSize
wxToolBar::GetMaxSize() const
340 // The button size is bigger than the bitmap size
341 wxSize
wxToolBar::GetToolSize() const
343 // TODO not necessary?
344 return wxSize(m_defaultWidth
+ 8, m_defaultHeight
+ 7);
347 void wxToolBar::EnableTool(int toolIndex
, bool enable
)
349 wxNode
*node
= m_tools
.Find((long)toolIndex
);
352 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
353 tool
->m_enabled
= enable
;
355 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
356 if (widget
== (WXWidget
) 0)
359 XtSetSensitive((Widget
) widget
, (Boolean
) enable
);
363 void wxToolBar::ToggleTool(int toolIndex
, bool toggle
)
365 wxNode
*node
= m_tools
.Find((long)toolIndex
);
368 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
369 if (tool
->m_isToggle
)
371 tool
->m_toggleState
= toggle
;
373 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
374 if (widget
== (WXWidget
) 0)
377 XmToggleButtonSetState((Widget
) widget
, (Boolean
) toggle
, False
);
382 void wxToolBar::ClearTools()
384 wxNode
* node
= m_widgets
.First();
387 Widget button
= (Widget
) node
->Data();
388 XtDestroyWidget(button
);
394 wxToolBarBase::ClearTools();
397 void wxToolBar::DestroyPixmaps()
399 wxNode
* node
= m_pixmaps
.First();
402 Pixmap pixmap
= (Pixmap
) node
->Data();
403 XmDestroyPixmap (DefaultScreenOfDisplay ((Display
*) GetXDisplay()), pixmap
);
409 // If pushedBitmap is NULL, a reversed version of bitmap is
410 // created and used as the pushed/toggled image.
411 // If toggle is TRUE, the button toggles between the two states.
413 wxToolBarTool
*wxToolBar::AddTool(int index
, const wxBitmap
& bitmap
, const wxBitmap
& WXUNUSED(pushedBitmap
),
414 bool toggle
, wxCoord xPos
, wxCoord yPos
, wxObject
*clientData
, const wxString
& helpString1
, const wxString
& helpString2
)
416 wxToolBarTool
*tool
= new wxToolBarTool(index
, bitmap
, wxNullBitmap
, toggle
, xPos
, yPos
, helpString1
, helpString2
);
417 tool
->m_clientData
= clientData
;
422 tool
->m_x
= m_xMargin
;
427 tool
->m_y
= m_yMargin
;
429 wxSize size
= GetToolSize();
430 tool
->SetSize(size
.x
, size
.y
);
432 m_tools
.Append((long)index
, tool
);
436 int wxToolBar::FindIndexForWidget(WXWidget w
)
438 wxNode
* node
= m_widgets
.First();
441 WXWidget widget
= (WXWidget
) node
->Data();
443 return (int) node
->GetKeyInteger();
449 WXWidget
wxToolBar::FindWidgetForIndex(int index
)
451 wxNode
* node
= m_widgets
.Find((long) index
);
455 return (WXWidget
) node
->Data();
458 WXWidget
wxToolBar::GetTopWidget() const
463 WXWidget
wxToolBar::GetClientWidget() const
468 WXWidget
wxToolBar::GetMainWidget() const
474 void wxToolButtonCallback (Widget w
, XtPointer clientData
,
475 XtPointer
WXUNUSED(ptr
))
477 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
478 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
482 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
485 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
486 if (tool
->m_isToggle
)
487 tool
->m_toggleState
= !tool
->m_toggleState
;
489 (void) toolBar
->OnLeftClick(index
, tool
->m_toggleState
);
495 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
496 XEvent
*event
, Boolean
*WXUNUSED(continue_to_dispatch
))
498 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
499 int delayMilli
= 800;
500 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
502 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
506 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
509 wxString
str(toolBar
->GetToolShortHelp(index
));
510 if (str
.IsNull() || str
== "")
513 if (!wxTheToolBarTimer
)
514 wxTheToolBarTimer
= new wxToolBarTimer
;
516 wxToolBarTimer::buttonWidget
= w
;
517 wxToolBarTimer::helpString
= str
;
520 /************************************************************/
521 /* Popup help label */
522 /************************************************************/
523 if (event
->type
== EnterNotify
)
525 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
527 XtDestroyWidget (wxToolBarTimer::help_popup
);
528 XtPopdown (wxToolBarTimer::help_popup
);
530 wxToolBarTimer::help_popup
= (Widget
) 0;
533 wxTheToolBarTimer
->Start(delayMilli
, TRUE
);
536 /************************************************************/
537 /* Popdown help label */
538 /************************************************************/
539 else if (event
->type
== LeaveNotify
)
541 if (wxTheToolBarTimer
)
542 wxTheToolBarTimer
->Stop();
543 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
545 XtDestroyWidget (wxToolBarTimer::help_popup
);
546 XtPopdown (wxToolBarTimer::help_popup
);
548 wxToolBarTimer::help_popup
= (Widget
) 0;
553 void wxToolBarTimer::Notify()
557 /************************************************************/
558 /* Create shell without window decorations */
559 /************************************************************/
560 help_popup
= XtVaCreatePopupShell ("shell",
561 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
564 /************************************************************/
565 /* Get absolute position on display of toolbar button */
566 /************************************************************/
567 XtTranslateCoords (buttonWidget
,
572 // Move the tooltip more or less above the button
573 int yOffset
= 20; // TODO: What should be really?
575 if (y
< yOffset
) y
= 0;
577 /************************************************************/
578 /* Set the position of the help popup */
579 /************************************************************/
580 XtVaSetValues (help_popup
,
585 /************************************************************/
586 /* Create help label */
587 /************************************************************/
588 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
589 XtVaCreateManagedWidget ("help_label",
590 xmLabelWidgetClass
, help_popup
,
591 XmNlabelString
, text
,
593 XmNforeground
, XtRString
, "black",
596 XmNbackground
, XtRString
, "LightGoldenrod",
597 strlen("LightGoldenrod")+1,
601 /************************************************************/
602 /* Popup help label */
603 /************************************************************/
604 XtPopup (help_popup
, XtGrabNone
);