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