Files
wxWidgets/src/motif/toolbar.cpp
Mattia Barbon 00dd3b1897 Do not #include an header where a forward declaration suffixes. Do not
include wx/wx.h directly.


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@19091 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2003-02-03 20:56:40 +00:00

726 lines
24 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: motif/toolbar.cpp
// Purpose: wxToolBar
// Author: Julian Smart
// Modified by: 13.12.99 by VZ during toolbar classes reorganization
// Created: 04/01/98
// RCS-ID: $Id$
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#ifdef __GNUG__
#pragma implementation "toolbar.h"
#endif
#ifdef __VMS
#define XtDisplay XTDISPLAY
#endif
#include "wx/settings.h"
#include "wx/app.h"
#include "wx/timer.h"
#include "wx/toolbar.h"
#include "wx/frame.h"
#ifdef __VMS__
#pragma message disable nosimpint
#endif
#include <Xm/Xm.h>
#include <Xm/PushBG.h>
#include <Xm/PushB.h>
#include <Xm/Label.h>
#include <Xm/ToggleB.h>
#include <Xm/ToggleBG.h>
#include <Xm/Form.h>
#ifdef __VMS__
#pragma message enable nosimpint
#endif
#include "wx/motif/private.h"
// ----------------------------------------------------------------------------
// wxWin macros
// ----------------------------------------------------------------------------
#if !USE_SHARED_LIBRARY
IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxToolBarBase)
#endif
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
static void wxToolButtonCallback (Widget w, XtPointer clientData,
XtPointer ptr);
static void wxToolButtonPopupCallback (Widget w, XtPointer client_data,
XEvent *event, Boolean *continue_to_dispatch);
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
class wxToolBarTimer : public wxTimer
{
public:
virtual void Notify();
static Widget help_popup;
static Widget buttonWidget;
static wxString helpString;
};
class wxToolBarTool : public wxToolBarToolBase
{
public:
wxToolBarTool(wxToolBar *tbar,
int id,
const wxString& label,
const wxBitmap& bmpNormal,
const wxBitmap& bmpToggled,
wxItemKind kind,
wxObject *clientData,
const wxString& shortHelp,
const wxString& longHelp)
: wxToolBarToolBase(tbar, id, label, bmpNormal, bmpToggled, kind,
clientData, shortHelp, longHelp)
{
Init();
}
wxToolBarTool(wxToolBar *tbar, wxControl *control)
: wxToolBarToolBase(tbar, control)
{
Init();
}
virtual ~wxToolBarTool();
// accessors
void SetWidget(Widget widget) { m_widget = widget; }
Widget GetButtonWidget() const { return m_widget; }
void SetPixmap(Pixmap pixmap) { m_pixmap = pixmap; }
Pixmap GetPixmap() const { return m_pixmap; }
protected:
void Init();
Widget m_widget;
Pixmap m_pixmap;
};
// ----------------------------------------------------------------------------
// globals
// ----------------------------------------------------------------------------
static wxToolBarTimer* wxTheToolBarTimer = (wxToolBarTimer*) NULL;
Widget wxToolBarTimer::help_popup = (Widget) 0;
Widget wxToolBarTimer::buttonWidget = (Widget) 0;
wxString wxToolBarTimer::helpString;
// ============================================================================
// implementation
// ============================================================================
// ----------------------------------------------------------------------------
// wxToolBarTool
// ----------------------------------------------------------------------------
wxToolBarToolBase *wxToolBar::CreateTool(int id,
const wxString& label,
const wxBitmap& bmpNormal,
const wxBitmap& bmpToggled,
wxItemKind kind,
wxObject *clientData,
const wxString& shortHelp,
const wxString& longHelp)
{
return new wxToolBarTool(this, id, label, bmpNormal, bmpToggled, kind,
clientData, shortHelp, longHelp);
}
wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
{
return new wxToolBarTool(this, control);
}
void wxToolBarTool::Init()
{
m_widget = (Widget)0;
m_pixmap = (Pixmap)0;
}
wxToolBarTool::~wxToolBarTool()
{
if ( m_widget )
XtDestroyWidget(m_widget);
// note: do not delete m_pixmap here because it will be deleted
// by the base class when the bitmap is destroyed.
}
// ----------------------------------------------------------------------------
// wxToolBar construction
// ----------------------------------------------------------------------------
void wxToolBar::Init()
{
m_maxWidth = -1;
m_maxHeight = -1;
m_defaultWidth = 24;
m_defaultHeight = 22;
m_toolPacking = 2;
m_toolSeparation = 8;
m_xMargin = 2;
m_yMargin = 2;
m_maxRows = 100;
m_maxCols = 100;
}
bool wxToolBar::Create(wxWindow *parent,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style,
const wxString& name)
{
if( !wxControl::CreateControl( parent, id, pos, size, style,
wxDefaultValidator, name ) )
return FALSE;
m_backgroundColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
Widget parentWidget = (Widget) parent->GetClientWidget();
Widget toolbar = XtVaCreateManagedWidget("toolbar",
xmBulletinBoardWidgetClass, (Widget) parentWidget,
XmNmarginWidth, 0,
XmNmarginHeight, 0,
XmNresizePolicy, XmRESIZE_NONE,
NULL);
/*
Widget toolbar = XtVaCreateManagedWidget("toolbar",
xmFormWidgetClass, (Widget) m_clientWidget,
XmNtraversalOn, False,
XmNhorizontalSpacing, 0,
XmNverticalSpacing, 0,
XmNleftOffset, 0,
XmNrightOffset, 0,
XmNmarginWidth, 0,
XmNmarginHeight, 0,
NULL);
*/
m_mainWidget = (WXWidget) toolbar;
ChangeFont(FALSE);
wxPoint rPos = pos;
wxSize rSize = size;
if( rPos.x == -1 ) rPos.x = 0;
if( rPos.y == -1 ) rPos.y = 0;
if( rSize.x == -1 && GetParent() )
rSize.x = GetParent()->GetSize().x;
SetCanAddEventHandler(TRUE);
AttachWidget (parent, m_mainWidget, (WXWidget) NULL,
rPos.x, rPos.y, rSize.x, rSize.y);
ChangeBackgroundColour();
return TRUE;
}
wxToolBar::~wxToolBar()
{
delete wxTheToolBarTimer;
wxTheToolBarTimer = NULL;
}
bool wxToolBar::Realize()
{
if ( m_tools.GetCount() == 0 )
{
// nothing to do
return TRUE;
}
bool isVertical = GetWindowStyle() & wxTB_VERTICAL;
// Separator spacing
const int separatorSize = GetToolSeparation(); // 8;
wxSize margins = GetToolMargins();
int packing = GetToolPacking();
int marginX = margins.x;
int marginY = margins.y;
int currentX = marginX;
int currentY = marginY;
int buttonHeight = 0, buttonWidth = 0;
int currentSpacing = 0;
Widget button;
Pixmap pixmap, insensPixmap;
wxBitmap bmp;
wxToolBarToolsList::Node *node = m_tools.GetFirst();
while ( node )
{
wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
switch ( tool->GetStyle() )
{
case wxTOOL_STYLE_CONTROL:
{
wxControl* control = tool->GetControl();
wxSize sz = control->GetSize();
wxPoint pos = control->GetPosition();
// Allow a control to specify a y[x]-offset by setting
// its initial position, but still don't allow it to
// position itself above the top[left] margin.
int controlY = (pos.y > 0) ? currentY + pos.y : currentY;
int controlX = (pos.x > 0) ? currentX + pos.x : currentX;
control->Move( isVertical ? controlX : currentX,
isVertical ? currentY : controlY );
if ( isVertical )
currentY += sz.y + packing;
else
currentX += sz.x + packing;
break;
}
case wxTOOL_STYLE_SEPARATOR:
// skip separators for vertical toolbars
if( isVertical ) break;
currentX += separatorSize;
break;
case wxTOOL_STYLE_BUTTON:
button = (Widget) 0;
if ( tool->CanBeToggled() )
{
button = XtVaCreateWidget("toggleButton",
xmToggleButtonWidgetClass, (Widget) m_mainWidget,
XmNx, currentX, XmNy, currentY,
XmNindicatorOn, False,
XmNshadowThickness, 2,
XmNborderWidth, 0,
XmNspacing, 0,
XmNmarginWidth, 0,
XmNmarginHeight, 0,
XmNmultiClick, XmMULTICLICK_KEEP,
XmNlabelType, XmPIXMAP,
NULL);
XtAddCallback ((Widget) button, XmNvalueChangedCallback, (XtCallbackProc) wxToolButtonCallback,
(XtPointer) this);
XtVaSetValues ((Widget) button,
XmNselectColor, m_backgroundColour.AllocColour(XtDisplay((Widget) button)),
NULL);
}
else
{
button = XtVaCreateWidget("button",
xmPushButtonWidgetClass, (Widget) m_mainWidget,
XmNx, currentX, XmNy, currentY,
XmNpushButtonEnabled, True,
XmNmultiClick, XmMULTICLICK_KEEP,
XmNlabelType, XmPIXMAP,
NULL);
XtAddCallback (button,
XmNactivateCallback, (XtCallbackProc) wxToolButtonCallback,
(XtPointer) this);
}
DoChangeBackgroundColour((WXWidget) button, m_backgroundColour, TRUE);
tool->SetWidget(button);
// For each button, if there is a mask, we must create
// a new wxBitmap that has the correct background colour
// for the button. Otherwise the background will just be
// e.g. black if a transparent XPM has been loaded.
bmp = tool->GetNormalBitmap();
if ( bmp.GetMask() )
{
int backgroundPixel;
XtVaGetValues(button, XmNbackground, &backgroundPixel,
NULL);
wxColour col;
col.SetPixel(backgroundPixel);
bmp = wxCreateMaskedBitmap(bmp, col);
tool->SetNormalBitmap(bmp);
}
// Create a selected/toggled bitmap. If there isn't a 2nd
// bitmap, we need to create it (with a darker, selected
// background)
int backgroundPixel;
if ( tool->CanBeToggled() )
XtVaGetValues(button, XmNselectColor, &backgroundPixel,
NULL);
else
XtVaGetValues(button, XmNarmColor, &backgroundPixel,
NULL);
wxColour col;
col.SetPixel(backgroundPixel);
// FIXME: we use disabled bitmap as the bitmap for the toggled
// state, we probably need a GetToggledBitmap() instead
wxBitmap bmpToggled = tool->GetDisabledBitmap();
if ( bmpToggled.Ok() && bmpToggled.GetMask())
{
// Use what's there
wxBitmap newBitmap = wxCreateMaskedBitmap(bmpToggled, col);
tool->SetDisabledBitmap(newBitmap);
}
else
{
// Use unselected bitmap
if ( bmp.GetMask() )
{
wxBitmap newBitmap = wxCreateMaskedBitmap(bmp, col);
tool->SetDisabledBitmap(newBitmap);
}
else
tool->SetDisabledBitmap(bmp);
}
// FIXME: and here we should use GetDisabledBitmap()...
pixmap = (Pixmap) bmp.GetPixmap();
insensPixmap = (Pixmap) bmp.GetInsensPixmap();
if (tool->CanBeToggled())
{
// Toggle button
Pixmap pixmap2 = (Pixmap) 0;
Pixmap insensPixmap2 = (Pixmap) 0;
// If there's a bitmap for the toggled state, use it,
// otherwise generate one.
//
// FIXME: see above
if ( bmpToggled.Ok() )
{
pixmap2 = (Pixmap) bmpToggled.GetPixmap();
insensPixmap2 = (Pixmap) bmpToggled.GetInsensPixmap();
}
else
{
pixmap2 = (Pixmap) bmp.GetArmPixmap(button);
insensPixmap2 = XCreateInsensitivePixmap((Display*) wxGetDisplay(), pixmap2);
}
tool->SetPixmap(pixmap2);
XtVaSetValues (button,
XmNfillOnSelect, True,
XmNlabelPixmap, pixmap,
XmNselectPixmap, pixmap2,
XmNlabelInsensitivePixmap, insensPixmap,
XmNselectInsensitivePixmap, insensPixmap2,
XmNlabelType, XmPIXMAP,
NULL);
}
else
{
Pixmap pixmap2 = (Pixmap) 0;
// If there's a bitmap for the armed state, use it,
// otherwise generate one.
if ( bmpToggled.Ok() )
{
pixmap2 = (Pixmap) bmpToggled.GetPixmap();
}
else
{
pixmap2 = (Pixmap) bmp.GetArmPixmap(button);
}
tool->SetPixmap(pixmap2);
// Normal button
XtVaSetValues(button,
XmNlabelPixmap, pixmap,
XmNlabelInsensitivePixmap, insensPixmap,
XmNarmPixmap, pixmap2,
NULL);
}
XtManageChild(button);
{
Dimension width, height;
XtVaGetValues(button,
XmNwidth, &width,
XmNheight, & height,
NULL);
if ( isVertical )
currentY += height + packing;
else
currentX += width + packing;
buttonHeight = wxMax(buttonHeight, height);
buttonWidth = wxMax(buttonWidth, width);
}
XtAddEventHandler (button, EnterWindowMask | LeaveWindowMask,
False, wxToolButtonPopupCallback, (XtPointer) this);
currentSpacing = 0;
break;
}
node = node->GetNext();
}
SetSize( -1, -1,
isVertical ? buttonWidth + 2 * marginX : currentX,
isVertical ? currentY : buttonHeight + 2*marginY );
return TRUE;
}
wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord WXUNUSED(x),
wxCoord WXUNUSED(y)) const
{
wxFAIL_MSG( _T("TODO") );
return (wxToolBarToolBase *)NULL;
}
bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
{
tool->Attach(this);
return TRUE;
}
bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
{
tool->Detach();
return TRUE;
}
void wxToolBar::DoEnableTool(wxToolBarToolBase *toolBase, bool enable)
{
wxToolBarTool *tool = (wxToolBarTool *)toolBase;
XtSetSensitive(tool->GetButtonWidget(), (Boolean) enable);
}
void wxToolBar::DoToggleTool(wxToolBarToolBase *toolBase, bool toggle)
{
wxToolBarTool *tool = (wxToolBarTool *)toolBase;
XmToggleButtonSetState(tool->GetButtonWidget(), (Boolean) toggle, False);
}
void wxToolBar::DoSetToggle(wxToolBarToolBase * WXUNUSED(tool),
bool WXUNUSED(toggle))
{
// nothing to do
}
void wxToolBar::DoSetSize(int x, int y, int width, int height, int sizeFlags)
{
int old_width, old_height;
GetSize(&old_width, &old_height);
wxToolBarBase::DoSetSize(x, y, width, height, sizeFlags);
// Correct width and height if needed.
if ( width == -1 || height == -1 )
{
int tmp_width, tmp_height;
GetSize(&tmp_width, &tmp_height);
if ( width == -1 )
width = tmp_width;
if ( height == -1 )
height = tmp_height;
}
// We must refresh the frame size when the toolbar changes size
// otherwise the toolbar can be shown incorrectly
if ( old_width != width || old_height != height )
{
// But before we send the size event check it
// we have a frame that is not being deleted.
wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
if ( frame && !frame->IsBeingDeleted() )
{
frame->SendSizeEvent();
}
}
}
// ----------------------------------------------------------------------------
// Motif callbacks
// ----------------------------------------------------------------------------
wxToolBarToolBase *wxToolBar::FindToolByWidget(WXWidget w) const
{
wxToolBarToolsList::Node* node = m_tools.GetFirst();
while ( node )
{
wxToolBarTool *tool = (wxToolBarTool *)node->GetData();
if ( tool->GetButtonWidget() == w)
{
return tool;
}
node = node->GetNext();
}
return (wxToolBarToolBase *)NULL;
}
static void wxToolButtonCallback(Widget w,
XtPointer clientData,
XtPointer WXUNUSED(ptr))
{
wxToolBar *toolBar = (wxToolBar *) clientData;
wxToolBarToolBase *tool = toolBar->FindToolByWidget((WXWidget) w);
if ( !tool )
return;
if ( tool->CanBeToggled() )
tool->Toggle();
if ( !toolBar->OnLeftClick(tool->GetId(), tool->IsToggled()) )
{
// revert
tool->Toggle();
}
}
static void wxToolButtonPopupCallback(Widget w,
XtPointer client_data,
XEvent *event,
Boolean *WXUNUSED(continue_to_dispatch))
{
// TODO: retrieve delay before popping up tooltip from wxSystemSettings.
static const int delayMilli = 800;
wxToolBar* toolBar = (wxToolBar*) client_data;
wxToolBarToolBase *tool = toolBar->FindToolByWidget((WXWidget) w);
if ( !tool )
return;
wxString tooltip = tool->GetShortHelp();
if ( !tooltip )
return;
if (!wxTheToolBarTimer)
wxTheToolBarTimer = new wxToolBarTimer;
wxToolBarTimer::buttonWidget = w;
wxToolBarTimer::helpString = tooltip;
/************************************************************/
/* Popup help label */
/************************************************************/
if (event->type == EnterNotify)
{
if (wxToolBarTimer::help_popup != (Widget) 0)
{
XtDestroyWidget (wxToolBarTimer::help_popup);
XtPopdown (wxToolBarTimer::help_popup);
}
wxToolBarTimer::help_popup = (Widget) 0;
// One shot
wxTheToolBarTimer->Start(delayMilli, TRUE);
}
/************************************************************/
/* Popdown help label */
/************************************************************/
else if (event->type == LeaveNotify)
{
if (wxTheToolBarTimer)
wxTheToolBarTimer->Stop();
if (wxToolBarTimer::help_popup != (Widget) 0)
{
XtDestroyWidget (wxToolBarTimer::help_popup);
XtPopdown (wxToolBarTimer::help_popup);
}
wxToolBarTimer::help_popup = (Widget) 0;
}
}
void wxToolBarTimer::Notify()
{
Position x, y;
/************************************************************/
/* Create shell without window decorations */
/************************************************************/
help_popup = XtVaCreatePopupShell ("shell",
overrideShellWidgetClass, (Widget) wxTheApp->GetTopLevelWidget(),
NULL);
/************************************************************/
/* Get absolute position on display of toolbar button */
/************************************************************/
XtTranslateCoords (buttonWidget,
(Position) 0,
(Position) 0,
&x, &y);
// Move the tooltip more or less above the button
int yOffset = 20; // TODO: What should be really?
y -= yOffset;
if (y < yOffset) y = 0;
/************************************************************/
/* Set the position of the help popup */
/************************************************************/
XtVaSetValues (help_popup,
XmNx, (Position) x,
XmNy, (Position) y,
NULL);
/************************************************************/
/* Create help label */
/************************************************************/
XmString text = XmStringCreateSimple ((char*) (const char*) helpString);
XtVaCreateManagedWidget ("help_label",
xmLabelWidgetClass, help_popup,
XmNlabelString, text,
XtVaTypedArg,
XmNforeground, XtRString, "black",
strlen("black")+1,
XtVaTypedArg,
XmNbackground, XtRString, "LightGoldenrod",
strlen("LightGoldenrod")+1,
NULL);
XmStringFree (text);
/************************************************************/
/* Popup help label */
/************************************************************/
XtPopup (help_popup, XtGrabNone);
}