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