1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/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 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
24 #define XtDisplay XTDISPLAY
27 #include "wx/toolbar.h"
33 #include "wx/settings.h"
38 #pragma message disable nosimpint
41 #include <Xm/PushBG.h>
44 #include <Xm/ToggleB.h>
45 #include <Xm/ToggleBG.h>
48 #pragma message enable nosimpint
51 #include "wx/motif/private.h"
52 #include "wx/motif/bmpmotif.h"
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
58 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxControl
)
60 // ----------------------------------------------------------------------------
62 // ----------------------------------------------------------------------------
64 static void wxToolButtonCallback (Widget w
, XtPointer clientData
,
66 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
67 XEvent
*event
, Boolean
*continue_to_dispatch
);
69 // ----------------------------------------------------------------------------
71 // ----------------------------------------------------------------------------
73 class wxToolBarTimer
: public wxTimer
76 virtual void Notify();
78 static Widget help_popup
;
79 static Widget buttonWidget
;
80 static wxString helpString
;
83 class wxToolBarTool
: public wxToolBarToolBase
86 wxToolBarTool(wxToolBar
*tbar
,
88 const wxString
& label
,
89 const wxBitmap
& bmpNormal
,
90 const wxBitmap
& bmpToggled
,
93 const wxString
& shortHelp
,
94 const wxString
& longHelp
)
95 : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpToggled
, kind
,
96 clientData
, shortHelp
, longHelp
)
101 wxToolBarTool(wxToolBar
*tbar
, wxControl
*control
)
102 : wxToolBarToolBase(tbar
, control
)
107 virtual ~wxToolBarTool();
110 void SetWidget(Widget widget
) { m_widget
= widget
; }
111 Widget
GetButtonWidget() const { return m_widget
; }
113 Pixmap
GetArmPixmap()
115 m_bitmapCache
.SetBitmap( GetNormalBitmap() );
116 return (Pixmap
)m_bitmapCache
.GetArmPixmap( (WXWidget
)m_widget
);
119 Pixmap
GetInsensPixmap()
121 m_bitmapCache
.SetBitmap( GetNormalBitmap() );
122 return (Pixmap
)m_bitmapCache
.GetInsensPixmap( (WXWidget
)m_widget
);
128 wxBitmapCache m_bitmapCache
;
131 // ----------------------------------------------------------------------------
133 // ----------------------------------------------------------------------------
135 static wxToolBarTimer
* wxTheToolBarTimer
= (wxToolBarTimer
*) NULL
;
137 Widget
wxToolBarTimer::help_popup
= (Widget
) 0;
138 Widget
wxToolBarTimer::buttonWidget
= (Widget
) 0;
139 wxString
wxToolBarTimer::helpString
;
141 // ============================================================================
143 // ============================================================================
145 // ----------------------------------------------------------------------------
147 // ----------------------------------------------------------------------------
149 wxToolBarToolBase
*wxToolBar::CreateTool(int id
,
150 const wxString
& label
,
151 const wxBitmap
& bmpNormal
,
152 const wxBitmap
& bmpToggled
,
154 wxObject
*clientData
,
155 const wxString
& shortHelp
,
156 const wxString
& longHelp
)
158 return new wxToolBarTool(this, id
, label
, bmpNormal
, bmpToggled
, kind
,
159 clientData
, shortHelp
, longHelp
);
163 wxToolBarToolBase
*wxToolBar::CreateTool(wxControl
*control
)
165 return new wxToolBarTool(this, control
);
168 void wxToolBarTool::Init()
170 m_widget
= (Widget
)0;
173 wxToolBarTool::~wxToolBarTool()
176 XtDestroyWidget(m_widget
);
179 // ----------------------------------------------------------------------------
180 // wxToolBar construction
181 // ----------------------------------------------------------------------------
183 void wxToolBar::Init()
188 m_defaultHeight
= 22;
190 m_toolSeparation
= 8;
197 bool wxToolBar::Create(wxWindow
*parent
,
202 const wxString
& name
)
204 if( !wxControl::CreateControl( parent
, id
, pos
, size
, style
,
205 wxDefaultValidator
, name
) )
208 m_backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
210 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
212 Widget toolbar
= XtVaCreateManagedWidget("toolbar",
213 xmBulletinBoardWidgetClass
, (Widget
) parentWidget
,
216 XmNresizePolicy
, XmRESIZE_NONE
,
219 Widget toolbar = XtVaCreateManagedWidget("toolbar",
220 xmFormWidgetClass, (Widget) m_clientWidget,
221 XmNtraversalOn, False,
222 XmNhorizontalSpacing, 0,
223 XmNverticalSpacing, 0,
231 m_mainWidget
= (WXWidget
) toolbar
;
238 if( rPos
.x
== -1 ) rPos
.x
= 0;
239 if( rPos
.y
== -1 ) rPos
.y
= 0;
240 if( rSize
.x
== -1 && GetParent() )
241 rSize
.x
= GetParent()->GetSize().x
;
243 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
,
244 rPos
.x
, rPos
.y
, rSize
.x
, rSize
.y
);
246 ChangeBackgroundColour();
251 wxToolBar::~wxToolBar()
253 delete wxTheToolBarTimer
;
254 wxTheToolBarTimer
= NULL
;
257 bool wxToolBar::Realize()
259 if ( m_tools
.GetCount() == 0 )
265 bool isVertical
= GetWindowStyle() & wxTB_VERTICAL
;
268 const int separatorSize
= GetToolSeparation(); // 8;
269 wxSize margins
= GetToolMargins();
270 int packing
= GetToolPacking();
271 int marginX
= margins
.x
;
272 int marginY
= margins
.y
;
274 int currentX
= marginX
;
275 int currentY
= marginY
;
277 int buttonHeight
= 0, buttonWidth
= 0;
280 Pixmap pixmap
, insensPixmap
;
281 wxBitmap bmp
, insensBmp
;
283 wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
286 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
288 switch ( tool
->GetStyle() )
290 case wxTOOL_STYLE_CONTROL
:
292 wxControl
* control
= tool
->GetControl();
293 wxSize sz
= control
->GetSize();
294 wxPoint pos
= control
->GetPosition();
295 // Allow a control to specify a y[x]-offset by setting
296 // its initial position, but still don't allow it to
297 // position itself above the top[left] margin.
298 int controlY
= (pos
.y
> 0) ? pos
.y
: currentY
;
299 int controlX
= (pos
.x
> 0) ? pos
.x
: currentX
;
300 control
->Move( isVertical
? controlX
: currentX
,
301 isVertical
? currentY
: controlY
);
303 currentY
+= sz
.y
+ packing
;
305 currentX
+= sz
.x
+ packing
;
309 case wxTOOL_STYLE_SEPARATOR
:
310 // skip separators for vertical toolbars
313 currentX
+= separatorSize
;
317 case wxTOOL_STYLE_BUTTON
:
320 if ( tool
->CanBeToggled() && !tool
->GetButtonWidget() )
322 button
= XtVaCreateWidget("toggleButton",
323 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
324 XmNx
, currentX
, XmNy
, currentY
,
325 XmNindicatorOn
, False
,
326 XmNshadowThickness
, 2,
331 XmNmultiClick
, XmMULTICLICK_KEEP
,
332 XmNlabelType
, XmPIXMAP
,
334 XtAddCallback ((Widget
) button
,
335 XmNvalueChangedCallback
,
336 (XtCallbackProc
) wxToolButtonCallback
,
339 XtVaSetValues ((Widget
) button
,
341 m_backgroundColour
.AllocColour
342 (XtDisplay((Widget
) button
)),
345 else if( !tool
->GetButtonWidget() )
347 button
= XtVaCreateWidget("button",
348 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
349 XmNx
, currentX
, XmNy
, currentY
,
350 XmNpushButtonEnabled
, True
,
351 XmNmultiClick
, XmMULTICLICK_KEEP
,
352 XmNlabelType
, XmPIXMAP
,
354 XtAddCallback (button
,
356 (XtCallbackProc
) wxToolButtonCallback
,
360 if( !tool
->GetButtonWidget() )
362 wxDoChangeBackgroundColour((WXWidget
) button
,
363 m_backgroundColour
, true);
365 tool
->SetWidget(button
);
369 button
= (Widget
)tool
->GetButtonWidget();
370 XtVaSetValues( button
,
371 XmNx
, currentX
, XmNy
, currentY
,
375 // For each button, if there is a mask, we must create
376 // a new wxBitmap that has the correct background colour
377 // for the button. Otherwise the background will just be
378 // e.g. black if a transparent XPM has been loaded.
379 bmp
= tool
->GetNormalBitmap();
380 insensBmp
= tool
->GetDisabledBitmap();
381 if ( bmp
.GetMask() || insensBmp
.GetMask() )
384 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
388 col
.SetPixel(backgroundPixel
);
390 if( bmp
.Ok() && bmp
.GetMask() )
392 bmp
= wxCreateMaskedBitmap(bmp
, col
);
393 tool
->SetNormalBitmap(bmp
);
396 if( insensBmp
.Ok() && insensBmp
.GetMask() )
398 insensBmp
= wxCreateMaskedBitmap(insensBmp
, col
);
399 tool
->SetDisabledBitmap(insensBmp
);
403 // Create a selected/toggled bitmap. If there isn't a 2nd
404 // bitmap, we need to create it (with a darker, selected
407 if ( tool
->CanBeToggled() )
408 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
411 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
414 col
.SetPixel(backgroundPixel
);
416 pixmap
= (Pixmap
) bmp
.GetDrawable();
418 wxBitmap tmp
= tool
->GetDisabledBitmap();
420 insensPixmap
= tmp
.Ok() ?
421 (Pixmap
)tmp
.GetDrawable() :
422 tool
->GetInsensPixmap();
425 if (tool
->CanBeToggled())
428 Pixmap pixmap2
= tool
->GetArmPixmap();
429 Pixmap insensPixmap2
= tool
->GetInsensPixmap();
431 XtVaSetValues (button
,
432 XmNfillOnSelect
, True
,
433 XmNlabelPixmap
, pixmap
,
434 XmNselectPixmap
, pixmap2
,
435 XmNlabelInsensitivePixmap
, insensPixmap
,
436 XmNselectInsensitivePixmap
, insensPixmap2
,
437 XmNlabelType
, XmPIXMAP
,
442 Pixmap pixmap2
= tool
->GetArmPixmap();
445 XtVaSetValues(button
,
446 XmNlabelPixmap
, pixmap
,
447 XmNlabelInsensitivePixmap
, insensPixmap
,
448 XmNarmPixmap
, pixmap2
,
452 XtManageChild(button
);
455 Dimension width
, height
;
456 XtVaGetValues(button
,
461 currentY
+= height
+ packing
;
463 currentX
+= width
+ packing
;
464 buttonHeight
= wxMax(buttonHeight
, height
);
465 buttonWidth
= wxMax(buttonWidth
, width
);
468 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
469 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
474 node
= node
->GetNext();
478 isVertical
? buttonWidth
+ 2 * marginX
: -1,
479 isVertical
? -1 : 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
)
503 bool isVertical
= GetWindowStyle() & wxTB_VERTICAL
;
504 const int separatorSize
= GetToolSeparation(); // 8;
505 int packing
= GetToolPacking();
508 for( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
509 node
; node
= node
->GetNext() )
511 wxToolBarTool
*t
= (wxToolBarTool
*)node
->GetData();
515 switch ( t
->GetStyle() )
517 case wxTOOL_STYLE_CONTROL
:
519 wxSize size
= t
->GetControl()->GetSize();
520 offset
= isVertical
? size
.y
: size
.x
;
524 case wxTOOL_STYLE_SEPARATOR
:
525 offset
= isVertical
? 0 : separatorSize
;
527 case wxTOOL_STYLE_BUTTON
:
529 Widget w
= t
->GetButtonWidget();
530 Dimension width
, height
;
537 offset
= isVertical
? height
: width
;
545 switch ( t
->GetStyle() )
547 case wxTOOL_STYLE_CONTROL
:
549 wxPoint location
= t
->GetControl()->GetPosition();
552 location
.y
-= offset
;
554 location
.x
-= offset
;
556 t
->GetControl()->Move( location
);
559 case wxTOOL_STYLE_SEPARATOR
:
561 case wxTOOL_STYLE_BUTTON
:
564 XtVaGetValues( t
->GetButtonWidget(),
570 y
= (Dimension
)(y
- offset
);
572 x
= (Dimension
)(x
- offset
);
574 XtVaSetValues( t
->GetButtonWidget(),
587 void wxToolBar::DoEnableTool(wxToolBarToolBase
*toolBase
, bool enable
)
589 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
590 if (tool
->GetButtonWidget()){
591 XtSetSensitive(tool
->GetButtonWidget(), (Boolean
) enable
);
592 } else if (wxTOOL_STYLE_CONTROL
== tool
->GetStyle()){
593 // Controls (such as wxChoice) do not have button widgets
594 tool
->GetControl()->Enable(enable
);
598 void wxToolBar::DoToggleTool(wxToolBarToolBase
*toolBase
, bool toggle
)
600 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
602 XmToggleButtonSetState(tool
->GetButtonWidget(), (Boolean
) toggle
, False
);
605 void wxToolBar::DoSetToggle(wxToolBarToolBase
* WXUNUSED(tool
),
606 bool WXUNUSED(toggle
))
611 void wxToolBar::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
613 int old_width
, old_height
;
614 GetSize(&old_width
, &old_height
);
616 // Correct width and height if needed.
617 if ( width
== -1 || height
== -1 )
619 wxSize defaultSize
= GetSize();
622 width
= defaultSize
.x
;
624 height
= defaultSize
.y
;
627 wxToolBarBase::DoSetSize(x
, y
, width
, height
, sizeFlags
);
629 // We must refresh the frame size when the toolbar changes size
630 // otherwise the toolbar can be shown incorrectly
631 if ( old_width
!= width
|| old_height
!= height
)
633 // But before we send the size event check it
634 // we have a frame that is not being deleted.
635 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
636 if ( frame
&& !frame
->IsBeingDeleted() )
638 frame
->SendSizeEvent();
643 // ----------------------------------------------------------------------------
645 // ----------------------------------------------------------------------------
647 wxToolBarToolBase
*wxToolBar::FindToolByWidget(WXWidget w
) const
649 wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
652 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
653 if ( tool
->GetButtonWidget() == w
)
658 node
= node
->GetNext();
661 return (wxToolBarToolBase
*)NULL
;
664 static void wxToolButtonCallback(Widget w
,
665 XtPointer clientData
,
666 XtPointer
WXUNUSED(ptr
))
668 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
669 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
673 if ( tool
->CanBeToggled() )
676 if ( !toolBar
->OnLeftClick(tool
->GetId(), tool
->IsToggled()) )
684 static void wxToolButtonPopupCallback(Widget w
,
685 XtPointer client_data
,
687 Boolean
*WXUNUSED(continue_to_dispatch
))
689 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
690 static const int delayMilli
= 800;
692 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
693 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
698 wxString tooltip
= tool
->GetShortHelp();
702 if (!wxTheToolBarTimer
)
703 wxTheToolBarTimer
= new wxToolBarTimer
;
705 wxToolBarTimer::buttonWidget
= w
;
706 wxToolBarTimer::helpString
= tooltip
;
708 /************************************************************/
709 /* Popup help label */
710 /************************************************************/
711 if (event
->type
== EnterNotify
)
713 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
715 XtDestroyWidget (wxToolBarTimer::help_popup
);
716 XtPopdown (wxToolBarTimer::help_popup
);
718 wxToolBarTimer::help_popup
= (Widget
) 0;
721 wxTheToolBarTimer
->Start(delayMilli
, true);
724 /************************************************************/
725 /* Popdown help label */
726 /************************************************************/
727 else if (event
->type
== LeaveNotify
)
729 if (wxTheToolBarTimer
)
730 wxTheToolBarTimer
->Stop();
731 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
733 XtDestroyWidget (wxToolBarTimer::help_popup
);
734 XtPopdown (wxToolBarTimer::help_popup
);
736 wxToolBarTimer::help_popup
= (Widget
) 0;
740 void wxToolBarTimer::Notify()
744 /************************************************************/
745 /* Create shell without window decorations */
746 /************************************************************/
747 help_popup
= XtVaCreatePopupShell ("shell",
748 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
751 /************************************************************/
752 /* Get absolute position on display of toolbar button */
753 /************************************************************/
754 XtTranslateCoords (buttonWidget
,
759 // Move the tooltip more or less above the button
760 int yOffset
= 20; // TODO: What should be really?
761 y
= (Position
)(y
- yOffset
);
762 if (y
< yOffset
) y
= 0;
764 /************************************************************/
765 /* Set the position of the help popup */
766 /************************************************************/
767 XtVaSetValues (help_popup
,
772 /************************************************************/
773 /* Create help label */
774 /************************************************************/
775 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
776 XtVaCreateManagedWidget ("help_label",
777 xmLabelWidgetClass
, help_popup
,
778 XmNlabelString
, text
,
780 XmNforeground
, XtRString
, "black",
783 XmNbackground
, XtRString
, "LightGoldenrod",
784 strlen("LightGoldenrod")+1,
788 /************************************************************/
789 /* Popup help label */
790 /************************************************************/
791 XtPopup (help_popup
, XtGrabNone
);