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