Files
wxWidgets/src/motif/toolbar.cpp
Vadim Zeitlin bf6c2b3505 1. wxGrid fixes contributed by Gerhard Gruber (client data for cells...)
2. Motif warnings removed
3. Using native msgbox under Motif (ok, it doesn't work, but generic doesn't
   work neither)


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@2930 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
1999-06-29 13:13:11 +00:00

606 lines
18 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: toolbar.cpp
// Purpose: wxToolBar
// Author: Julian Smart
// Modified by:
// Created: 04/01/98
// RCS-ID: $Id$
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__
#pragma implementation "toolbar.h"
#endif
#include "wx/wx.h"
#include "wx/app.h"
#include "wx/timer.h"
#include "wx/toolbar.h"
#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>
#include "wx/motif/private.h"
#if !USE_SHARED_LIBRARY
IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxToolBarBase)
BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
END_EVENT_TABLE()
#endif
static void wxToolButtonCallback (Widget w, XtPointer clientData,
XtPointer ptr);
static void wxToolButtonPopupCallback (Widget w, XtPointer client_data,
XEvent *event, Boolean *continue_to_dispatch);
class wxToolBarTimer: public wxTimer
{
public:
wxToolBarTimer() { }
virtual void Notify();
static Widget help_popup;
static Widget buttonWidget;
static wxString helpString;
};
static wxToolBarTimer* wxTheToolBarTimer = (wxToolBarTimer*) NULL;
Widget wxToolBarTimer::help_popup = (Widget) 0;
Widget wxToolBarTimer::buttonWidget = (Widget) 0;
wxString wxToolBarTimer::helpString = "";
wxToolBar::wxToolBar():
m_widgets(wxKEY_INTEGER)
{
m_maxWidth = -1;
m_maxHeight = -1;
m_defaultWidth = 24;
m_defaultHeight = 22;
}
bool wxToolBar::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
long style, const wxString& name)
{
m_maxWidth = -1;
m_maxHeight = -1;
m_defaultWidth = 24;
m_defaultHeight = 22;
SetName(name);
m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE);
m_foregroundColour = parent->GetForegroundColour();
m_windowStyle = style;
SetParent(parent);
if (parent) parent->AddChild(this);
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;
m_font = parent->GetFont();
ChangeFont(FALSE);
SetCanAddEventHandler(TRUE);
AttachWidget (parent, m_mainWidget, (WXWidget) NULL, pos.x, pos.y, size.x, size.y);
ChangeBackgroundColour();
return TRUE;
}
wxToolBar::~wxToolBar()
{
delete wxTheToolBarTimer;
wxTheToolBarTimer = NULL;
ClearTools();
DestroyPixmaps();
}
bool wxToolBar::CreateTools()
{
if (m_tools.Number() == 0)
return FALSE;
// Separator spacing
const int separatorSize = GetToolSeparation(); // 8;
wxSize margins = GetToolMargins();
int marginX = margins.x;
int marginY = margins.y;
int currentX = marginX;
int currentY = marginY;
int buttonHeight = 0;
int currentSpacing = 0;
m_widgets.Clear();
Widget prevButton = (Widget) 0;
wxNode* node = m_tools.First();
while (node)
{
wxToolBarTool *tool = (wxToolBarTool *)node->Data();
if (tool->m_toolStyle == wxTOOL_STYLE_SEPARATOR)
currentX += separatorSize;
else if (tool->m_bitmap1.Ok())
{
Widget button = (Widget) 0;
if (tool->m_isToggle)
{
button = XtVaCreateWidget("toggleButton",
xmToggleButtonWidgetClass, (Widget) m_mainWidget,
XmNx, currentX, XmNy, currentY,
// XmNpushButtonEnabled, True,
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);
// 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.
wxBitmap originalBitmap = tool->m_bitmap1;
if (tool->m_bitmap1.GetMask())
{
int backgroundPixel;
XtVaGetValues(button, XmNbackground, &backgroundPixel,
NULL);
wxColour col;
col.SetPixel(backgroundPixel);
wxBitmap newBitmap = wxCreateMaskedBitmap(tool->m_bitmap1, col);
tool->m_bitmap1 = newBitmap;
}
// Create a selected/toggled bitmap. If there isn't a m_bitmap2,
// we need to create it (with a darker, selected background)
int backgroundPixel;
if (tool->m_isToggle)
XtVaGetValues(button, XmNselectColor, &backgroundPixel,
NULL);
else
XtVaGetValues(button, XmNarmColor, &backgroundPixel,
NULL);
wxColour col;
col.SetPixel(backgroundPixel);
if (tool->m_bitmap2.Ok() && tool->m_bitmap2.GetMask())
{
// Use what's there
wxBitmap newBitmap = wxCreateMaskedBitmap(tool->m_bitmap2, col);
tool->m_bitmap2 = newBitmap;
}
else
{
// Use unselected bitmap
if (originalBitmap.GetMask())
{
wxBitmap newBitmap = wxCreateMaskedBitmap(originalBitmap, col);
tool->m_bitmap2 = newBitmap;
}
else
tool->m_bitmap2 = tool->m_bitmap1;
}
Pixmap pixmap = (Pixmap) tool->m_bitmap1.GetPixmap();
Pixmap insensPixmap = (Pixmap) tool->m_bitmap1.GetInsensPixmap();
if (tool->m_isToggle)
{
// Toggle button
Pixmap pixmap2 = (Pixmap) 0;
Pixmap insensPixmap2 = (Pixmap) 0;
// If there's a bitmap for the toggled state, use it,
// otherwise generate one.
if (tool->m_bitmap2.Ok())
{
pixmap2 = (Pixmap) tool->m_bitmap2.GetPixmap();
insensPixmap2 = (Pixmap) tool->m_bitmap2.GetInsensPixmap();
}
else
{
pixmap2 = (Pixmap) tool->m_bitmap1.GetArmPixmap(button);
insensPixmap2 = XCreateInsensitivePixmap((Display*) wxGetDisplay(), pixmap2);
m_pixmaps.Append((wxObject*) insensPixmap2); // Store for later deletion
}
XtVaSetValues (button,
XmNindicatorOn, False,
XmNshadowThickness, 2,
// XmNborderWidth, 0,
// XmNspacing, 0,
XmNmarginWidth, 0,
XmNmarginHeight, 0,
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 (tool->m_bitmap2.Ok())
{
pixmap2 = (Pixmap) tool->m_bitmap2.GetPixmap();
}
else
{
pixmap2 = (Pixmap) tool->m_bitmap1.GetArmPixmap(button);
}
// Normal button
XtVaSetValues(button,
XmNlabelPixmap, pixmap,
XmNlabelInsensitivePixmap, insensPixmap,
XmNarmPixmap, pixmap2,
NULL);
}
XtManageChild(button);
Dimension width, height;
XtVaGetValues(button, XmNwidth, & width, XmNheight, & height,
NULL);
currentX += width + marginX;
buttonHeight = wxMax(buttonHeight, height);
XtAddEventHandler (button, EnterWindowMask | LeaveWindowMask,
False, wxToolButtonPopupCallback, (XtPointer) this);
m_widgets.Append(tool->m_index, (wxObject*) button);
prevButton = button;
currentSpacing = 0;
}
node = node->Next();
}
SetSize(-1, -1, currentX, buttonHeight + 2*marginY);
return TRUE;
}
void wxToolBar::SetToolBitmapSize(const wxSize& size)
{
// TODO not necessary?
m_defaultWidth = size.x; m_defaultHeight = size.y;
}
wxSize wxToolBar::GetMaxSize() const
{
int w, h;
GetSize(& w, & h);
return wxSize(w, h);
}
// The button size is bigger than the bitmap size
wxSize wxToolBar::GetToolSize() const
{
// TODO not necessary?
return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
}
void wxToolBar::EnableTool(int toolIndex, bool enable)
{
wxNode *node = m_tools.Find((long)toolIndex);
if (node)
{
wxToolBarTool *tool = (wxToolBarTool *)node->Data();
tool->m_enabled = enable;
WXWidget widget = FindWidgetForIndex(tool->m_index);
if (widget == (WXWidget) 0)
return;
XtSetSensitive((Widget) widget, (Boolean) enable);
}
}
void wxToolBar::ToggleTool(int toolIndex, bool toggle)
{
wxNode *node = m_tools.Find((long)toolIndex);
if (node)
{
wxToolBarTool *tool = (wxToolBarTool *)node->Data();
if (tool->m_isToggle)
{
tool->m_toggleState = toggle;
WXWidget widget = FindWidgetForIndex(tool->m_index);
if (widget == (WXWidget) 0)
return;
XmToggleButtonSetState((Widget) widget, (Boolean) toggle, False);
}
}
}
void wxToolBar::ClearTools()
{
wxNode* node = m_widgets.First();
while (node)
{
Widget button = (Widget) node->Data();
XtDestroyWidget(button);
node = node->Next();
}
m_widgets.Clear();
DestroyPixmaps();
wxToolBarBase::ClearTools();
}
void wxToolBar::DestroyPixmaps()
{
wxNode* node = m_pixmaps.First();
while (node)
{
Pixmap pixmap = (Pixmap) node->Data();
XmDestroyPixmap (DefaultScreenOfDisplay ((Display*) GetXDisplay()), pixmap);
node = node->Next();
}
m_pixmaps.Clear();
}
// If pushedBitmap is NULL, a reversed version of bitmap is
// created and used as the pushed/toggled image.
// If toggle is TRUE, the button toggles between the two states.
wxToolBarTool *wxToolBar::AddTool(int index, const wxBitmap& bitmap, const wxBitmap& pushedBitmap,
bool toggle, long xPos, long yPos, wxObject *clientData, const wxString& helpString1, const wxString& helpString2)
{
wxToolBarTool *tool = new wxToolBarTool(index, bitmap, wxNullBitmap, toggle, xPos, yPos, helpString1, helpString2);
tool->m_clientData = clientData;
if (xPos > -1)
tool->m_x = xPos;
else
tool->m_x = m_xMargin;
if (yPos > -1)
tool->m_y = yPos;
else
tool->m_y = m_yMargin;
wxSize size = GetToolSize();
tool->SetSize(size.x, size.y);
m_tools.Append((long)index, tool);
return tool;
}
int wxToolBar::FindIndexForWidget(WXWidget w)
{
wxNode* node = m_widgets.First();
while (node)
{
WXWidget widget = (WXWidget) node->Data();
if (widget == w)
return (int) node->GetKeyInteger();
node = node->Next();
}
return -1;
}
WXWidget wxToolBar::FindWidgetForIndex(int index)
{
wxNode* node = m_widgets.Find((long) index);
if (!node)
return (WXWidget) 0;
else
return (WXWidget) node->Data();
}
WXWidget wxToolBar::GetTopWidget() const
{
return m_mainWidget;
}
WXWidget wxToolBar::GetClientWidget() const
{
return m_mainWidget;
}
WXWidget wxToolBar::GetMainWidget() const
{
return m_mainWidget;
}
void wxToolButtonCallback (Widget w, XtPointer clientData,
XtPointer ptr)
{
wxToolBar *toolBar = (wxToolBar *) clientData;
int index = toolBar->FindIndexForWidget((WXWidget) w);
if (index != -1)
{
wxNode *node = toolBar->GetTools().Find((long)index);
if (!node)
return;
wxToolBarTool *tool = (wxToolBarTool *)node->Data();
if (tool->m_isToggle)
tool->m_toggleState = !tool->m_toggleState;
(void) toolBar->OnLeftClick(index, tool->m_toggleState);
}
}
static void wxToolButtonPopupCallback (Widget w, XtPointer client_data,
XEvent *event, Boolean *continue_to_dispatch)
{
// TODO: retrieve delay before popping up tooltip from wxSystemSettings.
int delayMilli = 800;
wxToolBar* toolBar = (wxToolBar*) client_data;
int index = toolBar->FindIndexForWidget((WXWidget) w);
if (index != -1)
{
wxNode *node = toolBar->GetTools().Find((long)index);
if (!node)
return;
wxString str(toolBar->GetToolShortHelp(index));
if (str.IsNull() || str == "")
return;
if (!wxTheToolBarTimer)
wxTheToolBarTimer = new wxToolBarTimer;
wxToolBarTimer::buttonWidget = w;
wxToolBarTimer::helpString = str;
/************************************************************/
/* 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);
}