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 #pragma message disable nosimpint
25 #include <Xm/PushBG.h>
28 #include <Xm/ToggleB.h>
29 #include <Xm/ToggleBG.h>
32 #pragma message enable nosimpint
35 #include "wx/motif/private.h"
37 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxToolBarBase
)
39 BEGIN_EVENT_TABLE(wxToolBar
, wxToolBarBase
)
42 static void wxToolButtonCallback (Widget w
, XtPointer clientData
,
44 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
45 XEvent
*event
, Boolean
*continue_to_dispatch
);
47 class wxToolBarTimer
: public wxTimer
51 virtual void Notify();
53 static Widget help_popup
;
54 static Widget buttonWidget
;
55 static wxString helpString
;
58 static wxToolBarTimer
* wxTheToolBarTimer
= (wxToolBarTimer
*) NULL
;
60 Widget
wxToolBarTimer::help_popup
= (Widget
) 0;
61 Widget
wxToolBarTimer::buttonWidget
= (Widget
) 0;
62 wxString
wxToolBarTimer::helpString
= "";
64 wxToolBar::wxToolBar():
65 m_widgets(wxKEY_INTEGER
)
73 bool wxToolBar::Create(wxWindow
*parent
, wxWindowID id
, const wxPoint
& pos
, const wxSize
& size
,
74 long style
, const wxString
& name
)
83 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
);
84 m_foregroundColour
= parent
->GetForegroundColour();
85 m_windowStyle
= style
;
89 if (parent
) parent
->AddChild(this);
91 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
93 Widget toolbar
= XtVaCreateManagedWidget("toolbar",
94 xmBulletinBoardWidgetClass
, (Widget
) parentWidget
,
97 XmNresizePolicy
, XmRESIZE_NONE
,
100 Widget toolbar = XtVaCreateManagedWidget("toolbar",
101 xmFormWidgetClass, (Widget) m_clientWidget,
102 XmNtraversalOn, False,
103 XmNhorizontalSpacing, 0,
104 XmNverticalSpacing, 0,
112 m_mainWidget
= (WXWidget
) toolbar
;
114 m_font
= parent
->GetFont();
117 SetCanAddEventHandler(TRUE
);
118 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, size
.x
, size
.y
);
120 ChangeBackgroundColour();
125 wxToolBar::~wxToolBar()
127 delete wxTheToolBarTimer
;
128 wxTheToolBarTimer
= NULL
;
133 bool wxToolBar::CreateTools()
135 if (m_tools
.Number() == 0)
139 const int separatorSize
= GetToolSeparation(); // 8;
140 wxSize margins
= GetToolMargins();
141 int marginX
= margins
.x
;
142 int marginY
= margins
.y
;
144 int currentX
= marginX
;
145 int currentY
= marginY
;
147 int buttonHeight
= 0;
149 int currentSpacing
= 0;
152 Widget prevButton
= (Widget
) 0;
153 wxNode
* node
= m_tools
.First();
156 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
158 if (tool
->m_toolStyle
== wxTOOL_STYLE_SEPARATOR
)
159 currentX
+= separatorSize
;
160 else if (tool
->m_bitmap1
.Ok())
162 Widget button
= (Widget
) 0;
164 if (tool
->m_isToggle
)
166 button
= XtVaCreateWidget("toggleButton",
167 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
168 XmNx
, currentX
, XmNy
, currentY
,
169 // XmNpushButtonEnabled, True,
170 XmNmultiClick
, XmMULTICLICK_KEEP
,
171 XmNlabelType
, XmPIXMAP
,
173 XtAddCallback ((Widget
) button
, XmNvalueChangedCallback
, (XtCallbackProc
) wxToolButtonCallback
,
176 XtVaSetValues ((Widget
) button
,
177 XmNselectColor
, m_backgroundColour
.AllocColour(XtDisplay((Widget
) button
)),
182 button
= XtVaCreateWidget("button",
183 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
184 XmNx
, currentX
, XmNy
, currentY
,
185 XmNpushButtonEnabled
, True
,
186 XmNmultiClick
, XmMULTICLICK_KEEP
,
187 XmNlabelType
, XmPIXMAP
,
189 XtAddCallback (button
,
190 XmNactivateCallback
, (XtCallbackProc
) wxToolButtonCallback
,
194 DoChangeBackgroundColour((WXWidget
) button
, m_backgroundColour
, TRUE
);
196 // For each button, if there is a mask, we must create
197 // a new wxBitmap that has the correct background colour
198 // for the button. Otherwise the background will just be
199 // e.g. black if a transparent XPM has been loaded.
200 wxBitmap originalBitmap
= tool
->m_bitmap1
;
202 if (tool
->m_bitmap1
.GetMask())
205 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
210 col
.SetPixel(backgroundPixel
);
212 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap1
, col
);
214 tool
->m_bitmap1
= newBitmap
;
217 // Create a selected/toggled bitmap. If there isn't a m_bitmap2,
218 // we need to create it (with a darker, selected background)
220 if (tool
->m_isToggle
)
221 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
224 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
228 col
.SetPixel(backgroundPixel
);
230 if (tool
->m_bitmap2
.Ok() && tool
->m_bitmap2
.GetMask())
233 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap2
, col
);
234 tool
->m_bitmap2
= newBitmap
;
238 // Use unselected bitmap
239 if (originalBitmap
.GetMask())
241 wxBitmap newBitmap
= wxCreateMaskedBitmap(originalBitmap
, col
);
242 tool
->m_bitmap2
= newBitmap
;
245 tool
->m_bitmap2
= tool
->m_bitmap1
;
248 Pixmap pixmap
= (Pixmap
) tool
->m_bitmap1
.GetPixmap();
249 Pixmap insensPixmap
= (Pixmap
) tool
->m_bitmap1
.GetInsensPixmap();
251 if (tool
->m_isToggle
)
254 Pixmap pixmap2
= (Pixmap
) 0;
255 Pixmap insensPixmap2
= (Pixmap
) 0;
257 // If there's a bitmap for the toggled state, use it,
258 // otherwise generate one.
259 if (tool
->m_bitmap2
.Ok())
261 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
262 insensPixmap2
= (Pixmap
) tool
->m_bitmap2
.GetInsensPixmap();
266 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
267 insensPixmap2
= XCreateInsensitivePixmap((Display
*) wxGetDisplay(), pixmap2
);
268 m_pixmaps
.Append((wxObject
*) insensPixmap2
); // Store for later deletion
270 XtVaSetValues (button
,
271 XmNindicatorOn
, False
,
272 XmNshadowThickness
, 2,
273 // XmNborderWidth, 0,
277 XmNfillOnSelect
, True
,
278 XmNlabelPixmap
, pixmap
,
279 XmNselectPixmap
, pixmap2
,
280 XmNlabelInsensitivePixmap
, insensPixmap
,
281 XmNselectInsensitivePixmap
, insensPixmap2
,
282 XmNlabelType
, XmPIXMAP
,
287 Pixmap pixmap2
= (Pixmap
) 0;
289 // If there's a bitmap for the armed state, use it,
290 // otherwise generate one.
291 if (tool
->m_bitmap2
.Ok())
293 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
297 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
301 XtVaSetValues(button
,
302 XmNlabelPixmap
, pixmap
,
303 XmNlabelInsensitivePixmap
, insensPixmap
,
304 XmNarmPixmap
, pixmap2
,
307 XtManageChild(button
);
309 Dimension width
, height
;
310 XtVaGetValues(button
, XmNwidth
, & width
, XmNheight
, & height
,
312 currentX
+= width
+ marginX
;
313 buttonHeight
= wxMax(buttonHeight
, height
);
315 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
316 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
317 m_widgets
.Append(tool
->m_index
, (wxObject
*) button
);
325 SetSize(-1, -1, currentX
, buttonHeight
+ 2*marginY
);
330 void wxToolBar::SetToolBitmapSize(const wxSize
& size
)
332 // TODO not necessary?
333 m_defaultWidth
= size
.x
; m_defaultHeight
= size
.y
;
336 wxSize
wxToolBar::GetMaxSize() const
344 // The button size is bigger than the bitmap size
345 wxSize
wxToolBar::GetToolSize() const
347 // TODO not necessary?
348 return wxSize(m_defaultWidth
+ 8, m_defaultHeight
+ 7);
351 void wxToolBar::EnableTool(int toolIndex
, bool enable
)
353 wxNode
*node
= m_tools
.Find((long)toolIndex
);
356 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
357 tool
->m_enabled
= enable
;
359 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
360 if (widget
== (WXWidget
) 0)
363 XtSetSensitive((Widget
) widget
, (Boolean
) enable
);
367 void wxToolBar::ToggleTool(int toolIndex
, bool toggle
)
369 wxNode
*node
= m_tools
.Find((long)toolIndex
);
372 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
373 if (tool
->m_isToggle
)
375 tool
->m_toggleState
= toggle
;
377 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
378 if (widget
== (WXWidget
) 0)
381 XmToggleButtonSetState((Widget
) widget
, (Boolean
) toggle
, False
);
386 void wxToolBar::ClearTools()
388 wxNode
* node
= m_widgets
.First();
391 Widget button
= (Widget
) node
->Data();
392 XtDestroyWidget(button
);
398 wxToolBarBase::ClearTools();
401 void wxToolBar::DestroyPixmaps()
403 wxNode
* node
= m_pixmaps
.First();
406 Pixmap pixmap
= (Pixmap
) node
->Data();
407 XmDestroyPixmap (DefaultScreenOfDisplay ((Display
*) GetXDisplay()), pixmap
);
413 // If pushedBitmap is NULL, a reversed version of bitmap is
414 // created and used as the pushed/toggled image.
415 // If toggle is TRUE, the button toggles between the two states.
417 wxToolBarTool
*wxToolBar::AddTool(int index
, const wxBitmap
& bitmap
, const wxBitmap
& WXUNUSED(pushedBitmap
),
418 bool toggle
, wxCoord xPos
, wxCoord yPos
, wxObject
*clientData
, const wxString
& helpString1
, const wxString
& helpString2
)
420 wxToolBarTool
*tool
= new wxToolBarTool(index
, bitmap
, wxNullBitmap
, toggle
, xPos
, yPos
, helpString1
, helpString2
);
421 tool
->m_clientData
= clientData
;
426 tool
->m_x
= m_xMargin
;
431 tool
->m_y
= m_yMargin
;
433 wxSize size
= GetToolSize();
434 tool
->SetSize(size
.x
, size
.y
);
436 m_tools
.Append((long)index
, tool
);
440 int wxToolBar::FindIndexForWidget(WXWidget w
)
442 wxNode
* node
= m_widgets
.First();
445 WXWidget widget
= (WXWidget
) node
->Data();
447 return (int) node
->GetKeyInteger();
453 WXWidget
wxToolBar::FindWidgetForIndex(int index
)
455 wxNode
* node
= m_widgets
.Find((long) index
);
459 return (WXWidget
) node
->Data();
462 WXWidget
wxToolBar::GetTopWidget() const
467 WXWidget
wxToolBar::GetClientWidget() const
472 WXWidget
wxToolBar::GetMainWidget() const
478 void wxToolButtonCallback (Widget w
, XtPointer clientData
,
479 XtPointer
WXUNUSED(ptr
))
481 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
482 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
486 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
489 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
490 if (tool
->m_isToggle
)
491 tool
->m_toggleState
= !tool
->m_toggleState
;
493 (void) toolBar
->OnLeftClick(index
, tool
->m_toggleState
);
499 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
500 XEvent
*event
, Boolean
*WXUNUSED(continue_to_dispatch
))
502 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
503 int delayMilli
= 800;
504 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
506 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
510 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
513 wxString
str(toolBar
->GetToolShortHelp(index
));
514 if (str
.IsNull() || str
== "")
517 if (!wxTheToolBarTimer
)
518 wxTheToolBarTimer
= new wxToolBarTimer
;
520 wxToolBarTimer::buttonWidget
= w
;
521 wxToolBarTimer::helpString
= str
;
524 /************************************************************/
525 /* Popup help label */
526 /************************************************************/
527 if (event
->type
== EnterNotify
)
529 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
531 XtDestroyWidget (wxToolBarTimer::help_popup
);
532 XtPopdown (wxToolBarTimer::help_popup
);
534 wxToolBarTimer::help_popup
= (Widget
) 0;
537 wxTheToolBarTimer
->Start(delayMilli
, TRUE
);
540 /************************************************************/
541 /* Popdown help label */
542 /************************************************************/
543 else if (event
->type
== LeaveNotify
)
545 if (wxTheToolBarTimer
)
546 wxTheToolBarTimer
->Stop();
547 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
549 XtDestroyWidget (wxToolBarTimer::help_popup
);
550 XtPopdown (wxToolBarTimer::help_popup
);
552 wxToolBarTimer::help_popup
= (Widget
) 0;
557 void wxToolBarTimer::Notify()
561 /************************************************************/
562 /* Create shell without window decorations */
563 /************************************************************/
564 help_popup
= XtVaCreatePopupShell ("shell",
565 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
568 /************************************************************/
569 /* Get absolute position on display of toolbar button */
570 /************************************************************/
571 XtTranslateCoords (buttonWidget
,
576 // Move the tooltip more or less above the button
577 int yOffset
= 20; // TODO: What should be really?
579 if (y
< yOffset
) y
= 0;
581 /************************************************************/
582 /* Set the position of the help popup */
583 /************************************************************/
584 XtVaSetValues (help_popup
,
589 /************************************************************/
590 /* Create help label */
591 /************************************************************/
592 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
593 XtVaCreateManagedWidget ("help_label",
594 xmLabelWidgetClass
, help_popup
,
595 XmNlabelString
, text
,
597 XmNforeground
, XtRString
, "black",
600 XmNbackground
, XtRString
, "LightGoldenrod",
601 strlen("LightGoldenrod")+1,
605 /************************************************************/
606 /* Popup help label */
607 /************************************************************/
608 XtPopup (help_popup
, XtGrabNone
);