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 // 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 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 pos 
= t
->GetControl()->GetPosition(); 
 552                 t
->GetControl()->Move( pos 
); 
 555             case wxTOOL_STYLE_SEPARATOR
: 
 557             case wxTOOL_STYLE_BUTTON
: 
 560                 XtVaGetValues( t
->GetButtonWidget(), 
 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? 
 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
);