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