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 #if !USE_SHARED_LIBRARY
38 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxToolBarBase
)
40 BEGIN_EVENT_TABLE(wxToolBar
, wxToolBarBase
)
44 static void wxToolButtonCallback (Widget w
, XtPointer clientData
,
46 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
47 XEvent
*event
, Boolean
*continue_to_dispatch
);
49 class wxToolBarTimer
: public wxTimer
53 virtual void Notify();
55 static Widget help_popup
;
56 static Widget buttonWidget
;
57 static wxString helpString
;
60 static wxToolBarTimer
* wxTheToolBarTimer
= (wxToolBarTimer
*) NULL
;
62 Widget
wxToolBarTimer::help_popup
= (Widget
) 0;
63 Widget
wxToolBarTimer::buttonWidget
= (Widget
) 0;
64 wxString
wxToolBarTimer::helpString
= "";
66 wxToolBar::wxToolBar():
67 m_widgets(wxKEY_INTEGER
)
75 bool wxToolBar::Create(wxWindow
*parent
, wxWindowID id
, const wxPoint
& pos
, const wxSize
& size
,
76 long style
, const wxString
& name
)
85 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
);
86 m_foregroundColour
= parent
->GetForegroundColour();
87 m_windowStyle
= style
;
91 if (parent
) parent
->AddChild(this);
93 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
95 Widget toolbar
= XtVaCreateManagedWidget("toolbar",
96 xmBulletinBoardWidgetClass
, (Widget
) parentWidget
,
99 XmNresizePolicy
, XmRESIZE_NONE
,
102 Widget toolbar = XtVaCreateManagedWidget("toolbar",
103 xmFormWidgetClass, (Widget) m_clientWidget,
104 XmNtraversalOn, False,
105 XmNhorizontalSpacing, 0,
106 XmNverticalSpacing, 0,
114 m_mainWidget
= (WXWidget
) toolbar
;
116 m_font
= parent
->GetFont();
119 SetCanAddEventHandler(TRUE
);
120 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, size
.x
, size
.y
);
122 ChangeBackgroundColour();
127 wxToolBar::~wxToolBar()
129 delete wxTheToolBarTimer
;
130 wxTheToolBarTimer
= NULL
;
135 bool wxToolBar::CreateTools()
137 if (m_tools
.Number() == 0)
141 const int separatorSize
= GetToolSeparation(); // 8;
142 wxSize margins
= GetToolMargins();
143 int marginX
= margins
.x
;
144 int marginY
= margins
.y
;
146 int currentX
= marginX
;
147 int currentY
= marginY
;
149 int buttonHeight
= 0;
151 int currentSpacing
= 0;
154 Widget prevButton
= (Widget
) 0;
155 wxNode
* node
= m_tools
.First();
158 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
160 if (tool
->m_toolStyle
== wxTOOL_STYLE_SEPARATOR
)
161 currentX
+= separatorSize
;
162 else if (tool
->m_bitmap1
.Ok())
164 Widget button
= (Widget
) 0;
166 if (tool
->m_isToggle
)
168 button
= XtVaCreateWidget("toggleButton",
169 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
170 XmNx
, currentX
, XmNy
, currentY
,
171 // XmNpushButtonEnabled, True,
172 XmNmultiClick
, XmMULTICLICK_KEEP
,
173 XmNlabelType
, XmPIXMAP
,
175 XtAddCallback ((Widget
) button
, XmNvalueChangedCallback
, (XtCallbackProc
) wxToolButtonCallback
,
178 XtVaSetValues ((Widget
) button
,
179 XmNselectColor
, m_backgroundColour
.AllocColour(XtDisplay((Widget
) button
)),
184 button
= XtVaCreateWidget("button",
185 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
186 XmNx
, currentX
, XmNy
, currentY
,
187 XmNpushButtonEnabled
, True
,
188 XmNmultiClick
, XmMULTICLICK_KEEP
,
189 XmNlabelType
, XmPIXMAP
,
191 XtAddCallback (button
,
192 XmNactivateCallback
, (XtCallbackProc
) wxToolButtonCallback
,
196 DoChangeBackgroundColour((WXWidget
) button
, m_backgroundColour
, TRUE
);
198 // For each button, if there is a mask, we must create
199 // a new wxBitmap that has the correct background colour
200 // for the button. Otherwise the background will just be
201 // e.g. black if a transparent XPM has been loaded.
202 wxBitmap originalBitmap
= tool
->m_bitmap1
;
204 if (tool
->m_bitmap1
.GetMask())
207 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
212 col
.SetPixel(backgroundPixel
);
214 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap1
, col
);
216 tool
->m_bitmap1
= newBitmap
;
219 // Create a selected/toggled bitmap. If there isn't a m_bitmap2,
220 // we need to create it (with a darker, selected background)
222 if (tool
->m_isToggle
)
223 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
226 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
230 col
.SetPixel(backgroundPixel
);
232 if (tool
->m_bitmap2
.Ok() && tool
->m_bitmap2
.GetMask())
235 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap2
, col
);
236 tool
->m_bitmap2
= newBitmap
;
240 // Use unselected bitmap
241 if (originalBitmap
.GetMask())
243 wxBitmap newBitmap
= wxCreateMaskedBitmap(originalBitmap
, col
);
244 tool
->m_bitmap2
= newBitmap
;
247 tool
->m_bitmap2
= tool
->m_bitmap1
;
250 Pixmap pixmap
= (Pixmap
) tool
->m_bitmap1
.GetPixmap();
251 Pixmap insensPixmap
= (Pixmap
) tool
->m_bitmap1
.GetInsensPixmap();
253 if (tool
->m_isToggle
)
256 Pixmap pixmap2
= (Pixmap
) 0;
257 Pixmap insensPixmap2
= (Pixmap
) 0;
259 // If there's a bitmap for the toggled state, use it,
260 // otherwise generate one.
261 if (tool
->m_bitmap2
.Ok())
263 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
264 insensPixmap2
= (Pixmap
) tool
->m_bitmap2
.GetInsensPixmap();
268 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
269 insensPixmap2
= XCreateInsensitivePixmap((Display
*) wxGetDisplay(), pixmap2
);
270 m_pixmaps
.Append((wxObject
*) insensPixmap2
); // Store for later deletion
272 XtVaSetValues (button
,
273 XmNindicatorOn
, False
,
274 XmNshadowThickness
, 2,
275 // XmNborderWidth, 0,
279 XmNfillOnSelect
, True
,
280 XmNlabelPixmap
, pixmap
,
281 XmNselectPixmap
, pixmap2
,
282 XmNlabelInsensitivePixmap
, insensPixmap
,
283 XmNselectInsensitivePixmap
, insensPixmap2
,
284 XmNlabelType
, XmPIXMAP
,
289 Pixmap pixmap2
= (Pixmap
) 0;
291 // If there's a bitmap for the armed state, use it,
292 // otherwise generate one.
293 if (tool
->m_bitmap2
.Ok())
295 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
299 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
303 XtVaSetValues(button
,
304 XmNlabelPixmap
, pixmap
,
305 XmNlabelInsensitivePixmap
, insensPixmap
,
306 XmNarmPixmap
, pixmap2
,
309 XtManageChild(button
);
311 Dimension width
, height
;
312 XtVaGetValues(button
, XmNwidth
, & width
, XmNheight
, & height
,
314 currentX
+= width
+ marginX
;
315 buttonHeight
= wxMax(buttonHeight
, height
);
317 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
318 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
319 m_widgets
.Append(tool
->m_index
, (wxObject
*) button
);
327 SetSize(-1, -1, currentX
, buttonHeight
+ 2*marginY
);
332 void wxToolBar::SetToolBitmapSize(const wxSize
& size
)
334 // TODO not necessary?
335 m_defaultWidth
= size
.x
; m_defaultHeight
= size
.y
;
338 wxSize
wxToolBar::GetMaxSize() const
346 // The button size is bigger than the bitmap size
347 wxSize
wxToolBar::GetToolSize() const
349 // TODO not necessary?
350 return wxSize(m_defaultWidth
+ 8, m_defaultHeight
+ 7);
353 void wxToolBar::EnableTool(int toolIndex
, bool enable
)
355 wxNode
*node
= m_tools
.Find((long)toolIndex
);
358 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
359 tool
->m_enabled
= enable
;
361 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
362 if (widget
== (WXWidget
) 0)
365 XtSetSensitive((Widget
) widget
, (Boolean
) enable
);
369 void wxToolBar::ToggleTool(int toolIndex
, bool toggle
)
371 wxNode
*node
= m_tools
.Find((long)toolIndex
);
374 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
375 if (tool
->m_isToggle
)
377 tool
->m_toggleState
= toggle
;
379 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
380 if (widget
== (WXWidget
) 0)
383 XmToggleButtonSetState((Widget
) widget
, (Boolean
) toggle
, False
);
388 void wxToolBar::ClearTools()
390 wxNode
* node
= m_widgets
.First();
393 Widget button
= (Widget
) node
->Data();
394 XtDestroyWidget(button
);
400 wxToolBarBase::ClearTools();
403 void wxToolBar::DestroyPixmaps()
405 wxNode
* node
= m_pixmaps
.First();
408 Pixmap pixmap
= (Pixmap
) node
->Data();
409 XmDestroyPixmap (DefaultScreenOfDisplay ((Display
*) GetXDisplay()), pixmap
);
415 // If pushedBitmap is NULL, a reversed version of bitmap is
416 // created and used as the pushed/toggled image.
417 // If toggle is TRUE, the button toggles between the two states.
419 wxToolBarTool
*wxToolBar::AddTool(int index
, const wxBitmap
& bitmap
, const wxBitmap
& WXUNUSED(pushedBitmap
),
420 bool toggle
, wxCoord xPos
, wxCoord yPos
, wxObject
*clientData
, const wxString
& helpString1
, const wxString
& helpString2
)
422 wxToolBarTool
*tool
= new wxToolBarTool(index
, bitmap
, wxNullBitmap
, toggle
, xPos
, yPos
, helpString1
, helpString2
);
423 tool
->m_clientData
= clientData
;
428 tool
->m_x
= m_xMargin
;
433 tool
->m_y
= m_yMargin
;
435 wxSize size
= GetToolSize();
436 tool
->SetSize(size
.x
, size
.y
);
438 m_tools
.Append((long)index
, tool
);
442 int wxToolBar::FindIndexForWidget(WXWidget w
)
444 wxNode
* node
= m_widgets
.First();
447 WXWidget widget
= (WXWidget
) node
->Data();
449 return (int) node
->GetKeyInteger();
455 WXWidget
wxToolBar::FindWidgetForIndex(int index
)
457 wxNode
* node
= m_widgets
.Find((long) index
);
461 return (WXWidget
) node
->Data();
464 WXWidget
wxToolBar::GetTopWidget() const
469 WXWidget
wxToolBar::GetClientWidget() const
474 WXWidget
wxToolBar::GetMainWidget() const
480 void wxToolButtonCallback (Widget w
, XtPointer clientData
,
481 XtPointer
WXUNUSED(ptr
))
483 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
484 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
488 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
491 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
492 if (tool
->m_isToggle
)
493 tool
->m_toggleState
= !tool
->m_toggleState
;
495 (void) toolBar
->OnLeftClick(index
, tool
->m_toggleState
);
501 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
502 XEvent
*event
, Boolean
*WXUNUSED(continue_to_dispatch
))
504 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
505 int delayMilli
= 800;
506 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
508 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
512 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
515 wxString
str(toolBar
->GetToolShortHelp(index
));
516 if (str
.IsNull() || str
== "")
519 if (!wxTheToolBarTimer
)
520 wxTheToolBarTimer
= new wxToolBarTimer
;
522 wxToolBarTimer::buttonWidget
= w
;
523 wxToolBarTimer::helpString
= str
;
526 /************************************************************/
527 /* Popup help label */
528 /************************************************************/
529 if (event
->type
== EnterNotify
)
531 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
533 XtDestroyWidget (wxToolBarTimer::help_popup
);
534 XtPopdown (wxToolBarTimer::help_popup
);
536 wxToolBarTimer::help_popup
= (Widget
) 0;
539 wxTheToolBarTimer
->Start(delayMilli
, TRUE
);
542 /************************************************************/
543 /* Popdown help label */
544 /************************************************************/
545 else if (event
->type
== LeaveNotify
)
547 if (wxTheToolBarTimer
)
548 wxTheToolBarTimer
->Stop();
549 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
551 XtDestroyWidget (wxToolBarTimer::help_popup
);
552 XtPopdown (wxToolBarTimer::help_popup
);
554 wxToolBarTimer::help_popup
= (Widget
) 0;
559 void wxToolBarTimer::Notify()
563 /************************************************************/
564 /* Create shell without window decorations */
565 /************************************************************/
566 help_popup
= XtVaCreatePopupShell ("shell",
567 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
570 /************************************************************/
571 /* Get absolute position on display of toolbar button */
572 /************************************************************/
573 XtTranslateCoords (buttonWidget
,
578 // Move the tooltip more or less above the button
579 int yOffset
= 20; // TODO: What should be really?
581 if (y
< yOffset
) y
= 0;
583 /************************************************************/
584 /* Set the position of the help popup */
585 /************************************************************/
586 XtVaSetValues (help_popup
,
591 /************************************************************/
592 /* Create help label */
593 /************************************************************/
594 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
595 XtVaCreateManagedWidget ("help_label",
596 xmLabelWidgetClass
, help_popup
,
597 XmNlabelString
, text
,
599 XmNforeground
, XtRString
, "black",
602 XmNbackground
, XtRString
, "LightGoldenrod",
603 strlen("LightGoldenrod")+1,
607 /************************************************************/
608 /* Popup help label */
609 /************************************************************/
610 XtPopup (help_popup
, XtGrabNone
);