1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/motif/toolbar.cpp
4 // Author: Julian Smart
5 // Modified by: 13.12.99 by VZ during toolbar classes reorganization
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
22 #include "wx/toolbar.h"
28 #include "wx/settings.h"
32 #pragma message disable nosimpint
35 #include <Xm/PushBG.h>
38 #include <Xm/ToggleB.h>
39 #include <Xm/ToggleBG.h>
42 #pragma message enable nosimpint
45 #include "wx/motif/private.h"
46 #include "wx/motif/bmpmotif.h"
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxControl
)
54 // ----------------------------------------------------------------------------
56 // ----------------------------------------------------------------------------
58 static void wxToolButtonCallback (Widget w
, XtPointer clientData
,
60 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
61 XEvent
*event
, Boolean
*continue_to_dispatch
);
63 // ----------------------------------------------------------------------------
65 // ----------------------------------------------------------------------------
67 class wxToolBarTimer
: public wxTimer
70 virtual void Notify();
72 static Widget help_popup
;
73 static Widget buttonWidget
;
74 static wxString helpString
;
77 class wxToolBarTool
: public wxToolBarToolBase
80 wxToolBarTool(wxToolBar
*tbar
,
82 const wxString
& label
,
83 const wxBitmap
& bmpNormal
,
84 const wxBitmap
& bmpToggled
,
87 const wxString
& shortHelp
,
88 const wxString
& longHelp
)
89 : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpToggled
, kind
,
90 clientData
, shortHelp
, longHelp
)
95 wxToolBarTool(wxToolBar
*tbar
, wxControl
*control
, const wxString
& label
)
96 : wxToolBarToolBase(tbar
, control
, label
)
101 virtual ~wxToolBarTool();
104 void SetWidget(Widget widget
) { m_widget
= widget
; }
105 Widget
GetButtonWidget() const { return m_widget
; }
107 Pixmap
GetArmPixmap()
109 m_bitmapCache
.SetBitmap( GetNormalBitmap() );
110 return (Pixmap
)m_bitmapCache
.GetArmPixmap( (WXWidget
)m_widget
);
113 Pixmap
GetInsensPixmap()
115 m_bitmapCache
.SetBitmap( GetNormalBitmap() );
116 return (Pixmap
)m_bitmapCache
.GetInsensPixmap( (WXWidget
)m_widget
);
122 wxBitmapCache m_bitmapCache
;
125 // ----------------------------------------------------------------------------
127 // ----------------------------------------------------------------------------
129 static wxToolBarTimer
* wxTheToolBarTimer
= NULL
;
131 Widget
wxToolBarTimer::help_popup
= (Widget
) 0;
132 Widget
wxToolBarTimer::buttonWidget
= (Widget
) 0;
133 wxString
wxToolBarTimer::helpString
;
135 // ============================================================================
137 // ============================================================================
139 // ----------------------------------------------------------------------------
141 // ----------------------------------------------------------------------------
143 wxToolBarToolBase
*wxToolBar::CreateTool(int id
,
144 const wxString
& label
,
145 const wxBitmap
& bmpNormal
,
146 const wxBitmap
& bmpToggled
,
148 wxObject
*clientData
,
149 const wxString
& shortHelp
,
150 const wxString
& longHelp
)
152 return new wxToolBarTool(this, id
, label
, bmpNormal
, bmpToggled
, kind
,
153 clientData
, shortHelp
, longHelp
);
158 wxToolBar::CreateTool(wxControl
*control
, const wxString
& label
)
160 return new wxToolBarTool(this, control
, label
);
163 void wxToolBarTool::Init()
165 m_widget
= (Widget
)0;
168 wxToolBarTool::~wxToolBarTool()
171 XtDestroyWidget(m_widget
);
174 // ----------------------------------------------------------------------------
175 // wxToolBar construction
176 // ----------------------------------------------------------------------------
178 void wxToolBar::Init()
183 m_defaultHeight
= 22;
185 m_toolSeparation
= 8;
192 bool wxToolBar::Create(wxWindow
*parent
,
197 const wxString
& name
)
199 if( !wxControl::CreateControl( parent
, id
, pos
, size
, style
,
200 wxDefaultValidator
, name
) )
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
;
232 if( rPos
.x
== -1 ) rPos
.x
= 0;
233 if( rPos
.y
== -1 ) rPos
.y
= 0;
234 if( rSize
.x
== -1 && GetParent() )
235 rSize
.x
= GetParent()->GetSize().x
;
238 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
,
239 rPos
.x
, rPos
.y
, rSize
.x
, rSize
.y
);
244 wxToolBar::~wxToolBar()
246 wxDELETE(wxTheToolBarTimer
);
249 bool wxToolBar::Realize()
251 if ( m_tools
.GetCount() == 0 )
257 bool isVertical
= GetWindowStyle() & wxTB_VERTICAL
;
260 const int separatorSize
= GetToolSeparation(); // 8;
261 wxSize margins
= GetToolMargins();
262 int packing
= GetToolPacking();
263 int marginX
= margins
.x
;
264 int marginY
= margins
.y
;
266 int currentX
= marginX
;
267 int currentY
= marginY
;
269 int buttonHeight
= 0, buttonWidth
= 0;
272 Pixmap pixmap
, insensPixmap
;
273 wxBitmap bmp
, insensBmp
;
275 wxToolBarToolsList::compatibility_iterator 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[x]-offset by setting
288 // its initial position, but still don't allow it to
289 // position itself above the top[left] margin.
290 int controlY
= (pos
.y
> 0) ? pos
.y
: currentY
;
291 int controlX
= (pos
.x
> 0) ? pos
.x
: currentX
;
292 control
->Move( isVertical
? controlX
: currentX
,
293 isVertical
? currentY
: controlY
);
295 currentY
+= sz
.y
+ packing
;
297 currentX
+= sz
.x
+ packing
;
301 case wxTOOL_STYLE_SEPARATOR
:
302 // skip separators for vertical toolbars
305 currentX
+= separatorSize
;
309 case wxTOOL_STYLE_BUTTON
:
312 if ( tool
->CanBeToggled() && !tool
->GetButtonWidget() )
314 button
= XtVaCreateWidget("toggleButton",
315 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
316 XmNx
, currentX
, XmNy
, currentY
,
317 XmNindicatorOn
, False
,
318 XmNshadowThickness
, 2,
323 XmNmultiClick
, XmMULTICLICK_KEEP
,
324 XmNlabelType
, XmPIXMAP
,
326 XtAddCallback ((Widget
) button
,
327 XmNvalueChangedCallback
,
328 (XtCallbackProc
) wxToolButtonCallback
,
331 XtVaSetValues ((Widget
) button
,
333 m_backgroundColour
.AllocColour
334 (XtDisplay((Widget
) button
)),
337 else if( !tool
->GetButtonWidget() )
339 button
= XtVaCreateWidget("button",
340 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
341 XmNx
, currentX
, XmNy
, currentY
,
342 XmNpushButtonEnabled
, True
,
343 XmNmultiClick
, XmMULTICLICK_KEEP
,
344 XmNlabelType
, XmPIXMAP
,
346 XtAddCallback (button
,
348 (XtCallbackProc
) wxToolButtonCallback
,
352 if( !tool
->GetButtonWidget() )
354 wxDoChangeBackgroundColour((WXWidget
) button
,
355 m_backgroundColour
, true);
357 tool
->SetWidget(button
);
361 button
= (Widget
)tool
->GetButtonWidget();
362 XtVaSetValues( button
,
363 XmNx
, currentX
, XmNy
, currentY
,
367 // For each button, if there is a mask, we must create
368 // a new wxBitmap that has the correct background colour
369 // for the button. Otherwise the background will just be
370 // e.g. black if a transparent XPM has been loaded.
371 bmp
= tool
->GetNormalBitmap();
372 insensBmp
= tool
->GetDisabledBitmap();
373 if ( bmp
.GetMask() || insensBmp
.GetMask() )
375 WXPixel backgroundPixel
;
376 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
380 col
.SetPixel(backgroundPixel
);
382 if( bmp
.IsOk() && bmp
.GetMask() )
384 bmp
= wxCreateMaskedBitmap(bmp
, col
);
385 tool
->SetNormalBitmap(bmp
);
388 if( insensBmp
.IsOk() && insensBmp
.GetMask() )
390 insensBmp
= wxCreateMaskedBitmap(insensBmp
, col
);
391 tool
->SetDisabledBitmap(insensBmp
);
395 // Create a selected/toggled bitmap. If there isn't a 2nd
396 // bitmap, we need to create it (with a darker, selected
398 WXPixel backgroundPixel
;
399 if ( tool
->CanBeToggled() )
400 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
403 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
406 col
.SetPixel(backgroundPixel
);
408 pixmap
= (Pixmap
) bmp
.GetDrawable();
410 wxBitmap tmp
= tool
->GetDisabledBitmap();
412 insensPixmap
= tmp
.IsOk() ?
413 (Pixmap
)tmp
.GetDrawable() :
414 tool
->GetInsensPixmap();
417 if (tool
->CanBeToggled())
420 Pixmap pixmap2
= tool
->GetArmPixmap();
421 Pixmap insensPixmap2
= tool
->GetInsensPixmap();
423 XtVaSetValues (button
,
424 XmNfillOnSelect
, True
,
425 XmNlabelPixmap
, pixmap
,
426 XmNselectPixmap
, pixmap2
,
427 XmNlabelInsensitivePixmap
, insensPixmap
,
428 XmNselectInsensitivePixmap
, insensPixmap2
,
429 XmNlabelType
, XmPIXMAP
,
434 Pixmap pixmap2
= tool
->GetArmPixmap();
437 XtVaSetValues(button
,
438 XmNlabelPixmap
, pixmap
,
439 XmNlabelInsensitivePixmap
, insensPixmap
,
440 XmNarmPixmap
, pixmap2
,
444 XtManageChild(button
);
447 Dimension width
, height
;
448 XtVaGetValues(button
,
453 currentY
+= height
+ packing
;
455 currentX
+= width
+ packing
;
456 buttonHeight
= wxMax(buttonHeight
, height
);
457 buttonWidth
= wxMax(buttonWidth
, width
);
460 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
461 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
466 node
= node
->GetNext();
470 isVertical
? buttonWidth
+ 2 * marginX
: -1,
471 isVertical
? -1 : buttonHeight
+ 2*marginY
);
476 wxToolBarToolBase
*wxToolBar::FindToolForPosition(wxCoord
WXUNUSED(x
),
477 wxCoord
WXUNUSED(y
)) const
479 wxFAIL_MSG( wxT("TODO") );
484 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
491 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
495 bool isVertical
= GetWindowStyle() & wxTB_VERTICAL
;
496 const int separatorSize
= GetToolSeparation(); // 8;
497 int packing
= GetToolPacking();
500 for( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
501 node
; node
= node
->GetNext() )
503 wxToolBarTool
*t
= (wxToolBarTool
*)node
->GetData();
507 switch ( t
->GetStyle() )
509 case wxTOOL_STYLE_CONTROL
:
511 wxSize size
= t
->GetControl()->GetSize();
512 offset
= isVertical
? size
.y
: size
.x
;
516 case wxTOOL_STYLE_SEPARATOR
:
517 offset
= isVertical
? 0 : separatorSize
;
519 case wxTOOL_STYLE_BUTTON
:
521 Widget w
= t
->GetButtonWidget();
522 Dimension width
, height
;
529 offset
= isVertical
? height
: width
;
537 switch ( t
->GetStyle() )
539 case wxTOOL_STYLE_CONTROL
:
541 wxPoint location
= t
->GetControl()->GetPosition();
544 location
.y
-= offset
;
546 location
.x
-= offset
;
548 t
->GetControl()->Move( location
);
551 case wxTOOL_STYLE_SEPARATOR
:
553 case wxTOOL_STYLE_BUTTON
:
556 XtVaGetValues( t
->GetButtonWidget(),
562 y
= (Dimension
)(y
- offset
);
564 x
= (Dimension
)(x
- offset
);
566 XtVaSetValues( t
->GetButtonWidget(),
579 void wxToolBar::DoEnableTool(wxToolBarToolBase
*toolBase
, bool enable
)
581 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
582 if (tool
->GetButtonWidget()){
583 XtSetSensitive(tool
->GetButtonWidget(), (Boolean
) enable
);
584 } else if (wxTOOL_STYLE_CONTROL
== tool
->GetStyle()){
585 // Controls (such as wxChoice) do not have button widgets
586 tool
->GetControl()->Enable(enable
);
590 void wxToolBar::DoToggleTool(wxToolBarToolBase
*toolBase
, bool toggle
)
592 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
594 XmToggleButtonSetState(tool
->GetButtonWidget(), (Boolean
) toggle
, False
);
597 void wxToolBar::DoSetToggle(wxToolBarToolBase
* WXUNUSED(tool
),
598 bool WXUNUSED(toggle
))
603 void wxToolBar::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
605 int old_width
, old_height
;
606 GetSize(&old_width
, &old_height
);
608 // Correct width and height if needed.
609 if ( width
== -1 || height
== -1 )
611 wxSize defaultSize
= GetSize();
614 width
= defaultSize
.x
;
616 height
= defaultSize
.y
;
619 wxToolBarBase::DoSetSize(x
, y
, width
, height
, sizeFlags
);
621 // We must refresh the frame size when the toolbar changes size
622 // otherwise the toolbar can be shown incorrectly
623 if ( old_width
!= width
|| old_height
!= height
)
625 // But before we send the size event check it
626 // we have a frame that is not being deleted.
627 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
628 if ( frame
&& !frame
->IsBeingDeleted() )
630 frame
->SendSizeEvent();
635 // ----------------------------------------------------------------------------
637 // ----------------------------------------------------------------------------
639 wxToolBarToolBase
*wxToolBar::FindToolByWidget(WXWidget w
) const
641 wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
644 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
645 if ( tool
->GetButtonWidget() == w
)
650 node
= node
->GetNext();
656 static void wxToolButtonCallback(Widget w
,
657 XtPointer clientData
,
658 XtPointer
WXUNUSED(ptr
))
660 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
661 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
665 if ( tool
->CanBeToggled() )
668 if ( !toolBar
->OnLeftClick(tool
->GetId(), tool
->IsToggled()) )
676 static void wxToolButtonPopupCallback(Widget w
,
677 XtPointer client_data
,
679 Boolean
*WXUNUSED(continue_to_dispatch
))
681 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
682 static const int delayMilli
= 800;
684 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
685 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
690 wxString tooltip
= tool
->GetShortHelp();
694 if (!wxTheToolBarTimer
)
695 wxTheToolBarTimer
= new wxToolBarTimer
;
697 wxToolBarTimer::buttonWidget
= w
;
698 wxToolBarTimer::helpString
= tooltip
;
700 /************************************************************/
701 /* Popup help label */
702 /************************************************************/
703 if (event
->type
== EnterNotify
)
705 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
707 XtDestroyWidget (wxToolBarTimer::help_popup
);
708 XtPopdown (wxToolBarTimer::help_popup
);
710 wxToolBarTimer::help_popup
= (Widget
) 0;
713 wxTheToolBarTimer
->Start(delayMilli
, true);
716 /************************************************************/
717 /* Popdown help label */
718 /************************************************************/
719 else if (event
->type
== LeaveNotify
)
721 if (wxTheToolBarTimer
)
722 wxTheToolBarTimer
->Stop();
723 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
725 XtDestroyWidget (wxToolBarTimer::help_popup
);
726 XtPopdown (wxToolBarTimer::help_popup
);
728 wxToolBarTimer::help_popup
= (Widget
) 0;
732 void wxToolBarTimer::Notify()
736 /************************************************************/
737 /* Create shell without window decorations */
738 /************************************************************/
739 help_popup
= XtVaCreatePopupShell ("shell",
740 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
743 /************************************************************/
744 /* Get absolute position on display of toolbar button */
745 /************************************************************/
746 XtTranslateCoords (buttonWidget
,
751 // Move the tooltip more or less above the button
752 int yOffset
= 20; // TODO: What should be really?
753 y
= (Position
)(y
- yOffset
);
754 if (y
< yOffset
) y
= 0;
756 /************************************************************/
757 /* Set the position of the help popup */
758 /************************************************************/
759 XtVaSetValues (help_popup
,
764 /************************************************************/
765 /* Create help label */
766 /************************************************************/
767 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
768 XtVaCreateManagedWidget ("help_label",
769 xmLabelWidgetClass
, help_popup
,
770 XmNlabelString
, text
,
772 XmNforeground
, XtRString
, "black",
775 XmNbackground
, XtRString
, "LightGoldenrod",
776 strlen("LightGoldenrod")+1,
780 /************************************************************/
781 /* Popup help label */
782 /************************************************************/
783 XtPopup (help_popup
, XtGrabNone
);