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 // ----------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "toolbar.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
28 #define XtDisplay XTDISPLAY
31 #include "wx/settings.h"
34 #include "wx/toolbar.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 #if !USE_SHARED_LIBRARY
59 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxControl
)
62 // ----------------------------------------------------------------------------
64 // ----------------------------------------------------------------------------
66 static void wxToolButtonCallback (Widget w
, XtPointer clientData
,
68 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
69 XEvent
*event
, Boolean
*continue_to_dispatch
);
71 // ----------------------------------------------------------------------------
73 // ----------------------------------------------------------------------------
75 class wxToolBarTimer
: public wxTimer
78 virtual void Notify();
80 static Widget help_popup
;
81 static Widget buttonWidget
;
82 static wxString helpString
;
85 class wxToolBarTool
: public wxToolBarToolBase
88 wxToolBarTool(wxToolBar
*tbar
,
90 const wxString
& label
,
91 const wxBitmap
& bmpNormal
,
92 const wxBitmap
& bmpToggled
,
95 const wxString
& shortHelp
,
96 const wxString
& longHelp
)
97 : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpToggled
, kind
,
98 clientData
, shortHelp
, longHelp
)
103 wxToolBarTool(wxToolBar
*tbar
, wxControl
*control
)
104 : wxToolBarToolBase(tbar
, control
)
109 virtual ~wxToolBarTool();
112 void SetWidget(Widget widget
) { m_widget
= widget
; }
113 Widget
GetButtonWidget() const { return m_widget
; }
115 Pixmap
GetArmPixmap()
117 m_bitmapCache
.SetBitmap( GetNormalBitmap() );
118 return (Pixmap
)m_bitmapCache
.GetArmPixmap( (WXWidget
)m_widget
);
121 Pixmap
GetInsensPixmap()
123 m_bitmapCache
.SetBitmap( GetNormalBitmap() );
124 return (Pixmap
)m_bitmapCache
.GetInsensPixmap( (WXWidget
)m_widget
);
130 wxBitmapCache m_bitmapCache
;
133 // ----------------------------------------------------------------------------
135 // ----------------------------------------------------------------------------
137 static wxToolBarTimer
* wxTheToolBarTimer
= (wxToolBarTimer
*) NULL
;
139 Widget
wxToolBarTimer::help_popup
= (Widget
) 0;
140 Widget
wxToolBarTimer::buttonWidget
= (Widget
) 0;
141 wxString
wxToolBarTimer::helpString
;
143 // ============================================================================
145 // ============================================================================
147 // ----------------------------------------------------------------------------
149 // ----------------------------------------------------------------------------
151 wxToolBarToolBase
*wxToolBar::CreateTool(int id
,
152 const wxString
& label
,
153 const wxBitmap
& bmpNormal
,
154 const wxBitmap
& bmpToggled
,
156 wxObject
*clientData
,
157 const wxString
& shortHelp
,
158 const wxString
& longHelp
)
160 return new wxToolBarTool(this, id
, label
, bmpNormal
, bmpToggled
, kind
,
161 clientData
, shortHelp
, longHelp
);
165 wxToolBarToolBase
*wxToolBar::CreateTool(wxControl
*control
)
167 return new wxToolBarTool(this, control
);
170 void wxToolBarTool::Init()
172 m_widget
= (Widget
)0;
175 wxToolBarTool::~wxToolBarTool()
178 XtDestroyWidget(m_widget
);
181 // ----------------------------------------------------------------------------
182 // wxToolBar construction
183 // ----------------------------------------------------------------------------
185 void wxToolBar::Init()
190 m_defaultHeight
= 22;
192 m_toolSeparation
= 8;
199 bool wxToolBar::Create(wxWindow
*parent
,
204 const wxString
& name
)
206 if( !wxControl::CreateControl( parent
, id
, pos
, size
, style
,
207 wxDefaultValidator
, name
) )
210 m_backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
212 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
214 Widget toolbar
= XtVaCreateManagedWidget("toolbar",
215 xmBulletinBoardWidgetClass
, (Widget
) parentWidget
,
218 XmNresizePolicy
, XmRESIZE_NONE
,
221 Widget toolbar = XtVaCreateManagedWidget("toolbar",
222 xmFormWidgetClass, (Widget) m_clientWidget,
223 XmNtraversalOn, False,
224 XmNhorizontalSpacing, 0,
225 XmNverticalSpacing, 0,
233 m_mainWidget
= (WXWidget
) toolbar
;
240 if( rPos
.x
== -1 ) rPos
.x
= 0;
241 if( rPos
.y
== -1 ) rPos
.y
= 0;
242 if( rSize
.x
== -1 && GetParent() )
243 rSize
.x
= GetParent()->GetSize().x
;
245 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
,
246 rPos
.x
, rPos
.y
, rSize
.x
, rSize
.y
);
248 ChangeBackgroundColour();
253 wxToolBar::~wxToolBar()
255 delete wxTheToolBarTimer
;
256 wxTheToolBarTimer
= NULL
;
259 bool wxToolBar::Realize()
261 if ( m_tools
.GetCount() == 0 )
267 bool isVertical
= GetWindowStyle() & wxTB_VERTICAL
;
270 const int separatorSize
= GetToolSeparation(); // 8;
271 wxSize margins
= GetToolMargins();
272 int packing
= GetToolPacking();
273 int marginX
= margins
.x
;
274 int marginY
= margins
.y
;
276 int currentX
= marginX
;
277 int currentY
= marginY
;
279 int buttonHeight
= 0, buttonWidth
= 0;
281 int currentSpacing
= 0;
284 Pixmap pixmap
, insensPixmap
;
285 wxBitmap bmp
, insensBmp
;
287 wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
290 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
292 switch ( tool
->GetStyle() )
294 case wxTOOL_STYLE_CONTROL
:
296 wxControl
* control
= tool
->GetControl();
297 wxSize sz
= control
->GetSize();
298 wxPoint pos
= control
->GetPosition();
299 // Allow a control to specify a y[x]-offset by setting
300 // its initial position, but still don't allow it to
301 // position itself above the top[left] margin.
302 int controlY
= (pos
.y
> 0) ? pos
.y
: currentY
;
303 int controlX
= (pos
.x
> 0) ? pos
.x
: currentX
;
304 control
->Move( isVertical
? controlX
: currentX
,
305 isVertical
? currentY
: controlY
);
307 currentY
+= sz
.y
+ packing
;
309 currentX
+= sz
.x
+ packing
;
313 case wxTOOL_STYLE_SEPARATOR
:
314 // skip separators for vertical toolbars
317 currentX
+= separatorSize
;
321 case wxTOOL_STYLE_BUTTON
:
324 if ( tool
->CanBeToggled() && !tool
->GetButtonWidget() )
326 button
= XtVaCreateWidget("toggleButton",
327 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
328 XmNx
, currentX
, XmNy
, currentY
,
329 XmNindicatorOn
, False
,
330 XmNshadowThickness
, 2,
335 XmNmultiClick
, XmMULTICLICK_KEEP
,
336 XmNlabelType
, XmPIXMAP
,
338 XtAddCallback ((Widget
) button
,
339 XmNvalueChangedCallback
,
340 (XtCallbackProc
) wxToolButtonCallback
,
343 XtVaSetValues ((Widget
) button
,
345 m_backgroundColour
.AllocColour
346 (XtDisplay((Widget
) button
)),
349 else if( !tool
->GetButtonWidget() )
351 button
= XtVaCreateWidget("button",
352 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
353 XmNx
, currentX
, XmNy
, currentY
,
354 XmNpushButtonEnabled
, True
,
355 XmNmultiClick
, XmMULTICLICK_KEEP
,
356 XmNlabelType
, XmPIXMAP
,
358 XtAddCallback (button
,
360 (XtCallbackProc
) wxToolButtonCallback
,
364 if( !tool
->GetButtonWidget() )
366 wxDoChangeBackgroundColour((WXWidget
) button
,
367 m_backgroundColour
, TRUE
);
369 tool
->SetWidget(button
);
373 button
= (Widget
)tool
->GetButtonWidget();
374 XtVaSetValues( button
,
375 XmNx
, currentX
, XmNy
, currentY
,
379 // For each button, if there is a mask, we must create
380 // a new wxBitmap that has the correct background colour
381 // for the button. Otherwise the background will just be
382 // e.g. black if a transparent XPM has been loaded.
383 bmp
= tool
->GetNormalBitmap();
384 insensBmp
= tool
->GetDisabledBitmap();
385 if ( bmp
.GetMask() || insensBmp
.GetMask() )
388 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
392 col
.SetPixel(backgroundPixel
);
394 if( bmp
.Ok() && bmp
.GetMask() )
396 bmp
= wxCreateMaskedBitmap(bmp
, col
);
397 tool
->SetNormalBitmap(bmp
);
400 if( insensBmp
.Ok() && insensBmp
.GetMask() )
402 insensBmp
= wxCreateMaskedBitmap(insensBmp
, col
);
403 tool
->SetDisabledBitmap(insensBmp
);
407 // Create a selected/toggled bitmap. If there isn't a 2nd
408 // bitmap, we need to create it (with a darker, selected
411 if ( tool
->CanBeToggled() )
412 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
415 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
418 col
.SetPixel(backgroundPixel
);
420 pixmap
= (Pixmap
) bmp
.GetDrawable();
422 wxBitmap tmp
= tool
->GetDisabledBitmap();
424 insensPixmap
= tmp
.Ok() ?
425 (Pixmap
)tmp
.GetDrawable() :
426 tool
->GetInsensPixmap();
429 if (tool
->CanBeToggled())
432 Pixmap pixmap2
= tool
->GetArmPixmap();
433 Pixmap insensPixmap2
= tool
->GetInsensPixmap();
435 XtVaSetValues (button
,
436 XmNfillOnSelect
, True
,
437 XmNlabelPixmap
, pixmap
,
438 XmNselectPixmap
, pixmap2
,
439 XmNlabelInsensitivePixmap
, insensPixmap
,
440 XmNselectInsensitivePixmap
, insensPixmap2
,
441 XmNlabelType
, XmPIXMAP
,
446 Pixmap pixmap2
= tool
->GetArmPixmap();
449 XtVaSetValues(button
,
450 XmNlabelPixmap
, pixmap
,
451 XmNlabelInsensitivePixmap
, insensPixmap
,
452 XmNarmPixmap
, pixmap2
,
456 XtManageChild(button
);
459 Dimension width
, height
;
460 XtVaGetValues(button
,
465 currentY
+= height
+ packing
;
467 currentX
+= width
+ packing
;
468 buttonHeight
= wxMax(buttonHeight
, height
);
469 buttonWidth
= wxMax(buttonWidth
, width
);
472 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
473 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
479 node
= node
->GetNext();
483 isVertical
? buttonWidth
+ 2 * marginX
: -1,
484 isVertical
? -1 : buttonHeight
+ 2*marginY
);
489 wxToolBarToolBase
*wxToolBar::FindToolForPosition(wxCoord
WXUNUSED(x
),
490 wxCoord
WXUNUSED(y
)) const
492 wxFAIL_MSG( _T("TODO") );
494 return (wxToolBarToolBase
*)NULL
;
497 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
504 bool wxToolBar::DoDeleteTool(size_t pos
, wxToolBarToolBase
*tool
)
508 bool isVertical
= GetWindowStyle() & wxTB_VERTICAL
;
509 const int separatorSize
= GetToolSeparation(); // 8;
510 int packing
= GetToolPacking();
513 for( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
514 node
; node
= node
->GetNext() )
516 wxToolBarTool
*t
= (wxToolBarTool
*)node
->GetData();
520 switch ( t
->GetStyle() )
522 case wxTOOL_STYLE_CONTROL
:
524 wxSize size
= t
->GetControl()->GetSize();
525 offset
= isVertical
? size
.y
: size
.x
;
529 case wxTOOL_STYLE_SEPARATOR
:
530 offset
= isVertical
? 0 : separatorSize
;
532 case wxTOOL_STYLE_BUTTON
:
534 Widget w
= t
->GetButtonWidget();
535 Dimension width
, height
;
542 offset
= isVertical
? height
: width
;
550 switch ( t
->GetStyle() )
552 case wxTOOL_STYLE_CONTROL
:
554 wxPoint pos
= t
->GetControl()->GetPosition();
561 t
->GetControl()->Move( pos
);
564 case wxTOOL_STYLE_SEPARATOR
:
566 case wxTOOL_STYLE_BUTTON
:
569 XtVaGetValues( t
->GetButtonWidget(),
579 XtVaSetValues( t
->GetButtonWidget(),
592 void wxToolBar::DoEnableTool(wxToolBarToolBase
*toolBase
, bool enable
)
594 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
595 if (tool
->GetButtonWidget()){
596 XtSetSensitive(tool
->GetButtonWidget(), (Boolean
) enable
);
597 } else if (wxTOOL_STYLE_CONTROL
== tool
->GetStyle()){
598 // Controls (such as wxChoice) do not have button widgets
599 tool
->GetControl()->Enable(enable
);
603 void wxToolBar::DoToggleTool(wxToolBarToolBase
*toolBase
, bool toggle
)
605 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
607 XmToggleButtonSetState(tool
->GetButtonWidget(), (Boolean
) toggle
, False
);
610 void wxToolBar::DoSetToggle(wxToolBarToolBase
* WXUNUSED(tool
),
611 bool WXUNUSED(toggle
))
616 void wxToolBar::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
618 int old_width
, old_height
;
619 GetSize(&old_width
, &old_height
);
621 // Correct width and height if needed.
622 if ( width
== -1 || height
== -1 )
624 wxSize defaultSize
= GetSize();
627 width
= defaultSize
.x
;
629 height
= defaultSize
.y
;
632 wxToolBarBase::DoSetSize(x
, y
, width
, height
, sizeFlags
);
634 // We must refresh the frame size when the toolbar changes size
635 // otherwise the toolbar can be shown incorrectly
636 if ( old_width
!= width
|| old_height
!= height
)
638 // But before we send the size event check it
639 // we have a frame that is not being deleted.
640 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
641 if ( frame
&& !frame
->IsBeingDeleted() )
643 frame
->SendSizeEvent();
648 // ----------------------------------------------------------------------------
650 // ----------------------------------------------------------------------------
652 wxToolBarToolBase
*wxToolBar::FindToolByWidget(WXWidget w
) const
654 wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
657 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
658 if ( tool
->GetButtonWidget() == w
)
663 node
= node
->GetNext();
666 return (wxToolBarToolBase
*)NULL
;
669 static void wxToolButtonCallback(Widget w
,
670 XtPointer clientData
,
671 XtPointer
WXUNUSED(ptr
))
673 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
674 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
678 if ( tool
->CanBeToggled() )
681 if ( !toolBar
->OnLeftClick(tool
->GetId(), tool
->IsToggled()) )
689 static void wxToolButtonPopupCallback(Widget w
,
690 XtPointer client_data
,
692 Boolean
*WXUNUSED(continue_to_dispatch
))
694 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
695 static const int delayMilli
= 800;
697 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
698 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
703 wxString tooltip
= tool
->GetShortHelp();
707 if (!wxTheToolBarTimer
)
708 wxTheToolBarTimer
= new wxToolBarTimer
;
710 wxToolBarTimer::buttonWidget
= w
;
711 wxToolBarTimer::helpString
= tooltip
;
713 /************************************************************/
714 /* Popup help label */
715 /************************************************************/
716 if (event
->type
== EnterNotify
)
718 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
720 XtDestroyWidget (wxToolBarTimer::help_popup
);
721 XtPopdown (wxToolBarTimer::help_popup
);
723 wxToolBarTimer::help_popup
= (Widget
) 0;
726 wxTheToolBarTimer
->Start(delayMilli
, TRUE
);
729 /************************************************************/
730 /* Popdown help label */
731 /************************************************************/
732 else if (event
->type
== LeaveNotify
)
734 if (wxTheToolBarTimer
)
735 wxTheToolBarTimer
->Stop();
736 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
738 XtDestroyWidget (wxToolBarTimer::help_popup
);
739 XtPopdown (wxToolBarTimer::help_popup
);
741 wxToolBarTimer::help_popup
= (Widget
) 0;
745 void wxToolBarTimer::Notify()
749 /************************************************************/
750 /* Create shell without window decorations */
751 /************************************************************/
752 help_popup
= XtVaCreatePopupShell ("shell",
753 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
756 /************************************************************/
757 /* Get absolute position on display of toolbar button */
758 /************************************************************/
759 XtTranslateCoords (buttonWidget
,
764 // Move the tooltip more or less above the button
765 int yOffset
= 20; // TODO: What should be really?
767 if (y
< yOffset
) y
= 0;
769 /************************************************************/
770 /* Set the position of the help popup */
771 /************************************************************/
772 XtVaSetValues (help_popup
,
777 /************************************************************/
778 /* Create help label */
779 /************************************************************/
780 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
781 XtVaCreateManagedWidget ("help_label",
782 xmLabelWidgetClass
, help_popup
,
783 XmNlabelString
, text
,
785 XmNforeground
, XtRString
, "black",
788 XmNbackground
, XtRString
, "LightGoldenrod",
789 strlen("LightGoldenrod")+1,
793 /************************************************************/
794 /* Popup help label */
795 /************************************************************/
796 XtPopup (help_popup
, XtGrabNone
);