1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/motif/toolbar.cpp
3 // Purpose:     wxToolBar
4 // Author:      Julian Smart
5 // Modified by: 13.12.99 by VZ during toolbar classes reorganization
6 // Created:     04/01/98
7 // Copyright:   (c) Julian Smart
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 #include "wx/toolbar.h"
23 
24 #ifndef WX_PRECOMP
25     #include "wx/app.h"
26     #include "wx/frame.h"
27     #include "wx/timer.h"
28     #include "wx/settings.h"
29 #endif
30 
31 #ifdef __VMS__
32 #pragma message disable nosimpint
33 #endif
34 #include <Xm/Xm.h>
35 #include <Xm/PushBG.h>
36 #include <Xm/PushB.h>
37 #include <Xm/Label.h>
38 #include <Xm/ToggleB.h>
39 #include <Xm/ToggleBG.h>
40 #include <Xm/Form.h>
41 #ifdef __VMS__
42 #pragma message enable nosimpint
43 #endif
44 
45 #include "wx/motif/private.h"
46 #include "wx/motif/bmpmotif.h"
47 
48 // ----------------------------------------------------------------------------
49 // wxWin macros
50 // ----------------------------------------------------------------------------
51 
52 IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl)
53 
54 // ----------------------------------------------------------------------------
55 // private functions
56 // ----------------------------------------------------------------------------
57 
58 static void wxToolButtonCallback (Widget w, XtPointer clientData,
59                     XtPointer ptr);
60 static void wxToolButtonPopupCallback (Widget w, XtPointer client_data,
61                      XEvent *event, Boolean *continue_to_dispatch);
62 
63 // ----------------------------------------------------------------------------
64 // private classes
65 // ----------------------------------------------------------------------------
66 
67 class wxToolBarTimer : public wxTimer
68 {
69 public:
70     virtual void Notify();
71 
72     static Widget help_popup;
73     static Widget buttonWidget;
74     static wxString helpString;
75 };
76 
77 class wxToolBarTool : public wxToolBarToolBase
78 {
79 public:
wxToolBarTool(wxToolBar * tbar,int id,const wxString & label,const wxBitmap & bmpNormal,const wxBitmap & bmpToggled,wxItemKind kind,wxObject * clientData,const wxString & shortHelp,const wxString & longHelp)80     wxToolBarTool(wxToolBar *tbar,
81                   int id,
82                   const wxString& label,
83                   const wxBitmap& bmpNormal,
84                   const wxBitmap& bmpToggled,
85                   wxItemKind kind,
86                   wxObject *clientData,
87                   const wxString& shortHelp,
88                   const wxString& longHelp)
89         : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpToggled, kind,
90                             clientData, shortHelp, longHelp)
91     {
92         Init();
93     }
94 
wxToolBarTool(wxToolBar * tbar,wxControl * control,const wxString & label)95     wxToolBarTool(wxToolBar *tbar, wxControl *control, const wxString& label)
96         : wxToolBarToolBase(tbar, control, label)
97     {
98         Init();
99     }
100 
101     virtual ~wxToolBarTool();
102 
103     // accessors
SetWidget(Widget widget)104     void SetWidget(Widget widget) { m_widget = widget; }
GetButtonWidget() const105     Widget GetButtonWidget() const { return m_widget; }
106 
GetArmPixmap()107     Pixmap GetArmPixmap()
108     {
109         m_bitmapCache.SetBitmap( GetNormalBitmap() );
110         return (Pixmap)m_bitmapCache.GetArmPixmap( (WXWidget)m_widget );
111     }
112 
GetInsensPixmap()113     Pixmap GetInsensPixmap()
114     {
115         m_bitmapCache.SetBitmap( GetNormalBitmap() );
116         return (Pixmap)m_bitmapCache.GetInsensPixmap( (WXWidget)m_widget );
117     }
118 protected:
119     void Init();
120 
121     Widget m_widget;
122     wxBitmapCache m_bitmapCache;
123 };
124 
125 // ----------------------------------------------------------------------------
126 // globals
127 // ----------------------------------------------------------------------------
128 
129 static wxToolBarTimer* wxTheToolBarTimer = NULL;
130 
131 Widget wxToolBarTimer::help_popup = (Widget) 0;
132 Widget wxToolBarTimer::buttonWidget = (Widget) 0;
133 wxString wxToolBarTimer::helpString;
134 
135 // ============================================================================
136 // implementation
137 // ============================================================================
138 
139 // ----------------------------------------------------------------------------
140 // wxToolBarTool
141 // ----------------------------------------------------------------------------
142 
CreateTool(int id,const wxString & label,const wxBitmap & bmpNormal,const wxBitmap & bmpToggled,wxItemKind kind,wxObject * clientData,const wxString & shortHelp,const wxString & longHelp)143 wxToolBarToolBase *wxToolBar::CreateTool(int id,
144                                          const wxString& label,
145                                          const wxBitmap& bmpNormal,
146                                          const wxBitmap& bmpToggled,
147                                          wxItemKind kind,
148                                          wxObject *clientData,
149                                          const wxString& shortHelp,
150                                          const wxString& longHelp)
151 {
152     return new wxToolBarTool(this, id, label, bmpNormal, bmpToggled, kind,
153                              clientData, shortHelp, longHelp);
154 }
155 
156 
157 wxToolBarToolBase *
CreateTool(wxControl * control,const wxString & label)158 wxToolBar::CreateTool(wxControl *control, const wxString& label)
159 {
160     return new wxToolBarTool(this, control, label);
161 }
162 
Init()163 void wxToolBarTool::Init()
164 {
165     m_widget = (Widget)0;
166 }
167 
~wxToolBarTool()168 wxToolBarTool::~wxToolBarTool()
169 {
170     if ( m_widget )
171         XtDestroyWidget(m_widget);
172 }
173 
174 // ----------------------------------------------------------------------------
175 // wxToolBar construction
176 // ----------------------------------------------------------------------------
177 
Init()178 void wxToolBar::Init()
179 {
180     m_maxWidth = -1;
181     m_maxHeight = -1;
182     m_defaultWidth = 24;
183     m_defaultHeight = 22;
184     m_toolPacking = 2;
185     m_toolSeparation = 8;
186     m_xMargin = 2;
187     m_yMargin = 2;
188     m_maxRows = 100;
189     m_maxCols = 100;
190 }
191 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)192 bool wxToolBar::Create(wxWindow *parent,
193                        wxWindowID id,
194                        const wxPoint& pos,
195                        const wxSize& size,
196                        long style,
197                        const wxString& name)
198 {
199     if( !wxControl::CreateControl( parent, id, pos, size, style,
200                                    wxDefaultValidator, name ) )
201         return false;
202     PreCreation();
203 
204     FixupStyle();
205 
206     Widget parentWidget = (Widget) parent->GetClientWidget();
207 
208     Widget toolbar = XtVaCreateManagedWidget("toolbar",
209                     xmBulletinBoardWidgetClass, (Widget) parentWidget,
210                     XmNmarginWidth, 0,
211                     XmNmarginHeight, 0,
212                     XmNresizePolicy, XmRESIZE_NONE,
213                     NULL);
214 /*
215     Widget toolbar = XtVaCreateManagedWidget("toolbar",
216                 xmFormWidgetClass, (Widget) m_clientWidget,
217                 XmNtraversalOn, False,
218                 XmNhorizontalSpacing, 0,
219                 XmNverticalSpacing, 0,
220                 XmNleftOffset, 0,
221                 XmNrightOffset, 0,
222                 XmNmarginWidth, 0,
223                 XmNmarginHeight, 0,
224                 NULL);
225 */
226 
227     m_mainWidget = (WXWidget) toolbar;
228 
229     wxPoint rPos = pos;
230     wxSize  rSize = size;
231 
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;
236 
237     PostCreation();
238     AttachWidget (parent, m_mainWidget, (WXWidget) NULL,
239                   rPos.x, rPos.y, rSize.x, rSize.y);
240 
241     return true;
242 }
243 
~wxToolBar()244 wxToolBar::~wxToolBar()
245 {
246     wxDELETE(wxTheToolBarTimer);
247 }
248 
Realize()249 bool wxToolBar::Realize()
250 {
251     if ( m_tools.GetCount() == 0 )
252     {
253         // nothing to do
254         return true;
255     }
256 
257     bool isVertical = GetWindowStyle() & wxTB_VERTICAL;
258 
259     // Separator spacing
260     const int separatorSize = GetToolSeparation(); // 8;
261     wxSize margins = GetToolMargins();
262     int packing = GetToolPacking();
263     int marginX = margins.x;
264     int marginY = margins.y;
265 
266     int currentX = marginX;
267     int currentY = marginY;
268 
269     int buttonHeight = 0, buttonWidth = 0;
270 
271     Widget button;
272     Pixmap pixmap, insensPixmap;
273     wxBitmap bmp, insensBmp;
274 
275     wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
276     while ( node )
277     {
278         wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
279 
280         switch ( tool->GetStyle() )
281         {
282             case wxTOOL_STYLE_CONTROL:
283             {
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 );
294                 if ( isVertical )
295                     currentY += sz.y + packing;
296                 else
297                     currentX += sz.x + packing;
298 
299                 break;
300             }
301             case wxTOOL_STYLE_SEPARATOR:
302                 // skip separators for vertical toolbars
303                 if( !isVertical )
304                 {
305                     currentX += separatorSize;
306                 }
307                 break;
308 
309             case wxTOOL_STYLE_BUTTON:
310                 button = (Widget) 0;
311 
312                 if ( tool->CanBeToggled() && !tool->GetButtonWidget() )
313                 {
314                     button = XtVaCreateWidget("toggleButton",
315                             xmToggleButtonWidgetClass, (Widget) m_mainWidget,
316                             XmNx, currentX, XmNy, currentY,
317                             XmNindicatorOn, False,
318                             XmNshadowThickness, 2,
319                             XmNborderWidth, 0,
320                             XmNspacing, 0,
321                             XmNmarginWidth, 0,
322                             XmNmarginHeight, 0,
323                             XmNmultiClick, XmMULTICLICK_KEEP,
324                             XmNlabelType, XmPIXMAP,
325                             NULL);
326                     XtAddCallback ((Widget) button,
327                                    XmNvalueChangedCallback,
328                                    (XtCallbackProc) wxToolButtonCallback,
329                                    (XtPointer) this);
330 
331                     XtVaSetValues ((Widget) button,
332                                    XmNselectColor,
333                                    m_backgroundColour.AllocColour
334                                        (XtDisplay((Widget) button)),
335                                    NULL);
336                 }
337                 else if( !tool->GetButtonWidget() )
338                 {
339                     button = XtVaCreateWidget("button",
340                             xmPushButtonWidgetClass, (Widget) m_mainWidget,
341                             XmNx, currentX, XmNy, currentY,
342                             XmNpushButtonEnabled, True,
343                             XmNmultiClick, XmMULTICLICK_KEEP,
344                             XmNlabelType, XmPIXMAP,
345                             NULL);
346                     XtAddCallback (button,
347                                    XmNactivateCallback,
348                                    (XtCallbackProc) wxToolButtonCallback,
349                                    (XtPointer) this);
350                 }
351 
352                 if( !tool->GetButtonWidget() )
353                 {
354                     wxDoChangeBackgroundColour((WXWidget) button,
355                                                m_backgroundColour, true);
356 
357                     tool->SetWidget(button);
358                 }
359                 else
360                 {
361                     button = (Widget)tool->GetButtonWidget();
362                     XtVaSetValues( button,
363                                    XmNx, currentX, XmNy, currentY,
364                                    NULL );
365                 }
366 
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() )
374                 {
375                     WXPixel backgroundPixel;
376                     XtVaGetValues(button, XmNbackground, &backgroundPixel,
377                                   NULL);
378 
379                     wxColour col;
380                     col.SetPixel(backgroundPixel);
381 
382                     if( bmp.IsOk() && bmp.GetMask() )
383                     {
384                         bmp = wxCreateMaskedBitmap(bmp, col);
385                         tool->SetNormalBitmap(bmp);
386                     }
387 
388                     if( insensBmp.IsOk() && insensBmp.GetMask() )
389                     {
390                         insensBmp = wxCreateMaskedBitmap(insensBmp, col);
391                         tool->SetDisabledBitmap(insensBmp);
392                     }
393                 }
394 
395                 // Create a selected/toggled bitmap. If there isn't a 2nd
396                 // bitmap, we need to create it (with a darker, selected
397                 // background)
398                 WXPixel backgroundPixel;
399                 if ( tool->CanBeToggled() )
400                     XtVaGetValues(button, XmNselectColor, &backgroundPixel,
401                                   NULL);
402                 else
403                     XtVaGetValues(button, XmNarmColor, &backgroundPixel,
404                                   NULL);
405                 wxColour col;
406                 col.SetPixel(backgroundPixel);
407 
408                 pixmap = (Pixmap) bmp.GetDrawable();
409                 {
410                     wxBitmap tmp = tool->GetDisabledBitmap();
411 
412                     insensPixmap = tmp.IsOk() ?
413                             (Pixmap)tmp.GetDrawable() :
414                             tool->GetInsensPixmap();
415                 }
416 
417                 if (tool->CanBeToggled())
418                 {
419                     // Toggle button
420                     Pixmap pixmap2 = tool->GetArmPixmap();
421                     Pixmap insensPixmap2 = tool->GetInsensPixmap();
422 
423                     XtVaSetValues (button,
424                             XmNfillOnSelect, True,
425                             XmNlabelPixmap, pixmap,
426                             XmNselectPixmap, pixmap2,
427                             XmNlabelInsensitivePixmap, insensPixmap,
428                             XmNselectInsensitivePixmap, insensPixmap2,
429                             XmNlabelType, XmPIXMAP,
430                             NULL);
431                 }
432                 else
433                 {
434                     Pixmap pixmap2 = tool->GetArmPixmap();
435 
436                     // Normal button
437                     XtVaSetValues(button,
438                             XmNlabelPixmap, pixmap,
439                             XmNlabelInsensitivePixmap, insensPixmap,
440                             XmNarmPixmap, pixmap2,
441                             NULL);
442                 }
443 
444                 XtManageChild(button);
445 
446                 {
447                     Dimension width, height;
448                     XtVaGetValues(button,
449                                   XmNwidth, &width,
450                                   XmNheight, & height,
451                                   NULL);
452                     if ( isVertical )
453                         currentY += height + packing;
454                     else
455                         currentX += width + packing;
456                     buttonHeight = wxMax(buttonHeight, height);
457                     buttonWidth = wxMax(buttonWidth, width);
458                 }
459 
460                 XtAddEventHandler (button, EnterWindowMask | LeaveWindowMask,
461                         False, wxToolButtonPopupCallback, (XtPointer) this);
462 
463                 break;
464         }
465 
466         node = node->GetNext();
467     }
468 
469     SetSize( -1, -1,
470              isVertical ? buttonWidth + 2 * marginX : -1,
471              isVertical ? -1 : buttonHeight +  2*marginY );
472 
473     return true;
474 }
475 
FindToolForPosition(wxCoord WXUNUSED (x),wxCoord WXUNUSED (y)) const476 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord WXUNUSED(x),
477                                                   wxCoord WXUNUSED(y)) const
478 {
479     wxFAIL_MSG( wxT("TODO") );
480 
481     return NULL;
482 }
483 
DoInsertTool(size_t WXUNUSED (pos),wxToolBarToolBase * tool)484 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
485 {
486     tool->Attach(this);
487 
488     return true;
489 }
490 
DoDeleteTool(size_t WXUNUSED (pos),wxToolBarToolBase * tool)491 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
492 {
493     tool->Detach();
494 
495     bool isVertical = GetWindowStyle() & wxTB_VERTICAL;
496     const int separatorSize = GetToolSeparation(); // 8;
497     int packing = GetToolPacking();
498     int offset = 0;
499 
500     for( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
501          node; node = node->GetNext() )
502     {
503         wxToolBarTool *t = (wxToolBarTool*)node->GetData();
504 
505         if( t == tool )
506         {
507             switch ( t->GetStyle() )
508             {
509             case wxTOOL_STYLE_CONTROL:
510             {
511                 wxSize size = t->GetControl()->GetSize();
512                 offset = isVertical ? size.y : size.x;
513                 offset += packing;
514                 break;
515             }
516             case wxTOOL_STYLE_SEPARATOR:
517                 offset = isVertical ? 0 : separatorSize;
518                 break;
519             case wxTOOL_STYLE_BUTTON:
520             {
521                 Widget w = t->GetButtonWidget();
522                 Dimension width, height;
523 
524                 XtVaGetValues( w,
525                                XmNwidth, &width,
526                                XmNheight, &height,
527                                NULL );
528 
529                 offset = isVertical ? height : width;
530                 offset += packing;
531                 break;
532             }
533             }
534         }
535         else if( offset )
536         {
537             switch ( t->GetStyle() )
538             {
539             case wxTOOL_STYLE_CONTROL:
540             {
541                 wxPoint location = t->GetControl()->GetPosition();
542 
543                 if( isVertical )
544                     location.y -= offset;
545                 else
546                     location.x -= offset;
547 
548                 t->GetControl()->Move( location );
549                 break;
550             }
551             case wxTOOL_STYLE_SEPARATOR:
552                 break;
553             case wxTOOL_STYLE_BUTTON:
554             {
555                 Dimension x, y;
556                 XtVaGetValues( t->GetButtonWidget(),
557                                XmNx, &x,
558                                XmNy, &y,
559                                NULL );
560 
561                 if( isVertical )
562                     y = (Dimension)(y - offset);
563                 else
564                     x = (Dimension)(x - offset);
565 
566                 XtVaSetValues( t->GetButtonWidget(),
567                                XmNx, x,
568                                XmNy, y,
569                                NULL );
570                 break;
571             }
572             }
573         }
574     }
575 
576     return true;
577 }
578 
DoEnableTool(wxToolBarToolBase * toolBase,bool enable)579 void wxToolBar::DoEnableTool(wxToolBarToolBase *toolBase, bool enable)
580 {
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);
587     }
588 }
589 
DoToggleTool(wxToolBarToolBase * toolBase,bool toggle)590 void wxToolBar::DoToggleTool(wxToolBarToolBase *toolBase, bool toggle)
591 {
592     wxToolBarTool *tool = (wxToolBarTool *)toolBase;
593 
594     XmToggleButtonSetState(tool->GetButtonWidget(), (Boolean) toggle, False);
595 }
596 
DoSetToggle(wxToolBarToolBase * WXUNUSED (tool),bool WXUNUSED (toggle))597 void wxToolBar::DoSetToggle(wxToolBarToolBase * WXUNUSED(tool),
598                             bool WXUNUSED(toggle))
599 {
600     // nothing to do
601 }
602 
DoSetSize(int x,int y,int width,int height,int sizeFlags)603 void wxToolBar::DoSetSize(int x, int y, int width, int height, int sizeFlags)
604 {
605     int old_width, old_height;
606     GetSize(&old_width, &old_height);
607 
608     // Correct width and height if needed.
609     if ( width == -1 || height == -1 )
610     {
611         wxSize defaultSize = GetSize();
612 
613         if ( width == -1 )
614             width = defaultSize.x;
615         if ( height == -1 )
616             height = defaultSize.y;
617     }
618 
619     wxToolBarBase::DoSetSize(x, y, width, height, sizeFlags);
620 
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 )
624     {
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() )
629         {
630             frame->SendSizeEvent();
631         }
632     }
633 }
634 
635 // ----------------------------------------------------------------------------
636 // Motif callbacks
637 // ----------------------------------------------------------------------------
638 
FindToolByWidget(WXWidget w) const639 wxToolBarToolBase *wxToolBar::FindToolByWidget(WXWidget w) const
640 {
641     wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
642     while ( node )
643     {
644         wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
645         if ( tool->GetButtonWidget() == w)
646         {
647             return tool;
648         }
649 
650         node = node->GetNext();
651     }
652 
653     return NULL;
654 }
655 
wxToolButtonCallback(Widget w,XtPointer clientData,XtPointer WXUNUSED (ptr))656 static void wxToolButtonCallback(Widget w,
657                                  XtPointer clientData,
658                                  XtPointer WXUNUSED(ptr))
659 {
660     wxToolBar *toolBar = (wxToolBar *) clientData;
661     wxToolBarToolBase *tool = toolBar->FindToolByWidget((WXWidget) w);
662     if ( !tool )
663         return;
664 
665     if ( tool->CanBeToggled() )
666         tool->Toggle();
667 
668     if ( !toolBar->OnLeftClick(tool->GetId(), tool->IsToggled()) )
669     {
670         // revert
671         tool->Toggle();
672     }
673 }
674 
675 
wxToolButtonPopupCallback(Widget w,XtPointer client_data,XEvent * event,Boolean * WXUNUSED (continue_to_dispatch))676 static void wxToolButtonPopupCallback(Widget w,
677                                       XtPointer client_data,
678                                       XEvent *event,
679                                       Boolean *WXUNUSED(continue_to_dispatch))
680 {
681     // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
682     static const int delayMilli = 800;
683 
684     wxToolBar* toolBar = (wxToolBar*) client_data;
685     wxToolBarToolBase *tool = toolBar->FindToolByWidget((WXWidget) w);
686 
687     if ( !tool )
688         return;
689 
690     wxString tooltip = tool->GetShortHelp();
691     if ( !tooltip )
692         return;
693 
694     if (!wxTheToolBarTimer)
695         wxTheToolBarTimer = new wxToolBarTimer;
696 
697     wxToolBarTimer::buttonWidget = w;
698     wxToolBarTimer::helpString = tooltip;
699 
700     /************************************************************/
701     /* Popup help label                                         */
702     /************************************************************/
703     if (event->type == EnterNotify)
704     {
705         if (wxToolBarTimer::help_popup != (Widget) 0)
706         {
707             XtDestroyWidget (wxToolBarTimer::help_popup);
708             XtPopdown (wxToolBarTimer::help_popup);
709         }
710         wxToolBarTimer::help_popup = (Widget) 0;
711 
712         // One shot
713         wxTheToolBarTimer->Start(delayMilli, true);
714 
715     }
716     /************************************************************/
717     /* Popdown help label                                       */
718     /************************************************************/
719     else if (event->type == LeaveNotify)
720     {
721         if (wxTheToolBarTimer)
722             wxTheToolBarTimer->Stop();
723         if (wxToolBarTimer::help_popup != (Widget) 0)
724         {
725             XtDestroyWidget (wxToolBarTimer::help_popup);
726             XtPopdown (wxToolBarTimer::help_popup);
727         }
728         wxToolBarTimer::help_popup = (Widget) 0;
729     }
730 }
731 
Notify()732 void wxToolBarTimer::Notify()
733 {
734     Position x, y;
735 
736         /************************************************************/
737         /* Create shell without window decorations                  */
738         /************************************************************/
739         help_popup = XtVaCreatePopupShell ("shell",
740                                            overrideShellWidgetClass, (Widget) wxTheApp->GetTopLevelWidget(),
741                                            NULL);
742 
743         /************************************************************/
744         /* Get absolute position on display of toolbar button       */
745         /************************************************************/
746         XtTranslateCoords (buttonWidget,
747                            (Position) 0,
748                            (Position) 0,
749                            &x, &y);
750 
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;
755 
756         /************************************************************/
757         /* Set the position of the help popup                       */
758         /************************************************************/
759         XtVaSetValues (help_popup,
760                        XmNx, (Position) x,
761                        XmNy, (Position) y,
762                        NULL);
763 
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,
771                                  XtVaTypedArg,
772                                  XmNforeground, XtRString, "black",
773                                                 strlen("black")+1,
774                                  XtVaTypedArg,
775                                  XmNbackground, XtRString, "LightGoldenrod",
776                                                 strlen("LightGoldenrod")+1,
777                                  NULL);
778         XmStringFree (text);
779 
780         /************************************************************/
781         /* Popup help label                                         */
782         /************************************************************/
783         XtPopup (help_popup, XtGrabNone);
784 }
785