]> git.saurik.com Git - wxWidgets.git/blame - src/motif/toolbar.cpp
image handlers moved to separate headers (imagbmp.h etc.) This change is backward...
[wxWidgets.git] / src / motif / toolbar.cpp
CommitLineData
4bb6408c 1/////////////////////////////////////////////////////////////////////////////
8a0681f9 2// Name: motif/toolbar.cpp
4bb6408c
JS
3// Purpose: wxToolBar
4// Author: Julian Smart
8a0681f9 5// Modified by: 13.12.99 by VZ during toolbar classes reorganization
4bb6408c
JS
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
8a0681f9 9// Licence: wxWindows licence
4bb6408c
JS
10/////////////////////////////////////////////////////////////////////////////
11
8a0681f9
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
4bb6408c 20#ifdef __GNUG__
8a0681f9 21 #pragma implementation "toolbar.h"
4bb6408c
JS
22#endif
23
24#include "wx/wx.h"
1a3ac83f
JS
25#include "wx/app.h"
26#include "wx/timer.h"
1ccbb61a 27#include "wx/toolbar.h"
0d57be45 28
338dd992
JJ
29#ifdef __VMS__
30#pragma message disable nosimpint
31#endif
0d57be45
JS
32#include <Xm/Xm.h>
33#include <Xm/PushBG.h>
34#include <Xm/PushB.h>
1a3ac83f 35#include <Xm/Label.h>
0d57be45
JS
36#include <Xm/ToggleB.h>
37#include <Xm/ToggleBG.h>
38#include <Xm/Form.h>
338dd992
JJ
39#ifdef __VMS__
40#pragma message enable nosimpint
41#endif
0d57be45
JS
42
43#include "wx/motif/private.h"
4bb6408c 44
8a0681f9
VZ
45// ----------------------------------------------------------------------------
46// wxWin macros
47// ----------------------------------------------------------------------------
48
49#if !USE_SHARED_LIBRARY
50IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl)
51#endif
4bb6408c 52
8a0681f9
VZ
53// ----------------------------------------------------------------------------
54// private functions
55// ----------------------------------------------------------------------------
4bb6408c 56
1a3ac83f 57static void wxToolButtonCallback (Widget w, XtPointer clientData,
bf6c2b35 58 XtPointer ptr);
1a3ac83f
JS
59static void wxToolButtonPopupCallback (Widget w, XtPointer client_data,
60 XEvent *event, Boolean *continue_to_dispatch);
61
8a0681f9
VZ
62// ----------------------------------------------------------------------------
63// private classes
64// ----------------------------------------------------------------------------
65
66class wxToolBarTimer : public wxTimer
1a3ac83f
JS
67{
68public:
8a0681f9 69 virtual void Notify();
1a3ac83f 70
8a0681f9
VZ
71 static Widget help_popup;
72 static Widget buttonWidget;
73 static wxString helpString;
1a3ac83f
JS
74};
75
8a0681f9
VZ
76class wxToolBarTool : public wxToolBarToolBase
77{
78public:
79 wxToolBarTool(wxToolBar *tbar,
80 int id,
81 const wxBitmap& bitmap1,
82 const wxBitmap& bitmap2,
83 bool toggle,
84 wxObject *clientData,
85 const wxString& shortHelpString,
86 const wxString& longHelpString)
87 : wxToolBarToolBase(tbar, id, bitmap1, bitmap2, toggle,
88 clientData, shortHelpString, longHelpString)
89 {
90 Init();
91 }
92
93 wxToolBarTool(wxToolBar *tbar, wxControl *control)
94 : wxToolBarToolBase(tbar, control)
95 {
96 Init();
97 }
98
99 virtual ~wxToolBarTool();
100
101 // accessors
102 void SetWidget(Widget widget) { m_widget = widget; }
103 Widget GetButtonWidget() const { return m_widget; }
104
105 void SetPixmap(Pixmap pixmap) { m_pixmap = pixmap; }
106 Pixmap GetPixmap() const { return m_pixmap; }
107
108protected:
109 void Init();
110
111 Widget m_widget;
112 Pixmap m_pixmap;
113};
114
115// ----------------------------------------------------------------------------
116// globals
117// ----------------------------------------------------------------------------
118
1a3ac83f
JS
119static wxToolBarTimer* wxTheToolBarTimer = (wxToolBarTimer*) NULL;
120
121Widget wxToolBarTimer::help_popup = (Widget) 0;
122Widget wxToolBarTimer::buttonWidget = (Widget) 0;
8a0681f9
VZ
123wxString wxToolBarTimer::helpString;
124
125// ============================================================================
126// implementation
127// ============================================================================
128
129// ----------------------------------------------------------------------------
130// wxToolBarTool
131// ----------------------------------------------------------------------------
132
133wxToolBarToolBase *wxToolBarToolBase::New(wxToolBar *tbar,
134 int id,
135 const wxBitmap& bitmap1,
136 const wxBitmap& bitmap2,
137 bool toggle,
138 wxObject *clientData,
139 const wxString& shortHelpString,
140 const wxString& longHelpString)
141{
142 return new wxToolBarTool(tbar, id, bitmap1, bitmap2, toggle,
143 clientData, shortHelpString, longHelpString);
144}
1a3ac83f 145
8a0681f9 146wxToolBarToolBase *wxToolBarToolBase::New(wxToolBar *tbar, wxControl *control)
4bb6408c 147{
8a0681f9 148 return new wxToolBarTool(tbar, control);
4bb6408c
JS
149}
150
8a0681f9
VZ
151void wxToolBarTool::Init()
152{
153 m_widget = (Widget)0;
154 m_pixmap = (Pixmap)0;
155}
156
157wxToolBarTool::~wxToolBarTool()
158{
159 XtDestroyWidget(m_widget);
160 XmDestroyPixmap(DefaultScreenOfDisplay((Display*)wxGetDisplay()), m_pixmap);
161}
162
163// ----------------------------------------------------------------------------
164// wxToolBar construction
165// ----------------------------------------------------------------------------
166
167void wxToolBar::Init()
4bb6408c
JS
168{
169 m_maxWidth = -1;
170 m_maxHeight = -1;
4bb6408c
JS
171 m_defaultWidth = 24;
172 m_defaultHeight = 22;
8a0681f9
VZ
173}
174
175bool wxToolBar::Create(wxWindow *parent,
176 wxWindowID id,
177 const wxPoint& pos,
178 const wxSize& size,
179 long style,
180 const wxString& name)
181{
182 Init();
183
184 m_windowId = id;
185
4bb6408c 186 SetName(name);
0d57be45
JS
187 m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE);
188 m_foregroundColour = parent->GetForegroundColour();
4bb6408c
JS
189 m_windowStyle = style;
190
191 SetParent(parent);
192
193 if (parent) parent->AddChild(this);
194
0d57be45
JS
195 Widget parentWidget = (Widget) parent->GetClientWidget();
196
197 Widget toolbar = XtVaCreateManagedWidget("toolbar",
7fe7d506
JS
198 xmBulletinBoardWidgetClass, (Widget) parentWidget,
199 XmNmarginWidth, 0,
200 XmNmarginHeight, 0,
201 XmNresizePolicy, XmRESIZE_NONE,
202 NULL);
203/*
204 Widget toolbar = XtVaCreateManagedWidget("toolbar",
205 xmFormWidgetClass, (Widget) m_clientWidget,
0d57be45
JS
206 XmNtraversalOn, False,
207 XmNhorizontalSpacing, 0,
208 XmNverticalSpacing, 0,
1a3ac83f
JS
209 XmNleftOffset, 0,
210 XmNrightOffset, 0,
211 XmNmarginWidth, 0,
212 XmNmarginHeight, 0,
0d57be45 213 NULL);
7fe7d506 214*/
0d57be45
JS
215
216 m_mainWidget = (WXWidget) toolbar;
217
da175b2c 218 m_font = parent->GetFont();
4b5f3fe6
JS
219 ChangeFont(FALSE);
220
0d57be45
JS
221 SetCanAddEventHandler(TRUE);
222 AttachWidget (parent, m_mainWidget, (WXWidget) NULL, pos.x, pos.y, size.x, size.y);
223
0d57be45 224 ChangeBackgroundColour();
bf6c2b35 225
0d57be45 226 return TRUE;
4bb6408c
JS
227}
228
229wxToolBar::~wxToolBar()
230{
1a3ac83f
JS
231 delete wxTheToolBarTimer;
232 wxTheToolBarTimer = NULL;
4bb6408c
JS
233}
234
8a0681f9 235bool wxToolBar::Realize()
7fe7d506 236{
8a0681f9
VZ
237 if ( m_tools.GetCount() == 0 )
238 {
239 // nothing to do
240 return TRUE;
241 }
7fe7d506
JS
242
243 // Separator spacing
244 const int separatorSize = GetToolSeparation(); // 8;
245 wxSize margins = GetToolMargins();
246 int marginX = margins.x;
247 int marginY = margins.y;
248
249 int currentX = marginX;
250 int currentY = marginY;
251
252 int buttonHeight = 0;
253
254 int currentSpacing = 0;
255
8a0681f9
VZ
256 Widget button;
257 Pixmap pixmap, insensPixmap;
258 wxBitmap bmp;
259
260 wxToolBarToolsList::Node *node = m_tools.GetFirst();
261 while ( node )
7fe7d506 262 {
8a0681f9 263 wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
7fe7d506 264
8a0681f9 265 switch ( tool->GetStyle() )
7fe7d506 266 {
8a0681f9
VZ
267 case wxTOOL_STYLE_CONTROL:
268 wxFAIL_MSG( _T("not implemented") );
269 break;
7fe7d506 270
8a0681f9
VZ
271 case wxTOOL_STYLE_SEPARATOR:
272 currentX += separatorSize;
273 break;
7fe7d506 274
8a0681f9
VZ
275 case wxTOOL_STYLE_BUTTON:
276 button = (Widget) 0;
bf6c2b35 277
8a0681f9 278 if ( tool->CanBeToggled() )
7fe7d506 279 {
8a0681f9
VZ
280 button = XtVaCreateWidget("toggleButton",
281 xmToggleButtonWidgetClass, (Widget) m_mainWidget,
282 XmNx, currentX, XmNy, currentY,
283 // XmNpushButtonEnabled, True,
284 XmNmultiClick, XmMULTICLICK_KEEP,
285 XmNlabelType, XmPIXMAP,
286 NULL);
287 XtAddCallback ((Widget) button, XmNvalueChangedCallback, (XtCallbackProc) wxToolButtonCallback,
288 (XtPointer) this);
289
290 XtVaSetValues ((Widget) button,
291 XmNselectColor, m_backgroundColour.AllocColour(XtDisplay((Widget) button)),
292 NULL);
bf6c2b35 293 }
7fe7d506 294 else
8a0681f9
VZ
295 {
296 button = XtVaCreateWidget("button",
297 xmPushButtonWidgetClass, (Widget) m_mainWidget,
298 XmNx, currentX, XmNy, currentY,
299 XmNpushButtonEnabled, True,
300 XmNmultiClick, XmMULTICLICK_KEEP,
301 XmNlabelType, XmPIXMAP,
302 NULL);
303 XtAddCallback (button,
304 XmNactivateCallback, (XtCallbackProc) wxToolButtonCallback,
305 (XtPointer) this);
306 }
7fe7d506 307
8a0681f9 308 DoChangeBackgroundColour((WXWidget) button, m_backgroundColour, TRUE);
7fe7d506 309
8a0681f9 310 tool->SetWidget(button);
7fe7d506 311
8a0681f9
VZ
312 // For each button, if there is a mask, we must create
313 // a new wxBitmap that has the correct background colour
314 // for the button. Otherwise the background will just be
315 // e.g. black if a transparent XPM has been loaded.
316 bmp = tool->GetBitmap1();
317 if ( bmp.GetMask() )
7fe7d506 318 {
8a0681f9
VZ
319 int backgroundPixel;
320 XtVaGetValues(button, XmNbackground, &backgroundPixel,
321 NULL);
322
323 wxColour col;
324 col.SetPixel(backgroundPixel);
325
326 wxBitmap newBitmap = wxCreateMaskedBitmap(bmp, col);
327
328 tool->SetBitmap1(newBitmap);
7fe7d506 329 }
8a0681f9
VZ
330
331 // Create a selected/toggled bitmap. If there isn't a 2nd
332 // bitmap, we need to create it (with a darker, selected
333 // background)
334 int backgroundPixel;
335 if ( tool->CanBeToggled() )
336 XtVaGetValues(button, XmNselectColor, &backgroundPixel,
337 NULL);
7fe7d506 338 else
8a0681f9
VZ
339 XtVaGetValues(button, XmNarmColor, &backgroundPixel,
340 NULL);
341
342 wxColour col;
343 col.SetPixel(backgroundPixel);
344
345 if (tool->GetBitmap2().Ok() && tool->GetBitmap2().GetMask())
7fe7d506 346 {
8a0681f9
VZ
347 // Use what's there
348 wxBitmap newBitmap = wxCreateMaskedBitmap(tool->GetBitmap2(), col);
349 tool->SetBitmap2(newBitmap);
7fe7d506 350 }
8a0681f9 351 else
7fe7d506 352 {
8a0681f9
VZ
353 // Use unselected bitmap
354 if ( bmp.GetMask() )
355 {
356 wxBitmap newBitmap = wxCreateMaskedBitmap(bmp, col);
357 tool->SetBitmap2(newBitmap);
358 }
359 else
360 tool->SetBitmap2(bmp);
361 }
362
363 pixmap = (Pixmap) bmp.GetPixmap();
364 insensPixmap = (Pixmap) bmp.GetInsensPixmap();
365
366 if (tool->CanBeToggled())
367 {
368 // Toggle button
369 Pixmap pixmap2 = (Pixmap) 0;
370 Pixmap insensPixmap2 = (Pixmap) 0;
371
372 // If there's a bitmap for the toggled state, use it,
373 // otherwise generate one.
374 if (tool->GetBitmap2().Ok())
375 {
376 wxBitmap bmp2 = tool->GetBitmap2();
377 pixmap2 = (Pixmap) bmp2.GetPixmap();
378 insensPixmap2 = (Pixmap) bmp2.GetInsensPixmap();
379 }
380 else
381 {
382 pixmap2 = (Pixmap) bmp.GetArmPixmap(button);
383 insensPixmap2 = XCreateInsensitivePixmap((Display*) wxGetDisplay(), pixmap2);
384 }
385
386 XtVaSetValues (button,
387 XmNindicatorOn, False,
388 XmNshadowThickness, 2,
389 // XmNborderWidth, 0,
390 // XmNspacing, 0,
391 XmNmarginWidth, 0,
392 XmNmarginHeight, 0,
393 XmNfillOnSelect, True,
394 XmNlabelPixmap, pixmap,
395 XmNselectPixmap, pixmap2,
396 XmNlabelInsensitivePixmap, insensPixmap,
397 XmNselectInsensitivePixmap, insensPixmap2,
398 XmNlabelType, XmPIXMAP,
399 NULL);
7fe7d506
JS
400 }
401 else
402 {
8a0681f9
VZ
403 Pixmap pixmap2 = (Pixmap) 0;
404
405 // If there's a bitmap for the armed state, use it,
406 // otherwise generate one.
407 if (tool->GetBitmap2().Ok())
408 {
409 pixmap2 = (Pixmap) tool->GetBitmap2().GetPixmap();
410 }
411 else
412 {
413 pixmap2 = (Pixmap) bmp.GetArmPixmap(button);
414
415 }
416 // Normal button
417 XtVaSetValues(button,
418 XmNlabelPixmap, pixmap,
419 XmNlabelInsensitivePixmap, insensPixmap,
420 XmNarmPixmap, pixmap2,
421 NULL);
422 }
423 XtManageChild(button);
7fe7d506 424
8a0681f9
VZ
425 {
426 Dimension width, height;
427 XtVaGetValues(button,
428 XmNwidth, &width,
429 XmNheight, & height,
430 NULL);
431 currentX += width + marginX;
432 buttonHeight = wxMax(buttonHeight, height);
7fe7d506 433 }
8a0681f9
VZ
434
435 XtAddEventHandler (button, EnterWindowMask | LeaveWindowMask,
436 False, wxToolButtonPopupCallback, (XtPointer) this);
437
438 currentSpacing = 0;
439 break;
7fe7d506 440 }
8a0681f9
VZ
441
442 node = node->GetNext();
7fe7d506
JS
443 }
444
445 SetSize(-1, -1, currentX, buttonHeight + 2*marginY);
446
447 return TRUE;
448}
449
8a0681f9
VZ
450wxToolBarTool *wxToolBar::FindToolForPosition(wxCoord WXUNUSED(x),
451 wxCoord WXUNUSED(y)) const
4bb6408c 452{
8a0681f9 453 wxFAIL_MSG( _T("TODO") );
4b5f3fe6 454
8a0681f9 455 return (wxToolBarTool *)NULL;
4bb6408c
JS
456}
457
8a0681f9 458bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarTool *tool)
4bb6408c 459{
8a0681f9 460 tool->Attach(this);
4bb6408c 461
8a0681f9 462 return TRUE;
4bb6408c
JS
463}
464
8a0681f9 465bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarTool *tool)
4bb6408c 466{
8a0681f9 467 tool->Detach();
0d57be45 468
8a0681f9 469 return TRUE;
4bb6408c
JS
470}
471
8a0681f9 472void wxToolBar::DoEnableTool(wxToolBarTool *tool, bool enable)
1a3ac83f 473{
8a0681f9 474 XtSetSensitive(tool->GetButtonWidget(), (Boolean) enable);
1a3ac83f
JS
475}
476
8a0681f9 477void wxToolBar::DoToggleTool(wxToolBarTool *tool, bool toggle)
4bb6408c 478{
8a0681f9 479 XmToggleButtonSetState(tool->GetButtonWidget(), (Boolean) toggle, False);
4bb6408c
JS
480}
481
8a0681f9 482void wxToolBar::DoSetToggle(wxToolBarTool *tool, bool toggle)
1a3ac83f 483{
8a0681f9 484 wxFAIL_MSG( _T("TODO") );
1a3ac83f
JS
485}
486
8a0681f9
VZ
487// ----------------------------------------------------------------------------
488// Motif callbacks
489// ----------------------------------------------------------------------------
1a3ac83f 490
8a0681f9 491wxToolBarTool *wxToolBar::FindToolByWidget(WXWidget w) const
7fe7d506 492{
8a0681f9
VZ
493 wxToolBarToolsList::Node* node = m_tools.GetFirst();
494 while ( node )
495 {
496 wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
497 if ( tool->GetButtonWidget() == w)
498 {
499 return tool;
500 }
7fe7d506 501
8a0681f9
VZ
502 node = node->GetNext();
503 }
7fe7d506 504
8a0681f9 505 return (wxToolBarTool *)NULL;
7fe7d506
JS
506}
507
8a0681f9
VZ
508static void wxToolButtonCallback(Widget w,
509 XtPointer clientData,
510 XtPointer WXUNUSED(ptr))
1a3ac83f
JS
511{
512 wxToolBar *toolBar = (wxToolBar *) clientData;
8a0681f9
VZ
513 wxToolBarTool *tool = toolBar->FindToolByWidget((WXWidget) w);
514 if ( !tool )
515 return;
1a3ac83f 516
8a0681f9
VZ
517 if ( tool->CanBeToggled() )
518 tool->Toggle();
519
520 if ( !toolBar->OnLeftClick(tool->GetId(), tool->IsToggled()) )
1a3ac83f 521 {
8a0681f9
VZ
522 // revert
523 tool->Toggle();
1a3ac83f 524 }
1a3ac83f
JS
525}
526
1a3ac83f 527
8a0681f9
VZ
528static void wxToolButtonPopupCallback(Widget w,
529 XtPointer client_data,
530 XEvent *event,
531 Boolean *WXUNUSED(continue_to_dispatch))
1a3ac83f
JS
532{
533 // TODO: retrieve delay before popping up tooltip from wxSystemSettings.
8a0681f9 534 static const int delayMilli = 800;
1a3ac83f 535
8a0681f9
VZ
536 wxToolBar* toolBar = (wxToolBar*) client_data;
537 wxToolBarTool *tool = toolBar->FindToolByWidget((WXWidget) w);
1a3ac83f 538
8a0681f9
VZ
539 if ( !tool )
540 return;
1a3ac83f 541
8a0681f9
VZ
542 wxString tooltip = tool->GetShortHelp();
543 if ( !tooltip )
544 return;
1a3ac83f 545
8a0681f9
VZ
546 if (!wxTheToolBarTimer)
547 wxTheToolBarTimer = new wxToolBarTimer;
1a3ac83f 548
8a0681f9
VZ
549 wxToolBarTimer::buttonWidget = w;
550 wxToolBarTimer::helpString = tooltip;
1a3ac83f
JS
551
552 /************************************************************/
553 /* Popup help label */
554 /************************************************************/
555 if (event->type == EnterNotify)
556 {
557 if (wxToolBarTimer::help_popup != (Widget) 0)
558 {
559 XtDestroyWidget (wxToolBarTimer::help_popup);
560 XtPopdown (wxToolBarTimer::help_popup);
bf6c2b35 561 }
1a3ac83f
JS
562 wxToolBarTimer::help_popup = (Widget) 0;
563
564 // One shot
565 wxTheToolBarTimer->Start(delayMilli, TRUE);
566
567 }
568 /************************************************************/
569 /* Popdown help label */
570 /************************************************************/
571 else if (event->type == LeaveNotify)
572 {
573 if (wxTheToolBarTimer)
574 wxTheToolBarTimer->Stop();
575 if (wxToolBarTimer::help_popup != (Widget) 0)
576 {
577 XtDestroyWidget (wxToolBarTimer::help_popup);
578 XtPopdown (wxToolBarTimer::help_popup);
bf6c2b35 579 }
1a3ac83f
JS
580 wxToolBarTimer::help_popup = (Widget) 0;
581 }
1a3ac83f
JS
582}
583
584void wxToolBarTimer::Notify()
585{
586 Position x, y;
587
588 /************************************************************/
589 /* Create shell without window decorations */
590 /************************************************************/
bf6c2b35
VZ
591 help_popup = XtVaCreatePopupShell ("shell",
592 overrideShellWidgetClass, (Widget) wxTheApp->GetTopLevelWidget(),
1a3ac83f
JS
593 NULL);
594
595 /************************************************************/
596 /* Get absolute position on display of toolbar button */
597 /************************************************************/
598 XtTranslateCoords (buttonWidget,
bf6c2b35
VZ
599 (Position) 0,
600 (Position) 0,
1a3ac83f
JS
601 &x, &y);
602
603 // Move the tooltip more or less above the button
604 int yOffset = 20; // TODO: What should be really?
605 y -= yOffset;
606 if (y < yOffset) y = 0;
607
608 /************************************************************/
609 /* Set the position of the help popup */
610 /************************************************************/
bf6c2b35
VZ
611 XtVaSetValues (help_popup,
612 XmNx, (Position) x,
613 XmNy, (Position) y,
1a3ac83f 614 NULL);
bf6c2b35 615
1a3ac83f
JS
616 /************************************************************/
617 /* Create help label */
618 /************************************************************/
619 XmString text = XmStringCreateSimple ((char*) (const char*) helpString);
bf6c2b35
VZ
620 XtVaCreateManagedWidget ("help_label",
621 xmLabelWidgetClass, help_popup,
1a3ac83f 622 XmNlabelString, text,
bf6c2b35
VZ
623 XtVaTypedArg,
624 XmNforeground, XtRString, "black",
625 strlen("black")+1,
626 XtVaTypedArg,
627 XmNbackground, XtRString, "LightGoldenrod",
628 strlen("LightGoldenrod")+1,
1a3ac83f
JS
629 NULL);
630 XmStringFree (text);
631
632 /************************************************************/
633 /* Popup help label */
634 /************************************************************/
635 XtPopup (help_popup, XtGrabNone);
636}
637