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 // ----------------------------------------------------------------------------
21 #pragma implementation "toolbar.h"
25 #define XtDisplay XTDISPLAY
31 #include "wx/toolbar.h"
35 #pragma message disable nosimpint
38 #include <Xm/PushBG.h>
41 #include <Xm/ToggleB.h>
42 #include <Xm/ToggleBG.h>
45 #pragma message enable nosimpint
48 #include "wx/motif/private.h"
50 // ----------------------------------------------------------------------------
52 // ----------------------------------------------------------------------------
54 #if !USE_SHARED_LIBRARY
55 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxToolBarBase
)
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
62 static void wxToolButtonCallback (Widget w
, XtPointer clientData
,
64 static void wxToolButtonPopupCallback (Widget w
, XtPointer client_data
,
65 XEvent
*event
, Boolean
*continue_to_dispatch
);
67 // ----------------------------------------------------------------------------
69 // ----------------------------------------------------------------------------
71 class wxToolBarTimer
: public wxTimer
74 virtual void Notify();
76 static Widget help_popup
;
77 static Widget buttonWidget
;
78 static wxString helpString
;
81 class wxToolBarTool
: public wxToolBarToolBase
84 wxToolBarTool(wxToolBar
*tbar
,
86 const wxString
& label
,
87 const wxBitmap
& bmpNormal
,
88 const wxBitmap
& bmpToggled
,
91 const wxString
& shortHelp
,
92 const wxString
& longHelp
)
93 : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpToggled
, kind
,
94 clientData
, shortHelp
, longHelp
)
99 wxToolBarTool(wxToolBar
*tbar
, wxControl
*control
)
100 : wxToolBarToolBase(tbar
, control
)
105 virtual ~wxToolBarTool();
108 void SetWidget(Widget widget
) { m_widget
= widget
; }
109 Widget
GetButtonWidget() const { return m_widget
; }
111 void SetPixmap(Pixmap pixmap
) { m_pixmap
= pixmap
; }
112 Pixmap
GetPixmap() const { return m_pixmap
; }
121 // ----------------------------------------------------------------------------
123 // ----------------------------------------------------------------------------
125 static wxToolBarTimer
* wxTheToolBarTimer
= (wxToolBarTimer
*) NULL
;
127 Widget
wxToolBarTimer::help_popup
= (Widget
) 0;
128 Widget
wxToolBarTimer::buttonWidget
= (Widget
) 0;
129 wxString
wxToolBarTimer::helpString
;
131 // ============================================================================
133 // ============================================================================
135 // ----------------------------------------------------------------------------
137 // ----------------------------------------------------------------------------
139 wxToolBarToolBase
*wxToolBar::CreateTool(int id
,
140 const wxString
& label
,
141 const wxBitmap
& bmpNormal
,
142 const wxBitmap
& bmpToggled
,
144 wxObject
*clientData
,
145 const wxString
& shortHelp
,
146 const wxString
& longHelp
)
148 return new wxToolBarTool(this, id
, label
, bmpNormal
, bmpToggled
, kind
,
149 clientData
, shortHelp
, longHelp
);
153 wxToolBarToolBase
*wxToolBar::CreateTool(wxControl
*control
)
155 return new wxToolBarTool(this, control
);
158 void wxToolBarTool::Init()
160 m_widget
= (Widget
)0;
161 m_pixmap
= (Pixmap
)0;
164 wxToolBarTool::~wxToolBarTool()
167 XtDestroyWidget(m_widget
);
168 // note: do not delete m_pixmap here because it will be deleted
169 // by the base class when the bitmap is destroyed.
172 // ----------------------------------------------------------------------------
173 // wxToolBar construction
174 // ----------------------------------------------------------------------------
176 void wxToolBar::Init()
181 m_defaultHeight
= 22;
183 m_toolSeparation
= 8;
190 bool wxToolBar::Create(wxWindow
*parent
,
195 const wxString
& name
)
197 if( !wxControl::CreateControl( parent
, id
, pos
, size
, style
,
198 wxDefaultValidator
, name
) )
201 m_backgroundColour
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
203 Widget parentWidget
= (Widget
) parent
->GetClientWidget();
205 Widget toolbar
= XtVaCreateManagedWidget("toolbar",
206 xmBulletinBoardWidgetClass
, (Widget
) parentWidget
,
209 XmNresizePolicy
, XmRESIZE_NONE
,
212 Widget toolbar = XtVaCreateManagedWidget("toolbar",
213 xmFormWidgetClass, (Widget) m_clientWidget,
214 XmNtraversalOn, False,
215 XmNhorizontalSpacing, 0,
216 XmNverticalSpacing, 0,
224 m_mainWidget
= (WXWidget
) toolbar
;
231 if( rPos
.x
== -1 ) rPos
.x
= 0;
232 if( rPos
.y
== -1 ) rPos
.y
= 0;
233 if( rSize
.x
== -1 && GetParent() )
234 rSize
.x
= GetParent()->GetSize().x
;
236 SetCanAddEventHandler(TRUE
);
237 AttachWidget (parent
, m_mainWidget
, (WXWidget
) NULL
,
238 rPos
.x
, rPos
.y
, rSize
.x
, rSize
.y
);
240 ChangeBackgroundColour();
245 wxToolBar::~wxToolBar()
247 delete wxTheToolBarTimer
;
248 wxTheToolBarTimer
= NULL
;
251 bool wxToolBar::Realize()
253 if ( m_tools
.GetCount() == 0 )
259 bool isVertical
= GetWindowStyle() & wxTB_VERTICAL
;
262 const int separatorSize
= GetToolSeparation(); // 8;
263 wxSize margins
= GetToolMargins();
264 int packing
= GetToolPacking();
265 int marginX
= margins
.x
;
266 int marginY
= margins
.y
;
268 int currentX
= marginX
;
269 int currentY
= marginY
;
271 int buttonHeight
= 0, buttonWidth
= 0;
273 int currentSpacing
= 0;
276 Pixmap pixmap
, insensPixmap
;
279 wxToolBarToolsList::Node
*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) ? currentY
+ pos
.y
: currentY
;
295 int controlX
= (pos
.x
> 0) ? currentX
+ 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
307 if( isVertical
) break;
308 currentX
+= separatorSize
;
311 case wxTOOL_STYLE_BUTTON
:
314 if ( tool
->CanBeToggled() )
316 button
= XtVaCreateWidget("toggleButton",
317 xmToggleButtonWidgetClass
, (Widget
) m_mainWidget
,
318 XmNx
, currentX
, XmNy
, currentY
,
319 XmNindicatorOn
, False
,
320 XmNshadowThickness
, 2,
325 XmNmultiClick
, XmMULTICLICK_KEEP
,
326 XmNlabelType
, XmPIXMAP
,
328 XtAddCallback ((Widget
) button
, XmNvalueChangedCallback
, (XtCallbackProc
) wxToolButtonCallback
,
331 XtVaSetValues ((Widget
) button
,
332 XmNselectColor
, m_backgroundColour
.AllocColour(XtDisplay((Widget
) button
)),
337 button
= XtVaCreateWidget("button",
338 xmPushButtonWidgetClass
, (Widget
) m_mainWidget
,
339 XmNx
, currentX
, XmNy
, currentY
,
340 XmNpushButtonEnabled
, True
,
341 XmNmultiClick
, XmMULTICLICK_KEEP
,
342 XmNlabelType
, XmPIXMAP
,
344 XtAddCallback (button
,
345 XmNactivateCallback
, (XtCallbackProc
) wxToolButtonCallback
,
349 DoChangeBackgroundColour((WXWidget
) button
, m_backgroundColour
, TRUE
);
351 tool
->SetWidget(button
);
353 // For each button, if there is a mask, we must create
354 // a new wxBitmap that has the correct background colour
355 // for the button. Otherwise the background will just be
356 // e.g. black if a transparent XPM has been loaded.
357 bmp
= tool
->GetNormalBitmap();
361 XtVaGetValues(button
, XmNbackground
, &backgroundPixel
,
365 col
.SetPixel(backgroundPixel
);
366 bmp
= wxCreateMaskedBitmap(bmp
, col
);
368 tool
->SetNormalBitmap(bmp
);
371 // Create a selected/toggled bitmap. If there isn't a 2nd
372 // bitmap, we need to create it (with a darker, selected
375 if ( tool
->CanBeToggled() )
376 XtVaGetValues(button
, XmNselectColor
, &backgroundPixel
,
379 XtVaGetValues(button
, XmNarmColor
, &backgroundPixel
,
382 col
.SetPixel(backgroundPixel
);
384 // FIXME: we use disabled bitmap as the bitmap for the toggled
385 // state, we probably need a GetToggledBitmap() instead
386 wxBitmap bmpToggled
= tool
->GetDisabledBitmap();
387 if ( bmpToggled
.Ok() && bmpToggled
.GetMask())
390 wxBitmap newBitmap
= wxCreateMaskedBitmap(bmpToggled
, col
);
391 tool
->SetDisabledBitmap(newBitmap
);
395 // Use unselected bitmap
398 wxBitmap newBitmap
= wxCreateMaskedBitmap(bmp
, col
);
399 tool
->SetDisabledBitmap(newBitmap
);
402 tool
->SetDisabledBitmap(bmp
);
405 // FIXME: and here we should use GetDisabledBitmap()...
406 pixmap
= (Pixmap
) bmp
.GetPixmap();
407 insensPixmap
= (Pixmap
) bmp
.GetInsensPixmap();
409 if (tool
->CanBeToggled())
412 Pixmap pixmap2
= (Pixmap
) 0;
413 Pixmap insensPixmap2
= (Pixmap
) 0;
415 // If there's a bitmap for the toggled state, use it,
416 // otherwise generate one.
419 if ( bmpToggled
.Ok() )
421 pixmap2
= (Pixmap
) bmpToggled
.GetPixmap();
422 insensPixmap2
= (Pixmap
) bmpToggled
.GetInsensPixmap();
426 pixmap2
= (Pixmap
) bmp
.GetArmPixmap(button
);
427 insensPixmap2
= XCreateInsensitivePixmap((Display
*) wxGetDisplay(), pixmap2
);
430 tool
->SetPixmap(pixmap2
);
432 XtVaSetValues (button
,
433 XmNfillOnSelect
, True
,
434 XmNlabelPixmap
, pixmap
,
435 XmNselectPixmap
, pixmap2
,
436 XmNlabelInsensitivePixmap
, insensPixmap
,
437 XmNselectInsensitivePixmap
, insensPixmap2
,
438 XmNlabelType
, XmPIXMAP
,
443 Pixmap pixmap2
= (Pixmap
) 0;
445 // If there's a bitmap for the armed state, use it,
446 // otherwise generate one.
447 if ( bmpToggled
.Ok() )
449 pixmap2
= (Pixmap
) bmpToggled
.GetPixmap();
453 pixmap2
= (Pixmap
) bmp
.GetArmPixmap(button
);
457 tool
->SetPixmap(pixmap2
);
460 XtVaSetValues(button
,
461 XmNlabelPixmap
, pixmap
,
462 XmNlabelInsensitivePixmap
, insensPixmap
,
463 XmNarmPixmap
, pixmap2
,
467 XtManageChild(button
);
470 Dimension width
, height
;
471 XtVaGetValues(button
,
476 currentY
+= height
+ packing
;
478 currentX
+= width
+ packing
;
479 buttonHeight
= wxMax(buttonHeight
, height
);
480 buttonWidth
= wxMax(buttonWidth
, width
);
483 XtAddEventHandler (button
, EnterWindowMask
| LeaveWindowMask
,
484 False
, wxToolButtonPopupCallback
, (XtPointer
) this);
490 node
= node
->GetNext();
494 isVertical
? buttonWidth
+ 2 * marginX
: currentX
,
495 isVertical
? currentY
: buttonHeight
+ 2*marginY
);
500 wxToolBarToolBase
*wxToolBar::FindToolForPosition(wxCoord
WXUNUSED(x
),
501 wxCoord
WXUNUSED(y
)) const
503 wxFAIL_MSG( _T("TODO") );
505 return (wxToolBarToolBase
*)NULL
;
508 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
515 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
522 void wxToolBar::DoEnableTool(wxToolBarToolBase
*toolBase
, bool enable
)
524 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
526 XtSetSensitive(tool
->GetButtonWidget(), (Boolean
) enable
);
529 void wxToolBar::DoToggleTool(wxToolBarToolBase
*toolBase
, bool toggle
)
531 wxToolBarTool
*tool
= (wxToolBarTool
*)toolBase
;
533 XmToggleButtonSetState(tool
->GetButtonWidget(), (Boolean
) toggle
, False
);
536 void wxToolBar::DoSetToggle(wxToolBarToolBase
* WXUNUSED(tool
),
537 bool WXUNUSED(toggle
))
542 void wxToolBar::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
544 int old_width
, old_height
;
545 GetSize(&old_width
, &old_height
);
547 wxToolBarBase::DoSetSize(x
, y
, width
, height
, sizeFlags
);
549 // Correct width and height if needed.
550 if ( width
== -1 || height
== -1 )
552 int tmp_width
, tmp_height
;
553 GetSize(&tmp_width
, &tmp_height
);
561 // We must refresh the frame size when the toolbar changes size
562 // otherwise the toolbar can be shown incorrectly
563 if ( old_width
!= width
|| old_height
!= height
)
565 // But before we send the size event check it
566 // we have a frame that is not being deleted.
567 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
568 if ( frame
&& !frame
->IsBeingDeleted() )
570 frame
->SendSizeEvent();
575 // ----------------------------------------------------------------------------
577 // ----------------------------------------------------------------------------
579 wxToolBarToolBase
*wxToolBar::FindToolByWidget(WXWidget w
) const
581 wxToolBarToolsList::Node
* node
= m_tools
.GetFirst();
584 wxToolBarTool
*tool
= (wxToolBarTool
*)node
->GetData();
585 if ( tool
->GetButtonWidget() == w
)
590 node
= node
->GetNext();
593 return (wxToolBarToolBase
*)NULL
;
596 static void wxToolButtonCallback(Widget w
,
597 XtPointer clientData
,
598 XtPointer
WXUNUSED(ptr
))
600 wxToolBar
*toolBar
= (wxToolBar
*) clientData
;
601 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
605 if ( tool
->CanBeToggled() )
608 if ( !toolBar
->OnLeftClick(tool
->GetId(), tool
->IsToggled()) )
616 static void wxToolButtonPopupCallback(Widget w
,
617 XtPointer client_data
,
619 Boolean
*WXUNUSED(continue_to_dispatch
))
621 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
622 static const int delayMilli
= 800;
624 wxToolBar
* toolBar
= (wxToolBar
*) client_data
;
625 wxToolBarToolBase
*tool
= toolBar
->FindToolByWidget((WXWidget
) w
);
630 wxString tooltip
= tool
->GetShortHelp();
634 if (!wxTheToolBarTimer
)
635 wxTheToolBarTimer
= new wxToolBarTimer
;
637 wxToolBarTimer::buttonWidget
= w
;
638 wxToolBarTimer::helpString
= tooltip
;
640 /************************************************************/
641 /* Popup help label */
642 /************************************************************/
643 if (event
->type
== EnterNotify
)
645 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
647 XtDestroyWidget (wxToolBarTimer::help_popup
);
648 XtPopdown (wxToolBarTimer::help_popup
);
650 wxToolBarTimer::help_popup
= (Widget
) 0;
653 wxTheToolBarTimer
->Start(delayMilli
, TRUE
);
656 /************************************************************/
657 /* Popdown help label */
658 /************************************************************/
659 else if (event
->type
== LeaveNotify
)
661 if (wxTheToolBarTimer
)
662 wxTheToolBarTimer
->Stop();
663 if (wxToolBarTimer::help_popup
!= (Widget
) 0)
665 XtDestroyWidget (wxToolBarTimer::help_popup
);
666 XtPopdown (wxToolBarTimer::help_popup
);
668 wxToolBarTimer::help_popup
= (Widget
) 0;
672 void wxToolBarTimer::Notify()
676 /************************************************************/
677 /* Create shell without window decorations */
678 /************************************************************/
679 help_popup
= XtVaCreatePopupShell ("shell",
680 overrideShellWidgetClass
, (Widget
) wxTheApp
->GetTopLevelWidget(),
683 /************************************************************/
684 /* Get absolute position on display of toolbar button */
685 /************************************************************/
686 XtTranslateCoords (buttonWidget
,
691 // Move the tooltip more or less above the button
692 int yOffset
= 20; // TODO: What should be really?
694 if (y
< yOffset
) y
= 0;
696 /************************************************************/
697 /* Set the position of the help popup */
698 /************************************************************/
699 XtVaSetValues (help_popup
,
704 /************************************************************/
705 /* Create help label */
706 /************************************************************/
707 XmString text
= XmStringCreateSimple ((char*) (const char*) helpString
);
708 XtVaCreateManagedWidget ("help_label",
709 xmLabelWidgetClass
, help_popup
,
710 XmNlabelString
, text
,
712 XmNforeground
, XtRString
, "black",
715 XmNbackground
, XtRString
, "LightGoldenrod",
716 strlen("LightGoldenrod")+1,
720 /************************************************************/
721 /* Popup help label */
722 /************************************************************/
723 XtPopup (help_popup
, XtGrabNone
);