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/settings.h"
30 #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"
48 #include "wx/motif/bmpmotif.h"
50 // ----------------------------------------------------------------------------
52 // ----------------------------------------------------------------------------
54 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxControl
)
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 static void wxToolButtonCallback (Widget w
, XtPointer clientData
,
62 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
63 XEvent
*event
, Boolean
*continue_to_dispatch
);
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
69 class wxToolBarTimer
: public wxTimer
72 virtual void Notify();
74 static Widget help_popup
;
75 static Widget buttonWidget
;
76 static wxString helpString
;
79 class wxToolBarTool
: public wxToolBarToolBase
82 wxToolBarTool(wxToolBar
*tbar
,
84 const wxString
& label
,
85 const wxBitmap
& bmpNormal
,
86 const wxBitmap
& bmpToggled
,
89 const wxString
& shortHelp
,
90 const wxString
& longHelp
)
91 : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpToggled
, kind
,
92 clientData
, shortHelp
, longHelp
)
97 wxToolBarTool(wxToolBar
*tbar
, wxControl
*control
)
98 : wxToolBarToolBase(tbar
, control
)
103 virtual ~wxToolBarTool();
106 void SetWidget(Widget widget
) { m_widget
= widget
; }
107 Widget
GetButtonWidget() const { return m_widget
; }
109 Pixmap
GetArmPixmap()
111 m_bitmapCache
.SetBitmap( GetNormalBitmap() );
112 return (Pixmap
)m_bitmapCache
.GetArmPixmap( (WXWidget
)m_widget
);
115 Pixmap
GetInsensPixmap()
117 m_bitmapCache
.SetBitmap( GetNormalBitmap() );
118 return (Pixmap
)m_bitmapCache
.GetInsensPixmap( (WXWidget
)m_widget
);
124 wxBitmapCache m_bitmapCache
;
127 // ----------------------------------------------------------------------------
129 // ----------------------------------------------------------------------------
131 static wxToolBarTimer
* wxTheToolBarTimer
= (wxToolBarTimer
*) NULL
;
133 Widget
wxToolBarTimer::help_popup
= (Widget
) 0;
134 Widget
wxToolBarTimer::buttonWidget
= (Widget
) 0;
135 wxString
wxToolBarTimer::helpString
;
137 // ============================================================================
139 // ============================================================================
141 // ----------------------------------------------------------------------------
143 // ----------------------------------------------------------------------------
145 wxToolBarToolBase
*wxToolBar::CreateTool(int id
,
146 const wxString
& label
,
147 const wxBitmap
& bmpNormal
,
148 const wxBitmap
& bmpToggled
,
150 wxObject
*clientData
,
151 const wxString
& shortHelp
,
152 const wxString
& longHelp
)
154 return new wxToolBarTool(this, id
, label
, bmpNormal
, bmpToggled
, kind
,
155 clientData
, shortHelp
, longHelp
);
159 wxToolBarToolBase
*wxToolBar::CreateTool(wxControl
*control
)
161 return new wxToolBarTool(this, control
);
164 void wxToolBarTool::Init()
166 m_widget
= (Widget
)0;
169 wxToolBarTool::~wxToolBarTool()
172 XtDestroyWidget(m_widget
);
175 // ----------------------------------------------------------------------------
176 // wxToolBar construction
177 // ----------------------------------------------------------------------------
179 void wxToolBar::Init()
184 m_defaultHeight
= 22;
186 m_toolSeparation
= 8;
193 bool wxToolBar::Create(wxWindow
*parent
,
198 const wxString
& name
)
200 if( !wxControl::CreateControl( parent
, id
, pos
, size
, style
,
201 wxDefaultValidator
, name
) )
204 m_backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
206 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
208 Widget toolbar
= XtVaCreateManagedWidget("toolbar",
209 xmBulletinBoardWidgetClass
, (Widget
) parentWidget
,
212 XmNresizePolicy
, XmRESIZE_NONE
,
215 Widget toolbar = XtVaCreateManagedWidget("toolbar",
216 xmFormWidgetClass, (Widget) m_clientWidget,
217 XmNtraversalOn, False,
218 XmNhorizontalSpacing, 0,
219 XmNverticalSpacing, 0,
227 m_mainWidget
= (WXWidget
) toolbar
;
234 if( rPos
.x
== -1 ) rPos
.x
= 0;
235 if( rPos
.y
== -1 ) rPos
.y
= 0;
236 if( rSize
.x
== -1 && GetParent() )
237 rSize
.x
= GetParent()->GetSize().x
;
239 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
,
240 rPos
.x
, rPos
.y
, rSize
.x
, rSize
.y
);
242 ChangeBackgroundColour();
247 wxToolBar::~wxToolBar()
249 delete wxTheToolBarTimer
;
250 wxTheToolBarTimer
= NULL
;
253 bool wxToolBar::Realize()
255 if ( m_tools
.GetCount() == 0 )
261 bool isVertical
= GetWindowStyle() & wxTB_VERTICAL
;
264 const int separatorSize
= GetToolSeparation(); // 8;
265 wxSize margins
= GetToolMargins();
266 int packing
= GetToolPacking();
267 int marginX
= margins
.x
;
268 int marginY
= margins
.y
;
270 int currentX
= marginX
;
271 int currentY
= marginY
;
273 int buttonHeight
= 0, buttonWidth
= 0;
276 Pixmap pixmap
, insensPixmap
;
277 wxBitmap bmp
, insensBmp
;
279 wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
282 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
284 switch ( tool
->GetStyle() )
286 case wxTOOL_STYLE_CONTROL
:
288 wxControl
* control
= tool
->GetControl();
289 wxSize sz
= control
->GetSize();
290 wxPoint pos
= control
->GetPosition();
291 // Allow a control to specify a y[x]-offset by setting
292 // its initial position, but still don't allow it to
293 // position itself above the top[left] margin.
294 int controlY
= (pos
.y
> 0) ? pos
.y
: currentY
;
295 int controlX
= (pos
.x
> 0) ? pos
.x
: currentX
;
296 control
->Move( isVertical
? controlX
: currentX
,
297 isVertical
? currentY
: controlY
);
299 currentY
+= sz
.y
+ packing
;
301 currentX
+= sz
.x
+ packing
;
305 case wxTOOL_STYLE_SEPARATOR
:
306 // skip separators for vertical toolbars
309 currentX
+= separatorSize
;
313 case wxTOOL_STYLE_BUTTON
:
316 if ( tool
->CanBeToggled() && !tool
->GetButtonWidget() )
318 button
= XtVaCreateWidget("toggleButton",
319 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
320 XmNx
, currentX
, XmNy
, currentY
,
321 XmNindicatorOn
, False
,
322 XmNshadowThickness
, 2,
327 XmNmultiClick
, XmMULTICLICK_KEEP
,
328 XmNlabelType
, XmPIXMAP
,
330 XtAddCallback ((Widget
) button
,
331 XmNvalueChangedCallback
,
332 (XtCallbackProc
) wxToolButtonCallback
,
335 XtVaSetValues ((Widget
) button
,
337 m_backgroundColour
.AllocColour
338 (XtDisplay((Widget
) button
)),
341 else if( !tool
->GetButtonWidget() )
343 button
= XtVaCreateWidget("button",
344 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
345 XmNx
, currentX
, XmNy
, currentY
,
346 XmNpushButtonEnabled
, True
,
347 XmNmultiClick
, XmMULTICLICK_KEEP
,
348 XmNlabelType
, XmPIXMAP
,
350 XtAddCallback (button
,
352 (XtCallbackProc
) wxToolButtonCallback
,
356 if( !tool
->GetButtonWidget() )
358 wxDoChangeBackgroundColour((WXWidget
) button
,
359 m_backgroundColour
, true);
361 tool
->SetWidget(button
);
365 button
= (Widget
)tool
->GetButtonWidget();
366 XtVaSetValues( button
,
367 XmNx
, currentX
, XmNy
, currentY
,
371 // For each button, if there is a mask, we must create
372 // a new wxBitmap that has the correct background colour
373 // for the button. Otherwise the background will just be
374 // e.g. black if a transparent XPM has been loaded.
375 bmp
= tool
->GetNormalBitmap();
376 insensBmp
= tool
->GetDisabledBitmap();
377 if ( bmp
.GetMask() || insensBmp
.GetMask() )
380 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
384 col
.SetPixel(backgroundPixel
);
386 if( bmp
.Ok() && bmp
.GetMask() )
388 bmp
= wxCreateMaskedBitmap(bmp
, col
);
389 tool
->SetNormalBitmap(bmp
);
392 if( insensBmp
.Ok() && insensBmp
.GetMask() )
394 insensBmp
= wxCreateMaskedBitmap(insensBmp
, col
);
395 tool
->SetDisabledBitmap(insensBmp
);
399 // Create a selected/toggled bitmap. If there isn't a 2nd
400 // bitmap, we need to create it (with a darker, selected
403 if ( tool
->CanBeToggled() )
404 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
407 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
410 col
.SetPixel(backgroundPixel
);
412 pixmap
= (Pixmap
) bmp
.GetDrawable();
414 wxBitmap tmp
= tool
->GetDisabledBitmap();
416 insensPixmap
= tmp
.Ok() ?
417 (Pixmap
)tmp
.GetDrawable() :
418 tool
->GetInsensPixmap();
421 if (tool
->CanBeToggled())
424 Pixmap pixmap2
= tool
->GetArmPixmap();
425 Pixmap insensPixmap2
= tool
->GetInsensPixmap();
427 XtVaSetValues (button
,
428 XmNfillOnSelect
, True
,
429 XmNlabelPixmap
, pixmap
,
430 XmNselectPixmap
, pixmap2
,
431 XmNlabelInsensitivePixmap
, insensPixmap
,
432 XmNselectInsensitivePixmap
, insensPixmap2
,
433 XmNlabelType
, XmPIXMAP
,
438 Pixmap pixmap2
= tool
->GetArmPixmap();
441 XtVaSetValues(button
,
442 XmNlabelPixmap
, pixmap
,
443 XmNlabelInsensitivePixmap
, insensPixmap
,
444 XmNarmPixmap
, pixmap2
,
448 XtManageChild(button
);
451 Dimension width
, height
;
452 XtVaGetValues(button
,
457 currentY
+= height
+ packing
;
459 currentX
+= width
+ packing
;
460 buttonHeight
= wxMax(buttonHeight
, height
);
461 buttonWidth
= wxMax(buttonWidth
, width
);
464 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
465 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
470 node
= node
->GetNext();
474 isVertical
? buttonWidth
+ 2 * marginX
: -1,
475 isVertical
? -1 : buttonHeight
+ 2*marginY
);
480 wxToolBarToolBase
*wxToolBar::FindToolForPosition(wxCoord
WXUNUSED(x
),
481 wxCoord
WXUNUSED(y
)) const
483 wxFAIL_MSG( _T("TODO") );
485 return (wxToolBarToolBase
*)NULL
;
488 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
495 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
499 bool isVertical
= GetWindowStyle() & wxTB_VERTICAL
;
500 const int separatorSize
= GetToolSeparation(); // 8;
501 int packing
= GetToolPacking();
504 for( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
505 node
; node
= node
->GetNext() )
507 wxToolBarTool
*t
= (wxToolBarTool
*)node
->GetData();
511 switch ( t
->GetStyle() )
513 case wxTOOL_STYLE_CONTROL
:
515 wxSize size
= t
->GetControl()->GetSize();
516 offset
= isVertical
? size
.y
: size
.x
;
520 case wxTOOL_STYLE_SEPARATOR
:
521 offset
= isVertical
? 0 : separatorSize
;
523 case wxTOOL_STYLE_BUTTON
:
525 Widget w
= t
->GetButtonWidget();
526 Dimension width
, height
;
533 offset
= isVertical
? height
: width
;
541 switch ( t
->GetStyle() )
543 case wxTOOL_STYLE_CONTROL
:
545 wxPoint location
= t
->GetControl()->GetPosition();
548 location
.y
-= offset
;
550 location
.x
-= offset
;
552 t
->GetControl()->Move( location
);
555 case wxTOOL_STYLE_SEPARATOR
:
557 case wxTOOL_STYLE_BUTTON
:
560 XtVaGetValues( t
->GetButtonWidget(),
566 y
= (Dimension
)(y
- offset
);
568 x
= (Dimension
)(x
- offset
);
570 XtVaSetValues( t
->GetButtonWidget(),
583 void wxToolBar::DoEnableTool(wxToolBarToolBase
*toolBase
, bool enable
)
585 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
586 if (tool
->GetButtonWidget()){
587 XtSetSensitive(tool
->GetButtonWidget(), (Boolean
) enable
);
588 } else if (wxTOOL_STYLE_CONTROL
== tool
->GetStyle()){
589 // Controls (such as wxChoice) do not have button widgets
590 tool
->GetControl()->Enable(enable
);
594 void wxToolBar::DoToggleTool(wxToolBarToolBase
*toolBase
, bool toggle
)
596 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
598 XmToggleButtonSetState(tool
->GetButtonWidget(), (Boolean
) toggle
, False
);
601 void wxToolBar::DoSetToggle(wxToolBarToolBase
* WXUNUSED(tool
),
602 bool WXUNUSED(toggle
))
607 void wxToolBar::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
609 int old_width
, old_height
;
610 GetSize(&old_width
, &old_height
);
612 // Correct width and height if needed.
613 if ( width
== -1 || height
== -1 )
615 wxSize defaultSize
= GetSize();
618 width
= defaultSize
.x
;
620 height
= defaultSize
.y
;
623 wxToolBarBase::DoSetSize(x
, y
, width
, height
, sizeFlags
);
625 // We must refresh the frame size when the toolbar changes size
626 // otherwise the toolbar can be shown incorrectly
627 if ( old_width
!= width
|| old_height
!= height
)
629 // But before we send the size event check it
630 // we have a frame that is not being deleted.
631 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
632 if ( frame
&& !frame
->IsBeingDeleted() )
634 frame
->SendSizeEvent();
639 // ----------------------------------------------------------------------------
641 // ----------------------------------------------------------------------------
643 wxToolBarToolBase
*wxToolBar::FindToolByWidget(WXWidget w
) const
645 wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
648 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
649 if ( tool
->GetButtonWidget() == w
)
654 node
= node
->GetNext();
657 return (wxToolBarToolBase
*)NULL
;
660 static void wxToolButtonCallback(Widget w
,
661 XtPointer clientData
,
662 XtPointer
WXUNUSED(ptr
))
664 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
665 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
669 if ( tool
->CanBeToggled() )
672 if ( !toolBar
->OnLeftClick(tool
->GetId(), tool
->IsToggled()) )
680 static void wxToolButtonPopupCallback(Widget w
,
681 XtPointer client_data
,
683 Boolean
*WXUNUSED(continue_to_dispatch
))
685 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
686 static const int delayMilli
= 800;
688 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
689 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
694 wxString tooltip
= tool
->GetShortHelp();
698 if (!wxTheToolBarTimer
)
699 wxTheToolBarTimer
= new wxToolBarTimer
;
701 wxToolBarTimer::buttonWidget
= w
;
702 wxToolBarTimer::helpString
= tooltip
;
704 /************************************************************/
705 /* Popup help label */
706 /************************************************************/
707 if (event
->type
== EnterNotify
)
709 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
711 XtDestroyWidget (wxToolBarTimer::help_popup
);
712 XtPopdown (wxToolBarTimer::help_popup
);
714 wxToolBarTimer::help_popup
= (Widget
) 0;
717 wxTheToolBarTimer
->Start(delayMilli
, true);
720 /************************************************************/
721 /* Popdown help label */
722 /************************************************************/
723 else if (event
->type
== LeaveNotify
)
725 if (wxTheToolBarTimer
)
726 wxTheToolBarTimer
->Stop();
727 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
729 XtDestroyWidget (wxToolBarTimer::help_popup
);
730 XtPopdown (wxToolBarTimer::help_popup
);
732 wxToolBarTimer::help_popup
= (Widget
) 0;
736 void wxToolBarTimer::Notify()
740 /************************************************************/
741 /* Create shell without window decorations */
742 /************************************************************/
743 help_popup
= XtVaCreatePopupShell ("shell",
744 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
747 /************************************************************/
748 /* Get absolute position on display of toolbar button */
749 /************************************************************/
750 XtTranslateCoords (buttonWidget
,
755 // Move the tooltip more or less above the button
756 int yOffset
= 20; // TODO: What should be really?
757 y
= (Position
)(y
- yOffset
);
758 if (y
< yOffset
) y
= 0;
760 /************************************************************/
761 /* Set the position of the help popup */
762 /************************************************************/
763 XtVaSetValues (help_popup
,
768 /************************************************************/
769 /* Create help label */
770 /************************************************************/
771 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
772 XtVaCreateManagedWidget ("help_label",
773 xmLabelWidgetClass
, help_popup
,
774 XmNlabelString
, text
,
776 XmNforeground
, XtRString
, "black",
779 XmNbackground
, XtRString
, "LightGoldenrod",
780 strlen("LightGoldenrod")+1,
784 /************************************************************/
785 /* Popup help label */
786 /************************************************************/
787 XtPopup (help_popup
, XtGrabNone
);