1 /////////////////////////////////////////////////////////////////////////////
2 // Name: motif/toolbar.cpp
4 // Author: Julian Smart
5 // Modified by: 13.12.99 by VZ during toolbar classes reorganization
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "toolbar.h"
25 #define XtDisplay XTDISPLAY
31 #include "wx/toolbar.h"
34 #pragma message disable nosimpint
37 #include <Xm/PushBG.h>
40 #include <Xm/ToggleB.h>
41 #include <Xm/ToggleBG.h>
44 #pragma message enable nosimpint
47 #include "wx/motif/private.h"
49 // ----------------------------------------------------------------------------
51 // ----------------------------------------------------------------------------
53 #if !USE_SHARED_LIBRARY
54 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxToolBarBase
)
57 // ----------------------------------------------------------------------------
59 // ----------------------------------------------------------------------------
61 static void wxToolButtonCallback (Widget w
, XtPointer clientData
,
63 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
64 XEvent
*event
, Boolean
*continue_to_dispatch
);
66 // ----------------------------------------------------------------------------
68 // ----------------------------------------------------------------------------
70 class wxToolBarTimer
: public wxTimer
73 virtual void Notify();
75 static Widget help_popup
;
76 static Widget buttonWidget
;
77 static wxString helpString
;
80 class wxToolBarTool
: public wxToolBarToolBase
83 wxToolBarTool(wxToolBar
*tbar
,
85 const wxString
& label
,
86 const wxBitmap
& bmpNormal
,
87 const wxBitmap
& bmpToggled
,
90 const wxString
& shortHelp
,
91 const wxString
& longHelp
)
92 : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpToggled
, kind
,
93 clientData
, shortHelp
, longHelp
)
98 wxToolBarTool(wxToolBar
*tbar
, wxControl
*control
)
99 : wxToolBarToolBase(tbar
, control
)
104 virtual ~wxToolBarTool();
107 void SetWidget(Widget widget
) { m_widget
= widget
; }
108 Widget
GetButtonWidget() const { return m_widget
; }
110 void SetPixmap(Pixmap pixmap
) { m_pixmap
= pixmap
; }
111 Pixmap
GetPixmap() const { return m_pixmap
; }
120 // ----------------------------------------------------------------------------
122 // ----------------------------------------------------------------------------
124 static wxToolBarTimer
* wxTheToolBarTimer
= (wxToolBarTimer
*) NULL
;
126 Widget
wxToolBarTimer::help_popup
= (Widget
) 0;
127 Widget
wxToolBarTimer::buttonWidget
= (Widget
) 0;
128 wxString
wxToolBarTimer::helpString
;
130 // ============================================================================
132 // ============================================================================
134 // ----------------------------------------------------------------------------
136 // ----------------------------------------------------------------------------
138 wxToolBarToolBase
*wxToolBar::CreateTool(int id
,
139 const wxString
& label
,
140 const wxBitmap
& bmpNormal
,
141 const wxBitmap
& bmpToggled
,
143 wxObject
*clientData
,
144 const wxString
& shortHelp
,
145 const wxString
& longHelp
)
147 return new wxToolBarTool(this, id
, label
, bmpNormal
, bmpToggled
, kind
,
148 clientData
, shortHelp
, longHelp
);
152 wxToolBarToolBase
*wxToolBar::CreateTool(wxControl
*control
)
154 return new wxToolBarTool(this, control
);
157 void wxToolBarTool::Init()
159 m_widget
= (Widget
)0;
160 m_pixmap
= (Pixmap
)0;
163 wxToolBarTool::~wxToolBarTool()
166 XtDestroyWidget(m_widget
);
167 // note: do not delete m_pixmap here because it will be deleted
168 // by the base class when the bitmap is destroyed.
171 // ----------------------------------------------------------------------------
172 // wxToolBar construction
173 // ----------------------------------------------------------------------------
175 void wxToolBar::Init()
180 m_defaultHeight
= 22;
182 m_toolSeparation
= 8;
189 bool wxToolBar::Create(wxWindow
*parent
,
194 const wxString
& name
)
201 m_backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
202 m_foregroundColour
= parent
->GetForegroundColour();
203 m_windowStyle
= style
;
207 if (parent
) parent
->AddChild(this);
209 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
211 Widget toolbar
= XtVaCreateManagedWidget("toolbar",
212 xmBulletinBoardWidgetClass
, (Widget
) parentWidget
,
215 XmNresizePolicy
, XmRESIZE_NONE
,
218 Widget toolbar = XtVaCreateManagedWidget("toolbar",
219 xmFormWidgetClass, (Widget) m_clientWidget,
220 XmNtraversalOn, False,
221 XmNhorizontalSpacing, 0,
222 XmNverticalSpacing, 0,
230 m_mainWidget
= (WXWidget
) toolbar
;
232 m_font
= parent
->GetFont();
235 SetCanAddEventHandler(TRUE
);
236 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
, pos
.x
, pos
.y
, size
.x
, size
.y
);
238 ChangeBackgroundColour();
243 wxToolBar::~wxToolBar()
245 delete wxTheToolBarTimer
;
246 wxTheToolBarTimer
= NULL
;
249 bool wxToolBar::Realize()
251 if ( m_tools
.GetCount() == 0 )
258 const int separatorSize
= GetToolSeparation(); // 8;
259 wxSize margins
= GetToolMargins();
260 int packing
= GetToolPacking();
261 int marginX
= margins
.x
;
262 int marginY
= margins
.y
;
264 int currentX
= marginX
;
265 int currentY
= marginY
;
267 int buttonHeight
= 0;
269 int currentSpacing
= 0;
272 Pixmap pixmap
, insensPixmap
;
275 wxToolBarToolsList::Node
*node
= m_tools
.GetFirst();
278 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
280 switch ( tool
->GetStyle() )
282 case wxTOOL_STYLE_CONTROL
:
284 wxControl
* control
= tool
->GetControl();
285 wxSize sz
= control
->GetSize();
286 wxPoint pos
= control
->GetPosition();
287 // Allow a control to specify a y-offset by setting its initial position,
288 // but still don't allow it to position itself above the top margin.
289 int controlY
= (pos
.y
> 0) ? currentY
+ pos
.y
: currentY
;
290 control
->Move(currentX
, controlY
);
291 currentX
+= sz
.x
+ packing
;
295 case wxTOOL_STYLE_SEPARATOR
:
296 currentX
+= separatorSize
;
299 case wxTOOL_STYLE_BUTTON
:
302 if ( tool
->CanBeToggled() )
304 button
= XtVaCreateWidget("toggleButton",
305 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
306 XmNx
, currentX
, XmNy
, currentY
,
307 XmNindicatorOn
, False
,
308 XmNshadowThickness
, 2,
313 XmNmultiClick
, XmMULTICLICK_KEEP
,
314 XmNlabelType
, XmPIXMAP
,
316 XtAddCallback ((Widget
) button
, XmNvalueChangedCallback
, (XtCallbackProc
) wxToolButtonCallback
,
319 XtVaSetValues ((Widget
) button
,
320 XmNselectColor
, m_backgroundColour
.AllocColour(XtDisplay((Widget
) button
)),
325 button
= XtVaCreateWidget("button",
326 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
327 XmNx
, currentX
, XmNy
, currentY
,
328 XmNpushButtonEnabled
, True
,
329 XmNmultiClick
, XmMULTICLICK_KEEP
,
330 XmNlabelType
, XmPIXMAP
,
332 XtAddCallback (button
,
333 XmNactivateCallback
, (XtCallbackProc
) wxToolButtonCallback
,
337 DoChangeBackgroundColour((WXWidget
) button
, m_backgroundColour
, TRUE
);
339 tool
->SetWidget(button
);
341 // For each button, if there is a mask, we must create
342 // a new wxBitmap that has the correct background colour
343 // for the button. Otherwise the background will just be
344 // e.g. black if a transparent XPM has been loaded.
345 bmp
= tool
->GetNormalBitmap();
349 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
353 col
.SetPixel(backgroundPixel
);
355 bmp
= wxCreateMaskedBitmap(bmp
, col
);
357 tool
->SetNormalBitmap(bmp
);
360 // Create a selected/toggled bitmap. If there isn't a 2nd
361 // bitmap, we need to create it (with a darker, selected
364 if ( tool
->CanBeToggled() )
365 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
368 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
372 col
.SetPixel(backgroundPixel
);
374 // FIXME: we use disabled bitmap as the bitmap for the toggled
375 // state, we probably need a GetToggledBitmap() instead
376 wxBitmap bmpToggled
= tool
->GetDisabledBitmap();
377 if ( bmpToggled
.Ok() && bmpToggled
.GetMask())
380 wxBitmap newBitmap
= wxCreateMaskedBitmap(bmpToggled
, col
);
381 tool
->SetDisabledBitmap(newBitmap
);
385 // Use unselected bitmap
388 wxBitmap newBitmap
= wxCreateMaskedBitmap(bmp
, col
);
389 tool
->SetDisabledBitmap(newBitmap
);
392 tool
->SetDisabledBitmap(bmp
);
395 // FIXME: and here we should use GetDisabledBitmap()...
396 pixmap
= (Pixmap
) bmp
.GetPixmap();
397 insensPixmap
= (Pixmap
) bmp
.GetInsensPixmap();
399 if (tool
->CanBeToggled())
402 Pixmap pixmap2
= (Pixmap
) 0;
403 Pixmap insensPixmap2
= (Pixmap
) 0;
405 // If there's a bitmap for the toggled state, use it,
406 // otherwise generate one.
409 if ( bmpToggled
.Ok() )
411 pixmap2
= (Pixmap
) bmpToggled
.GetPixmap();
412 insensPixmap2
= (Pixmap
) bmpToggled
.GetInsensPixmap();
416 pixmap2
= (Pixmap
) bmp
.GetArmPixmap(button
);
417 insensPixmap2
= XCreateInsensitivePixmap((Display
*) wxGetDisplay(), pixmap2
);
420 tool
->SetPixmap(pixmap2
);
422 XtVaSetValues (button
,
423 XmNfillOnSelect
, True
,
424 XmNlabelPixmap
, pixmap
,
425 XmNselectPixmap
, pixmap2
,
426 XmNlabelInsensitivePixmap
, insensPixmap
,
427 XmNselectInsensitivePixmap
, insensPixmap2
,
428 XmNlabelType
, XmPIXMAP
,
433 Pixmap pixmap2
= (Pixmap
) 0;
435 // If there's a bitmap for the armed state, use it,
436 // otherwise generate one.
437 if ( bmpToggled
.Ok() )
439 pixmap2
= (Pixmap
) bmpToggled
.GetPixmap();
443 pixmap2
= (Pixmap
) bmp
.GetArmPixmap(button
);
447 tool
->SetPixmap(pixmap2
);
450 XtVaSetValues(button
,
451 XmNlabelPixmap
, pixmap
,
452 XmNlabelInsensitivePixmap
, insensPixmap
,
453 XmNarmPixmap
, pixmap2
,
457 XtManageChild(button
);
460 Dimension width
, height
;
461 XtVaGetValues(button
,
465 currentX
+= width
+ packing
;
466 buttonHeight
= wxMax(buttonHeight
, height
);
469 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
470 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
476 node
= node
->GetNext();
479 SetSize(-1, -1, currentX
, buttonHeight
+ 2*marginY
);
484 wxToolBarToolBase
*wxToolBar::FindToolForPosition(wxCoord
WXUNUSED(x
),
485 wxCoord
WXUNUSED(y
)) const
487 wxFAIL_MSG( _T("TODO") );
489 return (wxToolBarToolBase
*)NULL
;
492 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
499 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
506 void wxToolBar::DoEnableTool(wxToolBarToolBase
*toolBase
, bool enable
)
508 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
510 XtSetSensitive(tool
->GetButtonWidget(), (Boolean
) enable
);
513 void wxToolBar::DoToggleTool(wxToolBarToolBase
*toolBase
, bool toggle
)
515 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
517 XmToggleButtonSetState(tool
->GetButtonWidget(), (Boolean
) toggle
, False
);
520 void wxToolBar::DoSetToggle(wxToolBarToolBase
* WXUNUSED(tool
),
521 bool WXUNUSED(toggle
))
526 // ----------------------------------------------------------------------------
528 // ----------------------------------------------------------------------------
530 wxToolBarToolBase
*wxToolBar::FindToolByWidget(WXWidget w
) const
532 wxToolBarToolsList::Node
* node
= m_tools
.GetFirst();
535 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
536 if ( tool
->GetButtonWidget() == w
)
541 node
= node
->GetNext();
544 return (wxToolBarToolBase
*)NULL
;
547 static void wxToolButtonCallback(Widget w
,
548 XtPointer clientData
,
549 XtPointer
WXUNUSED(ptr
))
551 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
552 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
556 if ( tool
->CanBeToggled() )
559 if ( !toolBar
->OnLeftClick(tool
->GetId(), tool
->IsToggled()) )
567 static void wxToolButtonPopupCallback(Widget w
,
568 XtPointer client_data
,
570 Boolean
*WXUNUSED(continue_to_dispatch
))
572 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
573 static const int delayMilli
= 800;
575 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
576 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
581 wxString tooltip
= tool
->GetShortHelp();
585 if (!wxTheToolBarTimer
)
586 wxTheToolBarTimer
= new wxToolBarTimer
;
588 wxToolBarTimer::buttonWidget
= w
;
589 wxToolBarTimer::helpString
= tooltip
;
591 /************************************************************/
592 /* Popup help label */
593 /************************************************************/
594 if (event
->type
== EnterNotify
)
596 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
598 XtDestroyWidget (wxToolBarTimer::help_popup
);
599 XtPopdown (wxToolBarTimer::help_popup
);
601 wxToolBarTimer::help_popup
= (Widget
) 0;
604 wxTheToolBarTimer
->Start(delayMilli
, TRUE
);
607 /************************************************************/
608 /* Popdown help label */
609 /************************************************************/
610 else if (event
->type
== LeaveNotify
)
612 if (wxTheToolBarTimer
)
613 wxTheToolBarTimer
->Stop();
614 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
616 XtDestroyWidget (wxToolBarTimer::help_popup
);
617 XtPopdown (wxToolBarTimer::help_popup
);
619 wxToolBarTimer::help_popup
= (Widget
) 0;
623 void wxToolBarTimer::Notify()
627 /************************************************************/
628 /* Create shell without window decorations */
629 /************************************************************/
630 help_popup
= XtVaCreatePopupShell ("shell",
631 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
634 /************************************************************/
635 /* Get absolute position on display of toolbar button */
636 /************************************************************/
637 XtTranslateCoords (buttonWidget
,
642 // Move the tooltip more or less above the button
643 int yOffset
= 20; // TODO: What should be really?
645 if (y
< yOffset
) y
= 0;
647 /************************************************************/
648 /* Set the position of the help popup */
649 /************************************************************/
650 XtVaSetValues (help_popup
,
655 /************************************************************/
656 /* Create help label */
657 /************************************************************/
658 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
659 XtVaCreateManagedWidget ("help_label",
660 xmLabelWidgetClass
, help_popup
,
661 XmNlabelString
, text
,
663 XmNforeground
, XtRString
, "black",
666 XmNbackground
, XtRString
, "LightGoldenrod",
667 strlen("LightGoldenrod")+1,
671 /************************************************************/
672 /* Popup help label */
673 /************************************************************/
674 XtPopup (help_popup
, XtGrabNone
);