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 wxBitmap
wxCreateMaskedBitmap(wxBitmap
& bitmap
, wxColour
& colour
);
45 class wxToolBarTimer
: public wxTimer
49 virtual void Notify();
51 static Widget help_popup
;
52 static Widget buttonWidget
;
53 static wxString helpString
;
56 static wxToolBarTimer
* wxTheToolBarTimer
= (wxToolBarTimer
*) NULL
;
58 Widget
wxToolBarTimer::help_popup
= (Widget
) 0;
59 Widget
wxToolBarTimer::buttonWidget
= (Widget
) 0;
60 wxString
wxToolBarTimer::helpString
= "";
62 wxToolBar::wxToolBar():
63 m_widgets(wxKEY_INTEGER
)
71 bool wxToolBar::Create(wxWindow
*parent
, wxWindowID id
, const wxPoint
& pos
, const wxSize
& size
,
72 long style
, const wxString
& name
)
80 m_backgroundColour
= wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE
);
81 m_foregroundColour
= parent
->GetForegroundColour();
82 m_windowStyle
= style
;
86 if (parent
) parent
->AddChild(this);
88 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
90 Widget toolbar
= XtVaCreateManagedWidget("toolbar",
91 xmFormWidgetClass
, parentWidget
,
92 XmNtraversalOn
, False
,
93 XmNhorizontalSpacing
, 0,
94 XmNverticalSpacing
, 0,
101 m_mainWidget
= (WXWidget
) toolbar
;
103 SetCanAddEventHandler(TRUE
);
104 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, size
.x
, size
.y
);
106 SetFont(* parent
->GetFont());
107 ChangeBackgroundColour();
112 wxToolBar::~wxToolBar()
114 delete wxTheToolBarTimer
;
115 wxTheToolBarTimer
= NULL
;
120 bool wxToolBar::CreateTools()
122 if (m_tools
.Number() == 0)
126 const int separatorSize
= GetToolSeparation(); // 8;
128 int currentSpacing
= 0;
131 Widget prevButton
= (Widget
) 0;
132 wxNode
* node
= m_tools
.First();
135 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
137 if (tool
->m_toolStyle
== wxTOOL_STYLE_SEPARATOR
)
138 currentSpacing
= separatorSize
;
139 else if (tool
->m_bitmap1
.Ok())
141 Widget button
= (Widget
) 0;
143 if (tool
->m_isToggle
)
145 button
= XtVaCreateManagedWidget("toggleButton",
146 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
147 XmNleftAttachment
, (prevButton
== (Widget
) 0) ? XmATTACH_FORM
: XmATTACH_WIDGET
,
148 XmNleftWidget
, (prevButton
== (Widget
) 0) ? NULL
: prevButton
,
149 XmNleftOffset
, currentSpacing
,
150 XmNtopAttachment
, XmATTACH_FORM
,
151 // XmNpushButtonEnabled, True,
152 XmNmultiClick
, XmMULTICLICK_KEEP
,
153 XmNlabelType
, XmPIXMAP
,
155 XtAddCallback ((Widget
) button
, XmNvalueChangedCallback
, (XtCallbackProc
) wxToolButtonCallback
,
160 button
= XtVaCreateManagedWidget("button",
161 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
162 XmNleftAttachment
, (prevButton
== (Widget
) 0) ? XmATTACH_FORM
: XmATTACH_WIDGET
,
163 XmNleftWidget
, (prevButton
== (Widget
) 0) ? NULL
: prevButton
,
164 XmNleftOffset
, currentSpacing
,
165 XmNtopAttachment
, XmATTACH_FORM
,
166 XmNpushButtonEnabled
, True
,
167 XmNmultiClick
, XmMULTICLICK_KEEP
,
168 XmNlabelType
, XmPIXMAP
,
170 XtAddCallback (button
,
171 XmNactivateCallback
, (XtCallbackProc
) wxToolButtonCallback
,
175 // For each button, if there is a mask, we must create
176 // a new wxBitmap that has the correct background colour
177 // for the button. Otherwise the background will just be
178 // e.g. black if a transparent XPM has been loaded.
179 wxBitmap originalBitmap
= tool
->m_bitmap1
;
181 if (tool
->m_bitmap1
.GetMask())
184 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
189 col
.SetPixel(backgroundPixel
);
191 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap1
, col
);
193 tool
->m_bitmap1
= newBitmap
;
196 // Create a selected/toggled bitmap. If there isn't a m_bitmap2,
197 // we need to create it (with a darker, selected background)
199 if (tool
->m_isToggle
)
200 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
203 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
207 col
.SetPixel(backgroundPixel
);
209 if (tool
->m_bitmap2
.Ok() && tool
->m_bitmap2
.GetMask())
212 wxBitmap newBitmap
= wxCreateMaskedBitmap(tool
->m_bitmap2
, col
);
213 tool
->m_bitmap2
= newBitmap
;
217 // Use unselected bitmap
218 if (originalBitmap
.GetMask())
220 wxBitmap newBitmap
= wxCreateMaskedBitmap(originalBitmap
, col
);
221 tool
->m_bitmap2
= newBitmap
;
224 tool
->m_bitmap2
= tool
->m_bitmap1
;
227 Pixmap pixmap
= (Pixmap
) tool
->m_bitmap1
.GetPixmap();
228 Pixmap insensPixmap
= (Pixmap
) tool
->m_bitmap1
.GetInsensPixmap();
230 if (tool
->m_isToggle
)
233 Pixmap pixmap2
= (Pixmap
) 0;
234 Pixmap insensPixmap2
= (Pixmap
) 0;
236 // If there's a bitmap for the toggled state, use it,
237 // otherwise generate one.
238 if (tool
->m_bitmap2
.Ok())
240 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
241 insensPixmap2
= (Pixmap
) tool
->m_bitmap2
.GetInsensPixmap();
245 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
246 insensPixmap2
= XCreateInsensitivePixmap((Display
*) wxGetDisplay(), pixmap2
);
247 m_pixmaps
.Append((wxObject
*) insensPixmap2
); // Store for later deletion
249 XtVaSetValues (button
,
250 XmNindicatorOn
, False
,
251 XmNshadowThickness
, 2,
252 // XmNborderWidth, 0,
256 XmNfillOnSelect
, True
,
257 XmNlabelPixmap
, pixmap
,
258 XmNselectPixmap
, pixmap2
,
259 XmNlabelInsensitivePixmap
, insensPixmap
,
260 XmNselectInsensitivePixmap
, insensPixmap2
,
261 XmNlabelType
, XmPIXMAP
,
266 Pixmap pixmap2
= (Pixmap
) 0;
268 // If there's a bitmap for the armed state, use it,
269 // otherwise generate one.
270 if (tool
->m_bitmap2
.Ok())
272 pixmap2
= (Pixmap
) tool
->m_bitmap2
.GetPixmap();
276 pixmap2
= (Pixmap
) tool
->m_bitmap1
.GetArmPixmap(button
);
280 XtVaSetValues(button
,
281 XmNlabelPixmap
, pixmap
,
282 XmNlabelInsensitivePixmap
, insensPixmap
,
283 XmNarmPixmap
, pixmap2
,
287 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
288 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
289 m_widgets
.Append(tool
->m_index
, (wxObject
*) button
);
300 void wxToolBar::SetToolBitmapSize(const wxSize
& size
)
302 m_defaultWidth
= size
.x
; m_defaultHeight
= size
.y
;
306 wxSize
wxToolBar::GetMaxSize() const
312 // The button size is bigger than the bitmap size
313 wxSize
wxToolBar::GetToolSize() const
316 return wxSize(m_defaultWidth
+ 8, m_defaultHeight
+ 7);
319 void wxToolBar::EnableTool(int toolIndex
, bool enable
)
321 wxNode
*node
= m_tools
.Find((long)toolIndex
);
324 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
325 tool
->m_enabled
= enable
;
327 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
328 if (widget
== (WXWidget
) 0)
331 XtSetSensitive((Widget
) widget
, (Boolean
) enable
);
335 void wxToolBar::ToggleTool(int toolIndex
, bool toggle
)
337 wxNode
*node
= m_tools
.Find((long)toolIndex
);
340 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
341 if (tool
->m_isToggle
)
343 tool
->m_toggleState
= toggle
;
345 WXWidget widget
= FindWidgetForIndex(tool
->m_index
);
346 if (widget
== (WXWidget
) 0)
349 XmToggleButtonSetState((Widget
) widget
, (Boolean
) toggle
, False
);
354 void wxToolBar::ClearTools()
356 wxNode
* node
= m_widgets
.First();
359 Widget button
= (Widget
) node
->Data();
360 XtDestroyWidget(button
);
366 wxToolBarBase::ClearTools();
369 void wxToolBar::DestroyPixmaps()
371 wxNode
* node
= m_pixmaps
.First();
374 Pixmap pixmap
= (Pixmap
) node
->Data();
375 XmDestroyPixmap (DefaultScreenOfDisplay ((Display
*) GetXDisplay()), pixmap
);
381 // If pushedBitmap is NULL, a reversed version of bitmap is
382 // created and used as the pushed/toggled image.
383 // If toggle is TRUE, the button toggles between the two states.
385 wxToolBarTool
*wxToolBar::AddTool(int index
, const wxBitmap
& bitmap
, const wxBitmap
& pushedBitmap
,
386 bool toggle
, long xPos
, long yPos
, wxObject
*clientData
, const wxString
& helpString1
, const wxString
& helpString2
)
388 wxToolBarTool
*tool
= new wxToolBarTool(index
, bitmap
, (wxBitmap
*)NULL
, toggle
, xPos
, yPos
, helpString1
, helpString2
);
389 tool
->m_clientData
= clientData
;
394 tool
->m_x
= m_xMargin
;
399 tool
->m_y
= m_yMargin
;
401 tool
->SetSize(GetDefaultButtonWidth(), GetDefaultButtonHeight());
403 m_tools
.Append((long)index
, tool
);
407 int wxToolBar::FindIndexForWidget(WXWidget w
)
409 wxNode
* node
= m_widgets
.First();
412 WXWidget widget
= (WXWidget
) node
->Data();
414 return (int) node
->key
.integer
;
420 WXWidget
wxToolBar::FindWidgetForIndex(int index
)
422 wxNode
* node
= m_widgets
.Find((long) index
);
426 return (WXWidget
) node
->Data();
429 void wxToolButtonCallback (Widget w
, XtPointer clientData
,
432 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
433 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
437 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
440 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
441 if (tool
->m_isToggle
)
442 tool
->m_toggleState
= toolBar
->GetToolState(index
);
444 (void) toolBar
->OnLeftClick(index
, tool
->m_toggleState
);
449 // Creates a bitmap with transparent areas drawn in
451 wxBitmap
wxCreateMaskedBitmap(wxBitmap
& bitmap
, wxColour
& colour
)
453 wxBitmap
newBitmap(bitmap
.GetWidth(),
458 srcDC
.SelectObject(bitmap
);
459 destDC
.SelectObject(newBitmap
);
461 wxBrush
brush(colour
, wxSOLID
);
462 destDC
.SetOptimization(FALSE
);
463 destDC
.SetBackground(brush
);
465 destDC
.Blit(0, 0, bitmap
.GetWidth(), bitmap
.GetHeight(), & srcDC
, 0, 0, wxCOPY
, TRUE
);
471 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
472 XEvent
*event
, Boolean
*continue_to_dispatch
)
474 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
475 int delayMilli
= 800;
476 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
478 int index
= toolBar
->FindIndexForWidget((WXWidget
) w
);
482 wxNode
*node
= toolBar
->GetTools().Find((long)index
);
485 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->Data();
486 wxString
str(toolBar
->GetToolShortHelp(index
));
487 if (str
.IsNull() || str
== "")
490 if (!wxTheToolBarTimer
)
491 wxTheToolBarTimer
= new wxToolBarTimer
;
493 wxToolBarTimer::buttonWidget
= w
;
494 wxToolBarTimer::helpString
= str
;
497 /************************************************************/
498 /* Popup help label */
499 /************************************************************/
500 if (event
->type
== EnterNotify
)
502 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
504 XtDestroyWidget (wxToolBarTimer::help_popup
);
505 XtPopdown (wxToolBarTimer::help_popup
);
507 wxToolBarTimer::help_popup
= (Widget
) 0;
510 wxTheToolBarTimer
->Start(delayMilli
, TRUE
);
513 /************************************************************/
514 /* Popdown help label */
515 /************************************************************/
516 else if (event
->type
== LeaveNotify
)
518 if (wxTheToolBarTimer
)
519 wxTheToolBarTimer
->Stop();
520 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
522 XtDestroyWidget (wxToolBarTimer::help_popup
);
523 XtPopdown (wxToolBarTimer::help_popup
);
525 wxToolBarTimer::help_popup
= (Widget
) 0;
530 void wxToolBarTimer::Notify()
534 /************************************************************/
535 /* Create shell without window decorations */
536 /************************************************************/
537 help_popup
= XtVaCreatePopupShell ("shell",
538 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
541 /************************************************************/
542 /* Get absolute position on display of toolbar button */
543 /************************************************************/
544 XtTranslateCoords (buttonWidget
,
549 // Move the tooltip more or less above the button
550 int yOffset
= 20; // TODO: What should be really?
552 if (y
< yOffset
) y
= 0;
554 /************************************************************/
555 /* Set the position of the help popup */
556 /************************************************************/
557 XtVaSetValues (help_popup
,
562 /************************************************************/
563 /* Create help label */
564 /************************************************************/
565 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
566 XtVaCreateManagedWidget ("help_label",
567 xmLabelWidgetClass
, help_popup
,
568 XmNlabelString
, text
,
570 XmNforeground
, XtRString
, "black",
573 XmNbackground
, XtRString
, "LightGoldenrod",
574 strlen("LightGoldenrod")+1,
578 /************************************************************/
579 /* Popup help label */
580 /************************************************************/
581 XtPopup (help_popup
, XtGrabNone
);