From 1a3ac83faf3338cd289023345e63df9fa24400a9 Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Thu, 22 Oct 1998 14:08:14 +0000 Subject: [PATCH] More-or-less finished reasonably cool wxToolBar class with tooltips. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@899 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/motif/todo.txt | 25 ++- include/wx/motif/toolbar.h | 9 + src/makeg95.env | 4 +- src/motif/bmpbuttn.cpp | 2 +- src/motif/statbmp.cpp | 2 +- src/motif/textctrl.cpp | 83 ++++---- src/motif/timer.cpp | 1 + src/motif/toolbar.cpp | 380 +++++++++++++++++++++++++++++++------ 8 files changed, 397 insertions(+), 109 deletions(-) diff --git a/docs/motif/todo.txt b/docs/motif/todo.txt index 1e7f001ba6..52eb135233 100644 --- a/docs/motif/todo.txt +++ b/docs/motif/todo.txt @@ -37,29 +37,19 @@ High Priority - wxSpinButton -- wxTextCtrl text file loading and saving. - - A generic version of wxNotebook that can be used in wxMotif and other toolkits that don't have a native control. Perhaps use wxTab as a starting point. -- Complete the MDI implementation. Could eventually alter the MDI - widgets to be more Windows-like -- currently it's half-hearted. - - Tidy dialogs such as the colour and font selectors. - Use generic wxTreeCtrl, wxListCtrl: debug and enhance these. -- Write a better generic wxToolBar class than wxToolBarSimple. - Alternatively, write a toolbar using Motif as described here: - http://www.motifzone.com/tmd/articles/Kurt_Huhner/jun96.html. - This article also explains how to implement tooltips. - - Find out why modal dialogs give a grab warning. -- Find out why UI updates aren't working (probably an OnIdle failure). - -- wxSystemSettings +- wxSystemSettings. Eventually, should have control panel-like utility + to change colours/fonts but meanwhile should maybe read them + from a file. - wxThread (hopefully, similar to wxGTK) @@ -106,8 +96,14 @@ Low Priority Netscape is running. See: http://www.motifzone.com/tmd/articles/John_Cwikla/index.html +- wxRCConfig (a config class using X .rc files). Could simply + implement it in terms of current wxGet/WriteResource functions. + - wxCheckBoxList +- Reimplement combobox using Lesstif's widget (avoiding GPL'ed + widget currently used). + - Write generic wxDirDialog (directory selector) - Use native Motif dialogs for wxMessageBox @@ -116,3 +112,6 @@ Low Priority Linux) - Blit scaling + +- Could eventually alter the MDI widgets to be more Windows-like + -- currently it's half-hearted. diff --git a/include/wx/motif/toolbar.h b/include/wx/motif/toolbar.h index f3c98e8d1e..590b417b4f 100644 --- a/include/wx/motif/toolbar.h +++ b/include/wx/motif/toolbar.h @@ -70,10 +70,19 @@ class WXDLLEXPORT wxToolBar: public wxToolBarBase // necessary for completing the toolbar construction. bool Realize() { return CreateTools(); }; +// Implementation + void DestroyPixmaps(); + int FindIndexForWidget(WXWidget w); + WXWidget FindWidgetForIndex(int index); + protected: // List of widgets in the toolbar, indexed by tool index wxList m_widgets; + // List of pixmaps to destroy when tools are recreated or + // or toolbar is destroyed. + wxList m_pixmaps; + DECLARE_EVENT_TABLE() }; diff --git a/src/makeg95.env b/src/makeg95.env index 374bdf15da..56230fadc7 100644 --- a/src/makeg95.env +++ b/src/makeg95.env @@ -39,8 +39,8 @@ MAKE=make LEX=flex.exe -t -L # YACC. byacc or bison -# YACC=byacc.exe -YACC=bison.exe +YACC=byacc.exe +# YACC=bison.exe # Resource compiler RESCOMP=windres.exe diff --git a/src/motif/bmpbuttn.cpp b/src/motif/bmpbuttn.cpp index 74a9f6f93e..e7d790bcf0 100644 --- a/src/motif/bmpbuttn.cpp +++ b/src/motif/bmpbuttn.cpp @@ -169,7 +169,7 @@ void wxBitmapButton::SetBitmapLabel(const wxBitmap& bitmap) // since it is no longer valid. XtVaSetValues ((Widget) m_mainWidget, XmNlabelType, XmSTRING, - XmNlabelPixmap, NULL, // TODO: Does this work? + XmNlabelPixmap, XmUNSPECIFIED_PIXMAP, XmNlabelInsensitivePixmap, NULL, XmNarmPixmap, NULL, NULL); diff --git a/src/motif/statbmp.cpp b/src/motif/statbmp.cpp index 009d175a64..68fb07baad 100644 --- a/src/motif/statbmp.cpp +++ b/src/motif/statbmp.cpp @@ -114,7 +114,7 @@ void wxStaticBitmap::SetBitmap(const wxBitmap& bitmap) // since it is no longer valid. XtVaSetValues (widget, XmNlabelType, XmSTRING, - XmNlabelPixmap, NULL, // TODO: Does this work? + XmNlabelPixmap, XmUNSPECIFIED_PIXMAP, NULL); } } diff --git a/src/motif/textctrl.cpp b/src/motif/textctrl.cpp index 3016f39932..284744f326 100644 --- a/src/motif/textctrl.cpp +++ b/src/motif/textctrl.cpp @@ -257,37 +257,36 @@ bool wxTextCtrl::LoadFile(const wxString& file) Clear(); - ifstream input((char*) (const char*) file, ios::nocreate | ios::in); + Widget textWidget = (Widget) m_mainWidget; + FILE *fp; - if (!input.bad()) + struct stat statb; + if ((stat ((char*) (const char*) file, &statb) == -1) || (statb.st_mode & S_IFMT) != S_IFREG || + !(fp = fopen ((char*) (const char*) file, "r"))) { - struct stat stat_buf; - if (stat(file, &stat_buf) < 0) - return FALSE; - // This may need to be a bigger buffer than the file size suggests, - // if it's a UNIX file. Give it an extra 1000 just in case. - char *tmp_buffer = (char*)malloc((size_t)(stat_buf.st_size+1+1000)); - long no_lines = 0; - long pos = 0; - while (!input.eof() && input.peek() != EOF) - { - input.getline(wxBuffer, 500); - int len = strlen(wxBuffer); - wxBuffer[len] = 13; - wxBuffer[len+1] = 10; - wxBuffer[len+2] = 0; - strcpy(tmp_buffer+pos, wxBuffer); - pos += strlen(wxBuffer); - no_lines++; - } - - // TODO add line - - free(tmp_buffer); - - return TRUE; + return FALSE; + } + else + { + long len = statb.st_size; + char *text; + if (!(text = XtMalloc ((unsigned) (len + 1)))) + { + fclose (fp); + return FALSE; + } + if (fread (text, sizeof (char), len, fp) != (size_t) len) + { + } + fclose (fp); + + text[len] = 0; + XmTextSetString (textWidget, text); + // m_textPosition = len; + XtFree (text); + m_modified = FALSE; + return TRUE; } - return FALSE; } // If file is null, try saved file name first @@ -301,13 +300,31 @@ bool wxTextCtrl::SaveFile(const wxString& file) return FALSE; m_fileName = theFile; - ofstream output((char*) (const char*) theFile); - if (output.bad()) - return FALSE; + Widget textWidget = (Widget) m_mainWidget; + FILE *fp; - // TODO get and save text + if (!(fp = fopen ((char*) (const char*) theFile, "w"))) + { + return FALSE; + } + else + { + char *text = XmTextGetString (textWidget); + long len = XmTextGetLastPosition (textWidget); - return FALSE; + if (fwrite (text, sizeof (char), len, fp) != (size_t) len) + { + // Did not write whole file + } + // Make sure newline terminates the file + if (text[len - 1] != '\n') + fputc ('\n', fp); + + fclose (fp); + XtFree (text); + m_modified = FALSE; + return TRUE; + } } void wxTextCtrl::WriteText(const wxString& text) diff --git a/src/motif/timer.cpp b/src/motif/timer.cpp index 1bf9297621..69b4917557 100644 --- a/src/motif/timer.cpp +++ b/src/motif/timer.cpp @@ -55,6 +55,7 @@ wxTimer::wxTimer() wxTimer::~wxTimer() { Stop(); + wxTimerList.DeleteObject(this); } bool wxTimer::Start(int milliseconds, bool mode) diff --git a/src/motif/toolbar.cpp b/src/motif/toolbar.cpp index d0db4cc532..903b69be33 100644 --- a/src/motif/toolbar.cpp +++ b/src/motif/toolbar.cpp @@ -14,11 +14,14 @@ #endif #include "wx/wx.h" +#include "wx/app.h" +#include "wx/timer.h" #include "wx/motif/toolbar.h" #include #include #include +#include #include #include #include @@ -32,6 +35,30 @@ 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); + +wxBitmap wxCreateMaskedBitmap(wxBitmap& bitmap, wxColour& colour); + +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) { @@ -39,7 +66,6 @@ wxToolBar::wxToolBar(): m_maxHeight = -1; m_defaultWidth = 24; m_defaultHeight = 22; - // TODO } bool wxToolBar::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, @@ -66,6 +92,10 @@ bool wxToolBar::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, cons XmNtraversalOn, False, XmNhorizontalSpacing, 0, XmNverticalSpacing, 0, + XmNleftOffset, 0, + XmNrightOffset, 0, + XmNmarginWidth, 0, + XmNmarginHeight, 0, NULL); m_mainWidget = (WXWidget) toolbar; @@ -81,7 +111,10 @@ bool wxToolBar::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, cons wxToolBar::~wxToolBar() { - // TODO + delete wxTheToolBarTimer; + wxTheToolBarTimer = NULL; + ClearTools(); + DestroyPixmaps(); } bool wxToolBar::CreateTools() @@ -89,13 +122,21 @@ bool wxToolBar::CreateTools() if (m_tools.Number() == 0) return FALSE; + // Separator spacing + const int separatorSize = GetToolSeparation(); // 8; + + 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) && tool->m_bitmap1.Ok()) + + if (tool->m_toolStyle == wxTOOL_STYLE_SEPARATOR) + currentSpacing = separatorSize; + else if (tool->m_bitmap1.Ok()) { Widget button = (Widget) 0; @@ -105,12 +146,14 @@ bool wxToolBar::CreateTools() xmToggleButtonWidgetClass, (Widget) m_mainWidget, XmNleftAttachment, (prevButton == (Widget) 0) ? XmATTACH_FORM : XmATTACH_WIDGET, XmNleftWidget, (prevButton == (Widget) 0) ? NULL : prevButton, - XmNleftOffset, 0, + XmNleftOffset, currentSpacing, XmNtopAttachment, XmATTACH_FORM, // XmNpushButtonEnabled, True, XmNmultiClick, XmMULTICLICK_KEEP, XmNlabelType, XmPIXMAP, NULL); + XtAddCallback ((Widget) button, XmNvalueChangedCallback, (XtCallbackProc) wxToolButtonCallback, + (XtPointer) this); } else { @@ -118,23 +161,25 @@ bool wxToolBar::CreateTools() xmPushButtonWidgetClass, (Widget) m_mainWidget, XmNleftAttachment, (prevButton == (Widget) 0) ? XmATTACH_FORM : XmATTACH_WIDGET, XmNleftWidget, (prevButton == (Widget) 0) ? NULL : prevButton, - XmNleftOffset, 0, + XmNleftOffset, currentSpacing, XmNtopAttachment, XmATTACH_FORM, XmNpushButtonEnabled, True, XmNmultiClick, XmMULTICLICK_KEEP, XmNlabelType, XmPIXMAP, NULL); - } + XtAddCallback (button, + XmNactivateCallback, (XtCallbackProc) wxToolButtonCallback, + (XtPointer) this); + } // 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()) { - wxBitmap newBitmap(tool->m_bitmap1.GetWidth(), - tool->m_bitmap1.GetHeight(), - tool->m_bitmap1.GetDepth()); int backgroundPixel; XtVaGetValues(button, XmNbackground, &backgroundPixel, NULL); @@ -143,50 +188,48 @@ bool wxToolBar::CreateTools() wxColour col; col.SetPixel(backgroundPixel); - wxMemoryDC destDC; - wxMemoryDC srcDC; - srcDC.SelectObject(tool->m_bitmap1); - destDC.SelectObject(newBitmap); - - wxBrush brush(col, wxSOLID); - destDC.SetOptimization(FALSE); - destDC.SetBackground(brush); - destDC.Clear(); - destDC.Blit(0, 0, tool->m_bitmap1.GetWidth(), tool->m_bitmap1.GetHeight(), & srcDC, 0, 0, wxCOPY, TRUE); + wxBitmap newBitmap = wxCreateMaskedBitmap(tool->m_bitmap1, col); tool->m_bitmap1 = newBitmap; } - if (tool->m_bitmap2.Ok() && tool->m_bitmap2.GetMask()) - { - wxBitmap newBitmap(tool->m_bitmap2.GetWidth(), - tool->m_bitmap2.GetHeight(), - tool->m_bitmap2.GetDepth()); - int backgroundPixel; - XtVaGetValues(button, XmNbackground, &backgroundPixel, - NULL); - - wxColour col; - col.SetPixel(backgroundPixel); - - wxMemoryDC destDC; - wxMemoryDC srcDC; - srcDC.SelectObject(tool->m_bitmap2); - destDC.SelectObject(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); - wxBrush brush(col, wxSOLID); - destDC.SetOptimization(FALSE); - destDC.SetBackground(brush); - destDC.Clear(); - destDC.Blit(0, 0, tool->m_bitmap2.GetWidth(), tool->m_bitmap2.GetHeight(), & srcDC, 0, 0, wxCOPY, TRUE); + 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; @@ -200,34 +243,53 @@ bool wxToolBar::CreateTools() else { pixmap2 = (Pixmap) tool->m_bitmap1.GetArmPixmap(button); - // This has to be both toggled and insensitive, but - // wxBitmap doesn't yet have a member to store & destroy - // it, so make it the same as pixmap2. Actually it's not - // used! - insensPixmap2 = pixmap2; + insensPixmap2 = XCreateInsensitivePixmap((Display*) wxGetDisplay(), pixmap2); + m_pixmaps.Append((wxObject*) insensPixmap2); // Store for later deletion } XtVaSetValues (button, - XmNlabelPixmap, pixmap, - XmNselectPixmap, pixmap, - XmNlabelInsensitivePixmap, insensPixmap, - XmNselectInsensitivePixmap, insensPixmap, - XmNarmPixmap, pixmap2, - XmNlabelType, XmPIXMAP, - NULL); - - } + 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, - NULL); + XmNlabelInsensitivePixmap, insensPixmap, + XmNarmPixmap, pixmap2, + NULL); } + XtAddEventHandler (button, EnterWindowMask | LeaveWindowMask, + False, wxToolButtonPopupCallback, (XtPointer) this); m_widgets.Append(tool->m_index, (wxObject*) button); prevButton = button; - + currentSpacing = 0; } node = node->Next(); } @@ -261,7 +323,12 @@ void wxToolBar::EnableTool(int toolIndex, bool enable) { wxToolBarTool *tool = (wxToolBarTool *)node->Data(); tool->m_enabled = enable; - // TODO enable button + + WXWidget widget = FindWidgetForIndex(tool->m_index); + if (widget == (WXWidget) 0) + return; + + XtSetSensitive((Widget) widget, (Boolean) enable); } } @@ -274,7 +341,12 @@ void wxToolBar::ToggleTool(int toolIndex, bool toggle) if (tool->m_isToggle) { tool->m_toggleState = toggle; - // TODO: set toggle state + + WXWidget widget = FindWidgetForIndex(tool->m_index); + if (widget == (WXWidget) 0) + return; + + XmToggleButtonSetState((Widget) widget, (Boolean) toggle, False); } } } @@ -289,10 +361,23 @@ void wxToolBar::ClearTools() 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. @@ -319,3 +404,180 @@ wxToolBarTool *wxToolBar::AddTool(int index, const wxBitmap& bitmap, const wxBit 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->key.integer; + 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(); +} + +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 = toolBar->GetToolState(index); + + (void) toolBar->OnLeftClick(index, tool->m_toggleState); + } + +} + +// Creates a bitmap with transparent areas drawn in +// the given colour. +wxBitmap wxCreateMaskedBitmap(wxBitmap& bitmap, wxColour& colour) +{ + wxBitmap newBitmap(bitmap.GetWidth(), + bitmap.GetHeight(), + bitmap.GetDepth()); + wxMemoryDC destDC; + wxMemoryDC srcDC; + srcDC.SelectObject(bitmap); + destDC.SelectObject(newBitmap); + + wxBrush brush(colour, wxSOLID); + destDC.SetOptimization(FALSE); + destDC.SetBackground(brush); + destDC.Clear(); + destDC.Blit(0, 0, bitmap.GetWidth(), bitmap.GetHeight(), & srcDC, 0, 0, wxCOPY, TRUE); + + return newBitmap; +} + + +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; + wxToolBarTool *tool = (wxToolBarTool *)node->Data(); + 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); +} + -- 2.47.2