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"
37 #pragma message disable nosimpint
40 #include <Xm/PushBG.h>
43 #include <Xm/ToggleB.h>
44 #include <Xm/ToggleBG.h>
47 #pragma message enable nosimpint
50 #include "wx/motif/private.h"
51 #include "wx/motif/bmpmotif.h"
53 // ----------------------------------------------------------------------------
55 // ----------------------------------------------------------------------------
57 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxControl
)
59 // ----------------------------------------------------------------------------
61 // ----------------------------------------------------------------------------
63 static void wxToolButtonCallback (Widget w
, XtPointer clientData
,
65 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
66 XEvent
*event
, Boolean
*continue_to_dispatch
);
68 // ----------------------------------------------------------------------------
70 // ----------------------------------------------------------------------------
72 class wxToolBarTimer
: public wxTimer
75 virtual void Notify();
77 static Widget help_popup
;
78 static Widget buttonWidget
;
79 static wxString helpString
;
82 class wxToolBarTool
: public wxToolBarToolBase
85 wxToolBarTool(wxToolBar
*tbar
,
87 const wxString
& label
,
88 const wxBitmap
& bmpNormal
,
89 const wxBitmap
& bmpToggled
,
92 const wxString
& shortHelp
,
93 const wxString
& longHelp
)
94 : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpToggled
, kind
,
95 clientData
, shortHelp
, longHelp
)
100 wxToolBarTool(wxToolBar
*tbar
, wxControl
*control
)
101 : wxToolBarToolBase(tbar
, control
)
106 virtual ~wxToolBarTool();
109 void SetWidget(Widget widget
) { m_widget
= widget
; }
110 Widget
GetButtonWidget() const { return m_widget
; }
112 Pixmap
GetArmPixmap()
114 m_bitmapCache
.SetBitmap( GetNormalBitmap() );
115 return (Pixmap
)m_bitmapCache
.GetArmPixmap( (WXWidget
)m_widget
);
118 Pixmap
GetInsensPixmap()
120 m_bitmapCache
.SetBitmap( GetNormalBitmap() );
121 return (Pixmap
)m_bitmapCache
.GetInsensPixmap( (WXWidget
)m_widget
);
127 wxBitmapCache m_bitmapCache
;
130 // ----------------------------------------------------------------------------
132 // ----------------------------------------------------------------------------
134 static wxToolBarTimer
* wxTheToolBarTimer
= (wxToolBarTimer
*) NULL
;
136 Widget
wxToolBarTimer::help_popup
= (Widget
) 0;
137 Widget
wxToolBarTimer::buttonWidget
= (Widget
) 0;
138 wxString
wxToolBarTimer::helpString
;
140 // ============================================================================
142 // ============================================================================
144 // ----------------------------------------------------------------------------
146 // ----------------------------------------------------------------------------
148 wxToolBarToolBase
*wxToolBar::CreateTool(int id
,
149 const wxString
& label
,
150 const wxBitmap
& bmpNormal
,
151 const wxBitmap
& bmpToggled
,
153 wxObject
*clientData
,
154 const wxString
& shortHelp
,
155 const wxString
& longHelp
)
157 return new wxToolBarTool(this, id
, label
, bmpNormal
, bmpToggled
, kind
,
158 clientData
, shortHelp
, longHelp
);
162 wxToolBarToolBase
*wxToolBar::CreateTool(wxControl
*control
)
164 return new wxToolBarTool(this, control
);
167 void wxToolBarTool::Init()
169 m_widget
= (Widget
)0;
172 wxToolBarTool::~wxToolBarTool()
175 XtDestroyWidget(m_widget
);
178 // ----------------------------------------------------------------------------
179 // wxToolBar construction
180 // ----------------------------------------------------------------------------
182 void wxToolBar::Init()
187 m_defaultHeight
= 22;
189 m_toolSeparation
= 8;
196 bool wxToolBar::Create(wxWindow
*parent
,
201 const wxString
& name
)
203 if( !wxControl::CreateControl( parent
, id
, pos
, size
, style
,
204 wxDefaultValidator
, name
) )
207 m_backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
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
;
237 if( rPos
.x
== -1 ) rPos
.x
= 0;
238 if( rPos
.y
== -1 ) rPos
.y
= 0;
239 if( rSize
.x
== -1 && GetParent() )
240 rSize
.x
= GetParent()->GetSize().x
;
242 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
,
243 rPos
.x
, rPos
.y
, rSize
.x
, rSize
.y
);
245 ChangeBackgroundColour();
250 wxToolBar::~wxToolBar()
252 delete wxTheToolBarTimer
;
253 wxTheToolBarTimer
= NULL
;
256 bool wxToolBar::Realize()
258 if ( m_tools
.GetCount() == 0 )
264 bool isVertical
= GetWindowStyle() & wxTB_VERTICAL
;
267 const int separatorSize
= GetToolSeparation(); // 8;
268 wxSize margins
= GetToolMargins();
269 int packing
= GetToolPacking();
270 int marginX
= margins
.x
;
271 int marginY
= margins
.y
;
273 int currentX
= marginX
;
274 int currentY
= marginY
;
276 int buttonHeight
= 0, buttonWidth
= 0;
279 Pixmap pixmap
, insensPixmap
;
280 wxBitmap bmp
, insensBmp
;
282 wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
285 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
287 switch ( tool
->GetStyle() )
289 case wxTOOL_STYLE_CONTROL
:
291 wxControl
* control
= tool
->GetControl();
292 wxSize sz
= control
->GetSize();
293 wxPoint pos
= control
->GetPosition();
294 // Allow a control to specify a y[x]-offset by setting
295 // its initial position, but still don't allow it to
296 // position itself above the top[left] margin.
297 int controlY
= (pos
.y
> 0) ? pos
.y
: currentY
;
298 int controlX
= (pos
.x
> 0) ? pos
.x
: currentX
;
299 control
->Move( isVertical
? controlX
: currentX
,
300 isVertical
? currentY
: controlY
);
302 currentY
+= sz
.y
+ packing
;
304 currentX
+= sz
.x
+ packing
;
308 case wxTOOL_STYLE_SEPARATOR
:
309 // skip separators for vertical toolbars
312 currentX
+= separatorSize
;
316 case wxTOOL_STYLE_BUTTON
:
319 if ( tool
->CanBeToggled() && !tool
->GetButtonWidget() )
321 button
= XtVaCreateWidget("toggleButton",
322 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
323 XmNx
, currentX
, XmNy
, currentY
,
324 XmNindicatorOn
, False
,
325 XmNshadowThickness
, 2,
330 XmNmultiClick
, XmMULTICLICK_KEEP
,
331 XmNlabelType
, XmPIXMAP
,
333 XtAddCallback ((Widget
) button
,
334 XmNvalueChangedCallback
,
335 (XtCallbackProc
) wxToolButtonCallback
,
338 XtVaSetValues ((Widget
) button
,
340 m_backgroundColour
.AllocColour
341 (XtDisplay((Widget
) button
)),
344 else if( !tool
->GetButtonWidget() )
346 button
= XtVaCreateWidget("button",
347 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
348 XmNx
, currentX
, XmNy
, currentY
,
349 XmNpushButtonEnabled
, True
,
350 XmNmultiClick
, XmMULTICLICK_KEEP
,
351 XmNlabelType
, XmPIXMAP
,
353 XtAddCallback (button
,
355 (XtCallbackProc
) wxToolButtonCallback
,
359 if( !tool
->GetButtonWidget() )
361 wxDoChangeBackgroundColour((WXWidget
) button
,
362 m_backgroundColour
, true);
364 tool
->SetWidget(button
);
368 button
= (Widget
)tool
->GetButtonWidget();
369 XtVaSetValues( button
,
370 XmNx
, currentX
, XmNy
, currentY
,
374 // For each button, if there is a mask, we must create
375 // a new wxBitmap that has the correct background colour
376 // for the button. Otherwise the background will just be
377 // e.g. black if a transparent XPM has been loaded.
378 bmp
= tool
->GetNormalBitmap();
379 insensBmp
= tool
->GetDisabledBitmap();
380 if ( bmp
.GetMask() || insensBmp
.GetMask() )
382 WXPixel backgroundPixel
;
383 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
387 col
.SetPixel(backgroundPixel
);
389 if( bmp
.Ok() && bmp
.GetMask() )
391 bmp
= wxCreateMaskedBitmap(bmp
, col
);
392 tool
->SetNormalBitmap(bmp
);
395 if( insensBmp
.Ok() && insensBmp
.GetMask() )
397 insensBmp
= wxCreateMaskedBitmap(insensBmp
, col
);
398 tool
->SetDisabledBitmap(insensBmp
);
402 // Create a selected/toggled bitmap. If there isn't a 2nd
403 // bitmap, we need to create it (with a darker, selected
405 WXPixel backgroundPixel
;
406 if ( tool
->CanBeToggled() )
407 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
410 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
413 col
.SetPixel(backgroundPixel
);
415 pixmap
= (Pixmap
) bmp
.GetDrawable();
417 wxBitmap tmp
= tool
->GetDisabledBitmap();
419 insensPixmap
= tmp
.Ok() ?
420 (Pixmap
)tmp
.GetDrawable() :
421 tool
->GetInsensPixmap();
424 if (tool
->CanBeToggled())
427 Pixmap pixmap2
= tool
->GetArmPixmap();
428 Pixmap insensPixmap2
= tool
->GetInsensPixmap();
430 XtVaSetValues (button
,
431 XmNfillOnSelect
, True
,
432 XmNlabelPixmap
, pixmap
,
433 XmNselectPixmap
, pixmap2
,
434 XmNlabelInsensitivePixmap
, insensPixmap
,
435 XmNselectInsensitivePixmap
, insensPixmap2
,
436 XmNlabelType
, XmPIXMAP
,
441 Pixmap pixmap2
= tool
->GetArmPixmap();
444 XtVaSetValues(button
,
445 XmNlabelPixmap
, pixmap
,
446 XmNlabelInsensitivePixmap
, insensPixmap
,
447 XmNarmPixmap
, pixmap2
,
451 XtManageChild(button
);
454 Dimension width
, height
;
455 XtVaGetValues(button
,
460 currentY
+= height
+ packing
;
462 currentX
+= width
+ packing
;
463 buttonHeight
= wxMax(buttonHeight
, height
);
464 buttonWidth
= wxMax(buttonWidth
, width
);
467 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
468 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
473 node
= node
->GetNext();
477 isVertical
? buttonWidth
+ 2 * marginX
: -1,
478 isVertical
? -1 : buttonHeight
+ 2*marginY
);
483 wxToolBarToolBase
*wxToolBar::FindToolForPosition(wxCoord
WXUNUSED(x
),
484 wxCoord
WXUNUSED(y
)) const
486 wxFAIL_MSG( _T("TODO") );
488 return (wxToolBarToolBase
*)NULL
;
491 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
498 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
502 bool isVertical
= GetWindowStyle() & wxTB_VERTICAL
;
503 const int separatorSize
= GetToolSeparation(); // 8;
504 int packing
= GetToolPacking();
507 for( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
508 node
; node
= node
->GetNext() )
510 wxToolBarTool
*t
= (wxToolBarTool
*)node
->GetData();
514 switch ( t
->GetStyle() )
516 case wxTOOL_STYLE_CONTROL
:
518 wxSize size
= t
->GetControl()->GetSize();
519 offset
= isVertical
? size
.y
: size
.x
;
523 case wxTOOL_STYLE_SEPARATOR
:
524 offset
= isVertical
? 0 : separatorSize
;
526 case wxTOOL_STYLE_BUTTON
:
528 Widget w
= t
->GetButtonWidget();
529 Dimension width
, height
;
536 offset
= isVertical
? height
: width
;
544 switch ( t
->GetStyle() )
546 case wxTOOL_STYLE_CONTROL
:
548 wxPoint location
= t
->GetControl()->GetPosition();
551 location
.y
-= offset
;
553 location
.x
-= offset
;
555 t
->GetControl()->Move( location
);
558 case wxTOOL_STYLE_SEPARATOR
:
560 case wxTOOL_STYLE_BUTTON
:
563 XtVaGetValues( t
->GetButtonWidget(),
569 y
= (Dimension
)(y
- offset
);
571 x
= (Dimension
)(x
- offset
);
573 XtVaSetValues( t
->GetButtonWidget(),
586 void wxToolBar::DoEnableTool(wxToolBarToolBase
*toolBase
, bool enable
)
588 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
589 if (tool
->GetButtonWidget()){
590 XtSetSensitive(tool
->GetButtonWidget(), (Boolean
) enable
);
591 } else if (wxTOOL_STYLE_CONTROL
== tool
->GetStyle()){
592 // Controls (such as wxChoice) do not have button widgets
593 tool
->GetControl()->Enable(enable
);
597 void wxToolBar::DoToggleTool(wxToolBarToolBase
*toolBase
, bool toggle
)
599 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
601 XmToggleButtonSetState(tool
->GetButtonWidget(), (Boolean
) toggle
, False
);
604 void wxToolBar::DoSetToggle(wxToolBarToolBase
* WXUNUSED(tool
),
605 bool WXUNUSED(toggle
))
610 void wxToolBar::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
612 int old_width
, old_height
;
613 GetSize(&old_width
, &old_height
);
615 // Correct width and height if needed.
616 if ( width
== -1 || height
== -1 )
618 wxSize defaultSize
= GetSize();
621 width
= defaultSize
.x
;
623 height
= defaultSize
.y
;
626 wxToolBarBase::DoSetSize(x
, y
, width
, height
, sizeFlags
);
628 // We must refresh the frame size when the toolbar changes size
629 // otherwise the toolbar can be shown incorrectly
630 if ( old_width
!= width
|| old_height
!= height
)
632 // But before we send the size event check it
633 // we have a frame that is not being deleted.
634 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
635 if ( frame
&& !frame
->IsBeingDeleted() )
637 frame
->SendSizeEvent();
642 // ----------------------------------------------------------------------------
644 // ----------------------------------------------------------------------------
646 wxToolBarToolBase
*wxToolBar::FindToolByWidget(WXWidget w
) const
648 wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
651 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
652 if ( tool
->GetButtonWidget() == w
)
657 node
= node
->GetNext();
660 return (wxToolBarToolBase
*)NULL
;
663 static void wxToolButtonCallback(Widget w
,
664 XtPointer clientData
,
665 XtPointer
WXUNUSED(ptr
))
667 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
668 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
672 if ( tool
->CanBeToggled() )
675 if ( !toolBar
->OnLeftClick(tool
->GetId(), tool
->IsToggled()) )
683 static void wxToolButtonPopupCallback(Widget w
,
684 XtPointer client_data
,
686 Boolean
*WXUNUSED(continue_to_dispatch
))
688 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
689 static const int delayMilli
= 800;
691 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
692 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
697 wxString tooltip
= tool
->GetShortHelp();
701 if (!wxTheToolBarTimer
)
702 wxTheToolBarTimer
= new wxToolBarTimer
;
704 wxToolBarTimer::buttonWidget
= w
;
705 wxToolBarTimer::helpString
= tooltip
;
707 /************************************************************/
708 /* Popup help label */
709 /************************************************************/
710 if (event
->type
== EnterNotify
)
712 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
714 XtDestroyWidget (wxToolBarTimer::help_popup
);
715 XtPopdown (wxToolBarTimer::help_popup
);
717 wxToolBarTimer::help_popup
= (Widget
) 0;
720 wxTheToolBarTimer
->Start(delayMilli
, true);
723 /************************************************************/
724 /* Popdown help label */
725 /************************************************************/
726 else if (event
->type
== LeaveNotify
)
728 if (wxTheToolBarTimer
)
729 wxTheToolBarTimer
->Stop();
730 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
732 XtDestroyWidget (wxToolBarTimer::help_popup
);
733 XtPopdown (wxToolBarTimer::help_popup
);
735 wxToolBarTimer::help_popup
= (Widget
) 0;
739 void wxToolBarTimer::Notify()
743 /************************************************************/
744 /* Create shell without window decorations */
745 /************************************************************/
746 help_popup
= XtVaCreatePopupShell ("shell",
747 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
750 /************************************************************/
751 /* Get absolute position on display of toolbar button */
752 /************************************************************/
753 XtTranslateCoords (buttonWidget
,
758 // Move the tooltip more or less above the button
759 int yOffset
= 20; // TODO: What should be really?
760 y
= (Position
)(y
- yOffset
);
761 if (y
< yOffset
) y
= 0;
763 /************************************************************/
764 /* Set the position of the help popup */
765 /************************************************************/
766 XtVaSetValues (help_popup
,
771 /************************************************************/
772 /* Create help label */
773 /************************************************************/
774 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
775 XtVaCreateManagedWidget ("help_label",
776 xmLabelWidgetClass
, help_popup
,
777 XmNlabelString
, text
,
779 XmNforeground
, XtRString
, "black",
782 XmNbackground
, XtRString
, "LightGoldenrod",
783 strlen("LightGoldenrod")+1,
787 /************************************************************/
788 /* Popup help label */
789 /************************************************************/
790 XtPopup (help_popup
, XtGrabNone
);