From 8704bf74fba8523e2e174bd5a8195b5202009cd0 Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Mon, 19 Oct 1998 21:51:15 +0000 Subject: [PATCH] More Motif additions: mdi and sashtest samples now just about work! git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@873 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- distrib/msw/motif.rsp | 25 +- include/wx/motif/mdi.h | 37 +- samples/mdi/mdi.cpp | 6 +- src/make.env | 3 + src/makeg95.env | 3 +- src/motif/combobox.cpp | 2 +- src/motif/frame.cpp | 21 +- src/motif/makefile.unx | 13 +- src/motif/mdi.cpp | 473 +++- src/motif/mdi/COPYRIGHT | 29 + src/motif/mdi/Imakefile | 9 + src/motif/mdi/config/C++.rules | 9 + src/motif/mdi/config/MDI.tmpl | 45 + src/motif/mdi/doc/canvas.html | 140 ++ src/motif/mdi/doc/mdi.html | 182 ++ src/motif/mdi/doc/mwindow.html | 277 +++ src/motif/mdi/doc/pics/classes.gif | Bin 0 -> 4051 bytes src/motif/mdi/doc/pics/mdi.gif | Bin 0 -> 13227 bytes src/motif/mdi/doc/pics/winclass.gif | Bin 0 -> 4652 bytes src/motif/mdi/lib/Imakefile | 21 + src/motif/mdi/lib/XsComponent.C | 201 ++ src/motif/mdi/lib/XsComponent.h | 98 + src/motif/mdi/lib/XsMDICanvas.C | 298 +++ src/motif/mdi/lib/XsMDICanvas.h | 100 + src/motif/mdi/lib/XsMDIWindow.C | 156 ++ src/motif/mdi/lib/XsMDIWindow.h | 89 + src/motif/mdi/lib/XsMotifWindow.C | 3368 +++++++++++++++++++++++++ src/motif/mdi/lib/XsMotifWindow.h | 665 +++++ src/motif/mdi/lib/XsMoveOutline.C | 82 + src/motif/mdi/lib/XsMoveOutline.h | 52 + src/motif/mdi/lib/XsOutline.C | 241 ++ src/motif/mdi/lib/XsOutline.h | 109 + src/motif/mdi/lib/XsResizeOutline.C | 231 ++ src/motif/mdi/lib/XsResizeOutline.h | 70 + src/motif/mdi/lib/xs_motif_icon.xbm | 27 + src/motif/mdi/test/Imakefile | 25 + src/motif/mdi/test/MDItest.C | 391 +++ src/motif/xmcombo/combobox.doc | 220 ++ src/motif/xmcombo/combobox.man | 1386 +++++++++++ src/motif/xmcombo/combop.h | 131 + src/motif/xmcombo/copying.txt | 339 +++ src/motif/xmcombo/demo.c | 214 ++ src/motif/xmcombo/xmcombo.c | 3543 +++++++++++++++++++++++++++ src/motif/xmcombo/xmcombo.h | 223 ++ src/msw/makefile.g95 | 2 +- 45 files changed, 13491 insertions(+), 65 deletions(-) create mode 100644 src/motif/mdi/COPYRIGHT create mode 100644 src/motif/mdi/Imakefile create mode 100644 src/motif/mdi/config/C++.rules create mode 100644 src/motif/mdi/config/MDI.tmpl create mode 100644 src/motif/mdi/doc/canvas.html create mode 100644 src/motif/mdi/doc/mdi.html create mode 100644 src/motif/mdi/doc/mwindow.html create mode 100644 src/motif/mdi/doc/pics/classes.gif create mode 100644 src/motif/mdi/doc/pics/mdi.gif create mode 100644 src/motif/mdi/doc/pics/winclass.gif create mode 100644 src/motif/mdi/lib/Imakefile create mode 100644 src/motif/mdi/lib/XsComponent.C create mode 100644 src/motif/mdi/lib/XsComponent.h create mode 100644 src/motif/mdi/lib/XsMDICanvas.C create mode 100644 src/motif/mdi/lib/XsMDICanvas.h create mode 100644 src/motif/mdi/lib/XsMDIWindow.C create mode 100644 src/motif/mdi/lib/XsMDIWindow.h create mode 100644 src/motif/mdi/lib/XsMotifWindow.C create mode 100644 src/motif/mdi/lib/XsMotifWindow.h create mode 100644 src/motif/mdi/lib/XsMoveOutline.C create mode 100644 src/motif/mdi/lib/XsMoveOutline.h create mode 100644 src/motif/mdi/lib/XsOutline.C create mode 100644 src/motif/mdi/lib/XsOutline.h create mode 100644 src/motif/mdi/lib/XsResizeOutline.C create mode 100644 src/motif/mdi/lib/XsResizeOutline.h create mode 100644 src/motif/mdi/lib/xs_motif_icon.xbm create mode 100644 src/motif/mdi/test/Imakefile create mode 100644 src/motif/mdi/test/MDItest.C create mode 100644 src/motif/xmcombo/combobox.doc create mode 100644 src/motif/xmcombo/combobox.man create mode 100644 src/motif/xmcombo/combop.h create mode 100644 src/motif/xmcombo/copying.txt create mode 100644 src/motif/xmcombo/demo.c create mode 100644 src/motif/xmcombo/xmcombo.c create mode 100644 src/motif/xmcombo/xmcombo.h diff --git a/distrib/msw/motif.rsp b/distrib/msw/motif.rsp index 5b311108a5..dea0cf7529 100644 --- a/distrib/msw/motif.rsp +++ b/distrib/msw/motif.rsp @@ -4,11 +4,26 @@ src/motif/*.h src/motif/makefile* src/motif/*.inc src/motif/*.xbm -src/motif/combobox/*.c -src/motif/combobox/*.h -src/motif/combobox/*.doc -src/motif/combobox/*.man -src/motif/combobox/*.txt +src/motif/xmcombo/*.c +src/motif/xmcombo/*.h +src/motif/xmcombo/*.doc +src/motif/xmcombo/*.man +src/motif/xmcombo/*.txt +src/motif/mdi/COPYRIGHT +src/motif/mdi/Imakefile +src/motif/mdi/Readme +src/motif/mdi/config/C++.rules +src/motif/mdi/config/MDI.tmpl +src/motif/mdi/doc/*.html +src/motif/mdi/doc/pics/*.gif +src/motif/mdi/lib/*.C +src/motif/mdi/lib/*.h +src/motif/mdi/lib/*.xbm +src/motif/mdi/lib/Imakefile +src/motif/mdi/test/*.C +src/motif/mdi/test/Imakefile + + src/make.env src/makeprog.env diff --git a/include/wx/motif/mdi.h b/include/wx/motif/mdi.h index fa1db5314c..d3ee46079d 100644 --- a/include/wx/motif/mdi.h +++ b/include/wx/motif/mdi.h @@ -26,6 +26,9 @@ WXDLLEXPORT_DATA(extern const char*) wxStatusLineNameStr; class WXDLLEXPORT wxMDIClientWindow; class WXDLLEXPORT wxMDIChildFrame; +class XsMDICanvas; +class wxXsMDIWindow; + class WXDLLEXPORT wxMDIParentFrame: public wxFrame { DECLARE_DYNAMIC_CLASS(wxMDIParentFrame) @@ -85,7 +88,6 @@ public: protected: - // TODO maybe have this member wxMDIClientWindow *m_clientWindow; DECLARE_EVENT_TABLE() @@ -120,13 +122,31 @@ public: // Set menu bar void SetMenuBar(wxMenuBar *menu_bar); + void SetTitle(const wxString& title); void SetClientSize(int width, int height); + void GetClientSize(int *width, int *height) const; + void SetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); + void GetSize(int *width, int *height) const; void GetPosition(int *x, int *y) const ; + // Set icon + virtual void SetIcon(const wxIcon& icon); + // MDI operations virtual void Maximize(); + inline void Minimize() { Iconize(TRUE); }; + virtual void Iconize(bool iconize); virtual void Restore(); virtual void Activate(); + virtual bool IsIconized() const ; + + bool Show(bool show); + void BuildClientArea(WXWidget parent); + inline WXWidget GetTopWidget() const { return m_mainWidget; }; + inline wxXsMDIWindow *GetMDIWindow() const { return m_mdiWindow; }; + +protected: + wxXsMDIWindow* m_mdiWindow ; }; /* The client window is a child of the parent MDI frame, and itself @@ -149,14 +169,29 @@ class WXDLLEXPORT wxMDIClientWindow: public wxWindow ~wxMDIClientWindow(); + void SetSize(int x, int y, int width, int height, int sizeFlags = wxSIZE_AUTO); + void SetClientSize(int width, int height); + void GetClientSize(int *width, int *height) const; + + void GetSize(int *width, int *height) const ; + void GetPosition(int *x, int *y) const ; + + // Note: this is virtual, to allow overridden behaviour. virtual bool CreateClient(wxMDIParentFrame *parent, long style = wxVSCROLL | wxHSCROLL); // Explicitly call default scroll behaviour void OnScroll(wxScrollEvent& event); + inline XsMDICanvas* GetMDICanvas() const { return m_mdiCanvas; } + + WXWidget GetTopWidget() const { return m_topWidget; } + protected: + XsMDICanvas* m_mdiCanvas; + WXWidget m_topWidget; + DECLARE_EVENT_TABLE() }; diff --git a/samples/mdi/mdi.cpp b/samples/mdi/mdi.cpp index f94ac448f8..e52b33de8e 100644 --- a/samples/mdi/mdi.cpp +++ b/samples/mdi/mdi.cpp @@ -23,7 +23,7 @@ #include -#ifdef __WXGTK__ +#if defined(__WXGTK__) || defined(__WXMOTIF__) #include "mondrian.xpm" #include "bitmaps/new.xpm" #include "bitmaps/open.xpm" @@ -142,6 +142,8 @@ void MyFrame::OnNewWindow(wxCommandEvent& WXUNUSED(event) ) // Give it an icon #ifdef __WXMSW__ subframe->SetIcon(wxIcon("chrt_icn")); +#else + subframe->SetIcon(wxIcon( mondrian_xpm )); #endif // Make a menubar @@ -186,7 +188,7 @@ END_EVENT_TABLE() // Define a constructor for my canvas MyCanvas::MyCanvas(wxWindow *parent, const wxPoint& pos, const wxSize& size): - wxScrolledWindow(parent, -1, pos, size, wxSUNKEN_BORDER) + wxScrolledWindow(parent, -1, pos, size, wxSUNKEN_BORDER|wxVSCROLL|wxHSCROLL) { } diff --git a/src/make.env b/src/make.env index 55a9efe36d..14d45519e3 100644 --- a/src/make.env +++ b/src/make.env @@ -88,6 +88,9 @@ LDLIBS = $(EXTRALDLIBS) $(GUILDLIBS) .cpp.o : $(CC) -c $(CPPFLAGS) -o $@ $< +.C.o : + $(CC) -c $(CPPFLAGS) -o $@ $< + ####################### Targets to allow multiple GUIs #################### dummy: diff --git a/src/makeg95.env b/src/makeg95.env index 9f63cdba4c..374bdf15da 100644 --- a/src/makeg95.env +++ b/src/makeg95.env @@ -31,8 +31,7 @@ CC = gcc CCC = $(CC) # Compiler used for LEX generated C -# AIX: use $(CCC) -CCLEX=$(CC) +CCLEX=gcc MAKE=make diff --git a/src/motif/combobox.cpp b/src/motif/combobox.cpp index 1ebd7a76ea..305a39a2b9 100644 --- a/src/motif/combobox.cpp +++ b/src/motif/combobox.cpp @@ -18,7 +18,7 @@ #if wxUSE_COMBOBOX #include -#include "combobox/combobox.h" +#include "xmcombo/xmcombo.h" void wxComboBoxCallback (Widget w, XtPointer clientData, XmComboBoxSelectionCallbackStruct * cbs); diff --git a/src/motif/frame.cpp b/src/motif/frame.cpp index 16be1d39c3..c0a24a49ef 100644 --- a/src/motif/frame.cpp +++ b/src/motif/frame.cpp @@ -51,7 +51,7 @@ #include "wx/motif/private.h" void wxCloseFrameCallback(Widget, XtPointer, XmAnyCallbackStruct *cbs); -static void wxFrameFocusProc(Widget workArea, XtPointer clientData, +void wxFrameFocusProc(Widget workArea, XtPointer clientData, XmAnyCallbackStruct *cbs); static void wxFrameMapProc(Widget frameShell, XtPointer clientData, XCrossingEvent * event); @@ -310,14 +310,21 @@ wxFrame::~wxFrame() XtDestroyWidget (statusLineWidget); */ - wxDeleteWindowFromTable((Widget) m_workArea); + if (m_workArea) + { + wxDeleteWindowFromTable((Widget) m_workArea); - XtDestroyWidget ((Widget) m_workArea); - XtDestroyWidget ((Widget) m_frameWidget); + XtDestroyWidget ((Widget) m_workArea); + } - wxDeleteWindowFromTable((Widget) m_frameWidget); + if (m_frameWidget) + { + wxDeleteWindowFromTable((Widget) m_frameWidget); + XtDestroyWidget ((Widget) m_frameWidget); + } - XtDestroyWidget ((Widget) m_frameShell); + if (m_frameShell) + XtDestroyWidget ((Widget) m_frameShell); SetMainWidget((WXWidget) NULL); @@ -982,7 +989,7 @@ void wxFrame::SetToolBar(wxToolBar *toolbar) wxToolBar *wxFrame::GetToolBar() const { return m_frameToolBar; } -static void wxFrameFocusProc(Widget workArea, XtPointer clientData, +void wxFrameFocusProc(Widget workArea, XtPointer clientData, XmAnyCallbackStruct *cbs) { wxFrame *frame = (wxFrame *)clientData; diff --git a/src/motif/makefile.unx b/src/motif/makefile.unx index 89c66ecb6b..cc4119e127 100644 --- a/src/motif/makefile.unx +++ b/src/motif/makefile.unx @@ -165,13 +165,22 @@ LIB_C_SRC=\ ../common/extended.c EXTRA_C_SRC=\ - combobox/combobox.c + xmcombo/xmcombo.c + +EXTRA_CPP_SRC=\ + mdi/lib/XsComponent.C\ + mdi/lib/XsMDICanvas.C\ + mdi/lib/XsMDIWindow.C\ + mdi/lib/XsMotifWindow.C\ + mdi/lib/XsMoveOutline.C\ + mdi/lib/XsOutline.C\ + mdi/lib/XsResizeOutline.C all: $(WXLIB) # Define library objects OBJECTS=\ - $(LIB_CPP_SRC:.cpp=.o) $(LIB_C_SRC:.c=.o) $(EXTRA_C_SRC:.c=.o) + $(LIB_CPP_SRC:.cpp=.o) $(LIB_C_SRC:.c=.o) $(EXTRA_C_SRC:.c=.o) $(EXTRA_CPP_SRC:.C=.o) $(WXLIB) : $(OBJECTS) ar $(AROPTIONS) $@ $(OBJECTS) diff --git a/src/motif/mdi.cpp b/src/motif/mdi.cpp index 113f78c50a..0ecb45e87b 100644 --- a/src/motif/mdi.cpp +++ b/src/motif/mdi.cpp @@ -17,8 +17,28 @@ #include "wx/menu.h" #include "wx/settings.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdi/lib/XsMDICanvas.h" +#include "mdi/lib/XsMotifWindow.h" + +#include "wx/motif/private.h" + extern wxList wxModelessWindows; +// Implemented in frame.cpp +extern void wxFrameFocusProc(Widget workArea, XtPointer clientData, + XmAnyCallbackStruct *cbs); + #if !USE_SHARED_LIBRARY IMPLEMENT_DYNAMIC_CLASS(wxMDIParentFrame, wxFrame) IMPLEMENT_DYNAMIC_CLASS(wxMDIChildFrame, wxFrame) @@ -36,10 +56,155 @@ END_EVENT_TABLE() #endif + /* +static void _doNothingCallback (Widget, XtPointer, XtPointer) +{ +} +*/ + +// wxXsMDIWindow represents the MDI child frame, as far as the MDI +// package is concerned. +// TODO: override raise, so we can tell which is the 'active' +// (raised) window. We can also use it to send wxActivateEvents, +// and switching menubars when we make the child frame menubar +// appear on the parent frame. + +// Note: see XsMotifWindow.C, _XsMotifMenu::_processItem for +// where user menu selections are processed. +// When Close is selected, _win->close() is called. + +class wxXsMDIWindow: public XsMotifWindow +{ +public: + wxMDIChildFrame* m_childFrame; + + wxXsMDIWindow(const char* name, wxMDIChildFrame* frame): XsMotifWindow(name) + { + m_childFrame = frame; + } + virtual void setSize(Dimension w, Dimension h) + { + XsMotifWindow::setSize(w, h); + + // Generate wxSizeEvent here, I think. Maybe also restore, maximize + // Probably don't need to generate size event here since work area + // is used + wxSizeEvent event(wxSize(w, h), m_childFrame->GetId()); + event.SetEventObject(m_childFrame); + m_childFrame->ProcessEvent(event); + } + virtual void close() + { + XsMotifWindow::close(); + m_childFrame->Close(); + } + virtual void _buildClientArea(Widget parent) + { + m_childFrame->BuildClientArea((WXWidget) parent); + + // Code from MDI sample +#if 0 + assert (parent != 0); + + Widget pulldown; + Widget cascade; + Widget button; + +// Create a main window with some dummy menus + + Widget mainW = XtVaCreateWidget ("mainWin", xmMainWindowWidgetClass, parent, + XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, + NULL); + +// Create a menubar + + Widget menuBar = XmCreateMenuBar (mainW, "menuBar", NULL, 0); + +// Create the "file" menu + + pulldown = XmCreatePulldownMenu (menuBar, "pulldown", NULL, 0); + cascade = XtVaCreateManagedWidget ("fileMenu", xmCascadeButtonGadgetClass, + menuBar, XmNsubMenuId, pulldown, NULL); + + button = XtVaCreateManagedWidget ("openMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + XtAddCallback (button, XmNactivateCallback, _doNothingCallback, (XtPointer)this); + + button = XtVaCreateManagedWidget ("newMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + // XtAddCallback (button, XmNactivateCallback, _newWindowCallback, (XtPointer)this); + +// Create the "edit" menu + + pulldown = XmCreatePulldownMenu (menuBar, "pulldown", NULL, 0); + cascade = XtVaCreateManagedWidget ("editMenu", xmCascadeButtonGadgetClass, + menuBar, XmNsubMenuId, pulldown, NULL); + + button = XtVaCreateManagedWidget ("cutMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + XtAddCallback (button, XmNactivateCallback, _doNothingCallback, (XtPointer)this); + + button = XtVaCreateManagedWidget ("copyMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + XtAddCallback (button, XmNactivateCallback, _doNothingCallback, (XtPointer)this); + + button = XtVaCreateManagedWidget ("pasteMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + XtAddCallback (button, XmNactivateCallback, _doNothingCallback, (XtPointer)this); + +// Create the help menu + + pulldown = XmCreatePulldownMenu (menuBar, "pulldown", NULL, 0); + cascade = XtVaCreateManagedWidget ("helpMenu", xmCascadeButtonGadgetClass, + menuBar, XmNsubMenuId, pulldown, NULL); + + button = XtVaCreateManagedWidget ("aboutMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + XtAddCallback (button, XmNactivateCallback, _doNothingCallback, (XtPointer)this); + + XtVaSetValues (menuBar, XmNmenuHelpWidget, cascade, NULL); + +// Manage the menubar + + XtManageChild (menuBar); + +// Create the work area + + const int nargs = 8; + Arg args[nargs]; + int n; + + n = 0; + XtSetArg (args[n], XmNscrollingPolicy, XmAUTOMATIC); n++; + XtSetArg (args[n], XmNhighlightThickness, (Dimension)0); n++; + XtSetArg (args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; + XtSetArg (args[n], XmNeditable, True); n++; + XtSetArg (args[n], XmNwordWrap, False); n++; + XtSetArg (args[n], XmNcursorPositionVisible, True); n++; + XtSetArg (args[n], XmNverifyBell, True); n++; + + assert (n <= nargs); + + Widget scrolledText = XmCreateScrolledText (mainW, "scrolledText", args, n); + XtManageChild (scrolledText); + +// Set the main window area + + XtVaSetValues (mainW, XmNmenuBar, menuBar, XmNworkWindow, + XtParent (scrolledText), NULL); + + XtManageChild (mainW); +#endif + } + void Show() { show(); } +}; + // Parent frame wxMDIParentFrame::wxMDIParentFrame() { + m_clientWindow = NULL; } bool wxMDIParentFrame::Create(wxWindow *parent, @@ -50,49 +215,39 @@ bool wxMDIParentFrame::Create(wxWindow *parent, long style, const wxString& name) { - if (!parent) - wxTopLevelWindows.Append(this); - - SetName(name); - m_windowStyle = style; - - if (parent) parent->AddChild(this); + m_clientWindow = NULL; - if ( id > -1 ) - m_windowId = id; + bool success = wxFrame::Create(parent, id, title, pos, size, style, name); + if (success) + { + // TODO: app cannot override OnCreateClient since + // wxMDIParentFrame::OnCreateClient will still be called + // (we're in the constructor). How to resolve? + + m_clientWindow = OnCreateClient(); + // Uses own style for client style + m_clientWindow->CreateClient(this, GetWindowStyleFlag()); + return TRUE; + } else - m_windowId = (int)NewControlId(); - - // TODO: create MDI parent frame - - wxModelessWindows.Append(this); - - return TRUE; + return FALSE; } wxMDIParentFrame::~wxMDIParentFrame() { + DestroyChildren(); + delete m_clientWindow; } // Get size *available for subwindows* i.e. excluding menu bar. void wxMDIParentFrame::GetClientSize(int *x, int *y) const { - // TODO + wxFrame::GetClientSize(x, y); } void wxMDIParentFrame::SetMenuBar(wxMenuBar *menu_bar) { - // TODO - if (!menu_bar) - { - m_frameMenuBar = NULL; - return; - } - - if (menu_bar->m_menuBarFrame) - return; - - m_frameMenuBar = menu_bar; + wxFrame::SetMenuBar(menu_bar); } void wxMDIParentFrame::OnSize(wxSizeEvent& event) @@ -187,74 +342,304 @@ bool wxMDIChildFrame::Create(wxMDIParentFrame *parent, if (parent) parent->AddChild(this); - // TODO: create child frame + int x = pos.x; int y = pos.y; + int width = size.x; int height = size.y; + + wxMDIClientWindow* clientWindow = parent->GetClientWindow(); + if (!clientWindow) + return FALSE; + + m_mdiWindow = new wxXsMDIWindow("mdiChildWindow", this); + clientWindow->GetMDICanvas()->add(m_mdiWindow); + m_mdiWindow->Show(); +#if 0 + m_mainWidget = (WXWidget) (Widget) (*m_mdiWindow); + + m_frameWidget = (WXWidget) XtVaCreateManagedWidget("main_window", + xmMainWindowWidgetClass, (Widget) m_mainWidget, + XmNresizePolicy, XmRESIZE_NONE, + NULL); + + m_workArea = (WXWidget) XtVaCreateWidget("form", + xmFormWidgetClass, (Widget) m_frameWidget, + XmNresizePolicy, XmRESIZE_NONE, + NULL); + + m_clientArea = (WXWidget) XtVaCreateWidget("client", + xmBulletinBoardWidgetClass, (Widget) m_workArea, + XmNmarginWidth, 0, + XmNmarginHeight, 0, + XmNrightAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, +// XmNresizePolicy, XmRESIZE_ANY, + NULL); + + XtVaSetValues((Widget) m_frameWidget, + XmNworkWindow, (Widget) m_workArea, + NULL); + + XtManageChild((Widget) m_clientArea); + XtManageChild((Widget) m_workArea); + + wxASSERT_MSG ((wxWidgetHashTable->Get((long)m_workArea) == (wxObject*) NULL), "Widget table clash in frame.cpp") ; + + wxAddWindowToTable((Widget) m_workArea, this); + + XtTranslations ptr ; + + XtOverrideTranslations((Widget) m_workArea, + ptr = XtParseTranslationTable(": resize()")); + + XtFree((char *)ptr); + + XtAddCallback((Widget) m_workArea, XmNfocusCallback, + (XtCallbackProc)wxFrameFocusProc, (XtPointer)this); + + if (x > -1) + XtVaSetValues((Widget) m_mainWidget, XmNx, x, NULL); + if (y > -1) + XtVaSetValues((Widget) m_mainWidget, XmNy, y, NULL); + if (width > -1) + XtVaSetValues((Widget) m_mainWidget, XmNwidth, width, NULL); + if (height > -1) + XtVaSetValues((Widget) m_mainWidget, XmNheight, height, NULL); +#endif + + SetTitle(title); + + PreResize(); + + wxSizeEvent sizeEvent(wxSize(width, height), GetId()); + sizeEvent.SetEventObject(this); + + GetEventHandler()->ProcessEvent(sizeEvent); wxModelessWindows.Append(this); - return FALSE; + return TRUE; +} + +void wxMDIChildFrame::BuildClientArea(WXWidget parent) +{ + m_mainWidget = parent; + + m_frameWidget = (WXWidget) XtVaCreateManagedWidget("main_window", + xmMainWindowWidgetClass, (Widget) m_mainWidget, + XmNresizePolicy, XmRESIZE_NONE, + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + m_workArea = (WXWidget) XtVaCreateWidget("form", + xmFormWidgetClass, (Widget) m_frameWidget, + XmNresizePolicy, XmRESIZE_NONE, + NULL); + + m_clientArea = (WXWidget) XtVaCreateWidget("client", + xmBulletinBoardWidgetClass, (Widget) m_workArea, + XmNmarginWidth, 0, + XmNmarginHeight, 0, + XmNrightAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, +// XmNresizePolicy, XmRESIZE_ANY, + NULL); + + XtVaSetValues((Widget) m_frameWidget, + XmNworkWindow, (Widget) m_workArea, + NULL); + + XtManageChild((Widget) m_clientArea); + XtManageChild((Widget) m_workArea); + + wxASSERT_MSG ((wxWidgetHashTable->Get((long)m_workArea) == (wxObject*) NULL), "Widget table clash in frame.cpp") ; + + wxAddWindowToTable((Widget) m_workArea, this); + + XtTranslations ptr ; + + XtOverrideTranslations((Widget) m_workArea, + ptr = XtParseTranslationTable(": resize()")); + + XtFree((char *)ptr); + + XtAddCallback((Widget) m_workArea, XmNfocusCallback, + (XtCallbackProc)wxFrameFocusProc, (XtPointer)this); + + /* + int x = pos.x; int y = pos.y; + int width = size.x; int height = size.y; + + if (x > -1) + XtVaSetValues((Widget) m_mainWidget, XmNx, x, NULL); + if (y > -1) + XtVaSetValues((Widget) m_mainWidget, XmNy, y, NULL); + if (width > -1) + XtVaSetValues((Widget) m_mainWidget, XmNwidth, width, NULL); + if (height > -1) + XtVaSetValues((Widget) m_mainWidget, XmNheight, height, NULL); + */ + + XtManageChild((Widget) m_frameWidget); } + wxMDIChildFrame::~wxMDIChildFrame() { + wxMDIClientWindow* clientWindow = ((wxMDIParentFrame*)GetParent())->GetClientWindow(); + clientWindow->GetMDICanvas()->remove(m_mdiWindow); + m_mainWidget = (WXWidget) 0; } // Set the client size (i.e. leave the calculation of borders etc. // to wxWindows) void wxMDIChildFrame::SetClientSize(int width, int height) { - // TODO + wxFrame::SetClientSize(width, height); +} + +void wxMDIChildFrame::GetClientSize(int* width, int* height) const +{ + wxFrame::GetClientSize(width, height); +} + +void wxMDIChildFrame::SetSize(int x, int y, int width, int height, int sizeFlags) +{ + wxWindow::SetSize(x, y, width, height, sizeFlags); +} + +void wxMDIChildFrame::GetSize(int* width, int* height) const +{ + wxWindow::GetSize(width, height); } void wxMDIChildFrame::GetPosition(int *x, int *y) const { - // TODO + wxWindow::GetPosition(x, y); +} + +bool wxMDIChildFrame::Show(bool show) +{ + m_visibleStatus = show; /* show-&-hide fix */ + return TRUE; } void wxMDIChildFrame::SetMenuBar(wxMenuBar *menu_bar) { // TODO - if (!menu_bar) + // Currently, the menu appears on the child frame. + // It should eventually be recreated on the main frame + // whenever the child is activated. + wxFrame::SetMenuBar(menu_bar); +} + +// Set icon +void wxMDIChildFrame::SetIcon(const wxIcon& icon) +{ + m_icon = icon; + if (m_icon.Ok()) { - m_frameMenuBar = NULL; - return; + /* TODO: doesn't work yet (crashes in XCopyArea) + Pixmap pixmap = (Pixmap) m_icon.GetPixmap(); + m_mdiWindow->setPixmap(pixmap); + */ } - - if (menu_bar->m_menuBarFrame) - return; - m_frameMenuBar = menu_bar; +} + +void wxMDIChildFrame::SetTitle(const wxString& title) +{ + m_title = title; + m_mdiWindow->setTitle(title); + m_mdiWindow->setIconName(title); } // MDI operations void wxMDIChildFrame::Maximize() { - // TODO + m_mdiWindow->maximize(); +} + +void wxMDIChildFrame::Iconize(bool iconize) +{ + if (iconize) + m_mdiWindow->minimize(); + else + m_mdiWindow->restore(); +} + +bool wxMDIChildFrame::IsIconized() const +{ + return m_mdiWindow->minimized(); } void wxMDIChildFrame::Restore() { - // TODO + m_mdiWindow->restore(); } void wxMDIChildFrame::Activate() { - // TODO + m_mdiWindow->raise(); } // Client window wxMDIClientWindow::wxMDIClientWindow() { + m_mdiCanvas = NULL; + m_topWidget = (WXWidget) 0; } wxMDIClientWindow::~wxMDIClientWindow() { + DestroyChildren(); + delete m_mdiCanvas; + + m_mainWidget = (WXWidget) 0; + m_topWidget = (WXWidget) 0; } bool wxMDIClientWindow::CreateClient(wxMDIParentFrame *parent, long style) { - // TODO create client window + m_windowParent = parent; m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_APPWORKSPACE); + m_mdiCanvas = new XsMDICanvas("mdiClientWindow", (Widget) parent->GetClientWidget()); + m_mainWidget = (WXWidget) m_mdiCanvas->GetDrawingArea(); + // m_topWidget = (WXWidget) m_mdiCanvas->GetBase(); + m_topWidget = (WXWidget) (Widget) (*m_mdiCanvas); + + m_mdiCanvas->show(); + + return TRUE; +} + +void wxMDIClientWindow::SetSize(int x, int y, int width, int height, int sizeFlags) +{ + wxWindow::SetSize(x, y, width, height, sizeFlags); +} - return FALSE; +void wxMDIClientWindow::SetClientSize(int width, int height) +{ + wxWindow::SetClientSize(width, height); +} + +void wxMDIClientWindow::GetClientSize(int *width, int *height) const +{ + wxWindow::GetClientSize(width, height); +} + +void wxMDIClientWindow::GetSize(int *width, int *height) const +{ + wxWindow::GetSize(width, height); +} + +void wxMDIClientWindow::GetPosition(int *x, int *y) const +{ + wxWindow::GetPosition(x, y); } // Explicitly call default scroll behaviour diff --git a/src/motif/mdi/COPYRIGHT b/src/motif/mdi/COPYRIGHT new file mode 100644 index 0000000000..90071d4a76 --- /dev/null +++ b/src/motif/mdi/COPYRIGHT @@ -0,0 +1,29 @@ +Copyright (c) 1996 Scott W. Sadler +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to use, +copy, modify, and distribute, copies of the Software, and to permit persons to +whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +SCOTT W. SADLER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of Scott W. Sadler shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization. + +Scott W. Sadler +Software Engineer +International TechneGroup Incorporated +5303 DuPont Circle +Milford, OH 45150 +sws@iti-oh.com +http://www.iti-oh.com/~sws diff --git a/src/motif/mdi/Imakefile b/src/motif/mdi/Imakefile new file mode 100644 index 0000000000..a2c6b73e42 --- /dev/null +++ b/src/motif/mdi/Imakefile @@ -0,0 +1,9 @@ +#include "config/MDI.tmpl" + +#define IHaveSubdirs +#define PassCDebugFlags 'CDEBUGFLAGS=$(CDEBUGFLAGS)' + +SUBDIRS = lib test + +MakeSubdirs($(SUBDIRS)) +DependSubdirs($(SUBDIRS)) diff --git a/src/motif/mdi/config/C++.rules b/src/motif/mdi/config/C++.rules new file mode 100644 index 0000000000..3cb56a69df --- /dev/null +++ b/src/motif/mdi/config/C++.rules @@ -0,0 +1,9 @@ +#define CxxRules() @@\ + @@\ +CxxSuffixRules() + +#define CxxSuffixRules() @@\ +.SUFFIX: .C .o @@\ +.C.o: @@\ + $(CXX) $(CFLAGS) $(EXTRA_FLAGS) -c $< + diff --git a/src/motif/mdi/config/MDI.tmpl b/src/motif/mdi/config/MDI.tmpl new file mode 100644 index 0000000000..dafc038c39 --- /dev/null +++ b/src/motif/mdi/config/MDI.tmpl @@ -0,0 +1,45 @@ +#undef FOUND_COMPILER + +#ifdef SGIArchitecture +CXX = CC +CC = $(CXX) +#define FOUND_COMPILER +#endif + +#ifdef SparcArchitecture +CXX = CC +CC = $(CXX) +#define FOUND_COMPILER +#endif + +#ifdef HPArchitecture +CXX = CC +CC = $(CXX) +#define FOUND_COMPILER +#endif + +#ifdef AIXArchitecture +CXX = xlC +CC = $(CXX) +EXTRA_FLAGS = -U__STR__ -D_POSIX_SOURCE +#define FOUND_COMPILER +#endif + +#ifdef OSF1Architecture +CXX = cxx +CC = $(CXX) +#define FOUND_COMPILER +#endif + +#ifdef LinuxArchitecture +CXX = gcc +CC = $(CXX) +#define FOUND_COMPILER +#endif + +#ifndef FOUND_COMPILER +CXX = gcc +CC = $(CXX) +#endif + +#include "C++.rules" diff --git a/src/motif/mdi/doc/canvas.html b/src/motif/mdi/doc/canvas.html new file mode 100644 index 0000000000..1ddbf3cdc4 --- /dev/null +++ b/src/motif/mdi/doc/canvas.html @@ -0,0 +1,140 @@ + + + +XsMDICanvas Class + + + +

+The XsMDICanvas Class +

+ +

+This section describes how to build and manipulate an MDI using the +XsMDICanvas class. Minimally, you must perform the following actions +to build and display an MDI canvas: + +

    +
  1. Create the XsMDICanvas object.
  2. +
  3. Create the documents as instances of subclasses of XsMDIWindow.
  4. +
  5. Add the documents to the canvas
  6. +
  7. Show the canvas
  8. +
+ +

+Constructor and Destructor: + +

+The XsMDICanvas accepts two arguments: + +

+
XsMDICanvas (const char *name, Widget parent)
+
+ +

+The name parameter specifies the name of the canvas and is used +as the widget name for the underlying implementation. The parent +parameter specifies the widget that is to be used as the parent of the +canvas. + +

+The XsMDICanvas destructor destroys the canvas, but it does not +destroy any of the underlying documents. It is up to the application to +destroy these. + +

+Adding and removing documents: + +

+After the documents are created, they must be added to the canvas. The +XsMDICanvas::add() member-function adds documents to the canvas: + +

+
virtual void add (XsMDIWindow *window)
+
+ +

+The behavior of adding the same document to the canvas more than once +is undefined. Documents can be removed from the canvas by using: + +

+
virtual void remove (XsMDIWindow *window)
+
+ +

+Additionally, all documents can be removed from the canvas with: + +

+
void removeAll ( )
+
+ +

+The number of documents currently installed in the canvas can be +retrieved with: + +

+
int numWindows ( ) const
+
+ +

+Showing the canvas: + +

+In order to show (manage) the canvas call the show member function: + +

+
virtual void show ( )
+
+ +This member-function is responsible for cycling all of the installed documents +and calling their respective XsMDIWindow::_buildClientArea() +member-functions. After each document has been created, show will then +manage each document and, finally, itself. + +

+Window Placement: + +

+The current implementation of XsMDICanvas uses a very simple algorithm +to place the documents on the canvas. In order to implement a more specific +placement algorithm, derive a class from XsMDICanvas and override +the member-function: + +

+
virtual void _placeWindow (XsMDIWindow *win)
+
+ +

+This member-function is called for each document in the canvas to compute +the location of the document. Please refer to the code (XsMDICanvas.C) +for more details. + +

+Canvas Behavior: + +

+The XsMDICanvas is implemented as an XmScrolledWindow with an +XmDrawingArea work-window. The instance name for the work-window +is canvas. Internal callbacks in the canvas class force the work-window +to be at-least the size of the clip-window. This prevents documents from +being clipped as they are moved around. + +

+By default, the XmDrawingArea work-window has its XmNresizePolicy +set to XmRESIZE_GROW. This will allow the work-area to grow to +whatever size necessary, but it will not automatically shrink as windows +are manipulated. If different behavior is desired, the XmNresizePolicy +resource on the work-area can be set to XmRESIZE_ANY. This will +force the work-window to recompute its size as windows are manipulated, and +it will grow and shrink as necessary. However, the XsMDICanvas will +still force the work-area to be at-least the size of the clip-window. + +

To change the default behavior, add the following resource: + +

+
<XsMDICanvas name>*canvas.resizePolicy: XmRESIZE_ANY
+
+ + + + diff --git a/src/motif/mdi/doc/mdi.html b/src/motif/mdi/doc/mdi.html new file mode 100644 index 0000000000..1ee82529ec --- /dev/null +++ b/src/motif/mdi/doc/mdi.html @@ -0,0 +1,182 @@ + + + +Motif Multi-Document Interface (MDI) + + + +
+[Class Structure] +

+ +The Motif Multi-Document Interface + +

+
+ +

+The Motif Multi-Document Interface (MDI) is a collection of C++ classes +that emulates the behavior of the Multi-Document Interface in Microsoft +Windows. The MDI framework allows a user to view multiple documents (windows) +constrained to a single parent window. + +

+


+ +

+ +CLASS +STRUCTURE: + + +

+[Class Structure] + +
+Figure 1. Inheritance Graph for MDI classes + +

+The XsMDICanvas is a self-contained component used to display and manage +any number of child document windows. All documents windows are derived from +the abstract base-class XsMDIWindow. To get the Motif-like functionality, +document windows should be derived from the XsMotifWindow class. + +

+


+ +

+ +EXAMPLE: + + +

+The process of building and displaying a Multi-Document Interface using MDI +consists of the following steps: + +

    +
  1. Creating the application document(s)
  2. +
  3. Creating the MDI canvas
  4. +
  5. Adding the document(s) to the canvas
  6. +
+ +
+
+#include "XsMDICanvas.h"
+#include "XsMotifWindow.h"
+
+// Application document (derived from XsMotifWindow)
+
+class MyDocument : public XsMotifWindow {
+   public:
+      MyDocument (const char *name);
+      virtual ~MyDocument ( );
+   protected:
+      virtual void _buildClientArea (Widget parent);
+};
+      
+void createCanvas (Widget parent) {
+
+// Create documents
+
+   MyDocument *doc1 = new MyDocument ("doc1");
+   MyDocument *doc2 = new MyDocument ("doc2");
+   
+// Create the canvas
+
+   XsMDICanvas *canvas = new XsMDICanvas ("canvas", parent);
+   
+// Add documents to canvas
+
+   canvas->add (doc1);
+   canvas->add (doc2);
+
+// Show the canvas
+
+   canvas->show ( );
+}
+   
+
+ +

+In this example, the application document MyDocument is derived +from XsMotifWindow. This provides a Motif-like window suitable for +use with the XsMDICanvas. + +

+Next, two MyDocument objects are created along with the XsMDICanvas. +The two documents are then added to the canvas using the add +member-function of the canvas. Lastly, the canvas is shown (managed) +using the show member-function. + +

+Creating the document MyDocument does not automatically create any +widgets. Rather, it only initializes internal variables. The widgets are +not created until the document is added to the canvas. The XsMDICanvas +is responsible for calling XsMotifWindow::_buildClientArea() at an +appropriate time. In this member-function, the application can create the +actual contents of the document. + +

+The member-function _buildClientArea is passed a widget to be used as +the parent of the document contents. This parent widget is an unmanaged +XmForm widget. The application is free to create whatever contents +it needs as a child of the XmForm parent. + +

+


+ +

+ +CLASS +REFERENCES: + + +

+Of the classes in the MDI package, only the following should be of +interest to MDI library users: + +

+ +

+


+ +

+ +EXPLORING +RESOURCES: + + +

+The MDI classes support a number of different X-resources (please refer +the the class manual pages for complete details). In order to get a feel +for the customization capabilities of the MDI library, try running the +test program (MDItest) with the following command-line options: + +

+
MDItest -xrm "*showBorder:false"
+
MDItest -xrm "*showTitle:false" -xrm "*showResize:false"
+
MDItest -xrm "*showMenu:false" -xrm "*showMaximize:false"
+
MDItest -xrm "*borderSize:4" -xrm "*buttonSize:14"
+
MDItest -xrm "*lowerOnIconify:true" -xrm "*title:Hello World"
+
+ +

+


+ +

+ +ADDITIONAL +IINFORMATION: + + +

+The test program MDItest.C gives a complete example of an MDI +application. It should serve as a good reference/example of the MDI library. + + + + + diff --git a/src/motif/mdi/doc/mwindow.html b/src/motif/mdi/doc/mwindow.html new file mode 100644 index 0000000000..effbdcda7e --- /dev/null +++ b/src/motif/mdi/doc/mwindow.html @@ -0,0 +1,277 @@ + + + +XsMotifWindow Class + + + +

+The XsMotifWindow Class +

+ +

+The XsMDICanvas requires that all documents be a subclass of +XsMDIWindow or a subclass of a class derived from it. By itself +XsMDIWindow does not define any appearance or behavior for the +documents. However, XsMotifWindow, derived from XsMDIWindow, +defines a MWM-like look-and-feel to a document. + +

+Documents in your application should be derived from XsMotifWindow. +This class provides the look-and-feel of Motif window and supports the +interaction with the XsMDICanvas. It is up to the application to +define the contents of each document. + +

+Constructor and Destructor: + +

+The XsMotifWindow constructor accepts one argument: + +

+
XsMotifWindow (const char *name)
+
+ +

+The name parameter specifies the name of the document and is used +as the widget name for the underlying implementation. The name parameter +is also used as the default title and icon-name for the document. + +

+Note: The XsMotifWindow constructor does not create any +widgets. Rather it only initializes internal variables. The widgets are +not created until the document is added to the canvas. The XsMDICanvas +calls the member-function XsMotifWindow::_buildClientArea() when it needs +to create the document widgets. + +

+The XsMotifWindow destructor destroys the document widgets (if they have +been created) and frees its internal storage. It is up to the application +to free all documents. The XsMDICanvas will not destroy the +documents for you. + +

+Document Utilities: + +

+Although rarely called from the application, the XsMotifWindow supports +a number of utility functions to manipulate the document. + +

+
virtual void raise ( )
+
virtual void lower ( )
+
virtual void minimize ( )
+
virtual void maximize ( )
+
virtual void restore ( )
+
virtual void close ( )
+
+ +

+The close member-function does not destroy the document, it simply +hides it from view. You can restore a closed document with +XsMotifWindow::show(). + +

+The following member-functions are used to change/query the appearance of +the document: + +

+
void setTitle (const char *name)
+
const char *title ( ) const
+
void setIconName (const char *name)
+
const char *iconName ( ) const
+
void setPixmap (Pixmap pixmap)
+
Pixmap pixmap ( ) const
+
Widget icon ( ) const
+
Boolean minimized ( ) const
+
Boolean maximized ( ) const
+
virtual void setPosition (Position x, Position y)
+
virtual void setSize (Dimension width, Dimension height)
+
+ +

+The setPixmap member-function accepts a pixmap which the document then +uses as the decoration on the icon. Because the document does not make a copy +of the pixmap, it is important that the application not free the pixmap until +all documents that reference it are deleted. The document does, however, make +a local copy of the title or icon-name string passed to it, so the application +is free to do whatever it wants to the passed-in string. The icon +member-function returns the widget that is used to implement the icon. + + +

+Creating Window Subclasses: + +

+The application must derive its documents from XsMotifWindow in order to +define the contents of the document. The XsMDICanvas calls the +protected member-function _buildClientArea when it creates the +document. Each class derived from XsMotifWindow must override +this pure-virtual member-function. + +

+The member-function _buildClientArea is called with a single argument: + +

+
virtual void _buildClientArea (Widget parent)
+
+ +The parent argument should be used as the parent of the contents of +the document. This widget is an unmanaged XmForm widget, and all of +the standard resources and constrains apply to it. The XsMDICanvas +is responsible for managing the parent widget at the appropriate time. + +

+As an example, consider the following: + +

+// _buildClientArea (called to create document contents)
+
+void MyDocument::_buildClientArea (Widget parent)
+{
+   assert (parent != 0);
+   
+// Create a main window with some dummy menus
+
+   Widget mainW = XtVaCreateWidget ("mainWin", xmMainWindowWidgetClass, parent,
+      XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM,
+      XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM,
+      NULL);
+   ...
+   
+   XtManageChild (mainW);
+}
+
+ +

+In this case, an XmMainWindow is created as the child of the parent +widget. The XmMainWindow is then attached to the 4 sides of the parent +form. Note also that the main window is managed before returning from the +function. + +

+Resources: + +

+The XsMotifWindow supports the following resources: + +

+   Name              Class             Type           Default
+------------------------------------------------------------------------------
+   borderSize        BorderSize        Dimension      6
+   buttonSize        ButtonSize        Dimension      23
+   title             Title             String         dynamic
+   titleFont         TitleFont         String         -*-helvetica-bold-o-normal-*-14-*-*-*-*-*-iso8859-1
+   iconSize          IconSize          Dimension      70
+   iconName          IconName          String         dynamic
+   iconFont          IconFont          String         *-helvetica-bold-r-normal-*-12-*-*-*-*-*-iso8859-1
+   XmNiconX          XmCIconX          Position       dynamic
+   XmNiconY          XmCIconY          Position       dynamic
+   saveUnder         SaveUnder         Boolean        True
+   restoreString     RestoreString     String         "Restore"
+   moveString        MoveString        String         "Move"
+   sizeString        SizeString        String         "Size"
+   minimizeString    MinimizeString    String         "Minimize"
+   maximizeString    MaximizeString    String         "Maximize"
+   raiseString       RaiseString       String         "Raise"
+   lowerString       LowerString       String         "Lower"
+   closeString       CloseString       String         "Close"
+   menuFont          MenuFont          String         -*-helvetica-bold-o-normal-*-14-*-*-*-*-*-iso8859-1
+   showBorder        ShowBorder        Boolean        True
+   showResize        ShowResize        Boolean        True
+   showTitle         ShowTitle         Boolean        True
+   showMenu          ShowMenu          Boolean        True
+   showMinimize      ShowMinimize      Boolean        True   
+   showMaximize      ShowMaximize      Boolean        True
+   lowerOnIconify    LowerOnIconify    Boolean        False
+   XmNminWidth       XmCMinWidth       Dimension      dynamic
+   XmNmaxWidth       XmCMaxWidth       Dimension      dynamic
+   XmNminHeight      XmCMinHeight      Dimension      dynamic
+   XmNmaxHeight      XmCMaxHeight      Dimension      dynamic
+
+ +
+
+
+
borderSize
+
Size of the window border.
+
buttonSize
+
Size of the window buttons.
+
title
+
Title of the window. The default is the name of the window instance.
+
titleFont
+
Font used to draw the window title.
+
iconSize
+
Size of the icon representation.
+
iconName
+
String used on the title. If unspecified, the window title is used.
+
iconFont
+
Font used to draw the icon-name.
+
XmNiconX
+
X-position of the icon. The default location is the top-left +corner of the window when it is iconified.
+
XmNiconY
+
Y-position of the icon. The default location is the top-left +corner of the window when it is iconified.
+
saveUnder
+
Enables/Disables save-unders for the menu.
+
restoreString
+
String used as the "restore" menu item.
+
moveString
+
String used as the "move" menu item.
+
sizeString
+
String used as the "size" menu item.
+
minimizeString
+
String used as the "minimize" menu item.
+
maximizeString
+
String used as the "maximize" menu item.
+
raiseString
+
String used as the "raise" menu item.
+
lowerString
+
String used as the the "lower" menu item.
+
closeString
+
String used as the "close" menu item.
+
menuFont
+
Font used to draw the menu strings.
+
showBorder
+
Enables/Disables the window border. If the border is disabled, +the resize-handles are automatically disabled.
+
showResize
+
Enables/Disables the window resize handles.
+
showTitle
+
Enables/Disables the window title. If the title is disabled, +all of the window buttons are automatically disabled.
+
showMenu
+
Enables/Disables the window menu button.
+
showMinimize
+
Enables/Disables the window minimize button.
+
showMaximize
+
Enables/Disables the window maximize button.
+
lowerOnIconify
+
Automatically lower windows when iconified.
+
XmNminWidth
+
Minimium window width. The default is about four times the size of +the window button.
+
XmNmaxWidth
+
Maximum window width. The default is not to constrain the maximum size.
+
XmNminHeight
+
Minimum window height. The default is about four times the size of +the window button.
+
XmNmaxHeight
+
Maximum window height. The default is not to constrain the maximum size.
+
+
+
+ +

+XsMotifWindow Implementation: + +

+As a convenience to those who wish to modify the XsMotifWindow code, +here is a diagram of the internal class structure: + +

+[Class Structure] + + + diff --git a/src/motif/mdi/doc/pics/classes.gif b/src/motif/mdi/doc/pics/classes.gif new file mode 100644 index 0000000000000000000000000000000000000000..9f5deb2c008436725d5bc654ac7a17f563f40557 GIT binary patch literal 4051 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 F06U_@5YYet literal 0 HcmV?d00001 diff --git a/src/motif/mdi/doc/pics/mdi.gif b/src/motif/mdi/doc/pics/mdi.gif new file mode 100644 index 0000000000000000000000000000000000000000..c43414bc62266d5cb5f524b85f7a2b7016acf30f GIT binary patch literal 13227 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 literal 0 HcmV?d00001 diff --git a/src/motif/mdi/lib/Imakefile b/src/motif/mdi/lib/Imakefile new file mode 100644 index 0000000000..2dd64024c3 --- /dev/null +++ b/src/motif/mdi/lib/Imakefile @@ -0,0 +1,21 @@ +#include "../config/MDI.tmpl" + +SRCS = XsComponent.C XsMDICanvas.C XsMDIWindow.C XsMotifWindow.C \ + XsMoveOutline.C XsOutline.C XsResizeOutline.C + +HEADERS = XsComponent.h XsMDICanvas.h XsMDIWindow.h XsMotifWindow.h \ + sMoveOutline.h XsOutline.h XsResizeOutline.h + +OBJS = XsComponent.o XsMDICanvas.o XsMDIWindow.o XsMotifWindow.o \ + XsMoveOutline.o XsOutline.o XsResizeOutline.o + +STD_INCLUDES = -I/usr/include + +INCLUDES = -I. + +LIBXSW = Xsw + +NormalLibraryObjectRule() +NormalLibraryTarget($(LIBXSW),$(OBJS)) +DependTarget() +CxxRules() diff --git a/src/motif/mdi/lib/XsComponent.C b/src/motif/mdi/lib/XsComponent.C new file mode 100644 index 0000000000..a09ed87733 --- /dev/null +++ b/src/motif/mdi/lib/XsComponent.C @@ -0,0 +1,201 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsComponent.C + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +// Includes + +#ifndef NDEBUG +#include +#endif + +#include +#include +#include +#include +#include "XsComponent.h" + +// Constructor + +XsComponent::XsComponent (const char *name) +{ + assert (name != 0); + +// Initialize + + _base = 0; + +// Copy component name + + int len = strlen (name); + _name = new char [len + 1]; + strcpy (_name, name); +} + +// Destructor + +XsComponent::~XsComponent ( ) +{ + +// Destroy the widget + + if (_base != 0) + { + _removeDestroyHandler ( ); + XtDestroyWidget (_base); + } + + delete [] _name; +} + +// show + +void XsComponent::show ( ) +{ + +#ifndef NDEBUG + if (XtIsManaged (_base)) + cout << "Re-managing a widget:" << _name << endl; +#endif + +// Make sure the _destroyHandler was installed + + assert (XtHasCallbacks (_base, XmNdestroyCallback) == XtCallbackHasSome); + + assert (_base != 0); + XtManageChild (_base); +} + +// hide + +void XsComponent::hide ( ) +{ + +#ifndef NDEBUG + if (!XtIsManaged (_base)) + cout << "Re-unmanaging a widget:" << _name << endl; +#endif + + assert (_base != 0); + XtUnmanageChild (_base); +} + +// Conversion operator + +XsComponent::operator Widget ( ) const +{ + assert (_base != 0); + return (_base); +} + +// operator == + +Boolean XsComponent::operator == (const XsComponent& rval) +{ + return (_base == rval._base); +} + +// className + +const char* XsComponent::className ( ) const +{ + return ("XsComponent"); +} + +// _installDestroyHandler + +void XsComponent::_installDestroyHandler ( ) +{ + assert (_base != 0); + +// Install the destroy handler + + XtAddCallback (_base, XmNdestroyCallback, _componentDestroyedCallback, (XtPointer)this); +} + +// _removeDestroyHandler + +void XsComponent::_removeDestroyHandler ( ) +{ + assert (_base != 0); + +// Remove the destroy handler + + XtRemoveCallback (_base, XmNdestroyCallback, _componentDestroyedCallback, (XtPointer)this); +} + +// _componentDestroyed + +void XsComponent::_componentDestroyed ( ) +{ + _base = 0; +} + +// _componentDestroyedCallback + +void XsComponent::_componentDestroyedCallback (Widget, XtPointer clientData, XtPointer) +{ + XsComponent *obj = (XsComponent*)clientData; + obj->_componentDestroyed ( ); +} + +// _setResources + +void XsComponent::_setResources (Widget w, const String *resources) +{ + assert (w != 0); + + XrmDatabase rdb = 0; + const int bufSize = 200; + char buffer[bufSize]; + int loop; + +// Create an empty resource database + + rdb = XrmGetStringDatabase (""); + +// Add the component resources + + loop = 0; + while (resources[loop] != 0) + { + sprintf (buffer, "*%s%s\n", _name, resources[loop++]); + assert (strlen (buffer) < bufSize); + XrmPutLineResource (&rdb, buffer); + } + +// Merge these resources into the database + + if (rdb != 0) + { + XrmDatabase db = XtDatabase (XtDisplay (w)); + XrmCombineDatabase (rdb, &db, FALSE); + } +} + +// _getResources + +void XsComponent::_getResources (const XtResourceList resources, int num) +{ + assert (_base != 0); + assert (resources != 0); + +// Validate input + + if (num <= 0) + return; + +// Get the subresources + + XtGetSubresources (XtParent (_base), (XtPointer)this, _name, + className ( ), resources, num, 0, 0); +} + diff --git a/src/motif/mdi/lib/XsComponent.h b/src/motif/mdi/lib/XsComponent.h new file mode 100644 index 0000000000..d2d71f061a --- /dev/null +++ b/src/motif/mdi/lib/XsComponent.h @@ -0,0 +1,98 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsComponent.h + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +#ifndef XSCOMPONENT_H +#define XSCOMPONENT_H + +// Includes + +#include + +// XsComponent class + +class XsComponent { + + public: + +// Destructor + + virtual ~XsComponent ( ); + +// Component manipulation + + virtual void show ( ); // Show the component + virtual void hide ( ); // Hide the component + +// Added JACS 19/10/98 + inline Widget GetBase() const { return _base; } + +// Component name + + const char *name ( ) const; + +// Utilities + + Widget base ( ) const; + virtual operator Widget ( ) const; + +// Operators + + Boolean operator == (const XsComponent&); + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Protected constructor + + XsComponent (const char *name); + +// Component life-cycle + + virtual void _componentDestroyed ( ); + void _installDestroyHandler ( ); + void _removeDestroyHandler ( ); + +// Resource manager + + void _setResources (Widget w, const String *); + void _getResources (const XtResourceList, int); + +// Implementation + + char *_name; // Component name + Widget _base; // Base widget + + private: + +// Callbacks + + static void _componentDestroyedCallback (Widget, XtPointer, XtPointer); +}; + +// Inline member functions + +inline Widget XsComponent::base ( ) const +{ + return (_base); +} + +inline const char* XsComponent::name ( ) const +{ + return (_name); +} + +#endif + diff --git a/src/motif/mdi/lib/XsMDICanvas.C b/src/motif/mdi/lib/XsMDICanvas.C new file mode 100644 index 0000000000..6d84aabe54 --- /dev/null +++ b/src/motif/mdi/lib/XsMDICanvas.C @@ -0,0 +1,298 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsMDICanvas.C + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +// Includes + +#include +#include +#include +#include "XsMDICanvas.h" +#include "XsMDIWindow.h" + +// Static definitions + +String XsMDICanvas::_resources[] = { + "*canvas.resizePolicy: XmRESIZE_GROW", + NULL +}; + +// Constructor + +XsMDICanvas::XsMDICanvas (const char *name, Widget parent) : XsComponent (name) +{ + assert (parent != 0); + +// Initialize + + _list = 0; + _num = 0; + _max = 0; + _place = 0; + +// Install resources + + _setResources (parent, _resources); + +// Create the scrolled window + + const int nargs = 10; + Arg args[nargs]; + int n = 0; + + XtSetArg (args[n], XmNscrollingPolicy, XmAUTOMATIC); n++; + XtSetArg (args[n], XmNscrolledWindowMarginHeight, (Dimension)0); n++; + XtSetArg (args[n], XmNscrolledWindowMarginWidth, (Dimension)0); n++; + XtSetArg (args[n], XmNmarginHeight, (Dimension)5); n++; + XtSetArg (args[n], XmNmarginWidth, (Dimension)5); n++; + + assert (n <= nargs); + + _base = XmCreateScrolledWindow (parent, _name, args, n); + +// Install the destroy handler + + _installDestroyHandler ( ); + +// Create the drawing area (canvas) + + _drawArea = XtVaCreateWidget ("canvas", xmDrawingAreaWidgetClass, + _base, XmNmarginHeight, (Dimension)0, XmNmarginWidth, (Dimension)0, + NULL); + +// Set resize callback on drawing area + + XtAddCallback (_drawArea, XmNresizeCallback, _canvasResizeCallback, (XtPointer)this); + +// Set resize callback on clip window + + XtVaGetValues (_base, XmNclipWindow, &_clipWin, NULL); + XtAddCallback (_clipWin, XmNresizeCallback, _clipResizeCallback, (XtPointer)this); +} + +// Destructor + +XsMDICanvas::~XsMDICanvas ( ) +{ + +/* + Remove callbacks to prevent calls to destroyed class-part of XsMDICanvas + while children are being destroyed. +*/ + + if (_drawArea) + XtRemoveCallback (_drawArea, XmNresizeCallback, _canvasResizeCallback, (XtPointer)this); + + if (_clipWin) + XtRemoveCallback (_clipWin, XmNresizeCallback, _clipResizeCallback, (XtPointer)this); + +// Remove all windows + + removeAll ( ); +} + +// add + +void XsMDICanvas::add (XsMDIWindow *win) +{ + assert (win != 0); + + const int increment = 10; + +// Check if we need to allocate more space + + if (_num >= _max) + { + XsMDIWindow **newList = new XsMDIWindow*[_max + increment]; + + for (int loop = 0; loop < _num; loop++) + newList[loop] = _list[loop]; + _max += increment; + + delete [] _list; + _list = newList; + } + +// Add the new window + + _list[_num++] = win; + +// Install the parent canvas + + win->_setWindowParent (_drawArea); + +// If the canvas is shown, place the window + + if (XtIsManaged (_base)) + _placeWindow (win); +} + +// remove + +void XsMDICanvas::remove (XsMDIWindow *win) +{ + assert (win != 0); + +// Remove the window + + int i, j; + + for (i = 0; i < _num; i++) + { + if (_list[i] == win) + { + win->hide ( ); + win->_setWindowParent (0); + + for (j = i; j < _num - 1; j++) + _list[j] = _list[j + 1]; + _num--; + + return; + } + } + + assert (0); // Couldn't find window +} + +// removeAll + +void XsMDICanvas::removeAll ( ) +{ + +// Delete and reset the list + + delete [] _list; + + _list = 0; + _num = 0; + _max = 0; +} + +// show + +void XsMDICanvas::show ( ) +{ + assert (_drawArea != 0); + +// Place all of the child windows + + for (int loop = 0; loop < _num; loop++) + _placeWindow (_list[loop]); + +// Manage the drawing area and canvas + + XtManageChild (_drawArea); + +// Call base class + + XsComponent::show ( ); +} + +// className + +const char* XsMDICanvas::className ( ) const +{ + return ("XsMDICanvas"); +} + +// _componentDestroyed + +void XsMDICanvas::_componentDestroyed ( ) +{ + +// Remove the callbacks + + XtRemoveCallback (_drawArea, XmNresizeCallback, _canvasResizeCallback, (XtPointer)this); + XtRemoveCallback (_clipWin, XmNresizeCallback, _clipResizeCallback, (XtPointer)this); + + _drawArea = 0; + _clipWin = 0; +} + +// _placeWindow + +void XsMDICanvas::_placeWindow (XsMDIWindow *win) +{ + assert (win != 0); + +// Compute window placement + + Position x, y; + + const int maxWin = 10; + const Position offset = 20; + const Position minOffset = 10; + + x = (_place * offset) + minOffset; + y = (_place * offset) + minOffset; + + if (++_place == maxWin) + _place = 0; + +// Set the window placement + + win->setPosition (x, y); + +// Show the window + + win->show ( ); +} + +// _resize + +void XsMDICanvas::_resize (XtPointer) +{ + Dimension clipHeight; + Dimension clipWidth; + Dimension canvasHeight; + Dimension canvasWidth; + +// Check if clip window and canvas are managed + + if (!XtIsManaged (_clipWin) || !XtIsManaged (_drawArea)) + return; + +// Get the clip window size + + XtVaGetValues (_clipWin, XmNwidth, &clipWidth, XmNheight, &clipHeight, NULL); + +// Get the canvas size + + XtVaGetValues (_drawArea, XmNwidth, &canvasWidth, XmNheight, &canvasHeight, NULL); + +// Force the canvas to be at least as big as the clip window + + if (canvasWidth < clipWidth) + canvasWidth = clipWidth; + if (canvasHeight < clipHeight) + canvasHeight = clipHeight; + + XtVaSetValues (_drawArea, XmNwidth, canvasWidth, XmNheight, canvasHeight, NULL); +} + +// _clipResizeCallback + +void XsMDICanvas::_clipResizeCallback (Widget, XtPointer clientData, XtPointer callData) +{ + XsMDICanvas *obj = (XsMDICanvas*)clientData; + obj->_resize (callData); +} + +// _canvasResizeCallback + +void XsMDICanvas::_canvasResizeCallback (Widget, XtPointer clientData, XtPointer callData) +{ + XsMDICanvas *obj = (XsMDICanvas*)clientData; + obj->_resize (callData); +} + diff --git a/src/motif/mdi/lib/XsMDICanvas.h b/src/motif/mdi/lib/XsMDICanvas.h new file mode 100644 index 0000000000..0e676b71cf --- /dev/null +++ b/src/motif/mdi/lib/XsMDICanvas.h @@ -0,0 +1,100 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsMDICanvas.h + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +#ifndef XSMDICANVAS_H +#define XSMDICANVAS_H + +// Includes + +#include "XsComponent.h" + +// Forward declarations + +class XsMDIWindow; + +// XsMDICanvas class + +class XsMDICanvas : public XsComponent { + + public: + +// Constructor/Destructor + + XsMDICanvas (const char *name, Widget parent); + virtual ~XsMDICanvas ( ); + +// MDI Window manipulation + + virtual void add (XsMDIWindow *win); // Add an MDI window + virtual void remove (XsMDIWindow *win); // Remove an MDI window + void removeAll ( ); // Remove all MDI windows + +// Added JACS 19/10/98 + inline Widget GetDrawingArea() const { return _drawArea; } + +// Utilities + + int numWindows ( ) const; // Number of MDI windows + +// Component methods + + virtual void show ( ); + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Component life-cycle + + virtual void _componentDestroyed ( ); + +// Geometry management + + virtual void _placeWindow (XsMDIWindow *win); + +// Canvas resize handler + + virtual void _resize (XtPointer); + +// Implementation + + Widget _clipWin; + Widget _drawArea; + + XsMDIWindow **_list; + int _num; + int _max; + int _place; + + private: + +// Callbacks + + static void _clipResizeCallback (Widget, XtPointer, XtPointer); + static void _canvasResizeCallback (Widget, XtPointer, XtPointer); + +// Resources + + static String _resources[]; +}; + +// Inline member functions + +inline XsMDICanvas::numWindows ( ) const +{ + return (_num); +} + +#endif diff --git a/src/motif/mdi/lib/XsMDIWindow.C b/src/motif/mdi/lib/XsMDIWindow.C new file mode 100644 index 0000000000..6d112a25f5 --- /dev/null +++ b/src/motif/mdi/lib/XsMDIWindow.C @@ -0,0 +1,156 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsMDIWindow.C + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +// Includes + +#include +#include +#include "XsMDIWindow.h" + +// Constructor + +XsMDIWindow::XsMDIWindow (const char *name) : XsComponent (name) +{ + +// Initialize + + _clientArea = 0; + _parent = 0; + +// Initial size and placement + + _initX = (Position)-1; + _initY = (Position)-1; + _initH = (Dimension)-1; + _initW = (Dimension)-1; + _placed = False; +} + +// Destructor + +XsMDIWindow::~XsMDIWindow ( ) +{ + // Empty +} + +// raise + +void XsMDIWindow::raise ( ) +{ + assert (_base != 0); + XRaiseWindow (XtDisplay (_base), XtWindow (_base)); +} + +// lower + +void XsMDIWindow::lower ( ) +{ + assert (_base != 0); + XLowerWindow (XtDisplay (_base), XtWindow (_base)); +} + +// show + +void XsMDIWindow::show ( ) +{ + +// Create the window (if necessary) + + if (_base == 0) + { + assert (_parent != 0); + _createWindow (_parent); + } + +// Manage the client area + + XtManageChild (_clientArea); + +// Configure the window position and size + + if (_placed == False) + { + const int nargs = 4; + Arg args[nargs]; + int n = 0; + + if (_initX != (Position)-1) + { + XtSetArg (args[n], XmNx, _initX); n++; + } + if (_initY != (Position)-1) + { + XtSetArg (args[n], XmNy, _initY); n++; + } + if (_initW != (Dimension)-1) + { + XtSetArg (args[n], XmNwidth, _initW); n++; + } + if (_initH != (Dimension)-1) + { + XtSetArg (args[n], XmNheight, _initH); n++; + } + + assert (n <= nargs); + XtSetValues (_base, args, n); + + _placed = True; + } + +// Call the base class + + XsComponent::show ( ); +} + +// setPosition + +void XsMDIWindow::setPosition (Position x, Position y) +{ + if (_base != 0) + XtVaSetValues (_base, XmNx, x, XmNy, y, NULL); + else + { + _initX = x; + _initY = y; + } +} + +// setSize + +void XsMDIWindow::setSize (Dimension w, Dimension h) +{ + if (_base != 0) + XtVaSetValues (_base, XmNwidth, w, XmNheight, h, NULL); + else + { + _initW = w; + _initH = h; + } +} + +// className + +const char* XsMDIWindow::className ( ) const +{ + return ("XsMDIWindow"); +} + +// _setWindowParent + +void XsMDIWindow::_setWindowParent (Widget p) +{ + +// This is called by the canvas to tell us who our parent is + + _parent = p; +} diff --git a/src/motif/mdi/lib/XsMDIWindow.h b/src/motif/mdi/lib/XsMDIWindow.h new file mode 100644 index 0000000000..ef12b3c3be --- /dev/null +++ b/src/motif/mdi/lib/XsMDIWindow.h @@ -0,0 +1,89 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsMDIWindow.h + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +#ifndef XSMDIWINDOW_H +#define XSMDIWINDOW_H + +// Includes + +#include "XsComponent.h" + +// XsMDIWindow class + +class XsMDIWindow : public XsComponent { + + friend class XsMDICanvas; + + public: + +// Constructor/Destructor + + XsMDIWindow (const char *name); + virtual ~XsMDIWindow ( ); + +// Window manipulation + + virtual void raise ( ); + virtual void lower ( ); + +// Utilities + + Widget clientArea ( ) const; + +// Position and size + + virtual void setPosition (Position x, Position y); + virtual void setSize (Dimension w, Dimension h); + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Only the friendly canvas can show a window + + virtual void show ( ); + +// Window creation functions + + virtual void _buildClientArea (Widget parent) = 0; + virtual void _createWindow (Widget parent) = 0; + +// Implementation + + Widget _clientArea; // Client work area + +// Initial window size and placement + + Position _initX, _initY; + Dimension _initW, _initH; + Boolean _placed; + + private: + +// Window parent installation + + void _setWindowParent (Widget); + Widget _parent; +}; + +// Inline member functions + +inline Widget XsMDIWindow::clientArea ( ) const +{ + return (_clientArea); +} + +#endif + diff --git a/src/motif/mdi/lib/XsMotifWindow.C b/src/motif/mdi/lib/XsMotifWindow.C new file mode 100644 index 0000000000..f1a2a4d2c3 --- /dev/null +++ b/src/motif/mdi/lib/XsMotifWindow.C @@ -0,0 +1,3368 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsMotifWindow.C + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +// Includes + +#include +#include +#include +#include +#include +#include +#include +#include "XsMotifWindow.h" +#include "XsResizeOutline.h" +#include "XsMoveOutline.h" +#include "xs_motif_icon.xbm" + +// Constants + +const int BorderSize_ = 6; +const int ButtonSize_ = 23; +const int IconSize_ = 70; + +/* + ---------------------------------------------------------------------------- + _XsMotifBase +*/ + +// Constructor + +_XsMotifBase::_XsMotifBase (const char *name, XsMotifWindow *win) : + XsComponent (name) +{ + assert (win != 0); + +// Initialize + + _win = win; + _topShadowGC = 0; + _bottomShadowGC = 0; +} + +// Destructor + +_XsMotifBase::~_XsMotifBase ( ) +{ + if (_topShadowGC) + XtReleaseGC (_base, _topShadowGC); + + if (_bottomShadowGC) + XtReleaseGC (_base, _bottomShadowGC); +} + +// show + +void _XsMotifBase::show ( ) +{ + assert (_base != 0); + +// Install event handler + + XtAddEventHandler (_base, StructureNotifyMask, False, _mapEventHandler, (XtPointer)this); + +// Call the base-class + + XsComponent::show ( ); +} + +// className + +const char* _XsMotifBase::className ( ) const +{ + return ("_XsMotifBase"); +} + +// _componentDestroyed ( ) + +void _XsMotifBase::_componentDestroyed ( ) +{ + +// Clean up the GCs + + if (_topShadowGC) + XtReleaseGC (_base, _topShadowGC); + + if (_bottomShadowGC) + XtReleaseGC (_base, _bottomShadowGC); + + _topShadowGC = 0; + _bottomShadowGC = 0; + +// Call the base-class + + XsComponent::_componentDestroyed ( ); +} + +// _drawShadows + +void _XsMotifBase::_drawShadows (Position x, Position y, Dimension width, + Dimension height, Dimension thick, Boolean reverse) +{ + assert (_base != 0); + assert (thick > 0); + + const int nsegs = 2; + XSegment segs[nsegs]; + GC topShadowGC; + GC bottomShadowGC; + +// Work out the graphics contexts + + topShadowGC = (reverse == False) ? _topShadowGC : _bottomShadowGC; + bottomShadowGC = (reverse == False) ? _bottomShadowGC : _topShadowGC; + + for (int loop = 0; loop < thick; loop++) + { + +/* + TOP SHADOW DRAWING +*/ + +// Across the top + + segs[0].x1 = x + loop; + segs[0].y1 = y + loop; + segs[0].x2 = x + width - loop - 2; + segs[0].y2 = y + loop; + +// Down the left side + + segs[1].x1 = x + loop; + segs[1].y1 = y + loop + 1; + segs[1].x2 = x + loop; + segs[1].y2 = y + height - loop - 2; + + XDrawSegments (XtDisplay (_base), XtWindow (_base), topShadowGC, segs, nsegs); + +/* + BOTTOM SHADOW DRAWING +*/ + +// Across the bottom + + segs[0].x1 = x + loop; + segs[0].y1 = y + height - loop - 1; + segs[0].x2 = x + width - loop - 1; + segs[0].y2 = y + height - loop - 1; + +// Down the right side + + segs[1].x1 = x + width - loop - 1; + segs[1].y1 = y + loop; + segs[1].x2 = x + width - loop - 1; + segs[1].y2 = y + height - loop - 1; + + XDrawSegments (XtDisplay (_base), XtWindow (_base), bottomShadowGC, segs, nsegs); + } +} + +// _drawLine + +void _XsMotifBase::_drawLine (Position x1, Position y1, Position x2, Position y2, GC &gc) +{ + assert (_base != 0); + XDrawLine (XtDisplay (_base), XtWindow (_base), gc, x1, y1, x2, y2); +} + +// _map + +void _XsMotifBase::_map ( ) +{ + +// Create the graphics contexts + + unsigned long valuemask; + XGCValues values; + Pixel topShadow; + Pixel bottomShadow; + + XtVaGetValues (_win->base ( ), XmNtopShadowColor, &topShadow, XmNbottomShadowColor, + &bottomShadow, NULL); + +// Create the graphics contexts + + valuemask = GCForeground | GCLineWidth | GCGraphicsExposures; + values.line_width = 0; + values.graphics_exposures = False; + + values.foreground = topShadow; + _topShadowGC = XtGetGC (_base, valuemask, &values); + + values.foreground = bottomShadow; + _bottomShadowGC = XtGetGC (_base, valuemask, &values); +} + +// _mapEventHandler + +void _XsMotifBase::_mapEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) +{ + if (event->type == MapNotify) + { + _XsMotifBase *obj = (_XsMotifBase*)clientData; + obj->_map ( ); + +// Remove the event handler + + XtRemoveEventHandler (obj->_base, StructureNotifyMask, False, obj->_mapEventHandler, clientData); + } +} + +/* + ---------------------------------------------------------------------------- + _XsMotifComponent +*/ + +Cursor _XsMotifComponent::_cursors[_XsMotifComponent::NumCursors]; + +int _XsMotifComponent::_mutex = 0; + +XtResource _XsMotifComponent::_resourceList[] = { + { + "borderSize", + "BorderSize", + XmRDimension, + sizeof (Dimension), + XtOffset (_XsMotifComponent*, _borderSize), + XmRImmediate, + (XtPointer)BorderSize_ + }, + { + "buttonSize", + "ButtonSize", + XmRDimension, + sizeof (Dimension), + XtOffset (_XsMotifComponent*, _buttonSize), + XmRImmediate, + (XtPointer)ButtonSize_ + } +}; + +// Constructor + +_XsMotifComponent::_XsMotifComponent (const char *name, XsMotifWindow *win, + Widget parent) : _XsMotifBase (name, win) +{ + +// Create cursors (if necessary) + + if (_mutex == 0) + { + + Display *dpy = XtDisplay (win->base ( )); + + _cursors[TopCursor] = XCreateFontCursor (dpy, XC_top_side); + _cursors[BottomCursor] = XCreateFontCursor (dpy, XC_bottom_side); + _cursors[LeftCursor] = XCreateFontCursor (dpy, XC_left_side); + _cursors[RightCursor] = XCreateFontCursor (dpy, XC_right_side); + _cursors[TopLeftCursor] = XCreateFontCursor (dpy, XC_top_left_corner); + _cursors[TopRightCursor] = XCreateFontCursor (dpy, XC_top_right_corner); + _cursors[BottomLeftCursor] = XCreateFontCursor (dpy, XC_bottom_left_corner); + _cursors[BottomRightCursor] = XCreateFontCursor (dpy, XC_bottom_right_corner); + + _mutex = 1; + } + +// Create the component + + _base = XtVaCreateWidget (name, widgetClass, (parent != 0) ? parent : _win->base ( ), NULL); + +// Install destroy handler + + _installDestroyHandler ( ); + +// Get resources + + _getResources (_resourceList, XtNumber (_resourceList)); + +// Compute the corner size + + _cornerSize = _buttonSize + _borderSize; + +// Install event handlers + + XtAddEventHandler (_base, ExposureMask, False, _exposeEventHandler, (XtPointer)this); + XtAddEventHandler (_base, ButtonPressMask | ButtonReleaseMask | Button1MotionMask | Button2MotionMask, False, _inputEventHandler, (XtPointer)this); +} + +// Destructor + +_XsMotifComponent::~_XsMotifComponent ( ) +{ + // Empty +} + +// className + +const char* _XsMotifComponent::className ( ) const +{ + return ("_XsMotifComponent"); +} + +// _input + +void _XsMotifComponent::_input (XEvent*) +{ + // Empty +} + +// _exposeEventHandler + +void _XsMotifComponent::_exposeEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) +{ + _XsMotifComponent *obj = (_XsMotifComponent*)clientData; + + if (event->xexpose.count == 0) + obj->_expose (event); +} + +// _inputEventHandler + +void _XsMotifComponent::_inputEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) +{ + _XsMotifComponent *obj = (_XsMotifComponent*)clientData; + obj->_input (event); +} + +/* + ---------------------------------------------------------------------------- + _XsMotifCorner +*/ + +// Constructor + +_XsMotifCorner::_XsMotifCorner (const char *name, XsMotifWindow *win, Corner corner) + : _XsMotifComponent (name, win) +{ + +// Initialize + + _corner = corner; + +// Configure component + + XtVaSetValues (_base, XmNwidth, _cornerSize, XmNheight, _cornerSize, + XmNborderWidth, (Dimension)0, NULL); +} + +// Destructor + +_XsMotifCorner::~_XsMotifCorner ( ) +{ + // Empty +} + +// className + +const char *_XsMotifCorner::className ( ) const +{ + return ("_XsMotifCorner"); +} + +// _expose + +void _XsMotifCorner::_expose (XEvent*) +{ + Dimension w, h; + +// Get the size of the corner + + XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL); + +// Draw the shadow + + _drawShadows (0, 0, w, h, 1); + +// Draw the extra lines and relief + + switch (_corner) + { + case TopLeft: + { + _drawLine (1, 1, w - 2, 1, _topShadowGC); + _drawLine (1, 1, 1, h - 2, _topShadowGC); + +// Relief + + _drawLine (_borderSize - 1, _borderSize - 1, _borderSize + + _buttonSize - 2, _borderSize - 1, _bottomShadowGC); + + _drawLine (_borderSize - 1, _borderSize - 1, _borderSize - 1, + _borderSize + _buttonSize - 2, _bottomShadowGC); + + break; + } + case TopRight: + { + _drawLine (1, 1, w - 2, 1, _topShadowGC); + _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC); + +// Relief + + _drawLine (0, _borderSize - 1, _buttonSize - 1, _borderSize - 1, + _bottomShadowGC); + + _drawLine (w - _borderSize, _borderSize - 1, w - _borderSize, + _borderSize + _buttonSize - 2, _topShadowGC); + + break; + } + case BottomLeft: + { + _drawLine (1, 1, 1, h - 2, _topShadowGC); + _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC); + +// Relief + + _drawLine (_borderSize - 1, h - _borderSize, _borderSize + + _buttonSize - 2, h - _borderSize, _topShadowGC); + + _drawLine (_borderSize - 1, 1, _borderSize - 1, + _buttonSize - 1, _bottomShadowGC); + + break; + } + case BottomRight: + { + _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC); + _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC); + +// Relief + + _drawLine (1, h - _borderSize, _buttonSize, h - _borderSize, + _topShadowGC); + + _drawLine (w - _borderSize, 1, w - _borderSize, + _buttonSize - 1, _topShadowGC); + + break; + } + default: + assert (0); + } +} + +// _input + +void _XsMotifCorner::_input (XEvent *event) +{ + switch (event->type) + { + case ButtonPress: + { + if (event->xbutton.button == 2) + { + XsMoveOutline move (_win->base ( )); + +// Start the move + + if (move.go ( ) != False) + { + +// Relocate the window + + _win->setPosition (move.x ( ), move.y ( )); + } + } + else if (event->xbutton.button == 3) + _win->popupMenu ( ); + + break; + } + case ButtonRelease: + { + switch (event->xbutton.button) + { + case 1: + case 2: + { + _win->raise ( ); // Raise the window + break; + } + } + break; + } + case MotionNotify: + { + +// Figure kind of resize we are doing + + int dir; + + if (_corner == TopLeft) + dir = XsResizeOutline::Up | XsResizeOutline::Left; + else if (_corner == TopRight) + dir = XsResizeOutline::Up | XsResizeOutline::Right; + else if (_corner == BottomLeft) + dir = XsResizeOutline::Down | XsResizeOutline::Left; + else if (_corner == BottomRight) + dir = XsResizeOutline::Down | XsResizeOutline::Right; + else + assert (0); + + XsResizeOutline resize (_win->base ( ), dir); + resize.setMinSize (_win->minWidth ( ), _win->minHeight ( )); + +// Start the resize + + if (resize.go ( ) != False) + { + +// Relocate the window + + _win->setPosition (resize.x ( ), resize.y ( )); + _win->setSize (resize.width ( ), resize.height ( )); + } + break; + } + } +} + +// _map + +void _XsMotifCorner::_map ( ) +{ + +// Call the base-class + + _XsMotifComponent::_map ( ); + +// Install the cursor + + if (_corner == TopLeft) + XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopLeftCursor]); + else if (_corner == TopRight) + XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopRightCursor]); + else if (_corner == BottomLeft) + XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomLeftCursor]); + else if (_corner == BottomRight) + XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomRightCursor]); + else + assert (0); +} + +/* + ---------------------------------------------------------------------------- + _XsMotifSide +*/ + +// Constructor + +_XsMotifSide::_XsMotifSide (const char *name, XsMotifWindow *win, Side side) : + _XsMotifComponent (name, win) +{ + +// Initialize + + _side = side; + _lastW = _lastH = -1; + +// Configure component + + switch (_side) + { + case Top: + case Bottom: + { + XtVaSetValues (_base, XmNheight, _borderSize, XmNborderWidth, + (Dimension)0, NULL); + break; + } + case Left: + case Right: + { + XtVaSetValues (_base, XmNwidth, _borderSize, XmNborderWidth, + (Dimension)0, NULL); + break; + } + default: + assert (0); + } + +// Install event handler + + XtAddEventHandler (_base, StructureNotifyMask, False, _configureEventHandler, (XtPointer)this); +} + +// Destructor + +_XsMotifSide::~_XsMotifSide ( ) +{ + // Empty +} + +// className + +const char *_XsMotifSide::className ( ) const +{ + return ("_XsMotifSide"); +} + +// _expose + +void _XsMotifSide::_expose (XEvent *event) +{ + +// Clear out the window first + + if (event != 0) + XClearWindow (XtDisplay (_base), XtWindow (_base)); + + Dimension w, h; + +// Get the size of the side + + XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL); + +// Draw the shadow + + _drawShadows (0, 0, w, h, 1); + +// Draw the extra lines + + switch (_side) + { + case Top: + { + _drawLine (1, 1, w - 2, 1, _topShadowGC); + break; + } + case Bottom: + { + _drawLine (1, h - 2, w - 2, h - 2, _bottomShadowGC); + break; + } + case Left: + { + _drawLine (1, 1, 1, h - 2, _topShadowGC); + break; + } + case Right: + { + _drawLine (w - 2, 1, w - 2, h - 2, _bottomShadowGC); + break; + } + default: + assert (0); + } +} + +// _input + +void _XsMotifSide::_input (XEvent *event) +{ + switch (event->type) + { + case ButtonPress: + { + if (event->xbutton.button == 2) + { + XsMoveOutline move (_win->base ( )); + +// Start the move + + if (move.go ( ) != False) + { + +// Relocate the window + + _win->setPosition (move.x ( ), move.y ( )); + } + } + else if (event->xbutton.button == 3) + _win->popupMenu ( ); + + break; + } + case ButtonRelease: + { + switch (event->xbutton.button) + { + case 1: + case 2: + { + _win->raise ( ); // Raise the window + break; + } + } + break; + } + case MotionNotify: + { + +// Figure kind of resize we are doing + + int dir; + + if (_side == Top) + dir = XsResizeOutline::Up; + else if (_side == Bottom) + dir = XsResizeOutline::Down; + else if (_side == Left) + dir = XsResizeOutline::Left; + else if (_side == Right) + dir = XsResizeOutline::Right; + else + assert (0); + + XsResizeOutline resize (_win->base ( ), dir); + resize.setMinSize (_win->minWidth ( ), _win->minHeight ( )); + +// Start the resize + + if (resize.go ( ) != False) + { + +// Relocate the window + + _win->setPosition (resize.x ( ), resize.y ( )); + _win->setSize (resize.width ( ), resize.height ( )); + } + break; + } + } +} + +// _map + +void _XsMotifSide::_map ( ) +{ + +// Call the base-class + + _XsMotifComponent::_map ( ); + +// Install the cursor + + if (_side == Top) + XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[TopCursor]); + else if (_side == Bottom) + XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[BottomCursor]); + else if (_side == Left) + XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[LeftCursor]); + else if (_side == Right) + XDefineCursor (XtDisplay (_base), XtWindow (_base), _cursors[RightCursor]); + else + assert (0); +} + +// _configure + +void _XsMotifSide::_configure (XEvent *event) +{ + XConfigureEvent *ce = (XConfigureEvent*)event; + +/* + Check if window has been resized. If so, generate an expose event + to redraw its contents. +*/ + + if ((_lastW != ce->width) || (_lastH != ce->height)) + { + if ((_base != 0) && XtIsManaged (_base)) + XClearArea (XtDisplay (_base), XtWindow (_base), 0, 0, 0, 0, True); + + _lastW = ce->width; + _lastH = ce->height; + } +} + +// _configureEventHandler + +void _XsMotifSide::_configureEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) +{ + if (event->type == ConfigureNotify) + { + _XsMotifSide *obj = (_XsMotifSide*)clientData; + obj->_configure (event); + } +} + +/* + ---------------------------------------------------------------------------- + _XsMotifButton +*/ + +// Constructor + +_XsMotifButton::_XsMotifButton (const char *name, XsMotifWindow *win, Button button) : + _XsMotifComponent (name, win) +{ + +// Initialize + + _pressed = False; + _button = button; + +// Configure the component + + XtVaSetValues (_base, XmNheight, _buttonSize, XmNwidth, _buttonSize, + XmNborderWidth, (Dimension)0, NULL); +} + +// Destructor + +_XsMotifButton::~_XsMotifButton ( ) +{ + // Empty +} + +// redraw + +void _XsMotifButton::redraw ( ) +{ + +// Make sure component is viewable + + if (!XtIsRealized (_base)) + return; + +// Check if window is viewable + + XWindowAttributes attrs; + XGetWindowAttributes (XtDisplay (_base), XtWindow (_base), &attrs); + + if (attrs.map_state == IsViewable) + _expose (0); // Just pretend we got an expose event +} + +// className + +const char *_XsMotifButton::className ( ) const +{ + return ("_XsMotifButton"); +} + +// _expose + +void _XsMotifButton::_expose (XEvent *event) +{ + Dimension w, h; + +// Get the size of the button + + XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL); + +// Draw the shadow + + _drawShadows (0, 0, w, h, 1, _pressed); + +// Draw the extra line + + _drawLine (1, h - 2, w - 2, h - 2, (_pressed) ? _topShadowGC : _bottomShadowGC); + +// Check if we need to draw the decal + + if ((_button != Maximize) && (event == 0)) + return; + +// Compute the decal size + + Dimension dw, dh; + Boolean reverse = False; + + switch (_button) + { + case Menu: + { + dw = _buttonSize - 6; + dh = 4; + break; + } + case Minimize: + { + dw = dh = 4; + break; + } + case Maximize: + { + dw = _buttonSize - 6; + dh = dw - 1; + + if (_win->maximized ( )) + reverse = True; + + break; + } + default: + assert (0); + } + +// Draw the decal + + _drawShadows ((w / 2) - (dw / 2), (h / 2) - (dh / 2), dw, dh, 1, reverse); +} + +// _input + +void _XsMotifButton::_input (XEvent *event) +{ + static Time lastTime = (Time)0; + + switch (event->type) + { + case ButtonPress: + { + if (event->xbutton.button == 1) + { + _pressed = True; + + if (_button == Menu) + { + +// Get double-click time + + int multiClick = XtGetMultiClickTime (XtDisplay (_base)); + +// Check for double-click + + if ((event->xbutton.time - lastTime) <= multiClick) + { + _win->close ( ); + return; + } + else + lastTime = event->xbutton.time; + +// Redraw the button (pushed-in) + + redraw ( ); + +// Popup the menu + + _win->popupMenu (False); + +// The menu will consume the ButtonRelease, so fake one + + _pressed = False; + redraw ( ); + + } + else if ((_button == Minimize) || (_button == Maximize)) + { + redraw ( ); + } + } + else if (event->xbutton.button == 2) + { + XsMoveOutline move (_win->base ( )); + +// Start the move + + if (move.go ( ) != False) + { + +// Relocate the window + + _win->setPosition (move.x ( ), move.y ( )); + } + } + else if (event->xbutton.button == 3) + _win->popupMenu ( ); + + break; + } + case ButtonRelease: + { + if (event->xbutton.button == 1) + { + _pressed = False; + +// Check if pointer is really in the window + + XButtonEvent *b = &event->xbutton; + Dimension width, height; + Boolean inWindow = False; + + XtVaGetValues (_base, XmNwidth, &width, XmNheight, &height, NULL); + if ((b->x >= 0) && (b->y >= 0) && (b->x < width) && (b->y < height)) + inWindow = True; + + if (_button == Minimize) + { + if (inWindow) + { + if (_win->minimized ( )) + _win->restore ( ); + else + _win->minimize ( ); + } + else + redraw ( ); + } + else if (_button == Maximize) + { + if (inWindow) + { + if (_win->maximized ( )) + _win->restore ( ); + else + _win->maximize ( ); + } + else + redraw ( ); + } + } + break; + } + } +} + +// _map + +void _XsMotifButton::_map ( ) +{ + +// Call the base-class + + _XsMotifComponent::_map ( ); + +// Raise ourself + + XRaiseWindow (XtDisplay (_base), XtWindow (_base)); +} + +/* + ---------------------------------------------------------------------------- + _XsMotifTitle +*/ + +XtResource _XsMotifTitle::_resourceList[] = { + { + "title", + "Title", + XmRString, + sizeof (String), + XtOffset (_XsMotifTitle*, _titleString), + XmRImmediate, + NULL + }, + { + "titleFont", + "TitleFont", + XmRFontStruct, + sizeof (XFontStruct*), + XtOffset (_XsMotifTitle*, _titleFont), + XmRString, + "-*-helvetica-bold-o-normal-*-14-*-*-*-*-*-iso8859-1" + } +}; + +// Constructor + +_XsMotifTitle::_XsMotifTitle (const char *name, XsMotifWindow *win) : + _XsMotifComponent (name, win) +{ + +// Initialize + + _pressed = False; + _titleString = 0; + _titleFont = 0; + _fontGC = 0; + _lastW = _lastH = -1; + +// Get resources + + _getResources (_resourceList, XtNumber (_resourceList)); + +// Copy title string to local memory + + if (_titleString != 0) + { + char *tmp = new char[strlen (_titleString) + 1]; + strcpy (tmp, _titleString); + _titleString = tmp; + } + +// Configure the title + + XtVaSetValues (_base, XmNheight, _buttonSize, XmNborderWidth, + (Dimension)0, NULL); + +// Install event handler + + XtAddEventHandler (_base, StructureNotifyMask, False, _configureEventHandler, (XtPointer)this); +} + +// Destructor + +_XsMotifTitle::~_XsMotifTitle ( ) +{ + if (_fontGC) + XtReleaseGC (_base, _fontGC); + + delete [] _titleString; +} + +// setTitle + +void _XsMotifTitle::setTitle (const char *title) +{ + assert (title != 0); + + delete [] _titleString; + + _titleString = new char[strlen (title) + 1]; + strcpy (_titleString, title); +} + +// className + +const char *_XsMotifTitle::className ( ) const +{ + return ("_XsMotifTitle"); +} + +// _componentDestroyed + +void _XsMotifTitle::_componentDestroyed ( ) +{ + +// Clean up the GCs + + if (_fontGC) + XtReleaseGC (_base, _fontGC); + + _fontGC = 0; + +// Call base-class + + _XsMotifComponent::_componentDestroyed ( ); +} + +// _redraw + +void _XsMotifTitle::_redraw ( ) +{ + _expose (0); // Just pretend we got an expose event +} + +// _expose + +void _XsMotifTitle::_expose (XEvent *event) +{ + +// Clear out the window first + + if (event != 0) + XClearWindow (XtDisplay (_base), XtWindow (_base)); + + Dimension w, h; + +// Get the size of the button + + XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL); + +// Draw the shadow + + _drawShadows (0, 0, w, h, 1, _pressed); + +// Draw the extra line + + _drawLine (1, h - 2, w - 2, h - 2, (_pressed) ? _topShadowGC : _bottomShadowGC); + +// If this is an artificial event, no need continuing + + if (event == 0) + return; + +// Draw the text string + + const int LeftOffset = 5; + const int TopOffset = 2; + +// Figure out the title + + const char *title = (_titleString != 0) ? _titleString : _win->name ( ); + + if ((title != 0) && (title[0] != '\0')) + { + int len = strlen (title); + + XDrawString (XtDisplay (_base), XtWindow (_base), _fontGC, + LeftOffset, TopOffset + _titleFont->ascent, title, len); + } +} + +// _input + +void _XsMotifTitle::_input (XEvent *event) +{ + switch (event->type) + { + case ButtonPress: + { + switch (event->xbutton.button) + { + case 1: + { + _pressed = True; + _redraw ( ); + break; + } + case 2: + { + XsMoveOutline move (_win->base ( )); + +// Start the move + + if (move.go ( ) != False) + { + +// Relocate the window + + _win->setPosition (move.x ( ), move.y ( )); + } + break; + } + case 3: + { + _win->popupMenu ( ); + break; + } + } + break; + } + case ButtonRelease: + { + switch (event->xbutton.button) + { + case 1: + case 2: + { + _pressed = False; + _redraw ( ); + + _win->raise ( ); + break; + } + } + break; + } + case MotionNotify: + { + XsMoveOutline move (_win->base ( )); + +// Start the move + + if (move.go ( ) != False) + { + +// Relocate the window + + _win->setPosition (move.x ( ), move.y ( )); + +// Redraw the title bar + + _pressed = False; + _redraw ( ); + } + break; + } + } +} + +// _map + +void _XsMotifTitle::_map ( ) +{ + +// Call the base-class + + _XsMotifComponent::_map ( ); + +// Raise ourself + + XRaiseWindow (XtDisplay (_base), XtWindow (_base)); + + unsigned long valuemask; + XGCValues values; + Pixel foreground; + Pixel background; + +// Get the pixels + + XtVaGetValues (_win->base ( ), XmNforeground, &foreground, XmNbackground, &background, NULL); + +// Create the font graphics context + + valuemask = GCForeground | GCBackground | GCGraphicsExposures | GCFont; + + values.foreground = foreground; + values.background = background; + values.font = _titleFont->fid; + values.graphics_exposures = False; + + _fontGC = XtGetGC (_base, valuemask, &values); +} + +// _configure + +void _XsMotifTitle::_configure (XEvent *event) +{ + XConfigureEvent *ce = (XConfigureEvent*)event; + +/* + Check if window has been resized. If so, generate an expose event + to redraw its contents. +*/ + + if ((_lastW != ce->width) || (_lastH != ce->height)) + { + if ((_base != 0) && XtIsManaged (_base)) + XClearArea (XtDisplay (_base), XtWindow (_base), 0, 0, 0, 0, True); + + _lastW = ce->width; + _lastH = ce->height; + } +} + +// _configureEventHandler + +void _XsMotifTitle::_configureEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) +{ + if (event->type == ConfigureNotify) + { + _XsMotifTitle *obj = (_XsMotifTitle*)clientData; + obj->_configure (event); + } +} + +/* + ---------------------------------------------------------------------------- + _XsMotifIcon +*/ + +XtResource _XsMotifIcon::_resourceList[] = { + { + "iconSize", + "IconSize", + XmRDimension, + sizeof (Dimension), + XtOffset (_XsMotifIcon*, _iconSize), + XmRImmediate, + (XtPointer)IconSize_ + }, + { + "iconName", + "IconName", + XmRString, + sizeof (String), + XtOffset (_XsMotifIcon*, _iconName), + XmRImmediate, + NULL + }, + { + "iconFont", + "IconFont", + XmRFontStruct, + sizeof (XFontStruct*), + XtOffset (_XsMotifIcon*, _iconFont), + XmRString, + "-*-helvetica-bold-r-normal-*-12-*-*-*-*-*-iso8859-1" + }, + { + XmNiconX, + XmCIconX, + XmRPosition, + sizeof (Position), + XtOffset (_XsMotifIcon*, _iconX), + XmRImmediate, + (XtPointer)-1 + }, + { + XmNiconY, + XmCIconY, + XmRPosition, + sizeof (Position), + XtOffset (_XsMotifIcon*, _iconY), + XmRImmediate, + (XtPointer)-1 + } +}; + +// Constructor + +_XsMotifIcon::_XsMotifIcon (const char *name, XsMotifWindow *win, Widget parent) : + _XsMotifComponent (name, win, parent) +{ + +// Initialize + + _pixmapGC = 0; + _fontGC = 0; + + _iconName = 0; + _pixmap = 0; + _freePixmap = False; + + _width = _height = 0; + _placed = 0; + +// Get resources + + _getResources (_resourceList, XtNumber (_resourceList)); + +// Copy icon name to local memory + + if (_iconName != 0) + { + char *tmp = new char[strlen (_iconName) + 1]; + strcpy (tmp, _iconName); + _iconName = tmp; + } + +// Configure the icon + + XtVaSetValues (_base, XmNwidth, _iconSize, XmNheight, _iconSize, NULL); +} + +// Destructor + +_XsMotifIcon::~_XsMotifIcon ( ) +{ + if (_fontGC) + XtReleaseGC (_base, _fontGC); + + if (_pixmapGC) + XtReleaseGC (_base, _pixmapGC); + + if (_freePixmap) + XFreePixmap (XtDisplay (_base), _pixmap); + + delete [] _iconName; +} + +// show + +void _XsMotifIcon::show ( ) +{ + +/* + Configure the icon position. Either use the position specified + in the resource, or place the icon at the top-left corner of the + window. +*/ + + if (_placed == False) + { + Position x, y; + + if (_iconX == -1) + { + XtVaGetValues (_win->base ( ), XmNx, &x, NULL); + if (x < 0) x = 0; + _iconX = x; + } + else + x = _iconX; + + if (_iconY == -1) + { + XtVaGetValues (_win->base ( ), XmNy, &y, NULL); + if (y < 0) y = 0; + _iconY = y; + } + else + y = _iconY; + + XtVaSetValues (_base, XmNx, x, XmNy, y, NULL); + + _placed = True; + } + +// Call the base class + + _XsMotifComponent::show ( ); +} + +// setIconName + +void _XsMotifIcon::setIconName (const char *iconName) +{ + assert (iconName != 0); + + delete [] _iconName; + + _iconName = new char[strlen (iconName) + 1]; + strcpy (_iconName, iconName); +} + +// setPixmap + +void _XsMotifIcon::setPixmap (Pixmap pixmap) +{ + assert (pixmap != 0); + +// Free the existing pixmap (if necessary) + + if (_freePixmap) + { + XFreePixmap (XtDisplay (_base), _pixmap); + _freePixmap = False; + } + +// Save the new pixmap + + _pixmap = pixmap; + +// Get the pixmap width and height + + Window dummy; + int xd, yd; + unsigned int uw, uh, ub, ud; + + XGetGeometry (XtDisplay (_base), _pixmap, &dummy, &xd, &yd, &uw, &uh, &ub, &ud); + + _width = uw; + _height = uh; +} + +// className + +const char *_XsMotifIcon::className ( ) const +{ + return ("_XsMotifIcon"); +} + +// _componentDestroyed + +void _XsMotifIcon::_componentDestroyed ( ) +{ + +// Clear up the GCs + + if (_fontGC) + XtReleaseGC (_base, _fontGC); + + if (_pixmapGC) + XtReleaseGC (_base, _pixmapGC); + + if (_freePixmap) + XFreePixmap (XtDisplay (_base), _pixmap); + + _fontGC = 0; + _pixmapGC = 0; + _freePixmap = 0; + +// Call the base-class + + _XsMotifComponent::_componentDestroyed ( ); +} + +// _input + +void _XsMotifIcon::_input (XEvent *event) +{ + static Time lastTime = (Time)0; + + switch (event->type) + { + case ButtonPress: + { + switch (event->xbutton.button) + { + case 1: + break; + + case 2: + { + XsMoveOutline move (_base); + +// Start the move + + if (move.go ( ) != False) + { + +// Relocate the window + + _win->setPosition (move.x ( ), move.y ( )); + } + break; + } + case 3: + { + _win->popupMenu ( ); + break; + } + } + break; + } + case ButtonRelease: + { + switch (event->xbutton.button) + { + case 1: + { + +// Get double-click time + + int multiClick = XtGetMultiClickTime (XtDisplay (_base)); + +// Check for double-click + + if ((event->xbutton.time - lastTime) <= multiClick) + _win->restore ( ); + else + { + lastTime = event->xbutton.time; + _win->raise ( ); + } + break; + } + } + break; + } + case MotionNotify: + { + XsMoveOutline move (_base); + +// Start the move + + if (move.go ( ) != False) + { + +// Relocate the icon + + _win->setPosition (move.x ( ), move.y ( )); + } + break; + } + } +} + +// _expose + +void _XsMotifIcon::_expose (XEvent *) +{ + Dimension iconHeight; + Dimension iconWidth; + +// Compute icon size + + XtVaGetValues (_base, XmNwidth, &iconWidth, XmNheight, &iconHeight, NULL); + +// Draw the shadow + + _drawShadows (0, 0, iconWidth, iconHeight, 2); + +// Figure out the icon string + + const char *iconName = (_iconName != 0) ? _iconName : (_win->title ( ) != 0) ? + _win->title ( ) : _win->name ( ); + + const int fontX = 3; + const int fontY = 3; + + if ((iconName != 0) && (iconName[0] != '\0')) + { + int textWidth; + int len = strlen (iconName); + +// Compute the text size + + textWidth = XTextWidth (_iconFont, iconName, len); + +// Center the text in the bottom of the icon (or left-justify it) + + int x, y; + + if (textWidth <= (iconWidth - (fontX * 2))) + x = (iconWidth - (int)textWidth) / 2; + else + x = fontX; + + y = (int)iconHeight - _iconFont->descent - fontY; + +// Draw the string + + XDrawString (XtDisplay (_base), XtWindow (_base), _fontGC, + x, y, iconName, len); + } + +// Compute label size + + int labelHeight = _iconFont->descent + _iconFont->ascent + (fontY * 2); + + if (labelHeight >= (iconHeight - 6)) + return; + +// Draw the separator + + int sepY = (iconHeight) - labelHeight; + + _drawLine (1, sepY, iconWidth - 2, sepY, _bottomShadowGC); + _drawLine (1, sepY + 1, iconWidth - 2, sepY + 1, _topShadowGC); + +// Draw the pixmap frame + + const int frameX = 4; + const int frameY = 4; + + if ((frameX + 6) >= sepY) + return; + + int frameWidth = iconWidth - (frameX * 2); + int frameHeight = sepY - frameY - 2; + + _drawShadows (frameX, frameY, frameWidth, frameHeight, 1, True); + + frameWidth -= 2; + frameHeight -= 2; + + _drawShadows (frameX + 1, frameY + 1, frameWidth, frameHeight, 1); + + frameWidth -= 2; + frameHeight -= 2; + +// Blit the pixmap + + if (_pixmap != 0) + { + if ((frameWidth > 0) && (frameHeight > 0)) + { + int origX, origY; + int drawW, drawH; + +// Center the pixmap or top-left orient it + + if (frameWidth > _width) + { + origX = (frameWidth - _width) / 2; + origX += frameX + 2; + drawW = _width; + } + else + { + origX = frameX + 2; + drawW = frameWidth; + } + + if (frameHeight > _height) + { + origY = (frameHeight - _height) / 2; + origY += frameY + 2; + drawH = _height; + } + else + { + origY = frameY + 2; + drawH = frameHeight; + } + + XCopyArea (XtDisplay (_base), _pixmap, XtWindow (_base), _pixmapGC, + 0, 0, drawW, drawH, origX, origY); + } + } +} + +// _map + +void _XsMotifIcon::_map ( ) +{ + unsigned long valuemask; + XGCValues values; + Pixel fg; + Pixel bg; + int depth; + +// Call the base-class + + _XsMotifComponent::_map ( ); + +// Get the icon pixels + + XtVaGetValues (_win->base ( ), XmNdepth, &depth, XmNbackground, &bg, + XmNforeground, &fg, NULL); + +// Create the default icon pixmap + + if (_pixmap == 0) + { + _pixmap = XCreatePixmapFromBitmapData (XtDisplay (_base), XtWindow (_base), + xs_motif_icon_bits, xs_motif_icon_width, xs_motif_icon_height, + fg, bg, depth); + +// Set this pixmap + + setPixmap (_pixmap); + + _freePixmap = True; + +// Create the icon pixmap graphics context + + valuemask = GCGraphicsExposures | GCForeground | GCBackground; + + values.graphics_exposures = False; + values.foreground = fg; + values.background = bg; + + _pixmapGC = XtGetGC (_base, valuemask, &values); + } + +// Create the font graphics context + + valuemask = GCForeground | GCBackground | GCGraphicsExposures | GCFont; + + values.foreground = fg; + values.background = bg; + values.font = _iconFont->fid; + values.graphics_exposures = False; + + _fontGC = XtGetGC (_base, valuemask, &values); +} + +/* + ---------------------------------------------------------------------------- + _XsMotifMenu +*/ + +// Static definitions + +int _XsMotifMenu::_count = 0; +Cursor _XsMotifMenu::_cursor = None; +Pixmap _XsMotifMenu::_stipple = None; +Display *_XsMotifMenu::_dpy = 0; + +// Resources + +XtResource _XsMotifMenu::_resourceList[] = { + { + "saveUnder", + "SaveUnder", + XmRBoolean, + sizeof (Boolean), + XtOffset (_XsMotifMenu*, _saveUnder), + XmRImmediate, + (XtPointer)True + }, + { + "restoreString", + "RestoreString", + XmRString, + sizeof (String), + XtOffset (_XsMotifMenu*, _strings[Restore]), + XmRString, + "Restore" + }, + { + "moveString", + "MoveString", + XmRString, + sizeof (String), + XtOffset (_XsMotifMenu*, _strings[Move]), + XmRString, + "Move" + }, + { + "sizeString", + "SizeString", + XmRString, + sizeof (String), + XtOffset (_XsMotifMenu*, _strings[Size]), + XmRString, + "Size" + }, + { + "minimizeString", + "MinimizeString", + XmRString, + sizeof (String), + XtOffset (_XsMotifMenu*, _strings[Minimize]), + XmRString, + "Minimize" + }, + { + "maximizeString", + "MaximizeString", + XmRString, + sizeof (String), + XtOffset (_XsMotifMenu*, _strings[Maximize]), + XmRString, + "Maximize" + }, + { + "raiseString", + "RaiseString", + XmRString, + sizeof (String), + XtOffset (_XsMotifMenu*, _strings[Raise]), + XmRString, + "Raise" + }, + { + "lowerString", + "LowerString", + XmRString, + sizeof (String), + XtOffset (_XsMotifMenu*, _strings[Lower]), + XmRString, + "Lower" + }, + { + "closeString", + "CloseString", + XmRString, + sizeof (String), + XtOffset (_XsMotifMenu*, _strings[Close]), + XmRString, + "Close" + }, + { + "menuFont", + "menuFont", + XmRFontStruct, + sizeof (XFontStruct*), + XtOffset (_XsMotifMenu*, _menuFont), + XmRString, + "-*-helvetica-bold-o-normal-*-14-*-*-*-*-*-iso8859-1" + } +}; + +// Constructor + +_XsMotifMenu::_XsMotifMenu (const char *name, XsMotifWindow *win) : + _XsMotifBase (name, win) +{ + +// Create the cursor (if necessary) + + if (_count++ == 0) + { + +// Create the menu cursor + + _cursor = XCreateFontCursor (XtDisplay (win->base ( )), XC_arrow); + +// Create a stippled pixmap + + Widget parent = _win->base ( ); + Pixel foreground; + Pixel background; + int depth; + + XtVaGetValues (parent, XmNforeground, &foreground, XmNbackground, + &background, XmNdepth, &depth, NULL); + + const int pixmapWidth = 2; + const int pixmapHeight = 2; + static unsigned char pixmapBits[] = { 0x02, 0x01 }; + + _dpy = XtDisplay (parent); + _stipple = XCreatePixmapFromBitmapData (_dpy, DefaultRootWindow (_dpy), + (char*)pixmapBits, pixmapWidth, pixmapHeight, foreground, background, + depth); + } + +// Initialize + + _fontGC = 0; + _grayGC = 0; + _backgroundGC = 0; + +// Create the component (why doesn't overrideShell work?) + + _base = XtVaCreatePopupShell (_name, topLevelShellWidgetClass, + XtParent (_win->base ( )), XmNoverrideRedirect, True, + XmNborderWidth, 1, NULL); + +// Install destroy handler + + _installDestroyHandler ( ); + +// Install event handler ('cause we never call _XsMotifBase::show) + + XtAddEventHandler (_base, StructureNotifyMask, False, _mapEventHandler, (XtPointer)this); + +// Get resources + + _getResources (_resourceList, XtNumber (_resourceList)); + +// Get the background color + + Pixel bg; + + XtVaGetValues (_win->base ( ), XmNbackground, &bg, NULL); + +// Compute the size of the (largest) menu item + + int textHeight = _menuFont->ascent + _menuFont->descent; + int textWidth = 0; + int tmp; + + for (int loop = 0; loop < Num; loop++) + { + tmp = XTextWidth (_menuFont, _strings[loop], strlen (_strings[loop])); + + if (tmp > textWidth) + textWidth = tmp; + } + +// Put a border around the buttons + + textWidth += (2 * HorizTextOffset); + textHeight += (2 * VertTextOffset); + +/* + The menu height is the menu-shadow (1 pixel on top and bottom) + the + items themselves. +*/ + + int menuHeight = (2 * ShadowThickness) + // Top and bottom shadow + (textHeight * Num); // The menu items + +/* + The menu width is the menu-shadow (1 pixel on the left and right) + + the largest menu text (calculated above) +*/ + + int menuWidth = (2 * ShadowThickness) + // Left and right shadow + textWidth; // Largest text item + +// Configure the popup + + XtVaSetValues (_base, XmNsaveUnder, _saveUnder, XmNwidth, menuWidth, + XmNheight, menuHeight, NULL); +} + +// Destructor + +_XsMotifMenu::~_XsMotifMenu ( ) +{ + if (_fontGC) + XtReleaseGC (_base, _fontGC); + + if (_grayGC) + XtReleaseGC (_base, _grayGC); + + if (_backgroundGC) + XtReleaseGC (_base, _backgroundGC); + +// Free the pixmap (if necessary) + + if (--_count == 0) + XFreePixmap (_dpy, _stipple); +} + +// popup + +void _XsMotifMenu::popup (Boolean atPointer) +{ + assert (_base != 0); + + Position x, y; + +// Compute the location of the menu. + + if (atPointer) + { + unsigned int mask; + Window win; + int winX, winY; + int rootX, rootY; + +// Menu at pointer location + + XQueryPointer (XtDisplay (_base), XtWindow (XtParent (_base)), + &win, &win, &rootX, &rootY, &winX, &winY, &mask); + + x = (Position)rootX; + y = (Position)rootY; + } + else + { + +// Menu at top-left corner of client area + + XtTranslateCoords (_win->clientArea ( ), 0, 0, &x, &y); + } + +// Move the menu + + XtVaSetValues (_base, XmNx, x, XmNy, y, NULL); + +// Initialize the item + + _curItem = NoItem; + +// Pop it up + + XtPopup (_base, XtGrabNone); + +// Grab the pointer + + if (_grabPointer ( ) == FALSE) + return; + +// Update the menu + + _processEvents ( ); + +// Pop the menu down + + XtPopdown (_base); + +// Ungrab the pointer + + _ungrabPointer ( ); + + if (_curItem != NoItem) + { + +/* + Post a work-proc to process this item. This will allow everything + to get caught up before we process the menu item +*/ + + XtAppContext appContext = XtWidgetToApplicationContext (_base); + XtAppAddWorkProc (appContext, _workProc, (XtPointer)this); + } +} + +// className + +const char *_XsMotifMenu::className ( ) const +{ + return ("_XsMotifMenu"); +} + +// _componentDestroyed + +void _XsMotifMenu::_componentDestroyed ( ) +{ + +// Clean up the GCs + + if (_fontGC) + XtReleaseGC (_base, _fontGC); + + if (_grayGC) + XtReleaseGC (_base, _grayGC); + + if (_backgroundGC) + XtReleaseGC (_base, _backgroundGC); + + _fontGC = 0; + _grayGC = 0; + _backgroundGC = 0; + +// Call the base-class + + _XsMotifBase::_componentDestroyed ( ); +} + +// _processEvents + +void _XsMotifMenu::_processEvents ( ) +{ + assert (_base != 0); + + XtAppContext appContext = XtWidgetToApplicationContext (_base); + XEvent event; + Display *dpy = XtDisplay (_base); + int done = 0; + + while (!done) + { + XtAppNextEvent (appContext, &event); + +// Process this event + + switch (event.type) + { + case ButtonRelease: + { + done = 1; + break; + } + case Expose: + { + _redrawMenu ( ); + break; + } + case MotionNotify: + { + XEvent next; + +// Process only the last motion event + + while (XPending (dpy) > 0) + { + XPeekEvent (dpy, &next); + if (next.type != MotionNotify) + break; + XtAppNextEvent (appContext, &event); + } + +// Track the mouse and toggle the menu items + + Item item = _trackPointer ((XMotionEvent*)&event); + +// Unselect the current item (if the item is different) + + if (item != _curItem) + { + _toggleItem (_curItem, False); + +// Select the new item + + _toggleItem ((_curItem = item), True); + } + + break; + } + default: + { + XtDispatchEvent (&event); + break; + } + } + } +} + +// _processItem + +void _XsMotifMenu::_processItem (Item item) +{ + if (item == NoItem) + return; + + switch (item) + { + case Restore: + { + _win->restore ( ); + break; + } + case Move: + { + Widget base = (_win->minimized ( )) ? _win->icon ( ) : _win->base ( ); + +// Warp the pointer to the center of the window + + Dimension width, height; + XtVaGetValues (base, XmNwidth, &width, XmNheight, &height, NULL); + + XWarpPointer (XtDisplay (_base), None, XtWindow (base), 0, 0, 0, 0, + (width / 2), (height / 2)); + +// Move the window + + XsMoveOutline move (base); + +// Start the move + + if (move.go (True) != False) + { + +// Relocate the window + + _win->setPosition (move.x ( ), move.y ( )); + } + break; + } + case Size: + { + Widget base = (_win->minimized ( )) ? _win->icon ( ) : _win->base ( ); + +// Warp the pointer to the center of the window + + Dimension width, height; + XtVaGetValues (base, XmNwidth, &width, XmNheight, &height, NULL); + + XWarpPointer (XtDisplay (_base), None, XtWindow (base), 0, 0, 0, 0, + (width / 2), (height / 2)); + +// Resize the window + + XsResizeOutline resize (_win->base ( ), XsResizeOutline::Undetermined); + resize.setMinSize (_win->minWidth ( ), _win->minHeight ( )); + +// Start the resize + + if (resize.go (True) != False) + { + +// Relocate the window + + _win->setPosition (resize.x ( ), resize.y ( )); + _win->setSize (resize.width ( ), resize.height ( )); + } + break; + } + case Minimize: + { + _win->minimize ( ); + break; + } + case Maximize: + { + _win->maximize ( ); + break; + } + case Raise: + { + _win->raise ( ); + break; + } + case Lower: + { + _win->lower ( ); + break; + } + case Close: + { + _win->close ( ); + break; + } + default: + assert (0); + } +} + +// _redrawMenu + +void _XsMotifMenu::_redrawMenu ( ) +{ + Dimension w, h; + +// Get the size of the menu + + XtVaGetValues (_base, XmNwidth, &w, XmNheight, &h, NULL); + +// Draw a shadow around the menu + + _drawShadows (0, 0, w, h, ShadowThickness); + +// Cycle and draw all of the elements + + for (int loop = 0; loop < Num; loop++) + _redrawItem ((Item)loop); +} + +// _redrawItem + +void _XsMotifMenu::_redrawItem (Item item) +{ + if (item == NoItem) + return; + + int x = ShadowThickness + HorizTextOffset; + int y; + +/* + Compute the y-position of the element. This will be the size of the + top-shadow + the items before it + the offset of the item itself +*/ + + y = ShadowThickness + // Top shadow + (item * ((VertTextOffset * 2) + (_menuFont->descent + _menuFont->ascent))) + + (VertTextOffset + _menuFont->ascent); // The item iteself + +// Figure out the graphics-context + + GC gc; + + if (_win->minimized ( )) + gc = ((item == Size) || (item == Minimize)) ? _grayGC : _fontGC; + else if (_win->maximized ( )) + gc = (item == Maximize) ? _grayGC : _fontGC; + else + gc = (item == Restore) ? _grayGC : _fontGC; + +// Draw the string + + XDrawString (XtDisplay (_base), XtWindow (_base), gc, x, y, + _strings[item], strlen (_strings[item])); +} + +// _toggleItem + +void _XsMotifMenu::_toggleItem (Item item, Boolean active) +{ + if (item == NoItem) + return; + +/* + Either draw the background of the specified item in the active color + or the standard background color +*/ + + GC gc = (active) ? _topShadowGC : _backgroundGC; + +// Get the width of the menu + + Dimension menuWidth; + XtVaGetValues (_base, XmNwidth, &menuWidth, NULL); + +// Compute the location and size of the rectangle + + int x, y; + unsigned int width, height; + + x = ShadowThickness; + height = ((VertTextOffset * 2) + (_menuFont->descent + _menuFont->ascent)); + y = ShadowThickness + (item * height); + width = menuWidth - (2 * ShadowThickness); + +// Draw the filled rectangle + + XFillRectangle (XtDisplay (_base), XtWindow (_base), gc, x, y, width, height); + +// Redraw the text + + _redrawItem (item); +} + +// _trackPointer + +_XsMotifMenu::Item _XsMotifMenu::_trackPointer (XMotionEvent *event) +{ + assert (_base != 0); + + Dimension menuWidth; + Dimension menuHeight; + Position x, y; + +// Get the menu size and position + + XtVaGetValues (_base, XmNwidth, &menuWidth, XmNheight, &menuHeight, + XmNx, &x, XmNy, &y, NULL); + +// Make sure the pointer is in the menu + + if ((event->x_root < x) || (event->x_root > (x + menuWidth))) + return (NoItem); + + if ((event->y_root < y) || (event->y_root > (y + menuHeight))) + return (NoItem); + +// Make sure the pointer is on the confines of the shadow + + if ((event->x < ShadowThickness) || (event->x > (menuWidth - (2 * ShadowThickness)))) + return (NoItem); + + if ((event->y < ShadowThickness) || (event->y > (menuHeight - (2 * ShadowThickness)))) + return (NoItem); + +/* + Now we are just concerned with the y-position. Subtract off the + shadow thickness to normalize the location +*/ + + int yPos = event->y - ShadowThickness; + +// Compute which item the mouse is in + + int itemHeight = (VertTextOffset * 2) + (_menuFont->descent + _menuFont->ascent); + + Item item = (Item)(yPos / itemHeight); + +// Validate that the item is not grayed-out + + if (_win->minimized ( )) + { + if ((item == Size) || (item == Minimize)) + item = NoItem; + } + else if (_win->maximized ( )) + { + if (item == Maximize) + item = NoItem; + } + else if (item == Restore) + item = NoItem; + + return (item); +} + +// _grabPointer + +Boolean _XsMotifMenu::_grabPointer ( ) +{ + +// Sync everything up before being grabby + + XSync (XtDisplay (_base), False); + +// Grab the pointer + + if (XGrabPointer (XtDisplay (_base), XtWindow (_base), False, + (unsigned int)(ButtonPressMask | ButtonReleaseMask | PointerMotionMask | + EnterWindowMask | LeaveWindowMask), GrabModeAsync, + GrabModeAsync, None, _cursor, CurrentTime) != GrabSuccess) + { + XBell (XtDisplay (_base), 100); + return (False); + } + + return (True); +} + +// _ungrabPointer + +void _XsMotifMenu::_ungrabPointer ( ) +{ + +// Ungrab the pointer + + XUngrabPointer (XtDisplay (_base), CurrentTime); + +// Sync everything back up + + XSync (XtDisplay (_base), False); +} + +// _map + +void _XsMotifMenu::_map ( ) +{ + +// Call the base-class + + _XsMotifBase::_map ( ); + + unsigned long valuemask; + XGCValues values; + Pixel foreground; + Pixel background; + +// Get the pixels + + XtVaGetValues (XtParent (_base), XmNforeground, &foreground, NULL); + XtVaGetValues (_base, XmNbackground, &background, NULL); + +// Create the font graphics context + + valuemask = GCForeground | GCBackground | GCGraphicsExposures | GCFont; + + values.foreground = foreground; + values.background = background; + values.font = _menuFont->fid; + values.graphics_exposures = False; + + _fontGC = XtGetGC (_base, valuemask, &values); + +// Create the insensitive font graphics context + + valuemask |= (GCFillStyle | GCTile); + + values.fill_style = FillTiled; + values.tile = _stipple; + + _grayGC = XtGetGC (_base, valuemask, &values); + +// Create the background contexts + + valuemask = GCForeground | GCLineWidth | GCGraphicsExposures; + values.line_width = 0; + values.graphics_exposures = False; + values.foreground = background; + + _backgroundGC = XtGetGC (_base, valuemask, &values); +} + +// _workProc + +Boolean _XsMotifMenu::_workProc (XtPointer clientData) +{ + _XsMotifMenu *obj = (_XsMotifMenu*)clientData; + if (obj->_curItem != NoItem) + obj->_processItem (obj->_curItem); + + return (True); +} + +/* + ---------------------------------------------------------------------------- + XsMotifWindow +*/ + +// Static definitions + +XtResource XsMotifWindow::_resourceList[] = { + { + "showBorder", + "ShowBorder", + XmRBoolean, + sizeof (Boolean), + XtOffset (XsMotifWindow*, _showBorder), + XmRImmediate, + (XtPointer)True + }, + { + "showResize", + "ShowResize", + XmRBoolean, + sizeof (Boolean), + XtOffset (XsMotifWindow*, _showResize), + XmRImmediate, + (XtPointer)True + }, + { + "showTitle", + "ShowTitle", + XmRBoolean, + sizeof (Boolean), + XtOffset (XsMotifWindow*, _showTitle), + XmRImmediate, + (XtPointer)True + }, + { + "showMenu", + "ShowMenu", + XmRBoolean, + sizeof (Boolean), + XtOffset (XsMotifWindow*, _showMenu), + XmRImmediate, + (XtPointer)True + }, + { + "showMinimize", + "ShowMinimize", + XmRBoolean, + sizeof (Boolean), + XtOffset (XsMotifWindow*, _showMinimize), + XmRImmediate, + (XtPointer)True + }, + { + "showMaximize", + "ShowMaximize", + XmRBoolean, + sizeof (Boolean), + XtOffset (XsMotifWindow*, _showMaximize), + XmRImmediate, + (XtPointer)True + }, + { + "lowerOnIconify", + "LowerOnIconify", + XmRBoolean, + sizeof (Boolean), + XtOffset (XsMotifWindow*, _lowerOnIconify), + XmRImmediate, + (XtPointer)False + }, + { + XmNminWidth, + XmCMinWidth, + XmRDimension, + sizeof (Dimension), + XtOffset (XsMotifWindow*, _minW), + XmRImmediate, + (XtPointer)((BorderSize_ + ButtonSize_) * 3) + }, + { + XmNmaxWidth, + XmCMaxWidth, + XmRDimension, + sizeof (Dimension), + XtOffset (XsMotifWindow*, _maxW), + XmRImmediate, + (XtPointer)-1 + }, + { + XmNminHeight, + XmCMinHeight, + XmRDimension, + sizeof (Dimension), + XtOffset (XsMotifWindow*, _minH), + XmRImmediate, + (XtPointer)((BorderSize_ + ButtonSize_) * 3) + }, + { + XmNmaxHeight, + XmCMaxHeight, + XmRDimension, + sizeof (Dimension), + XtOffset (XsMotifWindow*, _maxH), + XmRImmediate, + (XtPointer)-1 + } +}; + +// Constructor + +XsMotifWindow::XsMotifWindow (const char *name) : XsMDIWindow (name) +{ + int loop; + +// Initialize + + for (loop = 0; loop < _XsMotifSide::Max; loop++) + { + _corners[loop] = 0; + _sides[loop] = 0; + } + + for (loop = 0; loop < _XsMotifButton::Max; loop++) + _buttons[loop] = 0; + + _title = 0; + _icon = 0; + _menu = 0; + + _maximized = False; + _minimized = False; +} + +// Destructor + +XsMotifWindow::~XsMotifWindow ( ) +{ + int loop; + + for (loop = 0; loop < _XsMotifSide::Max; loop++) + { + delete _corners[loop]; + delete _sides[loop]; + } + + for (loop = 0; loop < _XsMotifButton::Max; loop++) + delete _buttons[loop]; + + delete _title; + delete _icon; + delete _menu; +} + +// raise + +void XsMotifWindow::raise ( ) +{ + Widget w = (_minimized == True) ? _icon->base ( ) : _base; + assert (w != 0); + XRaiseWindow (XtDisplay (w), XtWindow (w)); +} + +// lower + +void XsMotifWindow::lower ( ) +{ + Widget w = (_minimized == True) ? _icon->base ( ) : _base; + assert (w != 0); + XLowerWindow (XtDisplay (w), XtWindow (w)); +} + +// minimize + +void XsMotifWindow::minimize ( ) +{ + assert (_base != 0); + +// Check if we are already minimized + + if (_minimized == True) + return; + +// Minimize the window + + hide ( ); + + _minimized = True; + +// Lower (if necessary) + + if (_lowerOnIconify) + lower ( ); + + _icon->show ( ); +} + +// maximize + +void XsMotifWindow::maximize ( ) +{ + assert (_base != 0); + +// Check if we are already in this state + + if (_maximized == True) + return; + +// Restore (if necessary) + + if (_minimized) + restore ( ); + +// Save current dimensions + + XtVaGetValues (_base, XmNx, &_savedX, XmNy, &_savedY, XmNwidth, + &_savedWidth, XmNheight, &_savedHeight, NULL); + +/* + Constrain the new window size. The size of the maximized window + is equal to the size of the current clip-window of the canvas. +*/ + + const Dimension offset = 5; // Border around max'd window + + Widget clipWindow = XtParent (XtParent (_base)); + assert (clipWindow != 0); + Dimension clipW, clipH; + Window child; + int newX, newY; + + XtVaGetValues (clipWindow, XmNheight, &clipH, XmNwidth, &clipW, NULL); + +// Add in offset + + if (clipW > (offset * 2)) + clipW -= (offset * 2); + + if (clipH > (offset * 2)) + clipH -= (offset * 2); + +// Compute the new window position (map clip-window to work-area) + + XTranslateCoordinates (XtDisplay (_base), XtWindow (clipWindow), + XtWindow (XtParent (_base)), (int)offset, (int)offset, + &newX, &newY, &child); + +// Set new maximum dimensions + + setPosition ((Position)newX, (Position)newY); + setSize (clipW, clipH); + + _maximized = True; + +// Redraw the maximize button + + _buttons[_XsMotifButton::Maximize]->redraw ( ); +} + +// restore + +void XsMotifWindow::restore ( ) +{ + assert (_base != 0); + +// Check if we are already restored + + if ((_maximized == False) && (_minimized == False)) + return; + +// Either un-minimize or un-maximize + + if (_minimized) + { + +// Restore the window + + _icon->hide ( ); + _minimized = False; + +// If maximized, restore again + + if (_maximized) + restore ( ); + +// Show the window + + show ( ); + } + else + { + +// Restore saved dimensions + + setPosition (_savedX, _savedY); + setSize (_savedWidth, _savedHeight); + + _maximized = False; + +// Redraw the maximize button + + _buttons[_XsMotifButton::Maximize]->redraw ( ); + } +} + +// close + +void XsMotifWindow::close ( ) +{ + +/* + Don't delete the window (because its not ours to delete). + Just hide it. +*/ + + if (_minimized) + _icon->hide ( ); + else + hide ( ); +} + +// setTitle + +void XsMotifWindow::setTitle (const char *title) +{ + if (_title != 0) + _title->setTitle (title); +} + +// setIconName + +void XsMotifWindow::setIconName (const char *iconName) +{ + if (_icon != 0) + _icon->setIconName (iconName); +} + +// setPixmap + +void XsMotifWindow::setPixmap (Pixmap pixmap) +{ + if (_icon != 0) + _icon->setPixmap (pixmap); +} + +// popupMenu + +void XsMotifWindow::popupMenu (Boolean b) +{ + if (_menu != 0) + _menu->popup (b); +} + +// setPosition + +void XsMotifWindow::setPosition (Position x, Position y) +{ + if (_base != 0) + { + Widget w = (_minimized == True) ? _icon->base ( ) : _base; + assert (w != 0); + XtVaSetValues (w, XmNx, x, XmNy, y, NULL); + } + else + XsMDIWindow::setPosition (x, y); // Cache the points +} + +// setSize + +void XsMotifWindow::setSize (Dimension w, Dimension h) +{ + +// Set the window size + + if (_base != 0) + { + if (w < _minW) + w = _minW; + else if ((_maxW != (Dimension)-1) && (w > _maxW)) + w = _maxW; + + if (h < _minH) + h = _minH; + else if ((_maxH != (Dimension)-1) && (h > _maxH)) + h = _maxH; + + if (_minimized == False) + XtVaSetValues (_base, XmNwidth, w, XmNheight, h, NULL); + } + else + XsMDIWindow::setSize (w, h); // Cache the points +} + +// className + +const char* XsMotifWindow::className ( ) const +{ + return ("XsMotifWindow"); +} + +// _createWindow + +void XsMotifWindow::_createWindow (Widget parent) +{ + assert (parent != 0); + +// Create the window frame + + _base = XtVaCreateWidget (_name, xmFormWidgetClass, parent, + XmNborderWidth, (Dimension)1, NULL); + +// Install destroy handler + + _installDestroyHandler ( ); + +// Get resources + + _getResources (_resourceList, XtNumber (_resourceList)); + +/* + Fix configuration inter-dependencies. Here are the rules: + + 1) If there is no border, then there are no resize handles + 2) If there is no title, then there are no buttons (would look stupid) +*/ + + if (_showBorder == False) + _showResize = False; + + if (_showTitle == False) + { + _showMenu = False; + _showMinimize = False; + _showMaximize = False; + } + +/* + Corners +*/ + + if (_showResize) + { + +// Top-Left + + _corners[_XsMotifCorner::TopLeft] = new _XsMotifCorner ("topLeft", this, _XsMotifCorner::TopLeft); + + XtVaSetValues (_corners[_XsMotifCorner::TopLeft]->base ( ), XmNtopAttachment, + XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, + XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, NULL); + +// Top-Right + + _corners[_XsMotifCorner::TopRight] = new _XsMotifCorner ("topRight", this, _XsMotifCorner::TopRight); + + XtVaSetValues (_corners[_XsMotifCorner::TopRight]->base ( ), XmNtopAttachment, + XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, + XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, NULL); + +// Bottom-Left + + _corners[_XsMotifCorner::BottomLeft] = new _XsMotifCorner ("bottomLeft", this, _XsMotifCorner::BottomLeft); + + XtVaSetValues (_corners[_XsMotifCorner::BottomLeft]->base ( ), XmNtopAttachment, + XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, + XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, NULL); + +// Bottom-Right + + _corners[_XsMotifCorner::BottomRight] = new _XsMotifCorner ("bottomRight", this, _XsMotifCorner::BottomRight); + + XtVaSetValues (_corners[_XsMotifCorner::BottomRight]->base ( ), XmNtopAttachment, + XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, + XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, NULL); + } + +/* + Sides +*/ + + if (_showBorder) + { + +// Top + + _sides[_XsMotifSide::Top] = new _XsMotifSide ("top", this, _XsMotifSide::Top); + + XtVaSetValues (_sides[_XsMotifSide::Top]->base ( ), XmNtopAttachment, + XmATTACH_FORM, XmNbottomAttachment, XmATTACH_NONE, NULL); + + if (_showResize) + { + XtVaSetValues (_sides[_XsMotifSide::Top]->base ( ), XmNleftAttachment, + XmATTACH_WIDGET, XmNleftWidget, _corners[_XsMotifCorner::TopLeft]->base ( ), + XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, + _corners[_XsMotifCorner::TopRight]->base ( ), NULL); + } + else + { + XtVaSetValues (_sides[_XsMotifSide::Top]->base ( ), XmNleftAttachment, + XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); + } + +// Bottom + + _sides[_XsMotifSide::Bottom] = new _XsMotifSide ("bottom", this, _XsMotifSide::Bottom); + + XtVaSetValues (_sides[_XsMotifSide::Bottom]->base ( ), XmNtopAttachment, + XmATTACH_NONE, XmNbottomAttachment, XmATTACH_FORM, NULL); + + if (_showResize) + { + XtVaSetValues (_sides[_XsMotifSide::Bottom]->base ( ), XmNleftAttachment, + XmATTACH_WIDGET, XmNleftWidget, _corners[_XsMotifCorner::BottomLeft]->base ( ), + XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, + _corners[_XsMotifCorner::BottomRight]->base ( ), NULL); + } + else + { + XtVaSetValues (_sides[_XsMotifSide::Bottom]->base ( ), XmNleftAttachment, + XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); + } + +// Left side + + _sides[_XsMotifSide::Left] = new _XsMotifSide ("left", this, _XsMotifSide::Left); + + XtVaSetValues (_sides[_XsMotifSide::Left]->base ( ), XmNleftAttachment, + XmATTACH_FORM, XmNrightAttachment, XmATTACH_NONE, NULL); + + if (_showResize) + { + XtVaSetValues (_sides[_XsMotifSide::Left]->base ( ), XmNtopAttachment, + XmATTACH_WIDGET, XmNtopWidget, _corners[_XsMotifCorner::TopLeft]->base ( ), + XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, + _corners[_XsMotifCorner::BottomLeft]->base ( ), NULL); + } + else + { + XtVaSetValues (_sides[_XsMotifSide::Left]->base ( ), XmNtopAttachment, + XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); + } + +// Right side + + _sides[_XsMotifSide::Right] = new _XsMotifSide ("right", this, _XsMotifSide::Right); + + XtVaSetValues (_sides[_XsMotifSide::Right]->base ( ), XmNleftAttachment, + XmATTACH_NONE, XmNrightAttachment, XmATTACH_FORM, NULL); + + if (_showResize) + { + XtVaSetValues (_sides[_XsMotifSide::Right]->base ( ), XmNtopAttachment, + XmATTACH_WIDGET, XmNtopWidget, _corners[_XsMotifCorner::TopRight]->base ( ), + XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, + _corners[_XsMotifCorner::BottomRight]->base ( ), NULL); + } + else + { + XtVaSetValues (_sides[_XsMotifSide::Right]->base ( ), XmNtopAttachment, + XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); + } + } + +// Menu button + + if (_showMenu) + { + _buttons[_XsMotifButton::Menu] = new _XsMotifButton ("menu", this, _XsMotifButton::Menu); + + XtVaSetValues (_buttons[_XsMotifButton::Menu]->base ( ), XmNbottomAttachment, + XmATTACH_NONE, XmNrightAttachment, XmATTACH_NONE, NULL); + + if (_showBorder) + { + XtVaSetValues (_buttons[_XsMotifButton::Menu]->base ( ), XmNleftAttachment, + XmATTACH_WIDGET, XmNleftWidget, _sides[_XsMotifSide::Left]->base ( ), + XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ), + NULL); + } + else + { + XtVaSetValues (_buttons[_XsMotifButton::Menu]->base ( ), XmNleftAttachment, + XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); + } + } + +// Maximize button + + if (_showMaximize) + { + _buttons[_XsMotifButton::Maximize] = new _XsMotifButton ("maximize", this, _XsMotifButton::Maximize); + + XtVaSetValues (_buttons[_XsMotifButton::Maximize]->base ( ), XmNbottomAttachment, + XmATTACH_NONE, XmNleftAttachment, XmATTACH_NONE, NULL); + + if (_showBorder) + { + XtVaSetValues (_buttons[_XsMotifButton::Maximize]->base ( ), XmNtopAttachment, + XmATTACH_WIDGET, XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ), + XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, _sides[_XsMotifSide::Right]->base ( ), + NULL); + } + else + { + XtVaSetValues (_buttons[_XsMotifButton::Maximize]->base ( ), XmNtopAttachment, + XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); + } + } + +// Minimize button + + if (_showMinimize) + { + _buttons[_XsMotifButton::Minimize] = new _XsMotifButton ("minimize", this, _XsMotifButton::Minimize); + + XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ), + XmNbottomAttachment, XmATTACH_NONE, XmNleftAttachment, XmATTACH_NONE, + NULL); + + if (_showBorder) + { + XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ), XmNtopAttachment, + XmATTACH_WIDGET, XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ), + XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, + _sides[_XsMotifSide::Right]->base ( ), NULL); + } + else + { + XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ), + XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, + NULL); + } + + if (_showMaximize) + { + XtVaSetValues (_buttons[_XsMotifButton::Minimize]->base ( ), + XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, + _buttons[_XsMotifButton::Maximize]->base ( ), NULL); + } + } + +/* + Titlebar +*/ + + if (_showTitle) + { + _title = new _XsMotifTitle ("title", this); + + XtVaSetValues (_title->base ( ), XmNbottomAttachment, XmATTACH_NONE, + NULL); + + if (_showBorder) + { + XtVaSetValues (_title->base ( ), XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, _sides[_XsMotifSide::Top]->base ( ), + XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, + _sides[_XsMotifSide::Left]->base ( ), XmNrightAttachment, + XmATTACH_WIDGET, XmNrightWidget, _sides[_XsMotifSide::Right]->base ( ), + NULL); + } + else + { + XtVaSetValues (_title->base ( ), XmNtopAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, + NULL); + } + + if (_showMenu) + { + XtVaSetValues (_title->base ( ), XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, _buttons[_XsMotifButton::Menu]->base ( ), NULL); + } + + Widget ba = (_buttons[_XsMotifButton::Minimize] != 0) ? + _buttons[_XsMotifButton::Minimize]->base ( ) : + (_buttons[_XsMotifButton::Maximize] != 0) ? + _buttons[_XsMotifButton::Maximize]->base ( ) : 0; + + if (ba) + { + XtVaSetValues (_title->base ( ), XmNrightAttachment, XmATTACH_WIDGET, + XmNrightWidget, ba, NULL); + } + } + +/* + Icon +*/ + + _icon = new _XsMotifIcon ("icon", this, parent); + +/* + Menu +*/ + + _menu = new _XsMotifMenu ("menu", this); + +/* + Client Area +*/ + + _clientArea = XtVaCreateWidget ("clientArea", xmFormWidgetClass, _base, NULL); + + if (_showBorder) + { + XtVaSetValues (_clientArea, XmNleftAttachment, XmATTACH_WIDGET, + XmNleftWidget, _sides[_XsMotifSide::Left]->base ( ), XmNrightAttachment, + XmATTACH_WIDGET, XmNrightWidget, _sides[_XsMotifSide::Right]->base ( ), + XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, + _sides[_XsMotifSide::Bottom]->base ( ), NULL); + } + else + { + XtVaSetValues (_clientArea, XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, + NULL); + } + + Widget topW = (_showTitle) ? _title->base ( ) : + (_showBorder) ? _sides[_XsMotifSide::Top]->base ( ) : 0; + + if (topW) + { + XtVaSetValues (_clientArea, XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, topW, NULL); + } + else + XtVaSetValues (_clientArea, XmNtopAttachment, XmATTACH_FORM, NULL); + +// Call the class function to create the contents of the window + + _buildClientArea (_clientArea); + +// Add an event handler to be called when this window is mapped + + XtAddEventHandler (_base, StructureNotifyMask, False, _mapEventHandler, (XtPointer)this); + +// Show everything + + int loop; + + for (loop = 0; loop < _XsMotifSide::Max; loop++) + { + if (_corners[loop] != 0) + _corners[loop]->show ( ); + if (_sides[loop] != 0) + _sides[loop]->show ( ); + } + + for (loop = 0; loop < _XsMotifButton::Max; loop++) + { + if (_buttons[loop] != 0) + _buttons[loop]->show ( ); + } + + if (_title != 0) + _title->show ( ); +} + +// _mapEvent + +void XsMotifWindow::_mapEvent ( ) +{ + +// Raise the client-area + + XRaiseWindow (XtDisplay (_clientArea), XtWindow (_clientArea)); +} + +// _mapEventHandler + +void XsMotifWindow::_mapEventHandler (Widget, XtPointer clientData, XEvent *event, Boolean*) +{ + if (event->type == MapNotify) + { + XsMotifWindow *obj = (XsMotifWindow*)clientData; + obj->_mapEvent ( ); + XtRemoveEventHandler (obj->_base, StructureNotifyMask, False, obj->_mapEventHandler, clientData); + } +} diff --git a/src/motif/mdi/lib/XsMotifWindow.h b/src/motif/mdi/lib/XsMotifWindow.h new file mode 100644 index 0000000000..203e13d949 --- /dev/null +++ b/src/motif/mdi/lib/XsMotifWindow.h @@ -0,0 +1,665 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsMotifWindow.h + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +#ifndef XSMOTIFWINDOW_H +#define XSMOTIFWINDOW_H + +// Includes + +#include +#include "XsMDIWindow.h" + +// Forward declarations + +class XsMotifWindow; + +/* + ---------------------------------------------------------------------------- + _XsMotifBase class +*/ + +class _XsMotifBase : public XsComponent { + + public: + +// Destructor + + virtual ~_XsMotifBase ( ); + +// Window actions + + virtual void show ( ); + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Protected constructor + + _XsMotifBase (const char *name, XsMotifWindow *win); + +// Component life-cycle + + virtual void _componentDestroyed ( ); + +// Utilities + + void _drawShadows (Position x, Position y, Dimension width, + Dimension height, Dimension thick, Boolean reverse = False); + + void _drawLine (Position x1, Position y1, Position x2, Position y2, GC &gc); + +// Implementation + + XsMotifWindow *_win; + + GC _topShadowGC; + GC _bottomShadowGC; + +// Event handlers + + virtual void _map ( ); + +// Internal Event handlers + + static void _mapEventHandler (Widget, XtPointer, XEvent*, Boolean*); +}; + +/* + ---------------------------------------------------------------------------- + _XsMotifComponent class +*/ + +class _XsMotifComponent : public _XsMotifBase { + + public: + +// Destructor + + virtual ~_XsMotifComponent ( ); + +// Enumerations + + enum Cursors { + TopCursor = 0, BottomCursor, LeftCursor, RightCursor, + TopLeftCursor, TopRightCursor, BottomLeftCursor, + BottomRightCursor, NumCursors }; + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Protected constructor + + _XsMotifComponent (const char *name, XsMotifWindow *win, Widget parent = 0); + +// Cursors + + static Cursor _cursors[NumCursors]; + +// Component parameters + + Dimension _borderSize; + Dimension _buttonSize; + Dimension _cornerSize; + +// Event handlers + + virtual void _expose (XEvent*) = 0; + virtual void _input (XEvent*); + + private: + +// Internal Event handlers + + static void _exposeEventHandler (Widget, XtPointer, XEvent*, Boolean*); + static void _inputEventHandler (Widget, XtPointer, XEvent*, Boolean*); + +// Resources + + static XtResource _resourceList[]; + + static int _mutex; +}; + +/* + ---------------------------------------------------------------------------- + _XsMotifCorner class +*/ + +class _XsMotifCorner : public _XsMotifComponent { + + public: + +// Enumerations + + enum Corner { TopLeft = 0, TopRight, BottomLeft, BottomRight, Max }; + +// Constructor/Destructor + + _XsMotifCorner (const char *name, XsMotifWindow *win, Corner corner); + virtual ~_XsMotifCorner ( ); + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Implementation + + Corner _corner; + +// Event handlers + + virtual void _expose (XEvent*); + virtual void _input (XEvent*); + virtual void _map ( ); +}; + +/* + ---------------------------------------------------------------------------- + _XsMotifSide class +*/ + +class _XsMotifSide : public _XsMotifComponent { + + public: + +// Enumerations + + enum Side { Top = 0, Bottom, Left, Right, Max }; + +// Constructor/Destructor + + _XsMotifSide (const char *name, XsMotifWindow *win, Side side); + virtual ~_XsMotifSide ( ); + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Implementation + + Side _side; + + int _lastW; + int _lastH; + +// Event handlers + + virtual void _expose (XEvent*); + virtual void _input (XEvent*); + virtual void _map ( ); + virtual void _configure (XEvent *); + + private: + +// Callbacks + + static void _configureEventHandler (Widget, XtPointer, XEvent*, Boolean*); +}; + +/* + ---------------------------------------------------------------------------- + _XsMotifButton class +*/ + +class _XsMotifButton : public _XsMotifComponent { + + public: + +// Enumerations + + enum Button { Menu = 0, Minimize, Maximize, Max }; + +// Constructor/Destructor + + _XsMotifButton (const char *name, XsMotifWindow *win, Button button); + virtual ~_XsMotifButton ( ); + +// Utilities + + virtual void redraw ( ); + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Implementation + + Boolean _pressed; + Button _button; + +// Event handlers + + virtual void _expose (XEvent*); + virtual void _input (XEvent*); + virtual void _map ( ); +}; + +/* + ---------------------------------------------------------------------------- + _XsMotifTitle class +*/ + +class _XsMotifTitle : public _XsMotifComponent { + + public: + +// Constructor/Destructor + + _XsMotifTitle (const char *name, XsMotifWindow *win); + virtual ~_XsMotifTitle ( ); + +// Title string + + void setTitle (const char *name); + const char *title ( ) const; + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Implementation + + Boolean _pressed; + String _titleString; + GC _fontGC; + + XFontStruct *_titleFont; + + int _lastW; + int _lastH; + +// Component life-cycle + + virtual void _componentDestroyed ( ); + +// Utilities + + virtual void _redraw ( ); + +// Event handlers + + virtual void _expose (XEvent*); + virtual void _input (XEvent*); + virtual void _map ( ); + virtual void _configure (XEvent*); + + private: + +// Callbacks + + static void _configureEventHandler (Widget, XtPointer, XEvent*, Boolean*); + +// Resources + + static XtResource _resourceList[]; +}; + +// Inline member functions + +inline const char *_XsMotifTitle::title ( ) const +{ + return (_titleString); +} + +/* + ---------------------------------------------------------------------------- + _XsMotifIcon class +*/ + +class _XsMotifIcon : public _XsMotifComponent { + + public: + +// Constructor/Destructor + + _XsMotifIcon (const char *name, XsMotifWindow *win, Widget parent); + virtual ~_XsMotifIcon ( ); + +// Window operations + + virtual void show ( ); + +// Icon name/pixmap + + void setIconName (const char *name); + const char *iconName ( ) const; + + void setPixmap (Pixmap pm); + Pixmap pixmap ( ) const; + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Implementation + + GC _fontGC; + GC _pixmapGC; + + Dimension _iconSize; + String _iconName; + XFontStruct *_iconFont; + Pixmap _pixmap; + Boolean _freePixmap; + + Dimension _width, _height; + Position _iconX, _iconY; + Boolean _placed; + +// Component life-cycle + + virtual void _componentDestroyed ( ); + +// Event handlers + + virtual void _expose (XEvent*); + virtual void _input (XEvent*); + virtual void _map ( ); + + private: + +// Resources + + static XtResource _resourceList[]; +}; + +// Inline member-functions + +inline const char *_XsMotifIcon::iconName ( ) const +{ + return (_iconName); +} + +inline Pixmap _XsMotifIcon::pixmap ( ) const +{ + return (_pixmap); +} + +/* + ---------------------------------------------------------------------------- + _XsMotifMenu class +*/ + +class _XsMotifMenu : public _XsMotifBase { + + public: + +// Constructor/Destructor + + _XsMotifMenu (const char *name, XsMotifWindow *win); + virtual ~_XsMotifMenu ( ); + +// Utilities + + virtual void popup (Boolean atPointer = True); + +// Enumerations + + enum Item { + NoItem = -1, Restore, Move, Size, Minimize, + Maximize, Raise, Lower, Close, Num + }; + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Dimensions + + enum { ShadowThickness = 1 }; + enum { VertTextOffset = 3 }; + enum { HorizTextOffset = 10 }; + +// Implementation + + static Cursor _cursor; + static Pixmap _stipple; + static Display *_dpy; + + Boolean _saveUnder; + + String _strings[Num]; + XFontStruct *_menuFont; + + GC _fontGC; + GC _grayGC; + GC _backgroundGC; + + Item _curItem; + +// Component life-cycle + + virtual void _componentDestroyed ( ); + +// Menu event processing + + virtual void _processEvents ( ); + +// Utilities + + virtual void _processItem (Item item); + virtual void _redrawMenu ( ); + + void _redrawItem (Item); + void _toggleItem (Item, Boolean active = False); + Item _trackPointer (XMotionEvent *event); + +// Pointer grabs + + Boolean _grabPointer ( ); + void _ungrabPointer ( ); + +// Event handlers + + virtual void _map ( ); + + private: + +// Work procedure + + static Boolean _workProc (XtPointer); + +// Resources + + static XtResource _resourceList[]; + static int _count; +}; + + +/* + ---------------------------------------------------------------------------- + XsMotifWindow class +*/ + +class XsMotifWindow : public XsMDIWindow { + + public: + +// Constructor/Destructor + + XsMotifWindow (const char *name); + virtual ~XsMotifWindow ( ); + +// Window manipulation + + virtual void raise ( ); + virtual void lower ( ); + + virtual void minimize ( ); + virtual void maximize ( ); + virtual void restore ( ); + + virtual void close ( ); + +// Window and icon strings + + void setTitle (const char *name); + const char *title ( ) const; + + void setIconName (const char *name); + const char *iconName ( ) const; + + void setPixmap (Pixmap pm); + Pixmap pixmap ( ) const; + +// Window icon handle + + Widget icon ( ) const; + +// Menu settings + + void popupMenu (Boolean atPointer = True); + +// Utilities + + Boolean maximized ( ) const; + Boolean minimized ( ) const; + +// Position and size + + virtual void setPosition (Position, Position); + virtual void setSize (Dimension, Dimension); + + Dimension minWidth ( ) const; + Dimension minHeight ( ) const; + +// Class name + + virtual const char *className ( ) const; + + protected: + +// Window creation functions + + virtual void _buildClientArea (Widget parent) = 0; + virtual void _createWindow (Widget parent); + +// Window components + + _XsMotifCorner *_corners[_XsMotifCorner::Max]; + _XsMotifSide *_sides[_XsMotifSide::Max]; + _XsMotifButton *_buttons[_XsMotifButton::Max]; + _XsMotifTitle *_title; + _XsMotifIcon *_icon; + _XsMotifMenu *_menu; + +// Window dimensions + + Dimension _savedWidth, _savedHeight; + Position _savedX, _savedY; + Dimension _minW, _maxW; + Dimension _minH, _maxH; + +// Window parameters + + Boolean _showBorder; + Boolean _showResize; + Boolean _showTitle; + Boolean _showMenu; + Boolean _showMinimize; + Boolean _showMaximize; + Boolean _lowerOnIconify; + +// Window state + + Boolean _maximized; + Boolean _minimized; + +// Callbacks + + virtual void _mapEvent ( ); + + private: + +// Internal event handlers + + static void _mapEventHandler (Widget, XtPointer, XEvent*, Boolean*); + +// Resources + + static XtResource _resourceList[]; +}; + +// Inline member functions + +inline Boolean XsMotifWindow::maximized ( ) const +{ + return (_maximized); +} + +inline Boolean XsMotifWindow::minimized ( ) const +{ + return (_minimized); +} + +inline const char *XsMotifWindow::title ( ) const +{ + if (_title != 0) + return (_title->title ( )); + else + return (0); +} + +inline const char *XsMotifWindow::iconName ( ) const +{ + if (_icon != 0) + return (_icon->iconName ( )); + else + return (0); +} + +inline Pixmap XsMotifWindow::pixmap ( ) const +{ + if (_icon != 0) + return (_icon->pixmap ( )); + else + return (None); +} + +inline Widget XsMotifWindow::icon ( ) const +{ + if (_icon != 0) + return (_icon->base ( )); + else + return (0); +} + +inline Dimension XsMotifWindow::minWidth ( ) const +{ + return (_minW); +} + +inline Dimension XsMotifWindow::minHeight ( ) const +{ + return (_minH); +} + +#endif diff --git a/src/motif/mdi/lib/XsMoveOutline.C b/src/motif/mdi/lib/XsMoveOutline.C new file mode 100644 index 0000000000..f00118f72e --- /dev/null +++ b/src/motif/mdi/lib/XsMoveOutline.C @@ -0,0 +1,82 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsMoveOutline.C + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +// Includes + +#include +#include "XsMoveOutline.h" +#include + +// Static definitions + +Cursor XsMoveOutline::_fleur = None; + +// Constructor + +XsMoveOutline::XsMoveOutline (Widget w) : XsOutline (w) +{ + unsigned int mask; // Not used + Window root; + int xy; + +// Create the cursor (if necessary) + + if (_fleur == None) + _fleur = XCreateFontCursor (XtDisplay (_w), XC_fleur); + +// Get the current mouse root coordinates + + XQueryPointer (XtDisplay (_w), XtWindow (_w), &root, &root, &_rootX, + &_rootY, &xy, &xy, &mask); +} + +// Destructor + +XsMoveOutline::~XsMoveOutline ( ) +{ + // Empty +} + +// _motionHandler + +void XsMoveOutline::_motionHandler (XEvent *event) +{ + int curX, curY; + +// Get current mouse position + + curX = event->xbutton.x_root; + curY = event->xbutton.y_root; + +// Compute the new window position + + _x += (curX - _rootX); + _y += (curY - _rootY); + +// Move the window + + _drawOutline (False); + +// Save the new root position + + _rootX = curX; + _rootY = curY; +} + +// _getCursor + +Cursor XsMoveOutline::_getCursor ( ) const +{ + return (_fleur); +} + diff --git a/src/motif/mdi/lib/XsMoveOutline.h b/src/motif/mdi/lib/XsMoveOutline.h new file mode 100644 index 0000000000..7e830c6ed0 --- /dev/null +++ b/src/motif/mdi/lib/XsMoveOutline.h @@ -0,0 +1,52 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsMoveOutline.h + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +#ifndef XSMOVEOUTLINE_H +#define XSMOVEOUTLINE_H + +// Includes + +#include "XsOutline.h" + +// XsMoveOutline class + +class XsMoveOutline : public XsOutline { + + public: + +// Constructor/Destructor + + XsMoveOutline (Widget w); + virtual ~XsMoveOutline ( ); + + protected: + +// Motion handler + + virtual void _motionHandler (XEvent*); + +// Moving cursor + + virtual Cursor _getCursor ( ) const; + + private: + +// Implementation + + int _rootX; + int _rootY; + + static Cursor _fleur; +}; + +#endif diff --git a/src/motif/mdi/lib/XsOutline.C b/src/motif/mdi/lib/XsOutline.C new file mode 100644 index 0000000000..63980462e2 --- /dev/null +++ b/src/motif/mdi/lib/XsOutline.C @@ -0,0 +1,241 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsOutline.C + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +// Includes + +#include +#include +#include "XsOutline.h" + +// Constructor + +XsOutline::XsOutline (Widget w) +{ + assert (w != 0); + +// Initialize + + _w = w; + +// Get window dimensions + + unsigned int moreJunk; + unsigned int uw, uh; + Window junk; + + XGetGeometry (XtDisplay (_w), XtWindow (_w), &junk, &_x, &_y, &uw, &uh, &moreJunk, &moreJunk); + + _width = uw; + _height = uh; + +// Get initial settings + + _savedX = _x; + _savedY = _y; + _savedH = _savedW = 0; + +// Create the graphics context + + XGCValues values; + unsigned long valuemask; + + Display *dpy = XtDisplay (_w); + + valuemask = GCFunction | GCLineWidth | GCSubwindowMode; + values.function = GXinvert; + values.line_width = 0; + values.subwindow_mode = IncludeInferiors; + + _gc = XCreateGC (dpy, XtWindow (_w), valuemask, &values); +} + +// Destructor + +XsOutline::~XsOutline ( ) +{ + XFreeGC (XtDisplay (_w), _gc); +} + +// go + +Boolean XsOutline::go (Boolean drawInitial) +{ + XtAppContext appContext = XtWidgetToApplicationContext (_w); + XEvent event; + int done = 0; + +// Grab the pointer + + if (_grabPointer ( ) == False) + return (False); + +// Draw the initial box (if requested) + + if (drawInitial) + _drawOutline (False); + +// Process the events locally + + while (!done) + { + XtAppNextEvent (appContext, &event); + + switch (event.type) + { + case ButtonRelease: + { + +// Clear the outline and break + + _drawOutline (True); + done = 1; + break; + } + case MotionNotify: + { + XEvent next; + +// Process only the last motion event + + while (XPending (XtDisplay (_w)) > 0) + { + XPeekEvent (XtDisplay (_w), &next); + if (next.type != MotionNotify) + break; + XtAppNextEvent (appContext, &event); + } + +// Send this event + + _motionHandler (&event); + + break; + } + default: + { + XtDispatchEvent (&event); + break; + } + } + } + +// Ungrab the pointer + + _ungrabPointer ( ); + + return (True); +} + +// _drawOutline + +void XsOutline::_drawOutline (Boolean clear) +{ + +// Clear the current outline + + if (_savedH || _savedW) + _drawIt (_savedX, _savedY, _savedW, _savedH); + +// Save current values + + _savedX = _x; _savedY = _y; + _savedW = _width; _savedH = _height; + +// Draw the new outline (unless flagged to just clear) + + if (!clear) + _drawIt (_x, _y, _width, _height); +} + +// _getCursor + +Cursor XsOutline::_getCursor ( ) const +{ + return (None); +} + +// _grabPointer + +Boolean XsOutline::_grabPointer ( ) +{ + +// Sync everything up before being grabby + + XSync (XtDisplay (_w), False); + +// Grab the pointer + + if (XGrabPointer (XtDisplay (_w), XtWindow (_w), False, GrabEventMask, + GrabModeAsync, GrabModeAsync, XtWindow (XtParent (_w)), _getCursor ( ), + CurrentTime) != GrabSuccess) + { + XBell (XtDisplay (_w), 100); + return (False); + } + + return (True); +} + +// _ungrabPointer + +void XsOutline::_ungrabPointer ( ) +{ + +// Ungrab the pointer + + XUngrabPointer (XtDisplay (_w), CurrentTime); +} + +// _drawIt + +void XsOutline::_drawIt (int x, int y, int w, int h) +{ + const int nsegs = 8; + XSegment segs[nsegs]; + +// Across the top + + segs[0].x1 = x; segs[0].y1 = y; + segs[0].x2 = x + w - 1; segs[0].y2 = y; + + segs[1].x1 = x + BorderSize; segs[1].y1 = y + BorderSize; + segs[1].x2 = x + w - BorderSize - 1; segs[1].y2 = y + BorderSize; + +// Down the left + + segs[2].x1 = x + w - 1; segs[2].y1 = y + 1; + segs[2].x2 = x + w - 1; segs[2].y2 = y + h - 1; + + segs[3].x1 = x + w - BorderSize - 1; segs[3].y1 = y + BorderSize + 1; + segs[3].x2 = x + w - BorderSize - 1; segs[3].y2 = y + h - BorderSize - 1; + +// Across the bottom + + segs[4].x1 = x + 1; segs[4].y1 = y + h - 1; + segs[4].x2 = x + w - 2; segs[4].y2 = y + h - 1; + + segs[5].x1 = x + BorderSize + 1; segs[5].y1 = y + h - BorderSize - 1; + segs[5].x2 = x + w - BorderSize - 2; segs[5].y2 = y + h - BorderSize - 1; + +// Up the left + + segs[6].x1 = x; segs[6].y1 = y + h - 1; + segs[6].x2 = x; segs[6].y2 = y + 1; + + segs[7].x1 = x + BorderSize; segs[7].y1 = y + h - BorderSize - 1; + segs[7].x2 = x + BorderSize; segs[7].y2 = y + BorderSize + 1; + +// Draw the segments + + XDrawSegments (XtDisplay (_w), XtWindow (XtParent (_w)), _gc, segs, nsegs); +} diff --git a/src/motif/mdi/lib/XsOutline.h b/src/motif/mdi/lib/XsOutline.h new file mode 100644 index 0000000000..51ca7494f4 --- /dev/null +++ b/src/motif/mdi/lib/XsOutline.h @@ -0,0 +1,109 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsOutline.h + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +#ifndef XSOUTLINE_H +#define XSOUTLINE_H + +// Includes + +#include + +// XsOutline class + +class XsOutline { + + public: + +// Constructor/Destructor + + XsOutline (Widget w); + virtual ~XsOutline ( ); + +// Event handler + + Boolean go (Boolean drawInitial = False); + +// Utilities + + int width ( ) const; + int height ( ) const; + int x ( ) const; + int y ( ) const; + + protected: + +// Enumerations + + enum { BorderSize = 6 }; + enum { GrabEventMask = (unsigned int)(ButtonPressMask | ButtonReleaseMask | PointerMotionMask) }; + +// Components + + Widget _w; + +// Graphics context + + GC _gc; + +// Current dimensions + + int _x, _y; + int _width; + int _height; + +// Outline utilities + + virtual void _motionHandler (XEvent*) = 0; + virtual Cursor _getCursor ( ) const; + void _drawOutline (Boolean); + + private: + +// Pointer grabs + + Boolean _grabPointer ( ); + void _ungrabPointer ( ); + +// Save dimensions + + int _savedX, _savedY; + int _savedW, _savedH; + +// Drawing + + void _drawIt (int, int, int, int); +}; + +// Inline member functions + +inline int XsOutline::width ( ) const +{ + return (_width); +} + +inline int XsOutline::height ( ) const +{ + return (_height); +} + +inline int XsOutline::x ( ) const +{ + return (_x); +} + +inline int XsOutline::y ( ) const +{ + return (_y); +} + +#endif diff --git a/src/motif/mdi/lib/XsResizeOutline.C b/src/motif/mdi/lib/XsResizeOutline.C new file mode 100644 index 0000000000..42e662cd1f --- /dev/null +++ b/src/motif/mdi/lib/XsResizeOutline.C @@ -0,0 +1,231 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsResizeOutline.C + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +// Includes + +#include +#include +#include "XsResizeOutline.h" + +// Static definitions + +Cursor XsResizeOutline::_cursors[XsResizeOutline::NumCursors]; +int XsResizeOutline::_mutex = 0; + +// Constructor + +XsResizeOutline::XsResizeOutline (Widget w, int direction) : XsOutline (w) +{ + +// Initialize + + _minWidth = 5; + _minHeight = 5; + _direction = direction; + +// Translate current window location to root coordinates + + Position xpos, ypos; + + XtTranslateCoords (XtParent (_w), (Position)_x, (Position)_y, &xpos, &ypos); + + _rootX = (int)xpos; + _rootY = (int)ypos; + +// Save the original window position and size + + _origX = _x; + _origY = _y; + _origW = _width; + _origH = _height; + + _origRootX = _rootX; + _origRootY = _rootY; + +// Create the cursors (if necessary) + + if (_mutex == 0) + { + Display *dpy = XtDisplay (_w); + +// Create cursors + + _cursors[TopCursor] = XCreateFontCursor (dpy, XC_top_side); + _cursors[BottomCursor] = XCreateFontCursor (dpy, XC_bottom_side); + _cursors[LeftCursor] = XCreateFontCursor (dpy, XC_left_side); + _cursors[RightCursor] = XCreateFontCursor (dpy, XC_right_side); + _cursors[TopLeftCursor] = XCreateFontCursor (dpy, XC_top_left_corner); + _cursors[TopRightCursor] = XCreateFontCursor (dpy, XC_top_right_corner); + _cursors[BottomLeftCursor] = XCreateFontCursor (dpy, XC_bottom_left_corner); + _cursors[BottomRightCursor] = XCreateFontCursor (dpy, XC_bottom_right_corner); + _cursors[Fleur] = XCreateFontCursor (dpy, XC_fleur); + _mutex = 1; + } +} + +// Destructor + +XsResizeOutline::~XsResizeOutline ( ) +{ + // Empty +} + +// setMinSize + +void XsResizeOutline::setMinSize (int minWidth, int minHeight) +{ + assert (minWidth > 0); + assert (minHeight > 0); + + _minWidth = minWidth; + _minHeight = minHeight; +} + +// _motionHandler + +void XsResizeOutline::_motionHandler (XEvent *event) +{ + int curX, curY; + int diff; + int x, y, w, h; + +// Get current mouse position + + curX = event->xbutton.x_root; + curY = event->xbutton.y_root; + + if (_direction & Undetermined) + { + +/* + Just let the mouse roam around until it crosses the outline. + When it does so, lock in the direction, change the cursor, and let + it rip. +*/ + + if (((curX <= _origRootX) || (curX >= (_origRootX + _origW))) + || ((curY <= _origRootY) || (curY >= (_origRootY + _origH)))) + { + + const int CornerOffset = 30; + +// Crossed box. Figure out where and set direction + + _direction = 0; + + if (curY <= (_origRootY + CornerOffset)) + _direction |= Up; + else if (curY >= (_origRootY + _origH - CornerOffset)) + _direction |= Down; + + if (curX <= (_origRootX + CornerOffset)) + _direction |= Left; + else if (curX >= (_origRootX + _origW - CornerOffset)) + _direction |= Right; + +// Get the new cursor + + XChangeActivePointerGrab (XtDisplay (_w), GrabEventMask, + _getCursor ( ), CurrentTime); + } + else + return; + } + +// Get the current values + + x = _x; y = _y; w = _width; h = _height; + +// Process the motion + + if (_direction & Up) + { + if (curY < (_origRootY + _origH - 1 - _minHeight)) + { + diff = _rootY - curY; + _rootY = curY; + _y -= diff; + _height = _origRootY + _origH - curY; + } + else + { + _rootY = _origRootY + _origH - 1 - _minHeight; + _y = _origY + _origH - 1 - _minHeight; + _height = _minHeight; + } + } + else if (_direction & Down) + { + if (curY > (_origRootY + _minHeight)) + _height = curY - _origRootY - 1; + else + _height = _minHeight; + } + + if (_direction & Left) + { + if (curX < (_origRootX + _origW - 1 - _minWidth)) + { + diff = _rootX - curX; + _rootX = curX; + _x -= diff; + _width = _origRootX + _origW - curX; + } + else + { + _rootX = _origRootX + _origW - 1 - _minWidth; + _x = _origX + _origW - 1 - _minWidth; + _width = _minWidth; + } + } + else if (_direction & Right) + { + if (curX > (_origRootX + _minWidth)) + _width = curX - _origRootX - 1; + else + _width = _minWidth; + } + +// Check if the values have "really" changed + + if ((w != _width) || (h != _height) || (x != _x) || (y != _y)) + _drawOutline (False); +} + +// _getCursor + +Cursor XsResizeOutline::_getCursor ( ) const +{ + if (_direction == Up) + return (_cursors[TopCursor]); + if (_direction == Down) + return (_cursors[BottomCursor]); + if (_direction == Left) + return (_cursors[LeftCursor]); + if (_direction == Right) + return (_cursors[RightCursor]); + if (_direction == (Up | Left)) + return (_cursors[TopLeftCursor]); + if (_direction == (Up | Right)) + return (_cursors[TopRightCursor]); + if (_direction == (Down | Left)) + return (_cursors[BottomLeftCursor]); + if (_direction == (Down | Right)) + return (_cursors[BottomRightCursor]); + if (_direction == Undetermined) + return (_cursors[Fleur]); + + assert (0); + return (None); +} + diff --git a/src/motif/mdi/lib/XsResizeOutline.h b/src/motif/mdi/lib/XsResizeOutline.h new file mode 100644 index 0000000000..d32f2050ae --- /dev/null +++ b/src/motif/mdi/lib/XsResizeOutline.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + XsResizeOutline.h + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +#ifndef XSRESIZEOUTLINE_H +#define XSRESIZEOUTLINE_H + +// Includes + +#include "XsOutline.h" + +class XsResizeOutline : public XsOutline { + + public: + +// Enumerations + + enum { Up = 0x0001, Right = 0x0002, Down = 0x0004, Left = 0x0008, + Undetermined = 0x0010 }; + + enum Cursors { + TopCursor = 0, BottomCursor, LeftCursor, RightCursor, TopLeftCursor, + TopRightCursor, BottomLeftCursor, BottomRightCursor, Fleur, + NumCursors }; + +// Constructor/Destructor + + XsResizeOutline (Widget w, int direction); + virtual ~XsResizeOutline ( ); + + void setMinSize (int minWidth, int minHeight); + + protected: + +// Motion handler + + virtual void _motionHandler (XEvent*); + +// Resize cursor + + virtual Cursor _getCursor ( ) const; + + private: + +// Implementation + + int _rootX, _rootY; // Root coordinates + int _origRootX, _origRootY; + + int _origX, _origY; // Window coordinates + int _origW, _origH; + + int _minWidth, _minHeight; + + int _direction; + + static Cursor _cursors[NumCursors]; + static int _mutex; +}; + +#endif diff --git a/src/motif/mdi/lib/xs_motif_icon.xbm b/src/motif/mdi/lib/xs_motif_icon.xbm new file mode 100644 index 0000000000..5541657a49 --- /dev/null +++ b/src/motif/mdi/lib/xs_motif_icon.xbm @@ -0,0 +1,27 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + xs_motif_icon.xbm + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +#define xs_motif_icon_width 32 +#define xs_motif_icon_height 32 +static char xs_motif_icon_bits[] = { + 0xff, 0x00, 0x00, 0xc0, 0xfe, 0x01, 0x00, 0xc0, 0xfc, 0x03, 0x00, 0x60, + 0xf8, 0x07, 0x00, 0x30, 0xf8, 0x07, 0x00, 0x18, 0xf0, 0x0f, 0x00, 0x0c, + 0xe0, 0x1f, 0x00, 0x06, 0xc0, 0x3f, 0x00, 0x06, 0xc0, 0x3f, 0x00, 0x03, + 0x80, 0x7f, 0x80, 0x01, 0x00, 0xff, 0xc0, 0x00, 0x00, 0xfe, 0x61, 0x00, + 0x00, 0xfe, 0x31, 0x00, 0x00, 0xfc, 0x33, 0x00, 0x00, 0xf8, 0x1b, 0x00, + 0x00, 0xf0, 0x0d, 0x00, 0x00, 0xf0, 0x0e, 0x00, 0x00, 0x60, 0x1f, 0x00, + 0x00, 0xb0, 0x3f, 0x00, 0x00, 0x98, 0x7f, 0x00, 0x00, 0x98, 0x7f, 0x00, + 0x00, 0x0c, 0xff, 0x00, 0x00, 0x06, 0xfe, 0x01, 0x00, 0x03, 0xfc, 0x03, + 0x80, 0x01, 0xfc, 0x03, 0xc0, 0x00, 0xf8, 0x07, 0xc0, 0x00, 0xf0, 0x0f, + 0x60, 0x00, 0xe0, 0x1f, 0x30, 0x00, 0xe0, 0x1f, 0x18, 0x00, 0xc0, 0x3f, + 0x0c, 0x00, 0x80, 0x7f, 0x06, 0x00, 0x00, 0xff}; diff --git a/src/motif/mdi/test/Imakefile b/src/motif/mdi/test/Imakefile new file mode 100644 index 0000000000..a9af9f4b85 --- /dev/null +++ b/src/motif/mdi/test/Imakefile @@ -0,0 +1,25 @@ +#include "../config/MDI.tmpl" + +SRCS = MDItest.C + +OBJS = MDItest.o + +STD_INCLUDES = -I/usr/include + +INCLUDES = -I../lib + +DEPLIBS = ../lib/libXsw.a + +#if defined(SunArchitecture) + SYSLIBS = -lgen +#endif + +LOCAL_LIBRARIES = ../lib/libXsw.a +SYSTEM_LIBRARIES = -lXm -lXt -lX11 $(SYSLIBS) + +PROGRAM = MDItest + +AllTarget($(PROGRAM)) +NormalProgramTarget($(PROGRAM),$(OBJS),$(DEPLIBS),$(LOCAL_LIBRARIES),$(SYSTEM_LIBRARIES)) +DependTarget() +CxxRules() diff --git a/src/motif/mdi/test/MDItest.C b/src/motif/mdi/test/MDItest.C new file mode 100644 index 0000000000..e615970d24 --- /dev/null +++ b/src/motif/mdi/test/MDItest.C @@ -0,0 +1,391 @@ +/* + Copyright (C) 1996 Scott W. Sadler + All rights reserved. +*/ + +/* + MDItest.c + + History + 03-Mar-96 1.0; Scott W. Sadler (sws@iti-oh.com) + Created +*/ + +// Includes + +#include +#include +#include +#include +#include +#include +#include +#include +#include "XsMDICanvas.h" +#include "XsMotifWindow.h" + +// Fallback resources + +static char *fallbacks[] = { + "*MDItest.height: 500", + "*MDItest.width: 500", + "*MDIinner.width: 300", + "*MDIinner.height: 300", + + "*fileMenu.labelString: File", + "*fileMenu.mnemonic: F", + "*openMenuItem.labelString: Open...", + "*openMenuItem.mnemonic: O", + "*newMenuItem.labelString: New...", + "*newMenuItem.mnemonic: N", + "*editMenu.labelString: Edit", + "*editMenu.mnemonic: E", + "*cutMenuItem.labelString: Cut", + "*cutMenuItem.mnemonic: t", + "*copyMenuItem.labelString: Copy", + "*copyMenuItem.mnemonic: C", + "*pasteMenuItem.labelString: Paste", + "*pasteMenuItem.mnemonic: P", + "*helpMenu.labelString: Help", + "*helpMenu.mnemonic: H", + "*aboutMenuItem.labelString: About", + "*aboutMenuItem.mnemonic: A", + "*scrolledText.rows: 10", + "*scrolledText.columns: 30", + + "*background: grey", + "*fontList: -*-helvetica-medium-r-normal-*-14-*-*-*-*-*-iso8859-1", + + NULL +}; + +/* + ---------------------------------------------------------------------------- + MyDocument class +*/ + +class MyDocument : public XsMotifWindow { + + public: + +// Constructor/Destructor + + MyDocument (const char *name, XsMDICanvas *canvas); + virtual ~MyDocument ( ); + + protected: + +// This member function is called to create the document contents + + virtual void _buildClientArea (Widget); + +// Implementation + + XsMDICanvas *_canvas; + +// Callbacks + + void _newWindow ( ); + void _doNothing ( ); + + private: + +// Callbacks + + static void _newWindowCallback (Widget, XtPointer, XtPointer); + static void _doNothingCallback (Widget, XtPointer, XtPointer); +}; + +// Constructor + +MyDocument::MyDocument (const char *name, XsMDICanvas *canvas) : + XsMotifWindow (name) +{ + assert (canvas != 0); + +// Initialize + + _canvas = canvas; +} + +// Destructor + +MyDocument::~MyDocument ( ) +{ + // Empty +} + +// _buildClientArea (called to create document contents) + +void MyDocument::_buildClientArea (Widget parent) +{ + assert (parent != 0); + + Widget pulldown; + Widget cascade; + Widget button; + +// Create a main window with some dummy menus + + Widget mainW = XtVaCreateWidget ("mainWin", xmMainWindowWidgetClass, parent, + XmNtopAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, + NULL); + +// Create a menubar + + Widget menuBar = XmCreateMenuBar (mainW, "menuBar", NULL, 0); + +// Create the "file" menu + + pulldown = XmCreatePulldownMenu (menuBar, "pulldown", NULL, 0); + cascade = XtVaCreateManagedWidget ("fileMenu", xmCascadeButtonGadgetClass, + menuBar, XmNsubMenuId, pulldown, NULL); + + button = XtVaCreateManagedWidget ("openMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + XtAddCallback (button, XmNactivateCallback, _doNothingCallback, (XtPointer)this); + + button = XtVaCreateManagedWidget ("newMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + XtAddCallback (button, XmNactivateCallback, _newWindowCallback, (XtPointer)this); + +// Create the "edit" menu + + pulldown = XmCreatePulldownMenu (menuBar, "pulldown", NULL, 0); + cascade = XtVaCreateManagedWidget ("editMenu", xmCascadeButtonGadgetClass, + menuBar, XmNsubMenuId, pulldown, NULL); + + button = XtVaCreateManagedWidget ("cutMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + XtAddCallback (button, XmNactivateCallback, _doNothingCallback, (XtPointer)this); + + button = XtVaCreateManagedWidget ("copyMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + XtAddCallback (button, XmNactivateCallback, _doNothingCallback, (XtPointer)this); + + button = XtVaCreateManagedWidget ("pasteMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + XtAddCallback (button, XmNactivateCallback, _doNothingCallback, (XtPointer)this); + +// Create the help menu + + pulldown = XmCreatePulldownMenu (menuBar, "pulldown", NULL, 0); + cascade = XtVaCreateManagedWidget ("helpMenu", xmCascadeButtonGadgetClass, + menuBar, XmNsubMenuId, pulldown, NULL); + + button = XtVaCreateManagedWidget ("aboutMenuItem", xmPushButtonGadgetClass, + pulldown, NULL); + XtAddCallback (button, XmNactivateCallback, _doNothingCallback, (XtPointer)this); + + XtVaSetValues (menuBar, XmNmenuHelpWidget, cascade, NULL); + +// Manage the menubar + + XtManageChild (menuBar); + +// Create the work area + + const int nargs = 8; + Arg args[nargs]; + int n; + + n = 0; + XtSetArg (args[n], XmNscrollingPolicy, XmAUTOMATIC); n++; + XtSetArg (args[n], XmNhighlightThickness, (Dimension)0); n++; + XtSetArg (args[n], XmNeditMode, XmMULTI_LINE_EDIT); n++; + XtSetArg (args[n], XmNeditable, True); n++; + XtSetArg (args[n], XmNwordWrap, False); n++; + XtSetArg (args[n], XmNcursorPositionVisible, True); n++; + XtSetArg (args[n], XmNverifyBell, True); n++; + + assert (n <= nargs); + + Widget scrolledText = XmCreateScrolledText (mainW, "scrolledText", args, n); + XtManageChild (scrolledText); + +// Set the main window area + + XtVaSetValues (mainW, XmNmenuBar, menuBar, XmNworkWindow, + XtParent (scrolledText), NULL); + + XtManageChild (mainW); +} + +// _newWindow + +void MyDocument::_newWindow ( ) +{ + +// Create a new document (this will leak, but who cares?) + + MyDocument *newDoc = new MyDocument ("Document", _canvas); + +// Add it to the canvas + + _canvas->add (newDoc); +} + +// _newWindowCallback + +void MyDocument::_newWindowCallback (Widget, XtPointer clientData, XtPointer) +{ + MyDocument *obj = (MyDocument*)clientData; + obj->_newWindow ( ); +} + +// _doNothingCallback + +void MyDocument::_doNothingCallback (Widget w, XtPointer, XtPointer) +{ + XBell (XtDisplayOfObject (w), 100); +} + +/* + ---------------------------------------------------------------------------- + MyDocument2 class +*/ + +class MyDocument2 : public XsMotifWindow { + + public: + +// Constructor/Destructor + + MyDocument2 (const char *name); + virtual ~MyDocument2 ( ); + + protected: + +// This member function is called to create the document contents + + virtual void _buildClientArea (Widget); + +// Implementation + + XsMDICanvas *_canvas; + MyDocument *_win1; +}; + +// Constructor + +MyDocument2::MyDocument2 (const char *name) : XsMotifWindow (name) +{ + _canvas = 0; + _win1 = 0; +} + +// Destructor + +MyDocument2::~MyDocument2 ( ) +{ + delete _canvas; + delete _win1; +} + +// _buildClientArea + +void MyDocument2::_buildClientArea (Widget parent) +{ + assert (parent != 0); + +// Create a nested MDI canvas + + _canvas = new XsMDICanvas ("MDIinner", parent); + +// Attach it up + + XtVaSetValues (_canvas->base ( ), XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, NULL); + +// Create a document + + _win1 = new MyDocument ("InnerWin", _canvas); + +// Add the document to the canvas + + _canvas->add (_win1); + +// Show the canvas + + _canvas->show ( ); +} + +/* + ---------------------------------------------------------------------------- + main +*/ + +static void _destroyCallback (Widget, XtPointer clientData, XtPointer) +{ + Boolean *quit = (Boolean*)clientData; + *quit = True; +} + +int main (int argc, char **argv) +{ + XtAppContext appContext; + Widget topLevel; + Boolean quit = False; + +// Initialize toolkit + + topLevel = XtVaAppInitialize (&appContext, "MDI", NULL, 0, &argc, argv, + fallbacks, XmNdeleteResponse, XmDO_NOTHING, NULL); + + Display *dpy = XtDisplay (topLevel); + +// Add protocols + + Atom WM_DELETE_WINDOW = XmInternAtom (dpy, "WM_DELETE_WINDOW", False); + + XmAddWMProtocolCallback (topLevel, WM_DELETE_WINDOW, _destroyCallback, + &quit); + +// Create the MDI canvas + + XsMDICanvas *canvas = new XsMDICanvas ("MDItest", topLevel); + +// Create the MDI documents + + MyDocument *win1 = new MyDocument ("Document", canvas); + MyDocument2 *win2 = new MyDocument2 ("Document 2"); + +// Add documents to MDI canvas + + canvas->add (win1); + canvas->add (win2); + +// Show the canvas + + canvas->show ( ); + +// Realize everything + + XtRealizeWidget (topLevel); + +// Let 'er rip + + XEvent event; + + while (!quit) + { + XtAppNextEvent (appContext, &event); + XtDispatchEvent (&event); + } + +// Cleanup + + delete win1; + delete win2; + delete canvas; + +// Close the X connection + + XtDestroyWidget (topLevel); + XtCloseDisplay (dpy); + XtDestroyApplicationContext (appContext); + + return (0); +} diff --git a/src/motif/xmcombo/combobox.doc b/src/motif/xmcombo/combobox.doc new file mode 100644 index 0000000000..41ec4ac5e1 --- /dev/null +++ b/src/motif/xmcombo/combobox.doc @@ -0,0 +1,220 @@ +Welcome to the ComboBox widget for Motif 1.1 or 1.2 (maybe even 2.0...)! +This is now version 1.32. +THERE ARE A LOT OF NEW RESOURCES AVAILABLE SO PLEASE READ THE +DOCUMENTATION (in ComboBox_eng.dvi)!!! + +If you're in doubt, the primary source of this widget is + ftp.informatik.rwth-aachen.de (137.226.112.172) + The source is in: /pub/packages/ComboBox/ComboBox.tar.gz +This is our campus server in Aachen, Germany. From outside Europe +please also contact: + ftp.x.org (198.112.44.100) + There you'll find the source in: + /contrib/widgets/motif/ComboBox/ComboBox.tar.gz +There are many local ftp servers that mirror the /contrib directory. Thus +with a delay of one or two days you'll also find the source on many other +ftp sites. + +PLEASE READ THIS INFORMATION CAREFULLY. IT ALWAYS CONTAINS THE MOST +RECENT INFORMATION. + +Whats new? (changes since the last version are marked with an asterisk) + * Some minor changes concerning the drop down list layout have been made in + order to correct some minor quirks. + * Updated files for VMS users (hellooooo -- where are you?!!) + - A real man page for use with troff/groff. It's in ComboBox.groff. + - Some applications like GUI development tools or TclMotif were unable to + get notice of these special resources because they were implemented + through the core's setValues method. Thus they don't appeared in the + resource list because there aren't any instance variables connected to + them. These mirror resources instead belong to child widgets. With 1.23 + the resource list (which can be queried by XtGetResourceList()) contains + entries for all mirror resources although the initial value setting is + always zero. But this should'nt matter. You can switch off these entries + by setting -DDONT_LOOK_IN_THE_MIRROR when compiling ComboBox.c. + - The selection policies XmSINGLE_SELECT and XmBROWSE_SELECT are now + supported. + - A new resource called XmNstaticList has been added, which switches the combo + box into a new mode with the drop down list statically displayed. + - Support of XmNautomaticSelection (like the resource known from XmList). + - New callbacks XmNunselectionCallback, XmNdefaultActionCallback, + XmNmodifyVerifyCallback, XmNmotionVerifyCallback and XmNvalueChangedCallback + added (don't know whether I forgot to mention one...). + - New convenience function XmComboBoxClearItemSelection() for deselecting + any selection in the combo box (if XmNselectionPolicy is XmSINGLE_SELECT). + - New demo app called FontSel. It shows how to realize a full blown + font selection dialog (even for scalable fonts) using combo boxes. + - Some additional casting has been added to the source, so it seems + now really to be ANSI compliant. + - can be compiled with Motif 1.2. (Tested on Sun & HP yet) + - many new resources & a callback that is called whenever the drop down + list gets dropped down or hidden. + - corrected a few minor typos in the header files (mis-spelled function + prototypes) and some minor quirks in the source. + - A FULL-BLOWN ENGLISH DOCUMENTATION (dvi file) + If you can't process dvi files you can download a post script variant + from ftp.informatik.rwth-aachen.de (137.226.112.172) as + /pub/packages/ComboBox/ComboBox_eng.ps.gz + - The XmNitems and XmNitemCount resources can now be set at any time (not + only when creating the ComboBox widget). + - Corrected some minor memory leaks in the source as well as some typos and + errors in the documentation. + - Drag'n'Drop is now supported with Motif 1.2. + - fvwm's handling of FocusOut events supported. + + +Well - if you never heard of ComboBoxes you'll have to figure out +yourself what these strange widgets really are. The following text +will only explain how to include it into your own code. (Just as a little +hint: combo boxes are well known from M$ Windoze. A combo box consists +of a text input field with an arrow button besides it. When you click +on the arrow button the combo box pops up a list just below its input +area. You can now browse in it or pop it down by pressing the arrow button +again.) + +The source code is now in (wide public) use for nearly a year. +(before this time it was tested for half a year in the Institut fuer +Geometrie und Praktische Mathematik, where I'm working). So you get a well +tested piece of widget magic. Please feel free to report any trouble you +have using the ComboBox widget. But be patient - I'm just a student. In the +meantime I've received a couple of reports and hopefully the widget now can +be used on many well known systems as well as with Motif 1.1 and 1.2. I've +heard of people using the ComboBox widget with Motif 2.0, because they need +the many features... But there seems to be problems with the subclassing +mechanism, so the sanity check CheckComboBox() fails. This check is now +disabled if the source detects a Motif 2.0 release. + +BTW - I'm collecting picture postcards...if you have one with a nice picture of +the place you're living in, don't hesitate... 8-) + +1. To compile you will need at least Motif :-) + (or :-( depending on your point of view...) + and an *ANSI* c compiler (the code is completely ANSI - + no more mess with the old K&R style)! + To compile, try something like + $ cc -DFUNCPROTO -c ComboBox.c + this should do it's work. -DFUNCPROTO is needed because the function + prototypes would be K&R style without it. In addition you often need + to specify to the compiler that the source is ANSI. (-ansi with gcc) + +2. Place a + #include "ComboBox.h" + at the top of your source file and create the widget just like any + other ordinary widget. The class is xmComboBoxWidgetClass. There is + no convenience function since it's hardly ever needed with this + widget. + + To compile the short demo: + $ cc -DFUNCPROTO ComboBoxDemo.c -o ComboBoxDemo ComboBox.o \ + -lXm -lXt -lX11 + On some machines you'll need to link additional libs (like network + and socket libs). + Or use the makefile (first edit it accordingly to your needs): + $ make demo + Run the demo with: + $ ./ComboBoxDemo + + I don't provide a makefile for every system/compiler combination + because this widget is intended to be placed seamless into the + existing Motif widget set. Thus, compile it and if all is ok, then + copy the includes to the Xm directory and the object file to a + suitable place in your file system -- but don't even think of + /dev/null as a good destination ;-) + + To compile the FontSel demo: + Edit the makefile (if you haven't already done so), then do a: + $ make FontSel + And run the Font Selector demo: + $ ./FontSel + + If you also have the ButtonFace Library you may want to do a + $ make FontSelX + instead. This will use my pictural push buttons for okay, cancel and help. + +3. The ComboBox consists primarily of a XmManager descendant - the + widget you'll get from XtCreateWidget(). This widget contains several + more widgets as its childs: a XmTextField and some other widgets. + You *must* not modify any resources of the TextField directly - this + leads sooner or later to trouble. Instead all the necessary instance + variables of the TextField are accessible through the main widget + (the one XtCreateWidget() returned). + There are many (convenience) functions like the ones for XmTextFields + and XmLists to set the TextField's text, add items to the drop down + list and and and... please see ComboBox.h for details (you know: + the documentation is under work...) + +4. There is one special resource called "persistentDropDown". It + defaults to "False". Its purpose it not easy to explain since that + has to do with the way your window manager is set up. If you're + using the explicit focus methode (that is: you move the keyboard + focus from application to application by clicking on the top level + window) you're lucky - don't ever think of this resource. For all + those other people (like me): if the window manager is set up to + give the keyboard focus to the top level window the mouse cursor + is over you'll notice one annoying "feature". (It's really *not* + a bug ;-) ) If you drop down the ComboBox's list (by clicking on + the arrow right beside the text field) and move the mouse cursor + out of the window the ComboBox resides in the list immediatly + disappears. That happens because the ComboBox looses the keyboard + focus. You can try to bypass that behavior by setting + "persistentDropDown" to "True" if you like. In the application's + resource file a line like + *YourApp*ComboBox.persistentDropDown: True + should do the job. But remember: whether this will work depends + on the window manager you're using. I have testet this with + Silicon Graphics' 4dwm (a mwm clone). + +5. On some window managers the drop down list gets hidden as soon as + the user moves the mouse cursor into the list. If this happens try + to set the resource "twmHandlingOn" to "True". You can do this + on the command line: + ComboBoxDemo -xrm "*.twmHandlingOn: True" + This should do it's job with twm as well as fvwm. With olwm you shouldn't + need to set one of the special resources. + +6. The combo box has been reported to run sucessfully on: + Silicon Graphics, Sun, HP, IBM RS6000, PC, even VMS! + Linux, of course...! + Attention VMS folks! You'll find two files called "motif11.opt" or + "motif12.opt" and "vmsmake.com" in this packages. They are provided by + Vincent Li. You'll hopefully know what to do with these two + files. They are provided "as is" with no warranty. Please read the file + "readme.vms". + +42. Known bugs: you will need a german dictionary to understand all the + jokes in the source and in the german documentation. + +That's it! Enjoy using this ComboBox widget. +(More than 160 downloads yet within the first 3 weeks -- seems that I've +filled in a real gap in Motif. Thanks to all who encouraged me to do +further work on the ComboBox widget -- especially Chris Marotz!) + +You may also want to visit my "Motif Programming Cornor" at + file://ftp.igpm.rwth-aachen.de/arc/pub/unix/html/motifcorner.html +with tips & tricks about Motif. + +I really don't understand why the folks at OSF didn't implemented +something like the M$ Windoze ComboBox in Motif. Maybe they have +had their moti"f"es... (Rumor has spread it that the mysterious +Motif 2.0 will have one - whow! after many years, the OSF folk got it!) + +P.S.: This software is Free Software. Please refer to the file + COPYING, which you should have received together this + file and the source code of the combo box widget. + However if you find this widget to be usefull, you are encouraged + to donate a reasonable amount to a charitable institution -- + there are enough people out there who need help! Sometimes I got + the strong impression that programmers tend to get lost in their + own "virtual reality" - sitting in front of their screen, hacking + new algorithms and forget about everything around them. So please + don't forget about people who need help. + +(c) 1993, 1994 Harald Albrecht +Institut fuer Geometrie und Praktische Mathematik +Rheinisch-Westfaelische Technische Universitaet Aachen, +D-52056 Aachen, Germany +albrecht@igpm.rwth-aachen.de + +Bad Aachen -- Die Stadt der Printe. Warum Aachen ein Kurbad ist? +-- Wieso Kurbad? "Bad" heisst doch nur, dass es hier staendig regnet (wenn +es eben 'mal nicht schneit...) diff --git a/src/motif/xmcombo/combobox.man b/src/motif/xmcombo/combobox.man new file mode 100644 index 0000000000..026f0a31f1 --- /dev/null +++ b/src/motif/xmcombo/combobox.man @@ -0,0 +1,1386 @@ + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + +NNAAMMEE + XmComboBox - The Combo Box widget class + +SSYYNNOOPPSSIISS + ##iinncclluuddee <> + + Depending on your system's configuration the place of this + include file may vary. In doubt, contact your local system + administrator. Or run in circles and shout. + + +DDEESSCCRRIIPPTTIIOONN + The ComboBox widget allows the user to select elements + from a list of choices, and enter their own values in a + text widget. To conserve screen space, the list of choices + is shown only when the user selects the down arrow button. + The choices may then be selected from this list. The list + will automatically by removed when the user selects an + item in the list. When the list is removed, the item that + was selected will be placed in the text widget. Typing the + escape key when the list is up, cancels the list popup. + + CCllaasssseess + ComboBox inherits behaviour and resources from CCoorree and + CCoommppoossiittee, CCoonnssttrraaiinntt and XXmmMMaannaaggeerr classes. + + The class pointer is xxmmCCoommbbooBBooxxWWiiddggeettCCllaassss. + + The class name is XXmmCCoommbbooBBooxx. + + NNeeww RReessoouurrcceess + The following table defines a set of widget resources used + by the programmer to specify data. The programmer can also + set the resource values for the inherited classes to set + attributes for this widget. To reference a resource by + name or by class in a .Xdefaults file, remove the XXmmNN or + XXmmCC prefix and use the remaining letters. To specify one + of the defined values for a resource in a .Xdefaults file, + remove the XXmm prefix and use the remaining letters (in + either lowercase or uppercase, but include any underscores + between words). The codes in the access column indicate if + the given resource can be set at creation time (C), set by + using XXttSSeettVVaalluueess (S), retrieved by using XXttGGeettVVaalluueess (G), + or is not applicable (N/A). + + XXmmCCoommbbooBBooxx RReessoouurrccee SSeett + ----------------------------------------------------------------- + NNaammee DDeeffaauulltt AAcccceessss + CCllaassss TTyyppee + ----------------------------------------------------------------- + XmNactivateCallback NULL C + XmCCallback XtCallbackList + ----------------------------------------------------------------- + + + + +Version 1.31 20 March 1995 1 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + XmNalignment XmALIGNMENT_CENTER CSG + XmCAlignment unsigned char + ----------------------------------------------------------------- + XmNarrowSpacingOn False CSG + XmNCArrowSpacingOn Boolean + ----------------------------------------------------------------- + XmNautomaticSelection False CSG + XmCAutomaticSelection Boolean + ----------------------------------------------------------------- + XmNblinkRate 500 CSG + XmCBlinkRate int + ----------------------------------------------------------------- + XmNcolumns dynamic CSG + XmCColumns short + ----------------------------------------------------------------- + XmNcursorPosition 0 CSG + XmCCursorPosition XmTextPosition + ----------------------------------------------------------------- + XmNcursorPositionVisible True CSG + XmCCursorPositionVisible Boolean + ----------------------------------------------------------------- + XmNdefaultActionCallback NULL CSG + XmCCallback XtCallbackList + ----------------------------------------------------------------- + XmNdropDownCallback NULL CSG + XmCDropDownCallback XtCallbackList + ----------------------------------------------------------------- + XmNdropDownCursor center_ptr CSG + XmCDropDownCursor Cursor + ----------------------------------------------------------------- + XmNdropDownOffset dynamic CSG + XmCDropDownOffset Position + ----------------------------------------------------------------- + XmNeditable False CG + XmCEditable Boolean + ----------------------------------------------------------------- + XmNfontList dynamic CSG + XmCFontList XmFontList + ----------------------------------------------------------------- + XmNitemCount 0 CSG + XmCItemCount int + ----------------------------------------------------------------- + XmNitems NULL CSG + XmCItems XmStringTable + ----------------------------------------------------------------- + XmNlabelFontList dynamic CSG + XmCLabelFontList XmFontList + ----------------------------------------------------------------- + XmNlabelInsensitivePixmap XmUNSPECIFIED_PIXMAP CSG + XmCLabelInsensitivePixmap Pixmap + ----------------------------------------------------------------- + XmNlabelMarginBottom 0 CSG + + + + + +Version 1.31 20 March 1995 2 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + XmCLabelMarginBottom Dimension + ----------------------------------------------------------------- + XmNlabelMarginHeight 2 CSG + XmCLabelMarginHeight Dimension + ----------------------------------------------------------------- + XmNlabelMarginLeft 0 CSG + XmCLabelMarginLeft Dimension + ----------------------------------------------------------------- + XmNlabelMarginRight 0 CSG + XmCLabelMarginRight Dimension + ----------------------------------------------------------------- + XmNlabelMarginTop 0 CSG + XmCLabelMarginTop Dimension + ----------------------------------------------------------------- + XmNlabelMarginWidth 0 CSG + XmCLabelMarginWidth Dimension + ----------------------------------------------------------------- + XmNlabelPixmap XmUNSPECIFIED_PIXMAP CSG + XmCLabelPixmap Pixmap + ----------------------------------------------------------------- + XmNlabelString dynamic CSG + XmCXmString XmString + ----------------------------------------------------------------- + XmNlabelType XmSTRING CSG + XmCLabelType unsigned char + ----------------------------------------------------------------- + XmNlistMarginHeight 0 CSG + XmCListMarginHeight Dimension + ----------------------------------------------------------------- + XmNlistMarginWidth 0 CSG + XmCListMarginWidth Dimension + ----------------------------------------------------------------- + XmNlistSizePolicy XmVARIABLE CG + XmCListSizePolicy unsigned char + ----------------------------------------------------------------- + XmNlistSpacing 0 CSG + XmCListSpacing Dimension + ----------------------------------------------------------------- + XmNmarginHeight 5 CSG + XmCMarginHeight Dimension + ----------------------------------------------------------------- + XmNmarginWidth 5 CSG + XmCMarginWidth Dimension + ----------------------------------------------------------------- + XmNmaxLength largest integer CSG + XmCMaxLength int + ----------------------------------------------------------------- + XmNmodifyVerifyCallback NULL CSG + XmCCallback XtCallbackList + ----------------------------------------------------------------- + XmNmotionVerifyCallback NULL CSG + XmCCallback XtCallbackList + ----------------------------------------------------------------- + + + + +Version 1.31 20 March 1995 3 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + XmNpersistentDropDown False CSG + XmCPersistentDropDown Boolean + ----------------------------------------------------------------- + XmNscrollBarDisplayPolicy XmAS_NEEDED CSG + XmCScrollBarDisplayPolicy unsigned char + ----------------------------------------------------------------- + XmNselectionCallback NULL CSG + XmCCallback XtCallbackList + ----------------------------------------------------------------- + XmNselectionPolicy XmBROWSE_SELECT CG + XmCSelectionPolicy unsigned char + ----------------------------------------------------------------- + XmNselectThreshold 5 CSG + XmCSelectThreshold int + ----------------------------------------------------------------- + XmNshowLabel False CG + XmCShowLabel Boolean + ----------------------------------------------------------------- + XmNsorted False CSG + XmCSorted Boolean + ----------------------------------------------------------------- + XmNsortingCallback NULL CSG + XmCCallback XtCallbackList + ----------------------------------------------------------------- + XmNsquareArrow False CSG + XmCSquareArrow Boolean + ----------------------------------------------------------------- + XmNstaticList False CSG + XmCStaticList Boolean + ----------------------------------------------------------------- + XmNstringDirection dynamic CSG + XmCStringDirection XmStringDirection + ----------------------------------------------------------------- + XmNtwmHandlingOn False CSG + XmCTwmHandlingOn Boolean + ----------------------------------------------------------------- + XmNtopItemPostion 1 G + XmCTopItemPostion int + ----------------------------------------------------------------- + XmNunselectionCallback NULL CSG + XmCCallback XtCallbackList + ----------------------------------------------------------------- + XmNvalue "" CSG + XmCValue String + ----------------------------------------------------------------- + XmNvalueChangedCallback NULL CSG + XmCCallback XtCallbackList + ----------------------------------------------------------------- + XmNvisibleItemCount 8 CSG + XmCVisibleItemCount Int + ----------------------------------------------------------------- + + XXmmNNaaccttiivvaatteeCCaallllbbaacckk + Specifies a list of callbacks to be called when the + + + +Version 1.31 20 March 1995 4 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + user presses either the key "Enter" or "Activate". + The type of the structure passed to this callback + is XXmmAAnnyyCCaallllbbaacckkSSttrruucctt and the reason is + XXmmCCRR__AACCTTIIVVAATTEE. + + XXmmNNaalliiggnnmmeenntt + The alignment (left to right) for the label's text + or pixmap. Possible values are XXmmAALLIIGGNN-- + MMEENNTT__BBEEGGIINNNNIINNGG, XXmmAALLIIGGNNMMEENNTT__CCEENNTTEERR, and XXmmAALLIIGGNN-- + MMEENNTT__EENNDD. + + XXmmNNaauuttoommaattiiccSSeelleeccttiioonn + Indicates whether the XXmmNNsseelleeccttiioonnCCaallllbbaacckk is + invoked each time the user moves into a new item if + XXmmNNaauuttoommaattiiccSSeelleeccttiioonn is TTrruuee and the selection + mode is XXmmBBRROOWWSSEE__SSEELLEECCTT. If set to FFaallssee the XXmmNNss-- + eelleeccttiioonnCCaallllbbaacckk is not invoked until the user + releases the mouse button. + + XXmmNNaarrrroowwSSppaacciinnggOOnn + Indicates whether a gap is displayed between the + arrow button and the text input field if this + resource is set to TTrruuee and XXmmNNeeddiittaabbllee is also set + to TTrruuee. If this resource is set to FFaallssee the + combo box widget will never display a gab between + the arrow button and the text area, irrespective of + the setting of XXmmNNeeddiittaabbllee. Note that setting + XXmmNNaarrrroowwSSppaacciinnggOOnn to FFaallssee doesn not conform to + common GUI styles. And it prevents the user from + easily recognizing whether the combo box is + editable or not. + + XXmmNNbblliinnkkRRaattee + The time in milliseconds that the cursor spends + being visible or invisible. A value of 0 prevents + the cursor from blinking. + + XXmmNNbboorrddeerrWWiiddtthh + That's no new resource but is already introduced in + the core class. This class overrides the default + value and sets it to zero. You can however override + it again if you're dissatisfied with the new + default setting. + + XXmmNNccoolluummnnss + Specifies the initial width of the input field mea- + sured in character spaces. The default value + depends on the value of the width of the combo box. + + XXmmNNccuurrssoorrPPoossiittiioonn + Indicates the position in the text where the insert + cursor is to be located. Its position is the offset + of characters and it starts with offset 0 at the + beginning of the text. + + + +Version 1.31 20 March 1995 5 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + XXmmNNccuurrssoorrPPoossiittiioonnVViissiibbllee + Flags whether the insert cursor position is marked + by a blinking cursor. + + XXmmNNddeeffaauullttAAccttiioonnCCaallllbbaacckk + Specifies a list of callbacks that is called every + time an item is double clicked. The reason is + XXmmCCRR__DDEEFFAAUULLTT__AACCTTIIOONN. Please remember that you + can't use this callback if XXmmNNssttaattiiccLLiisstt is FFaallssee + because the list is immediatly hidden after the + user selected an item from the list. Thus the user + can't double click on any item within the list. + + XXmmNNddrrooppDDoowwnnCCaallllbbaacckk + This is a list of callbacks to be called when the + list is about to be shown or hidden. The reasons + are XXmmCCRR__SSHHOOWW__LLIISSTT or XXmmCCRR__HHIIDDEE__LLIISSTT. + + XXmmNNddrrooppDDoowwnnCCuurrssoorr + Specifies the cursor to be used whenever the mouse + cursor is within the drop down list. + + XXmmNNddrrooppDDoowwnnOOffffsseett + Specifies the distance between the left border of + the list and the left border of the input field. + The default value is set to the width of the arrow + button. Only positive values are allowed for XXmmNN-- + ddrrooppDDoowwnnOOffffsseett, negative ones will be ignored. + + XXmmNNeeddiittaabbllee + Specifies the type of combo box. If set to True, + the combo box contains an editable input field. + Therefore, the user is free to select entries out + of the list and to enter new text or modify it. In + the other case, with XmNeditable set to False the + user can solely browse in and select entries out of + the list. + + XXmmNNffoonnttLLiisstt + Indicates the font list to be used for the input + field and the list. If the value is NULL at ini- + tialization, it is initialized by looking up the + parent hierarchy of the widget for an ancestor that + is a subclass of XXmmBBuulllleettiinnBBooaarrdd, XXmmVVeennddoorrSShheellll or + XXmmMMeennuuSShheellll. If such an ancestor is found, it's + font list will be taken by the combo box widget. + + XXmmNNiitteemmCCoouunntt + Specifies the total number of items in the list. + + XXmmNNiitteemmss + Points to an array of compound strings representing + the items to be displayed in the list. By means of + this a program can find out what items the list + + + +Version 1.31 20 March 1995 6 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + contains. It is also possible to set the contents + of the list box in one step by setting this + resource to a new array of compound strings. Please + remember: always set XXmmNNiitteemmss and XXmmNNiitteemmCCoouunntt + together in the same call to XXttSSeettVVaalluueess or + XXttVVaaSSeettVVaalluueess. If you ignore this rule the combo + box will ignore you and your attempt to set these + resources. + + XXmmNNllaabbeellIInnsseennssiittiivveePPiixxmmaapp + Specifies a pixmap used as the button face if XXmmNN-- + llaabbeellTTyyppee is set to XXmmPPIIXXMMAAPP and the combo box wid- + get is insensitive. + + XXmmNNllaabbeellPPiixxmmaapp + Specifies a pixmap to be displayed to the left of + the input field if XXmmNNllaabbeellTTyyppee is XXmmPPIIXXMMAAPP and + XXmmNNsshhoowwLLaabbeell is True (of course). + + XXmmNNllaabbeellSSttrriinngg + Specifies the the compound string to be displayed + if XXmmNNllaabbeellTTyyppee is set to XXmmSSTTRRIINNGG and XXmmNNsshhoowwLLaabbeell + is True. + + XXmmNNllaabbeellTTyyppee + The type of label (either string or pixmap). Possi- + ble values are XXmmPPIIXXMMAAPP and XXmmSSTTRRIINNGG. + + XXmmNNllaabbeellMMaarrggiinnTToopp,, XXmmNNllaabbeellMMaarrggiinnBBoottttoomm + XXmmNNllaabbeellMMaarrggiinnLLeefftt,, XXmmNNllaabbeellMMaarrggiinnRRiigghhtt + The amount of space between one side of the label + and the nearest margin. + + XXmmNNllaabbeellMMaarrggiinnHHeeiigghhtt,, XXmmNNllaabbeellMMaarrggiinnWWiiddtthh + The spacing between one side of the label and the + nearest edge of a shadow. + + XXmmNNlliissttMMaarrggiinnHHeeiigghhtt,, XXmmNNlliissttMMaarrggiinnWWiiddtthh + The height or width of the margin between the bor- + der of the list and the items in the list. + + XXmmNNlliissttSSiizzeePPoolliiccyy + Controls the reaction of the list when an item + grows horizontally beyond the current width of the + list and XXmmNNssttaattiiccLLiisstt is set to TTrruuee. If set to + XXmmCCOONNSSTTAANNTT, the list does not grow, and a horizon- + tal scroll bar is shown. If this resource is set to + XXmmVVAARRIIAABBLLEE, the list instead trys to grow such that + it match the size of the longest item, thus no hor- + izontal scroll bar will appear. When XXmmNNlliisstt-- + SSiizzeePPoolliiccyy is the list will again try to grow but + in case the width of the longest item in the list + is wider than the viewing area of the list a hori- + zontal scroll bar appears. + + + +Version 1.31 20 March 1995 7 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + XXmmNNlliissttSSppaacciinngg + The spacing between items in the list. + + XXmmNNmmaarrggiinnHHeeiigghhtt + Specifies the distance between the top and the bot- + tom of the widget window and the text displayed in + the input field. + + XXmmNNmmaarrggiinnWWiiddtthh + Like XmNmarginHeight this resource specifies the + distance between the left and the right border of + the widget window and the text. + + XXmmNNmmaaxxLLeennggtthh + Specifies the maximum length of the text string + that can be entered from the keyboard into the + input field of the combo box. Strings that are put + into the input field using XXmmCCoommbbooBBooxxSSeettSSttrriinngg + ignore this resource. + + XXmmNNmmooddiiffyyVVeerriiffyyCCaallllbbaacckk + Contains a list of callbacks called before text is + deleted from or inserted into the text area of the + combo box widget. The callbacks are called only if + XXmmNNeeddiittaabbllee is set to TTrruuee. The reason is + XXmmCCRR__MMOODDIIFFYYIINNGG__TTEEXXTT__VVAALLUUEE and the type of the + structure passed to this callback is XXmmCCoommbbooBBooxx-- + TTeexxttVVeerriiffyyCCaallllbbaacckkSSttrruucctt. + + XXmmNNmmoottiioonnVVeerriiffyyCCaallllbbaacckk + Specifies the list of callbacks that is called + before the insert cursor gets moved to another + position. The reason is XXmmCCRR__MMOOVVIINNGG__IINNSSEERRTT__CCUURRSSOORR + and the type of the structure whose address is + passed to the callback is XXmmCCoommbbooBBooxxTTeexxttVVeerriiffyyCCaallll-- + bbaacckk--SSttrruucctt. + + XXmmNNssccrroollllBBaarrDDiissppllaayyPPoolliiccyy + Controls the display of the vertical scroll bar in + the list when XXmmNNssttaattiiccLLiisstt is set to TTrruuee..When + XXmmNNssccrroollllBBaarrDDiissppllaayyPPoolliiccyy is set to XXmmAASS__NNEEEEDDEEDD, + the vertical scroll bar is displayed only when the + list contains more items than can be currently dis- + played. If set to XXmmSSTTAATTIICC the vertical scroll bar + is always displayed. + + XXmmNNppeerrssiisstteennttDDrrooppDDoowwnn + Welcome to the sad section in the life of X11 + applications. This resource and the inherent prob- + lems are due to the focus policy of the window man- + ager you're using. See the further details in the + later sections. + + + + + +Version 1.31 20 March 1995 8 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + XXmmNNsseelleeccttiioonnCCaallllbbaacckk + Specifies a list of callbacks that is called when + an item is selected. The reason is + XXmmCCRR__SSIINNGGLLEE__SSEELLEECCTT. The callbacks are NOT called + when the user browses through the items in the + list. + + XXmmNNsseelleeccttiioonnPPoolliiccyy + This resource controls whether the user can dese- + lect the currently selected item within a combo + box. The default value is XXmmBBRROOWWSSEE__SSEELLEECCTT, so + always one item gets selected if the combo box is + editable. In the case of XXmmSSIINNGGLLEE__SSEELLEECCTT the user + may deselect the current item either by clicking on + it in the drop down list or pressing the key + "Delete". Other values for XXmmNNsseelleeccttiioonnPPoolliiccyy are + currently not allowed. (Multiple selections will be + probably availabe with the next release.) + + XXmmNNsseelleeccttTThhrreesshhoolldd + Specifies the amount of pixels the mouse must move + until the selection of text is recognized in click + and drag mode. + + XXmmNNsshhoowwLLaabbeell + Specifies, whether a label containing text or a + pixmap should be displayed on the left side of the + combo box. This resource can only be specified dur- + ing the creation of the combo box, afterwards it + will have no effect. + + XXmmNNssoorrtteedd + Specifies whether the items in the list are sorted + or not In an unsorted list, the items are shown in + the order in which they're put into the list. When + adding an item to a sorted list, this item will be + put at the right place (alphabetically sorted). + + XXmmNNssoorrttiinnggCCaallllbbaacckk + Contains a list of callbacks that is called when- + ever a new item is added to the combo box widget + and XXmmNNssoorrtteedd is TTrruuee. The reason is XXmmCCRR__SSOORRTTIINNGG + and the type of the structure whose address is + passed to the callback is XXmmCCoommbbooBBooxxSSoorrttiinnggCCaallll-- + bbaacckk--SSttrruucctt. For detailed information see the fol- + lowing sections. + + XXmmNNssqquuaarreeAArrrrooww + Controls the width of the arrow button in respect + to its height. If this resource is TTrruuee the arrow + button is always layed out square. Otherwise the + arrow button's width will be approximatly 4/5th of + its height. + + + + +Version 1.31 20 March 1995 9 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + XXmmNNssttaattiiccLLiisstt + Controls whether the list is always statically dis- + played right below the text input area of the combo + box if set to TTrruuee. If you use a combo box with + XXmmNNssttaattiiccLLiisstt set to TTrruuee and XXmmNNeeddiittaabbllee set to + FFaallssee you should consider using a simple list wid- + get instead. + + XXmmNNssttrriinnggDDiirreeccttiioonn + Specifies the initial direction to draw the string + (from the left to the right or in the opposite + direction). The whole story seems to be incompre- + hensible... therefore this resource is provided for + completeness only. + + XXmmNNttwwmmHHaannddlliinnggOOnn + If you have trouble with the list then this + resource may help you. Set it to True, if the list + gets hidden at the moment the mouse cursor enters + the list. + + XXmmNNttooppIItteemmPPoossiittiioonn + This resource is intended as an informal hint. It + specifies the index of the item which is displayed + at the visible top of the list. + + XXmmNNvvaalluuee + Contains the text of the input field. This also + concerns combo boxes which are not editable ( + XXmmNNeeddiittaabbllee set to False). + + XXmmNNuunnsseelleeccttiioonnCCaallllbbaacckk + Specifies a list of callbacks that is called when- + ever the currently selected item is deselected and + no other item gets selected. This callback is acti- + vated only when XXmmNNsseelleeccttiioonnPPoolliiccyy is XXmmSSIINN-- + GGLLEE__SSEELLEECCTT. The reason is XXmmCCRR__UUNNSSEELLEECCTT. The type + of the structure whose address is passed to this + callback is XXmmAAnnyyCCaallllbbaacckkSSttrruucctt. + + XXmmNNvvaalluuee + Contains the text of the input field. This also + concerns combo boxes which are not editable ( + XXmmNNeeddiittaabbllee set to FFaallssee). + + XXmmNNvvaalluueeCChhaannggeeddCCaallllbbaacckk + Specifies a list of callbacks to be called after + text is deleted from or inserted into the text area + of the combo box widget. The reason is + XXmmCCRR__VVAALLUUEE__CCHHAANNGGEEDD. The type of the structure + whose address is passed to this callback is XXmmAAnnyy-- + CCaallllbbaacckkSSttrruucctt. + + + + + +Version 1.31 20 March 1995 10 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + XXmmNNvviissiibblleeIItteemmCCoouunntt + Specifies the number of items that can fit in the + visible space of the list. The combo box uses this + value to determine the height of its list. + + IInnhheerriitteedd RReessoouurrcceess + XmComboBox inherits behaviour and resources from the fol- + lowing superclasses. For a complete description of each + resource, refer to the man page for that superclass. + + CCaallllbbaacckk IInnffoorrmmaattiioonn + A pointer to the following structure is passed to the + XXmmNNddrrooppDDoowwnnCCaallllbbaacckk callback: + + ttyyppeeddeeff ssttrruucctt {{ + iinntt _r_e_a_s_o_n;; + XXEEvveenntt **_e_v_e_n_t;; + }} XXmmCCoommbbooBBooxxDDrrooppDDoowwnnCCaallllbbaacckkSSttrruucctt;; + + _r_e_a_s_o_n Within this structure, _r_e_a_s_o_n indicates the + reason why the callback was activated. This + can be XXmmCCRR__SSHHOOWW__LLIISSTT as well as + XXmmCCRR__HHIIDDEE__LLIISSTT. A callback is called with + the reason XXmmCCRR__SSHHOOWW__LLIISSTT just before the + list is dropped down, whereas the callback + is called with XXmmCCRR__HHIIDDEE__LLIISSTT after the + list is hidden. + + + _e_v_e_n_t Points to the XXEEvveenntt, which triggered the + callback. May be NNUULLLL if the callback is + triggered by a call to XXmmCCoommbbooBBooxxSShhoowwLLiisstt + or XXmmCCoommbbooBBooxxHHiiddeeLLiisstt. + + A pointer to the following structure is passed to the + XXmmNNaaccttiivvaatteeCCaallllbbaacckk callback: + + ttyyppeeddeeff ssttrruucctt {{ + iinntt _r_e_a_s_o_n;; + XXEEvveenntt **_e_v_e_n_t;; + }} XXmmAAnnyyCCaallllbbaacckkSSttrruucctt;; + + _r_e_a_s_o_n Indicates why the callback was invoked. + This is XXmmCCRR__AACCTTIIVVAATTEE for XXmmNNaaccttiivvaatteeCCaallll-- + bbaacckk. + + _e_v_e_n_t Points to the XXEEvveenntt, which triggered the + callback. + + A pointer to the following structure is passed to the + XXmmNNsseelleeccttiioonnCCaallllbbaacckk and XXmmNNddeeffaauullttAAccttiioonnCCaallllbbaacckk: + + ttyyppeeddeeff ssttrruucctt {{ + iinntt _r_e_a_s_o_n;; + + + +Version 1.31 20 March 1995 11 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + XXEEvveenntt **_e_v_e_n_t;; + XXmmSSttrriinngg _v_a_l_u_e;; + iinntt _i_n_d_e_x;; + }} XXmmCCoommbbooBBooxxSSeelleeccttiioonnCCaallllbbaacckkSSttrruucctt,, XXmmCCoommbbooBBooxxDDeeffaauullttAAcc-- + ttiioonnCCaallllbbaacckkSSttrruucctt;; + + _r_e_a_s_o_n Within this structure, _r_e_a_s_o_n indicates the + reason why the callback was activated. At + this time, the reason can be either + XXmmCCRR__SSIINNGGLLEE__SSEELLEECCTT or XXmmCCRR__BBRROOWWSSEE__SSEELLEECCTT + depending on the setting of XXmmNNsseelleeccttiioonn-- + PPoolliiccyy. It indicates that the user + selected a (potentially new) item in the + list. Whether this callback is activated + every time the user moves into a new item + of the list or only when the user releases + the mouse button is controlled through the + setting of XXmmNNaauuttoommaattiiccSSeelleeccttiioonn. + + _e_v_e_n_t Points to the XXEEvveenntt, which triggered the + callback. + + _v_a_l_u_e Points to a XXmmSSttrriinngg, which contains the + text of the current selected item. This + XXmmSSttrriinngg must never be freed or changed by + the called program code! + + _i_n_d_e_x Index (starting from 1) of the currently + selected item in the list. + + A pointer to the following structure is passed to the + XXmmNNuunnsseelleeccttiioonnCCaallllbbaacckk callback: + + ttyyppeeddeeff ssttrruucctt {{ + iinntt _r_e_a_s_o_n;; + XXEEvveenntt **_e_v_e_n_t;; + }} XXmmCCoommbbooBBooxxUUnnsseelleeccttiioonnCCaallllbbaacckkSSttrruucctt;; + + _r_e_a_s_o_n Indicates why the callback was invoked. + This is XXmmCCRR__UUNNSSEELLEECCTT. + + _e_v_e_n_t Points to the XXEEvveenntt, which triggered the + callback. + + A pointer to the following structure is passed to the + XXmmNNmmooddiiffyyVVeerriiffyyCCaallllbbaacckk and XXmmNNmmoottiioonnVVeerriiffyyCCaallllbbaacckk call- + backs: + + ttyyppeeddeeff ssttrruucctt {{ + iinntt _r_e_a_s_o_n;; + XXEEvveenntt **_e_v_e_n_t;; + BBoooolleeaann _d_o_i_t;; + PPoossiittiioonn _c_u_r_r_I_n_s_e_r_t_, _n_e_w_I_n_s_e_r_t;; + PPoossiittiioonn _s_t_a_r_t_P_o_s_, _e_n_d_P_o_s;; + + + +Version 1.31 20 March 1995 12 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + XXmmTTeexxttBBlloocckk _t_e_x_t;; + }} XXmmCCoommbbooBBooxxTTeexxttVVeerriiffyyCCaallllbbaacckkSSttrruucctt,, **XXmmCCoommbbooBBooxxTTeexxttVVeerrii-- + ffyyPPttrr;; + + _r_e_a_s_o_n Indicates the reason why the callback was + activated. This can be either + XXmmCCRR__MMOODDIIFFYYIINNGG__TTEEXXTT__VVAALLUUEE or + XXmmCCRR__MMOOVVIINNGG__IINNSSEERRTT__CCUURRSSOORR. + + _e_v_e_n_t Points to the XXEEvveenntt, which triggered the + callback. + + _d_o_i_t Indicates whether the offending action + should be performed. Setting this field of + the callback structure to FFaallssee denies the + action. + + _c_u_r_r_I_n_s_e_r_t Specifies the current position of the + insert cursor. + + Indicates the position at which the user + attempts to position the cursor. + + _s_t_a_r_t_P_o_s Indicates the starting position of the text + to modify. If the reason is + XXmmCCRR__MMOOVVIINNGG__IINNSSEERRTT__CCUURRSSOORR this value is the + same as ccuurrrrIInnsseerrtt. + + _e_n_d_P_o_s Specifies the ending position of the text + to modify. If no text is replaced or + deleted, then the value will be the same as + ssttaarrttPPooss. If the reason is + XXmmCCRR__MMOODDIIFFYYIINNGG__TTEEXXTT__VVAALLUUEE this value is the + same as _c_u_r_r_I_n_s_e_r_t. + + _t_e_x_t Holds the address of a structure of type + XXmmTTeexxttBBlloocckkRReecc which holds the textual + information to be inserted. + + The following table describes the reasons why the individ- + ual verification callback structure fields are valid. + + RReeaassoonn VVaalliidd FFiieellddss + ----------------------------------------------------- + XXmmCCRR__MMOODDIIFFYYIINNGG__TTEEXXTT__VVAALLUUEE _r_e_a_s_o_n, _e_v_e_n_t, _d_o_i_t, + _s_t_a_r_t_P_o_s, _e_n_d_P_o_s, _t_e_x_t + + XXmmCCRR__MMOOVVIINNGG__IINNSSEERRTT__CCUURRSSOORR _r_e_a_s_o_n, _e_v_e_n_t, _d_o_i_t, + _c_u_r_r_I_n_s_e_r_t, _n_e_w_I_n_s_e_r_t, + + A pointer to the following structure is passed to the XXmmNN-- + ssoorrttiinnggCCaallllbbaacckk callback: ttyyppeeddeeff ssttrruucctt {{ + iinntt _r_e_a_s_o_n;; + XXEEvveenntt **_e_v_e_n_t;; + + + +Version 1.31 20 March 1995 13 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + iinntt _o_p_e_r_a_t_i_o_n;; + vvooiidd **_i_t_e_m___i_n_t_e_r_n_a_l;; + XXmmSSttrriinngg _i_t_e_m;; + iinntt _r_e_s_u_l_t;; + }} XXmmCCoommbbooBBooxxSSoorrttiinnggCCaallllbbaacckkSSttrruucctt,, **XXmmCCoommbbooBBooxxSSoorrttiinnggPPttrr;; + + _r_e_a_s_o_n Indicates the reason why the callback was + activated. This is XXmmCCRR__SSOORRTTIINNGG. + + _e_v_e_n_t Contains always NNUULLLL and is just there for + compatibility reasons. + + _o_p_e_r_a_t_i_o_n Indicates the operation to carry out and + can be either XXmmOOPP__IINNIITT,XXmmOOPP__DDOONNEE or + XXmmOOPP__CCOOMMPPAARREE. + + _i_t_e_m___i_n_t_e_r_n_a_l Must be set during the XXmmOOPP__IINNIITT operation + to a suitable representation of the new + item which is to be added to the list. In + all subsequent calls to this callback with + XXmmOOPP__CCOOMMPPAARREEorXXmmOOPP__DDOONNEE this field will + contain whatever you've put into it during + XXmmOOPP__IINNIITT. For detailed information refer + to the documentation "_T_h_e _C_o_m_b_o_B_o_x _W_i_d_g_e_t". + + _i_t_e_m During XXmmOOPP__IINNIITT this field points to the + item to be added to the list. When sorting + the list ( XXmmOOPP__CCOOMMPPAARREE) the field contains + the address of an item in the list which + should be compared against the new item (as + remembered in _i_t_e_m___i_n_t_e_r_n_a_l). + + _r_e_s_u_l_t When comparing an item (out of the list) in + _i_t_e_m with the new item (as remembered in + _i_t_e_m___i_n_t_e_r_n_a_l) the result has to be stored + into this structure's field. + + The following table describes which individual callback + structure fields are valid during which operations. + + RReeaassoonn VVaalliidd FFiieellddss + --------------------------------------------- + XXmmOOPP__IINNIITT _r_e_a_s_o_n, _e_v_e_n_t, _o_p_e_r_a_t_i_o_n, + _i_t_e_m, _i_t_e_m___i_n_t_e_r_n_a_l + XXmmOOPP__DDOONNEE _r_e_a_s_o_n, _e_v_e_n_t, _o_p_e_r_a_t_i_o_n, + _i_t_e_m___i_n_t_e_r_n_a_l + XXmmOOPP__CCOOMMPPAARREE _r_e_a_s_o_n, _e_v_e_n_t, _o_p_e_r_a_t_i_o_n, + _i_t_e_m, _i_t_e_m___i_n_t_e_r_n_a_l, _r_e_s_u_l_t + + For more information about controlling the sorting order + see the acompanying documentation "_T_h_e _C_o_m_b_o_B_o_x _W_i_d_g_e_t". + + CCoonnvveenniieennccee rroouuttiinneess + ComboBox has a number of convenience routines to control + + + +Version 1.31 20 March 1995 14 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + the behavior and contents of its children. + + vvooiidd XXmmCCoommbbooBBooxxAAddddIItteemm((WWiiddggeett ww,, XXmmSSttrriinngg iitteemm,, iinntt ppooss)) + Add a new item to the list's contents. If XXmmNNssoorrtteedd + is set to True, the new item is inserted alphabeti- + cally. If the list is unsorted, the same assump- + tions can be applied as with XXmmLLiissttAAddddIItteemm. + + + vvooiidd XXmmCCoommbbooBBooxxAAddddIItteemmss((WWiiddggeett ww,, XXmmSSttrriinngg **iitteemmss,, + iinntt iitteemm__ccoouunntt,, iinntt ppooss)) + Similar to XXmmCCoommbbooBBooxxAAddddIItteemm. Also see XXmmLLiissttAAdd-- + ddIItteemmss. + + + vvooiidd XXmmCCoommbbooBBooxxAAddddIItteemmUUnnsseelleecctteedd((WWiiddggeett ww,, XXmmSSttrriinngg + iitteemm,, iinntt ppooss)) + See XXmmLLiissttAAddddIItteemmUUnnsseelleecctteedd. + + + vvooiidd XXmmCCoommbbooBBooxxCClleeaarrIItteemmSSeelleeccttiioonn((WWiiddggeett ww)) + Deselects all currently selected items when + XXmmNNsseelleeccttiioonnPPoolliiccyy is XXmmSSIINNGGLLEE__SSEELLEECCTT. + + + vvooiidd XXmmCCoommbbooBBooxxDDeelleetteeIItteemm((WWiiddggeett ww,, XXmmSSttrriinngg iitteemm)) + See XXmmLLiissttDDeelleetteeIItteemm. + + + vvooiidd XXmmCCoommbbooBBooxxDDeelleetteeIItteemmss((WWiiddggeett ww,, XXmmSSttrriinngg + **iitteemmss,, iinntt iitteemm__ccoouunntt)) + See XXmmLLiissttDDeelleetteeIItteemmss. + + + vvooiidd XXmmCCoommbbooBBooxxDDeelleetteePPooss((WWiiddggeett ww,, iinntt ppooss)) + See XXmmLLiissttDDeelleetteePPooss. + + + vvooiidd XXmmCCoommbbooBBooxxDDeelleetteeIItteemmssPPooss((WWiiddggeett ww,, iinntt iitteemm__ccoouunntt,, + iinntt ppooss)) + See XXmmLLiissttDDeelleetteeIItteemmssPPooss. + + + vvooiidd XXmmCCoommbbooBBooxxDDeelleetteeAAllllIItteemmss((WWiiddggeett ww)) + See XXmmLLiissttDDeelleetteeAAllllIItteemmss. + + + vvooiidd XXmmCCoommbbooBBooxxRReeppllaacceeIItteemmss((WWiiddggeett ww,, XXmmSSttrriinngg + **oolldd__iitteemmss,, iinntt iitteemm__ccoouunntt,, XXmmSSttrriinngg **nneeww__iitteemmss)) + See XXmmLLiissttRReeppllaacceeIItteemmss. + + + vvooiidd XXmmCCoommbbooBBooxxRReeppllaacceeIItteemmssPPooss((WWiiddggeett ww,, XXmmSSttrriinngg + **nneeww__iitteemmss,, iinntt iitteemm__ccoouunntt,, iinntt ppoossiittiioonn)) + + + +Version 1.31 20 March 1995 15 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + See XXmmLLiissttRReeppllaacceeIItteemmssPPooss. + + + BBoooolleeaann XXmmCCoommbbooBBooxxIItteemmEExxiissttss((WWiiddggeett ww,, XXmmSSttrriinngg iitteemm)) + See XXmmLLiissttIItteemmEExxiissttss. + + + iinntt XXmmCCoommbbooBBooxxIItteemmPPooss((WWiiddggeett ww,, XXmmSSttrriinngg iitteemm)) + See XXmmLLiissttIItteemmPPooss. + + + BBoooolleeaann XXmmCCoommbbooBBooxxGGeettMMaattcchhPPooss((WWiiddggeett ww,, XXmmSSttrriinngg + iitteemm,, iinntt ****ppooss__lliisstt,, iinntt **ppooss__ccoouunntt)) + See XXmmLLiissttGGeettMMaattcchhPPooss. + + + vvooiidd XXmmCCoommbbooBBooxxSSeelleeccttPPooss((WWiiddggeett ww,, iinntt ppooss,, BBoooolleeaann + nnoottiiffyy)) + See XXmmLLiissttSSeelleeccttPPooss. + + + vvooiidd XXmmCCoommbbooBBooxxSSeelleeccttIItteemm((WWiiddggeett ww,, XXmmSSttrriinngg iitteemm,, + BBoooolleeaann nnoottiiffyy)) + See XXmmLLiissttSSeelleeccttIItteemm. + + + iinntt XXmmCCoommbbooBBooxxGGeettSSeelleecctteeddPPooss((WWiiddggeett ww)) + This function differs from XXmmLLiissttGGeettSSeelleecctteeddPPooss. + The list in a combo box can contain only one + selected item. Therefore this function returns the + index of the selected item in the list or zero, if + none is currently selected. + + + vvooiidd XXmmCCoommbbooBBooxxCClleeaarrSSeelleeccttiioonn((WWiiddggeett ww,, TTiimmee ttiimmee)) + See XXmmTTeexxttFFiieellddCClleeaarrSSeelleeccttiioonn. + + + BBoooolleeaann XXmmCCoommbbooBBooxxCCooppyy((WWiiddggeett ww,, TTiimmee ttiimmee)) + See XXmmTTeexxttFFiieellddCCooppyy. + + + BBoooolleeaann XXmmCCoommbbooBBooxxCCuutt((WWiiddggeett ww,, TTiimmee ttiimmee)) + See XXmmTTeexxttFFiieellddCCuutt. + + + XXmmTTeexxttPPoossiittiioonn XXmmCCoommbbooBBooxxGGeettIInnsseerrttiioonnPPoossiittiioonn((WWiiddggeett ww)) + See XXmmTTeexxttFFiieellddGGeettIInnsseerrttiioonnPPoossiittiioonn. + + + XXmmTTeexxttPPoossiittiioonn XXmmCCoommbbooBBooxxGGeettLLaassttPPoossiittiioonn((WWiiddggeett ww)) + See XXmmTTeexxttFFiieellddGGeettLLaassttPPoossiittiioonn. + + + + + +Version 1.31 20 March 1995 16 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + iinntt XXmmCCoommbbooBBooxxGGeettMMaaxxLLeennggtthh((WWiiddggeett ww)) + See XXmmTTeexxttFFiieellddGGeettMMaaxxLLeennggtthh. + + + cchhaarr **XXmmCCoommbbooBBooxxGGeettSSeelleeccttiioonn((WWiiddggeett ww)) + See XXmmTTeexxttFFiieellddGGeettSSeelleeccttiioonn. + + + BBoooolleeaann XXmmCCoommbbooBBooxxGGeettSSeelleeccttiioonnPPoossiittiioonn((WWiiddggeett ww,, + XXmmTTeexxttPPoossiittiioonn **lleefftt,, XXmmTTeexxttPPoossiittiioonn **rriigghhtt)) + See XXmmTTeexxttFFiieellddGGeettSSeelleeccttiioonnPPoossiittiioonn. + + + cchhaarr **XXmmCCoommbbooBBooxxGGeettSSttrriinngg((WWiiddggeett ww)) + See XXmmTTeexxttFFiieellddGGeettSSttrriinngg. + + + vvooiidd XXmmCCoommbbooBBooxxIInnsseerrtt((WWiiddggeett ww,, XXmmTTeexxttPPoossiittiioonn + ppoossiittiioonn,, cchhaarr **vvaalluuee)) + See XXmmTTeexxttFFiieellddIInnsseerrtt. + + + BBoooolleeaann XXmmCCoommbbooBBooxxPPaassttee((WWiiddggeett ww)) + See XXmmTTeexxttFFiieellddPPaassttee. + + + BBoooolleeaann XXmmCCoommbbooBBooxxRReemmoovvee((WWiiddggeett ww)) + See XXmmTTeexxttFFiieellddRReemmoovvee. + + + vvooiidd XXmmCCoommbbooBBooxxRReeppllaaccee((WWiiddggeett ww,, XXmmTTeexxttPPoossiittiioonn + ffrroomm__ppooss,, XXmmTTeexxttPPoossiittiioonn ttoo__ppooss,, cchhaarr **vvaalluuee)) + See XXmmTTeexxttFFiieellddRReeppllaaccee. + + + vvooiidd XXmmCCoommbbooBBooxxSSeettAAddddMMooddee((WWiiddggeett ww,, BBoooolleeaann ssttaattee)) + See XXmmTTeexxttFFiieellddSSeettAAddddMMooddee. + + + vvooiidd XXmmCCoommbbooBBooxxSSeettHHiigghhlliigghhtt((WWiiddggeett ww,, XXmmTTeexxttPPoossiittiioonn + lleefftt,, XXmmTTeexxttPPoossiittiioonn rriigghhtt,, XXmmHHiigghhlliigghhttMMooddee mmooddee)) + See XXmmTTeexxttFFiieellddSSeettHHiigghhlliigghhtt. + + + vvooiidd XXmmCCoommbbooBBooxxSSeettIInnsseerrttiioonnPPoossiittiioonn((WWiiddggeett ww,, + XXmmTTeexxttPPoossiittiioonn ppoossiittiioonn)) + See XXmmTTeexxttFFiieellddSSeettIInnsseerrttiioonnPPoossiittiioonn. + + + vvooiidd XXmmCCoommbbooBBooxxSSeettMMaaxxLLeennggtthh((WWiiddggeett ww,, iinntt mmaaxx__lleennggtthh)) + See XXmmTTeexxttFFiieellddSSeettMMaaxxLLeennggtthh. + + + + + + +Version 1.31 20 March 1995 17 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + vvooiidd XXmmCCoommbbooBBooxxSSeettSSeelleeccttiioonn((WWiiddggeett ww,, XXmmTTeexxttPPoossiittiioonn + ffiirrsstt,, XXmmTTeexxttPPoossiittiioonn llaasstt,, TTiimmee ttiimmee)) + See XXmmTTeexxttFFiieellddSSeettSSeelleeccttiioonn. + + + vvooiidd XXmmCCoommbbooBBooxxSSeettSSttrriinngg((WWiiddggeett ww,, cchhaarr **vvaalluuee)) + At least Motif 1.1 contains a very anoying bug. If + you try to set the contents of an XmTextField to an + empty string (""), you'll get garbage, when asking + the XmTextField for its contents afterwards. This + interface function provides a work around. Also see + XXmmTTeexxttFFiieellddSSeettSSttrriinngg. + + + vvooiidd XXmmCCoommbbooBBooxxSShhoowwPPoossiittiioonn((WWiiddggeett ww,, XXmmTTeexxttPPoossiittiioonn ppoossii-- + ttiioonn)) + See XXmmTTeexxttFFiieellddSShhoowwPPoossiittiioonn. + + + TThhee DDiisslliikkeedd KKeeyybbooaarrdd FFooccuuss + Now I'll annotate a somewhat tricky subject. If the + resource XXmmNNppeerrssiisstteennttDDrrooppDDoowwnn defaults to its initial + value of FFaallssee, one can observe the following effect (this + may be annoying). + + When the user drops down the list and then moves the mouse + cursor out of the window where the combo box resides in, + the list will be hidden. This is because the widget lost + the keyboard focus. Some users are irritated because they + didn't expect that behavior, because they just moved the + mouse to get it out of the way. If your window manager's + focus policy is "pointer focus", i.e. if you move the + pointer into another window, that window will automati- + cally get the keyboard focus. On the other hand, if your + window manager's focus policy is "explicit", you have to + move the pointer into another window and click a mouse + button to give that window the keyboard focus. This is + often referred to as the "click-to-type" method. In + "explicit" mode, you will never see the list's annoying + behavior. + + To bypass this behavior on some window managers a really + dirty hack was used. The user can activate that hack, if + he sets XXmmNNppeerrssiisstteennttDDrrooppDDoowwnn to TTrruuee in the application's + resources. Sorry, on some window managers this will not + fix the annoying behavior. + + Try it if you like - but don't complain at me if it + doesn't work as expected. But at least it worked on the + author's machine: a cute little SGI Indigo running 4dwm as + the window manager. + + On some other window managers like twm you will face + another problem: the list gets hidden as soon as the mouse + + + +Version 1.31 20 March 1995 18 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + cursor enters the list. Try to set XXmmNNttwwmmHHaannddlliinnggOOnn to + TTrruuee. This resource will also work with other window man- + agers. + + + CCrreeaattiinngg aa CCoommbbooBBooxx + Using the combo box in your own programs is easy. Just + create the widget with one of the innumerable X toolkit + functions (like XXttCCrreeaatteeMMaannaaggeeddWWiiddggeett or XXttVVaaCCrreeaatteeMMaann-- + aaggeeddWWiiddggeett). + + + Specify as the widget class xmComboBoxWidgetClass - that's + all. There is also a so-called creation convenience func- + tion called XXmmCCrreeaatteeCCoommbbooBBooxx, but it isn't really needed. + + WWiiddggeett XXmmCCrreeaatteeCCoommbbooBBooxx((_p_a_r_e_n_t_, _n_a_m_e_, _a_r_g_l_i_s_t_, _a_r_g_c_o_u_n_t)) + WWiiddggeett _p_a_r_e_n_t; + SSttrriinngg _n_a_m_e; + AArrggLLiisstt _a_r_g_l_i_s_t; + CCaarrddiinnaall _a_r_g_c_o_u_n_t; + + Somewhere in your program you'll need something like the + following code fragment: + + + Widget ComboBox; + + ComboBox = XtVaCreateManagedWidget("combobox", + xmComboBoxWidgetClass, Parent, + XmNeditable, True or False, + other Resources... + NULL); + + + Setting the resource XXmmNNeeddiittaabbllee is not absolutely neces- + sary, but it's better to do so. + + After creation, items can be added to the combo box's list + by means of interface functions like XXmmCCoommbbooBBooxxAAdd-- + ddIItteemm((......)). Which item the user selected can be deter- + mined by calling XXmmCCoommbbooBBooxxGGeettSSttrriinngg((......)). + + + If you want to preselect an item (that is setting a + default item to the input field of the combo box) you can + use several convenience functions. On a combo box with a + non editable input field there are two ways to select an + item: + + + XmComboBoxSelectPos(ComboBox, item #, False); + + or: + + + +Version 1.31 20 March 1995 19 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + XmComboBoxSelectItem(ComboBox, itemString, False); + + The third parameter in these two function calls indicates + whether the XXmmNNsseelleeccttiioonnCCaallllbbaacckk should be called. The + only difference between these functions is the first one + is expecting an item number whereas the second one expects + a XmString. The list is then searched for this string and + if it is found the input field will be updated. + + On a combo box with XXmmNNeeddiittaabbllee set to TTrruuee use another + function: + + XmComboBoxSetString(ComboBox, string); + + This sets the contents of the text input field to string. + + + +BBUUGGSS + Not more than currently available in Motif 1.2.3 or Motif + 1.2.4, but less than in the upcomming Motif 2.0. Report + bugs to albrecht@igpm.rwth-aachen.de. Include a thoroughly + description, and say which version of the ComboBox widget + you are using. + + + +CCOOPPYYRRIIGGHHTT + Copyright 1993, 1994 Harald Albrecht. + + The ComboBox widget is free software; you can redistribute + it and/or modify it under the terms of the GNU General + Public License as published by the Free Software Founda- + tion; either version 2, or (at your option) any later ver- + sion. + + + +AAVVAAIILLAABBIILLIITTYY + The most recent released version of the ComboBox widget is + always available for anonymous ftp from either + + ftp.x.org (198.112.44.100) + /contrib/widgets/motif/ComboBox + + or from + + ftp.informatik.rwth-aachen.de (137.226.112.172) + /pub/packages/ComboBox + + + +AAUUTTHHOORR + Author of Software & Documentation: + + + +Version 1.31 20 March 1995 20 + + + + + +XmComboBox(3Xm) Harry's Motif Tools XmComboBox(3Xm) + + + Harald Albrecht + Institut fuer Geometrie und Praktische Mathematik + RWTH Aachen, Bundesrepublik Deutschland + e-mail: albrecht@igpm.rwth-aachen.de + + English Documentation: + Chris Marotz + Sterling Software ITD + e-mail: marotz@itd.sterling.com + + + +RREELLAATTEEDD IINNFFOORRMMAATTIIOONN + "_T_h_e _C_o_m_b_o_B_o_x _W_i_d_g_e_t" documentation + CCoorree((33XX)), XXmmCCoommppoossiittee((33XX)), XXmmLLiisstt((33XX)), XXmmTTeexxttFFiieelldd((33XX)) + _D_o_u_g_l_a_s _A_d_a_m_s_: _T_h_e _H_i_t_c_h_h_i_k_e_r_'_s _G_u_i_d_e _t_o _t_h_e _G_a_l_a_x_y_. + ffiillee::////113344..113300..116611..3300//aarrcc//ppuubb//uunniixx//hhttmmll//mmoottiiffccoorrnneerr..hhttmmll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Version 1.31 20 March 1995 21 + + diff --git a/src/motif/xmcombo/combop.h b/src/motif/xmcombo/combop.h new file mode 100644 index 0000000000..3e1c8591f8 --- /dev/null +++ b/src/motif/xmcombo/combop.h @@ -0,0 +1,131 @@ +/* + * ComboBoxP.h - Das schon lange schmerzlich vermisste Combo-Box- + * Widget -- nun endlich auf fuer Motif! + * Wahlweise Motif 1.1 oder 1.2. + * + * Letzte Modifikation: 04.10.1995 Revisionsstand: 1.32a + * + * (c) 1993, 1994 Harald Albrecht + * Institut fuer Geometrie und Praktische Mathematik + * RWTH Aachen, Germany + * albrecht@igpm.rwth-aachen.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING for more details); + * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, + * Cambridge, MA 02139, USA. + * + */ +#ifndef __ComboBoxWidgetP_h +#define __ComboBoxWidgetP_h + +#include "xmcombo.h" +#include +#if (XmVersion > 1001) /* sounds like tales from 1000 and 1 night.... */ +#include +#endif + +/********************************************************************* + * Klassendefinition + *********************************************************************/ +/* Neue Datenfelder fuer den Klassenrecord der Center-Widgetklasse */ +typedef struct _XmComboBoxClassPart { + int Just_to_keep_the_compiler_happy; /* Der Name ist Programm */ +} XmComboBoxClassPart; +/* + * Nun folgt die vollstaendige Klassenstruktur, mit all' den Felder, + * die bereits von den Vorfahren geerbt wurden. + */ +typedef struct _XmComboBoxClassRec { + CoreClassPart core_class; + CompositeClassPart composite_class; + ConstraintClassPart constraint_class; + XmManagerClassPart manager_class; + XmComboBoxClassPart combobox_class; +} XmComboBoxClassRec; +extern XmComboBoxClassRec xmComboBoxClassRec; + +/********************************************************************* + *Instanzdefinition + *********************************************************************/ +typedef struct _XmComboBoxPart { +/* Resourcen ... hierauf darf von aussen zugegriffen werden! */ + Boolean Editable; /* Editierbare Eingabezeile ? */ + Boolean StaticList; /* Liste immer dargestellt? */ + unsigned char SelectionPolicy; /* Was geht hier ab?! */ + unsigned char ScrollBarDisplayPolicy; + unsigned char ListSizePolicy; /* Rollbalken! */ + Boolean AutomaticSelection; /* Wann Callbacks aufrufen? */ + Boolean Sorted; /* Liste sortiert */ + XtCallbackList SortingCBL; /* Wie wird extern sortiert? */ + int VisibleItemCount; /* Anz dargstellte Eintraege */ + XmFontList Font; /* verwendete Fonts */ + XtCallbackList SelectionCBL; /* Auswahl aus Liste */ + XtCallbackList UnselectionCBL; /* Auswahl zurueckgenommen */ + XtCallbackList DefaultActionCBL; /* bei Doppelklick */ + XtCallbackList DropDownCBL; /* Liste angezeigt/versteckt */ + XtCallbackList ModifyVerifyCBL; /* Vor Aenderung im Textfeld */ + XtCallbackList ValueChangedCBL; /* Danach... */ + XtCallbackList MotionVerifyCBL; /* Der Cursor bewegt sich doch*/ + XtCallbackList ActivateCBL; /* Eingabe beendet? */ + Boolean SquareArrow; /* Quadratischer Pfeil? */ + Boolean ArrowSpacingOn; /* Abstand zw. Pfeil und Text */ + Boolean Persistent; /* Liste & Focus-Out */ + Boolean TwmHandlingOn; /* dto. */ + Boolean ShowLabel; /* Label anzeigen? */ + Position DropDownOffset; /* delta Ecke Eingabefeld, + Liste */ + +/* Ab hier wird's privat! */ + Widget EditCtrl; /* Editorzeile */ + Widget ArrowCtrl; /* Pfeil nach unten */ + Widget LabelCtrl; /* Text links neben dem Eingabefeld */ + + Widget PopupShell; /* Shell, in der die Liste liegt */ + Widget ListCtrl; /* Listenfeld */ + + Widget MyNextShell; + + Cursor ArrowCursor; + Boolean InInit; + + int LastSelection; + + Boolean ListVisible; + Boolean IgnoreFocusOut; + Boolean PendingFocusOut; + Boolean PendingOverrideInOut; + XtWorkProcId WorkProcID; + XEvent xevent; + + Boolean PassVerification; + Boolean ConvertBitmapToPixmap, + ConvertBitmapToPixmapInsensitive; + Pixmap LabelPixmap, LabelInsensitivePixmap; + + XtPointer Dummy; +} XmComboBoxPart; + +/* + * vollstaengige Instanzenstruktur + */ +typedef struct _XmComboBoxRec { + CorePart core; + CompositePart composite; + ConstraintPart constraint; + XmManagerPart manager; + XmComboBoxPart combobox; +} XmComboBoxRec; + +#endif +/* Ende von ComboBoxP.h */ diff --git a/src/motif/xmcombo/copying.txt b/src/motif/xmcombo/copying.txt new file mode 100644 index 0000000000..e77696ae8d --- /dev/null +++ b/src/motif/xmcombo/copying.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/motif/xmcombo/demo.c b/src/motif/xmcombo/demo.c new file mode 100644 index 0000000000..797f62bb64 --- /dev/null +++ b/src/motif/xmcombo/demo.c @@ -0,0 +1,214 @@ +/* + * demo.c -- Example how to use a ComboBox + * + * compile and link with: + * $ cc -DFUNCPROTO ComboBoxDemo.c ComboBox.o -o ComboBoxDemo \ + * -lXm -lXt -lX11 + * then run: + * $ ./ComboBoxDemo + * + * (c) 1993, 1994 Harald Albrecht + * Institut fuer Geometrie und Praktische Mathematik + * RWTH Aachen, Germany + * albrecht@igpm.rwth-aachen.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING for more details); + * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, + * Cambridge, MA 02139, USA. + * + */ +#include +#include +#include +#include +#include +#include +#include "combobox.h" + +Widget TopLevel, Form, Button, Text, Sepp, ComboBox1, ComboBox2, ComboBox3, Label; + +void QuitCB(Widget w, caddr_t pClientData, caddr_t pCallData) +{ + char *text; + + text = XmComboBoxGetString(ComboBox1); + fprintf(stderr, "You choosed \"%s\" out of the first ComboBox\n", text); + XtFree(text); + text = XmComboBoxGetString(ComboBox2); + fprintf(stderr, "You entered \"%s\" into the second ComboBox\n", text); + XtFree(text); + fprintf(stderr, "Bye! ... have fun with XmComboBox!\n"); + exit(0); +} /* QuitCB */ + +int main(int argc, String argv[]) +{ + XmString str; + Boolean Trav; + XtAppContext AppContext; + +#if (XmREVISION > 1) + XtSetLanguageProc(NULL,NULL,NULL); +#endif + TopLevel = XtAppInitialize(&AppContext, "XFontSelDemo", NULL, 0, +#if (XmREVISION > 1) + &argc, +#else + (Cardinal *) &argc, +#endif + argv, NULL, NULL, 0); + + Form = XtVaCreateManagedWidget("form", xmFormWidgetClass, TopLevel, NULL); + str = XmStringCreateLtoR("Click to quit", XmSTRING_DEFAULT_CHARSET); + Button = XtVaCreateManagedWidget("quit", xmPushButtonWidgetClass, Form, + XmNlabelString, str, + XmNleftAttachment, XmATTACH_FORM, + XmNleftOffset, 8, + XmNtopAttachment, XmATTACH_FORM, + XmNtopOffset, 8, + NULL); + XmStringFree(str); + XtAddCallback(Button, XmNactivateCallback, (XtCallbackProc) QuitCB, NULL); + + Sepp = XtVaCreateManagedWidget("separator1", xmSeparatorWidgetClass, Form, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopOffset, 8, + XmNtopWidget, Button, + NULL); + + str = XmStringCreateLtoR("Choose one:", XmSTRING_DEFAULT_CHARSET); + ComboBox1 = XtVaCreateManagedWidget("combobox1", xmComboBoxWidgetClass, Form, + XmNeditable, False, + XmNsorted, True, + XmNleftAttachment, XmATTACH_FORM, + XmNleftOffset, 8, + XmNrightAttachment, XmATTACH_FORM, + XmNrightOffset, 8, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopOffset, 8, + XmNtopWidget, Sepp, + XmNshowLabel, True, + XmNlabelString, str, + NULL); + XmStringFree(str); + /* Put string unordered into the combo box! They'll get sorted + * by the box. + */ + str = XmStringCreateLtoR("William the conquerior", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox1, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("Karl der Gro\337e", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox1, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("Henry VIII & his chicken band", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox1, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("Louis XIV", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox1, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("Louis de Funes", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox1, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("Helmut Kohl", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox1, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("James Major", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox1, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("James Bond", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox1, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("Billy Boy (M$ Windoze)", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox1, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("Francois Mitterand", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox1, str, 0); + XmComboBoxSelectItem(ComboBox1, str, False); + XmStringFree(str); + + str = XmStringCreateLtoR("Choose/edit:", XmSTRING_DEFAULT_CHARSET); + ComboBox2 = XtVaCreateManagedWidget("combobox2", xmComboBoxWidgetClass, Form, + XmNeditable, True, + XmNsorted, True, + XmNleftAttachment, XmATTACH_FORM, + XmNleftOffset, 8, + XmNrightAttachment, XmATTACH_FORM, + XmNrightOffset, 8, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopOffset, 8, + XmNtopWidget, ComboBox1, + XmNshowLabel, True, + XmNlabelString, str, + NULL); + str = XmStringCreateLtoR("item can be edited after choosing it", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox2, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("just to fill the list", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox2, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("so it contains more entries", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox2, str, 0); XmStringFree(str); + + str = XmStringCreateLtoR("Static ComboBox:", XmSTRING_DEFAULT_CHARSET); + ComboBox3 = XtVaCreateManagedWidget("combobox3", xmComboBoxWidgetClass, Form, + XmNeditable, True, + XmNstaticList, True, + XmNsorted, False, + XmNcolumns, 30, + XmNleftAttachment, XmATTACH_FORM, + XmNleftOffset, 8, + XmNrightAttachment, XmATTACH_FORM, + XmNrightOffset, 8, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopOffset, 8, + XmNtopWidget, ComboBox2, + XmNshowLabel, True, + XmNlabelString, str, + NULL); + XmStringFree(str); + str = XmStringCreateLtoR("ComboBox (noneditable)", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox3, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("ComboBox (editable)", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox3, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("ComboBox (editable & static List)", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox3, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("Center widget", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox3, str, 0); XmStringFree(str); + str = XmStringCreateLtoR("The ButtonFace Library", XmSTRING_DEFAULT_CHARSET); + XmComboBoxAddItem(ComboBox3, str, 0); XmStringFree(str); + + Sepp = XtVaCreateManagedWidget("separator", xmSeparatorWidgetClass, Form, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopOffset, 8, + XmNtopWidget, ComboBox3, + NULL); + + str = XmStringCreateLtoR( +"xmComboBoxWidgetClass Demo\n\nby Harald Albrecht\n\n\ +albrecht@igpm.rwth-aachen.de", XmSTRING_DEFAULT_CHARSET); + Label = XtVaCreateManagedWidget("label", xmLabelWidgetClass, Form, + XmNlabelString, str, + XmNleftAttachment, XmATTACH_FORM, + XmNleftOffset, 80, + XmNrightAttachment, XmATTACH_FORM, + XmNrightOffset, 80, + XmNbottomAttachment, XmATTACH_FORM, + XmNbottomOffset, 24, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, Sepp, + XmNtopOffset, 24, + NULL); + XmStringFree(str); + + XtRealizeWidget(TopLevel); + + XtAppMainLoop(AppContext); + return 0; /* Never will reach this */ +} /* main */ + + +/* End of ComboBoxDemo.c */ diff --git a/src/motif/xmcombo/xmcombo.c b/src/motif/xmcombo/xmcombo.c new file mode 100644 index 0000000000..f612df4e95 --- /dev/null +++ b/src/motif/xmcombo/xmcombo.c @@ -0,0 +1,3543 @@ +/* + * ComboBox.c - Das schon lange schmerzlich vermisste Combo-Box- + * Widget -- nun endlich auf fuer Motif! + * + * Version 1.32a -- 04.10.95 + * + * Letzte Modifikation: + * 04.10.1995 Layoutfehler behoben, der bei angezeigter horizontaler Liste + * dazu fuehrt, dass das Listenfeld schrumpft. Daneben wird + * jetzt auch der Fall beruecksichtigt, dass das Listenfeld am + * unteren Bildschirmrand abgeschnitten wuerde. In diesem Fall + * erscheint das Listenfeld oberhalb des Eingabefeldes. + * 20.03.1995 XmNscrollbarDisplayPolicy,... koennen nun immer vom Pro- + * grammierer gesetzt werden, statische Liste hin und her. + * 21.10.1994 Fehler in SetValues behoben, der auftritt, wenn man versucht, + * XmNitems und XmNitemCount zu setzen. + * 01.10.1994 Externe Sortierung wird nun unterstuetzt sowie seitenweises + * Rollen in der Liste mittels PgUp und PgDn. + * 25.09.1994 Unterstuetzung fuer XmNautomaticSelection implementiert. + * Damit wird die Sache noch ein bischen runder in der Bedienung. + * Des weiteren sind etliche Callbacks neu hinzugekommen. + * 04.09.1994 Erweiterungen fuer XmSINGLE_SELECT eingebaut. Ausserdem + * kann die Liste jetzt auch statisch unterhalb des Eingabe- + * felds erscheinen. Damit sind wir nun noch kompatibler ge- + * worden -- fragt sich nur, zu was?! + * 29.08.1994 Alle Mirror-Ressourcen tauchen nun auch in der Ressourcen- + * liste der ComboBox-Klasse auf. Allerdings stehen keine + * sinnvollen Werte fuer die Initialisierung 'drin. Weiterhin + * den GeometryManager so veraendert, dass ab sofort das + * Label in der Breite wachsen oder schrumpfen darf. + * 07.06.1994 XmNmnemonic und XmNmnemonicCharSet implementiert. + * 29.05.1994 XmNsensitive angepasst. XmNcursorPositionVisible ist nun + * False, falls die ComboBox nicht editierbar ist. + * 07.05.1994 Drag'n'Drop funktioniert endlich!!! Zudem Anpassung an + * den fvwm ausgefuehrt ('st vom Focus-Verhalten ja ein halber + * twm). Hach', so'ne Linux-Box mit Motif 1.2 macht doch + * einfach Spass... vor allem geht hier so richtig die Post ab. + * Das kann man ja von M$ Windoze (Windoze for Mondays) nicht + * behaupten! + * 14.04.1994 Ein paar Speicherlecks korrigiert. + * 21.02.1994 Die Resourcen XmNitems und XmNitemCount lassen sich nun + * auch von einer Resourcendatei aus initialisieren. ACHTUNG: + * diese beiden Resourcen mussen immer beide beim Aufruf von + * XtSetValues zugleich angegeben werden, ansonsten werden + * diese Angaben ignoriert. + * 03.02.1994 Convenience-Funktionen auf Vordermann gebracht und noch + * einen Callback eingebaut, der immer dann aufgerufen wird, + * wenn die List angezeigt oder wieder versteckt wird. + * 01.02.1994 Motif 1.2-fest!!! Das wird aber heute abend gefeiert!! + * Endlich EIN Alptraum weniger! Naja, Drag'n'Drop bleibt + * noch zu loesen. Spaeter... + * 31.01.1994 VAX-fest (mit Hilfe von Vincenct Li) + * owlm sollte man abschaffen! Aber es scheint so, als ob + * ich jetzt doch noch das FocusOut-Problem geknackt habe. + * Ebenso die OSF...mit viel Arbeit habe ich nun auch noch + * eine anstaendige Initialisierung der Fontliste des Label- + * Kinds erreicht. + * 12.01.1994 Revisionsstand: 1.10a + * nun wirklich voll ANSI-faehiger C-Code + * Pixmaps werden ggf. aufgeraeumt; Druckrichtung + * wird vom Vater erfragt und an das Label weiter- + * gegeben. + * ESC-Behandlung implementiert. + * Spiegel-Ressourcen-Initialisierung aus Ressourcen-Daten- + * bank implementiert. + * Weitergabe von neu gesetzten Farben an die Kinder + * implementiert. + * Combo-Box kann jetzt wahlweise auch links neben dem + * Eingabefeld ein Label anzeigen. + * 09.12.1993 Revisionsstand: 1.00 + * erste oeffentlich zugaengliche Version der Combo-Box + * + * (c) 1993, 1994, 1995 Harald Albrecht + * Institut fuer Geometrie und Praktische Mathematik + * RWTH Aachen, Germany + * albrecht@igpm.rwth-aachen.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING for more details); + * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, + * Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#ifdef VMS /* Huch, wo gibt's denn noch sowas ... ?! */ + /* Bitte keine Mail bzgl. dieser Bemerkung schicken... + * Ich weiss, das ist ein Vorurteil...aber es gibt + * ja auch wahre Vorurteile.... + */ +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#include /* define toupper */ +#include "combop.h" + +#include + +/* --- Systemspezifische Definitionen */ +#ifdef VMS +#define strcasecmp(s1, s2) strcmp(s1, s2) +#endif + +/* --- sonstiger Quark */ +/* #ifdef DEBUG */ +#if 0 +#define LOG(p1) fprintf(stderr, p1); +#define LOG2(p1, p2) fprintf(stderr, p1, p2); +#define LOG3(p1, p2, p3) fprintf(stderr, p1, p2, p3); +#else +#define LOG(p1) +#define LOG2(p1, p2) +#define LOG3(p1, p2, p3) +#endif + +/* --------------------------------------------------------------------------- + * Resourcen-Liste... + * Hier werden diejenigen Resourcen definiert, die von "aussen" - also fuer + * den Programmierer oder Anwender - benutzbar und veraenderbar sind. + * + * Der Aufbau der einzelnen Eintraege ist immer wieder gleich: + * Resourcen-Name XmN... oder XtN + * Resourcen-Klasse XmC... oder XtC + * Resourcen-Type XmR... oder XtR (Datentyp der Variable in der + * struct der jeweiligen Widgetinstanz) + * Resourcen-Groesse aktuelle Groesse dieses Datentyps + * Resourcen-Offset Lage der Variable innerhalb der struct der + * Widgetinstanz + * Defaultwert-Type Typ des Defaultwertes + * Defaultwert (normalerweise) Zeiger auf den Defaultwert + */ +#define offset(field) XtOffsetOf(XmComboBoxRec, field) +static XtResource resources[] = { + { /* Eingabefeld kann veraendert werden, oder aber es sind nur + * die Vorgaben aus der Liste auswaehlbar. + */ + XmNeditable, XmCEditable, XmRBoolean, sizeof(Boolean), + offset(combobox.Editable), XmRString, "False" + }, + { /* Liste wird automatisch sortiert -- wie konnten die bei + * der OSF denn SOETWAS nur vergessen ?? + */ + XmNsorted, XmCSorted, XmRBoolean, sizeof(Boolean), + offset(combobox.Sorted), XmRString, "False" + }, + { /* externe Sortierreihenfolge */ + XmNsortingCallback, XmCSortingCallback, XmRCallback, + sizeof(XtCallbackList), + offset(combobox.SortingCBL), XmRCallback, NULL + }, + { /* Anzahl auf einmal sichtbarer Eintraege in der Liste (ent- + * spricht damit der Listenhoehe. + */ + XmNvisibleItemCount, XmCVisibleItemCount, XmRInt, sizeof(int), + offset(combobox.VisibleItemCount), XmRImmediate, (caddr_t) 8 + }, + { /* Fuer das Eingabefeld sowie die Liste verwandte Fonts */ + XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList), + offset(combobox.Font), XmRImmediate, NULL + }, + { /* Rueckruf bei Anwahl */ + XmNselectionCallback, XmCSelectionCallback, XmRCallback, + sizeof(XtCallbackList), + offset(combobox.SelectionCBL), XmRCallback, NULL + }, + { /* Gegenteil zum vorherigen Callback! */ + XmNunselectionCallback, XmCUnselectionCallback, XmRCallback, + sizeof(XtCallbackList), + offset(combobox.UnselectionCBL), XmRCallback, NULL + }, + { /* Doppelklick in der Liste */ + XmNdefaultActionCallback, XmCCallback, XmRCallback, + sizeof(XtCallbackList), + offset(combobox.DefaultActionCBL), XmRCallback, NULL + }, + { /* Rueckruf bei Liste ausklappen/verstecken */ + XmNdropDownCallback, XmCDropDownCallback, XmRCallback, + sizeof(XtCallbackList), + offset(combobox.DropDownCBL), XmRCallback, NULL + }, + { /* Eingabe abchecken... */ + XmNmodifyVerifyCallback, XmCCallback, XmRCallback, + sizeof(XtCallbackList), + offset(combobox.ModifyVerifyCBL), XmRCallback, NULL + }, + { + XmNvalueChangedCallback, XmCCallback, XmRCallback, + sizeof(XtCallbackList), + offset(combobox.ValueChangedCBL), XmRCallback, NULL + }, + { + XmNactivateCallback, XmCCallback, XmRCallback, + sizeof(XtCallbackList), + offset(combobox.ActivateCBL), XmRCallback, NULL + }, + { + XmNmotionVerifyCallback, XmCCallback, XmRCallback, + sizeof(XtCallbackList), + offset(combobox.MotionVerifyCBL), XmRCallback, NULL + }, + { /* Verhalten der ausgeklappten Liste bei Focus-Out */ + XmNpersistentDropDown, XmCPersistentDropDown, XmRBoolean, + sizeof(Boolean), + offset(combobox.Persistent), XmRString, "False" + }, + { /* Wie verhaelt sich der Window-Manager? */ + XmNtwmHandlingOn, XmCTwmHandlingOn, XmRBoolean, sizeof(Boolean), + offset(combobox.TwmHandlingOn), XmRString, "False" + }, + { /* Label anzeigen oder nicht? */ + XmNshowLabel, XmCShowLabel, XmRBoolean, sizeof(Boolean), + offset(combobox.ShowLabel), XmRString, "False" + }, + { /* Abstand zw. linkem Rand Eingabefeld und linkem Rand Liste */ + XmNdropDownOffset, XmCDropDownOffset, XmRPosition, + sizeof(Position), offset(combobox.DropDownOffset), + XmRImmediate, (caddr_t) -1 + }, + { /* Neue Voreinstellung bzgl. des Randes */ + XmNborderWidth, XmCBorderWidth, XmRDimension, sizeof(Dimension), + offset(core.border_width), XmRImmediate, (caddr_t) 0 + }, + { /* welcher Cursor soll in der Dropdown-Liste benutzt werden? */ + XmNdropDownCursor, XmCDropDownCursor, XmRCursor, sizeof(Cursor), + offset(combobox.ArrowCursor), XmRString, "center_ptr" + }, + { /* wie lassen sich Eintraege auswaehlen? */ + XmNselectionPolicy, XmCSelectionPolicy, XmRSelectionPolicy, sizeof(unsigned char), + offset(combobox.SelectionPolicy), XmRImmediate, (caddr_t) XmBROWSE_SELECT + }, + { /* Wann werden die Callbacks aufgerufen? */ + XmNautomaticSelection, XmCAutomaticSelection, XmRBoolean, sizeof(Boolean), + offset(combobox.AutomaticSelection), XmRString, "False" + }, + { /* erscheint die Liste staendig? */ + XmNstaticList, XmCStaticList, XmRBoolean, sizeof(Boolean), + offset(combobox.StaticList), XmRString, "False" + }, + { + XmNscrollBarDisplayPolicy, XmCScrollBarDisplayPolicy, XmRScrollBarDisplayPolicy, sizeof(unsigned char), + offset(combobox.ScrollBarDisplayPolicy), XmRImmediate, (caddr_t) XmAS_NEEDED + }, + { + XmNlistSizePolicy, XmCListSizePolicy, XmRListSizePolicy, sizeof(unsigned char), + offset(combobox.ListSizePolicy), XmRImmediate, (caddr_t) XmVARIABLE + }, + { + XmNsquareArrow, XmCSquareArrow, XmRBoolean, sizeof(Boolean), + offset(combobox.SquareArrow), XmRString, "False" + }, + { + XmNarrowSpacingOn, XmCArrowSpacingOn, XmRBoolean, sizeof(Boolean), + offset(combobox.ArrowSpacingOn), XmRString, "True" + }, +#ifndef DONT_LOOK_IN_THE_MIRROR + /* Mirror-Ressourcen, Adressen sind ungueltig!!!! */ + { + XmNalignment, XmCAlignment, XmRAlignment, sizeof(unsigned char), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNblinkRate, XmCBlinkRate, XmRInt, sizeof(int), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNcolumns, XmCColumns, XmRShort, sizeof(short), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNcursorPosition, XmCCursorPosition, XmRTextPosition, sizeof(XmTextPosition), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNitemCount, XmCItemCount, XmRInt, sizeof(int), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNitems, XmCItems, XmRXmStringTable, sizeof(XmStringTable), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlabelFontList, XmCLabelFontList, XmRFontList, sizeof(XmFontList), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlabelInsensitivePixmap, XmCLabelInsensitivePixmap, XmRPixmap, sizeof(Pixmap), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlabelMarginBottom, XmCLabelMarginBottom, XmRDimension, sizeof(Dimension), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlabelMarginHeight, XmCLabelMarginHeight, XmRDimension, sizeof(Dimension), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlabelMarginLeft, XmCLabelMarginLeft, XmRDimension, sizeof(Dimension), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlabelMarginRight, XmCLabelMarginRight, XmRDimension, sizeof(Dimension), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlabelMarginTop, XmCLabelMarginTop, XmRDimension, sizeof(Dimension), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlabelMarginWidth, XmCLabelMarginWidth, XmRDimension, sizeof(Dimension), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlabelPixmap, XmCLabelPixmap, XmRPixmap, sizeof(Pixmap), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlabelString, XmCLabelString, XmRString, sizeof(XmString), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlabelType, XmCLabelType, XmRLabelType, sizeof(unsigned char), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlistMarginHeight, XmCListMarginHeight, XmRDimension, sizeof(Dimension), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlistMarginWidth, XmCListMarginWidth, XmRDimension, sizeof(Dimension), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNlistSpacing, XmCListSpacing, XmRDimension, sizeof(Dimension), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNmarginHeight, XmCMarginHeight, XmRDimension, sizeof(Dimension), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNmarginWidth, XmCMarginWidth, XmRDimension, sizeof(Dimension), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNmaxLength, XmCMaxLength, XmRInt, sizeof(int), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNselectThreshold, XmCSelectThreshold, XmRInt, sizeof(int), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNstringDirection, XmCStringDirection, XmRStringDirection, sizeof(XmStringDirection), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNtopItemPosition, XmCTopItemPosition, XmRInt, sizeof(int), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNvalue, XmCValue, XmRString, sizeof(String), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, + { + XmNvalue, XmCValue, XmRInt, sizeof(int), + offset(combobox.Dummy), XmRImmediate, (caddr_t) 0 + }, +#endif +}; /* resources[] */ + +/* --------------------------------------------------------------------------- + * Funktions-Prototypen fuer die 'Methoden' des ComboBox-Widgets. Diese + * 'Methoden' werden vom Xt-Toolkit aufgerufen und sorgen dafuer, dass eine + * ComboBox sich wie ein anstaendiges Widget verhaelt. + */ +static void Initialize (Widget, XmComboBoxWidget, ArgList, + Cardinal *); +static void Destroy (XmComboBoxWidget); +static void Resize (XmComboBoxWidget); +static Boolean SetValues (XmComboBoxWidget, XmComboBoxWidget, + XmComboBoxWidget, ArgList, Cardinal *); +static void GetValuesAlmost(XmComboBoxWidget, ArgList, Cardinal *); +static XtGeometryResult QueryGeometry (XmComboBoxWidget, XtWidgetGeometry *, + XtWidgetGeometry *); +static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *, + XtWidgetGeometry *); +static void ClassInit (); +static void Realize (XmComboBoxWidget, Mask *, + XSetWindowAttributes *); +/* --------------------------------------------------------------------------- + * diverse restliche Prototypen... naja, hier halt etwas mager! Hierbei + */ +static void ShowHideDropDownList (XmComboBoxWidget w, XEvent *event, + Boolean Show); +static void ShellCallback (Widget w, XtPointer cbw, + XEvent *event, Boolean *ContDispatch); +static void DoLayout (XmComboBoxWidget w); +/* -------------------------------------------------------------------- + * Klassen-Definition + */ +XmComboBoxClassRec xmComboBoxClassRec = { + { /*** core-Klasse ***/ + /* superclass */ (WidgetClass) &xmManagerClassRec, + /* class_name */ "XmComboBox", + /* widget_size */ sizeof(XmComboBoxRec), + /* class_initialize */ (XtProc) ClassInit, + /* class_part_initialize */ NULL, + /* class_inited */ False, /* IMMER mit FALSE initialisieren !! */ + /* initialize */ (XtInitProc) Initialize, + /* initialize_hook */ NULL, + /* realize */ (XtRealizeProc) Realize, + /* actions */ NULL, + /* num_actions */ 0, + /* resources */ resources, + /* num_resources */ XtNumber(resources), + /* xrm_class */ NULLQUARK, + /* compress_motion */ True, + /* compress_exposure */ XtExposeCompressMultiple, + /* compress_enterleave */ True, + /* visible_interest */ False, + /* destroy */ (XtWidgetProc) Destroy, + /* resize */ (XtWidgetProc) Resize, + /* expose */ NULL, + /* set_values */ (XtSetValuesFunc) SetValues, + /* set_values_hook */ NULL, + /* set_values_almost */ XtInheritSetValuesAlmost, + /* get_values_hook */ (XtArgsProc) GetValuesAlmost, + /* accept_focus */ NULL, + /* version */ XtVersion, + /* callback_private */ NULL, + /* tm_table */ NULL, + /* query_geometry */ (XtGeometryHandler) QueryGeometry, + /* display_accelerator */ XtInheritDisplayAccelerator, + /* extension */ NULL + }, + { /*** composite-Klasse ***/ + /* geometry_manager */ (XtGeometryHandler) GeometryManager, + /* change_managed */ XtInheritChangeManaged, + /* insert_child */ XtInheritInsertChild, + /* delete_child */ XtInheritDeleteChild, + /* extension */ NULL + }, + { /*** constraint-Klasse ***/ + /* resources */ NULL, + /* num_resources */ 0, + /* constraint_size */ sizeof(XmManagerConstraintPart), + /* initialize */ NULL, + /* destroy */ NULL, + /* set_values */ NULL, + /* extension */ NULL + }, + { /*** xmManager-Klasse ***/ + /* translations */ XtInheritTranslations, + /* syn_resources */ NULL, + /* num_syn_resources */ 0, + /* syn_constraint_resources */ NULL, + /* num_syn_constraint_resources */ 0, + /* parent_process */ XmInheritParentProcess, + /* extension */ NULL + }, + { /*** combobox-Klasse ***/ + /* */ 0 + } +}; /* xmComboBoxClassRec */ +WidgetClass xmComboBoxWidgetClass = (WidgetClass) &xmComboBoxClassRec; + +/* -------------------------------------------------------------------- + * -------------------------------------------------------------------- + * Translation-Tabelle (hier allerdings fuer das Eingabefeld!) + * Tjaja....mit der Reihenfolge von Translations ist das schon so eine + * ziemlich boese Sache! + */ +static char newEditTranslations[] = + "AltosfDown: ComboBox-Manager(show-hide-list) \n\ + MetaosfDown: ComboBox-Manager(show-hide-list) \n\ + AltosfUp: ComboBox-Manager(hide-list) \n\ + MetaosfUp: ComboBox-Manager(hide-list) \n\ + osfUp: ComboBox-Manager(up) \n\ + osfDown: ComboBox-Manager(down) \n\ + osfPageUp: ComboBox-Manager(page-up) \n\ + osfPageDown: ComboBox-Manager(page-down) \n\ + osfCancel: ComboBox-Manager(cancel) \n\ + Return: ComboBox-Manager(activate) activate()" + ; +/* speziell bei der nicht editierbaren Combo-Box sind noch einige + * andere Tasten belegt, die sonst dem Eingabefeld alleine gehoeren. + * Die dazugehoerigen neuen Translations befinden sich in dieser + * zusaetzlichen Tabelle, das Anhaengsel ...NE ist dabei die Ab- + * kuerzung fuer "non editable". + */ +static char newEditTranslationsNE[] = + "osfDelete: ComboBox-Manager(wipe-out) \n\ + osfBeginLine: ComboBox-Manager(top) \n\ + osfEndLine: ComboBox-Manager(bottom) " + ; +/* Momentan gibt es noch Aerger mit dem Drag'n'Drop-Mechanismus + * von Motif 1.2. Legen wir ihn deshalb erst einmal still, solange + * bis ich weiss, warum, und eine Loesung parat habe. NEU: Nur wenn + * Sie mit einer libXm geschlagen sind, die partout nicht funktionieren + * will, muessen Sie Drag'n'Drop stillegen, ansonsten klappts doch! + */ +#ifdef NODRAGNDROP +static char newListTranslations[] = + ": ComboBox-Manager(no-operation) "; +#endif +static char newListTranslationsE[] = + "osfPageUp: ComboBox-Manager(page-up) \n\ + osfPageDown: ComboBox-Manager(page-down) "; + +/* --------------------------------------------------------------------------- + * --------------------------------------------------------------------------- + * Aktionen-Tabelle: Hierdurch werden den einzelnen Translations die dazuge- + * hoerigen C-Routinen zugeordnet. Da wir hier ein anstaendiges ANSI-C be- + * nutzen, werden hier zuerst einmal die Prototypen faellig... Ach ja, noch + * ein Hinweis in eigener Sache... der ComboBox-Manager muss applikationsweit + * registriert werden, da er auch von Translationen in den Kindern der Combo- + * Box aktiviert wird. Bei diesem Namen der 'Aktion' steht aber nicht zu be- + * fuerchten, dass er anderweitig bereits in Anwendung ist. + */ +static void CBoxManager(Widget w, XEvent *event, String *params, + Cardinal *num_params); + +static XtActionsRec actions[] = { + { "ComboBox-Manager", CBoxManager }, + { NULL, NULL } +}; /* actions */ + + +/* -------------------------------------------------------------------- + * Eine Instanz dieser Widget-Klasse wird erstmalig in Betrieb ge- + * nommen, daher sind noch Vorbereitungen notwendig, die nun hier + * durchgefuehrt werden. + */ +static XtTranslations NewEditTranslations, NewEditTranslationsNE, + NewListTranslations, NewListTranslationsE; + +static XtConvertArgRec ConverterScreenConvertArg[] = { + { XtBaseOffset, (XtPointer) XtOffset(Widget, core.screen), + sizeof(Screen *) } +}; + +static void ClassInit() +{ + NewEditTranslations = + XtParseTranslationTable(newEditTranslations); + NewEditTranslationsNE = + XtParseTranslationTable(newEditTranslationsNE); +#ifdef NODRAGNDROP + NewListTranslations = + XtParseTranslationTable(newListTranslations); +#endif + NewListTranslationsE = + XtParseTranslationTable(newListTranslationsE); + XtAddConverter(XtRString, XtRBitmap, + XmuCvtStringToBitmap, + ConverterScreenConvertArg, + XtNumber(ConverterScreenConvertArg)); +} /* ClassInit */ + +/* --------------------------------------------------------------------------- + * Weil es sich bei diesem Widget um ein etwas komplizierteres zusammengesetz- + * tes Widget handelt, muessen wir hier - wo eigentlich nur das die Combobox + * bildende Fenster auf dem X-Server erzeugt wird - noch einmal das Layout + * auf Vordermann bringen. Den Aerger loest dabei das Listenfeld der OSF aus, + * das einfach keine Geometrie-Nachfragen verschickt, solange es nicht + * 'realized' ist!!! Nicht, dass ich mich ueber so einen Sauhaufen aufregen + * wuerde...ich doch nicht! ABER MACHT IHR DENN NUR SO'N MIST...? WARUM KOENNT + * IHR DENN NICHT EINMAL DIESES ****(BIEP)**** MOTIF TOOLKIT ANSTAENDIG + * DOKUMENTIEREN! Ich glaub', ich kann mich nach dem Chaos eigentlich nur noch + * hemmungslos besaufen... Die Suche nach der Ursache (bzw. Urheber = OSF) hat + * mich doch einige Tage gekostet (jaja...die Mannstunden!). + */ +static void Realize(XmComboBoxWidget w, Mask *ValueMask, + XSetWindowAttributes *Attributes) +{ + /* + * Also: wenn die Liste staendig sichtbar ist, dann zuerst noch einmal + * das Layout berechnen. Sonst wird vorne und hinten 'was abgeschnitten. + */ + if ( w->combobox.StaticList ) + DoLayout(w); + (*w->core.widget_class->core_class.superclass->core_class.realize) + ((Widget) w, ValueMask, Attributes); +} /* Realize */ + +/* --------------------------------------------------------------------------- + * Suche dasjenige Fenster, in dem unsere Shell liegt, in der wiederum die + * Combo-Box steckt. Diese Information wird benoetigt, um die Drop-Down-Liste + * innerhalb des Fensterstacks immer direkt oberhalb der Shell mit der Combo- + * Box zu halten. Jajaja -- ich muss halt davon ausgehen, dass der Fenster- + * manager ein sog. "reparenting wm" ist; also die Dekorationen in einem + * Fenster dargestellt werden und unsere Shell in dieses Fenster hineingepackt + * ist. Die Dekoration ist damit ein Kind des 'root window' - wie die Shell, + * in der die Drop-Down-Liste steckt. Und da nur Geschwisterfenster (sibling + * windows) im gleichen Stapel stecken, reicht das Shellfenster nicht aus. + * Alle gaengigen Fenstermanager sind solche "reparenting wm's", so dass ich + * hier zu diesem Trick greifen kann, um die Drop-Down-Liste immer ueber der + * ComboBox zu halten. + * + * Parameter: + * w Diejenige Combo-Box, fuer die wir dasjenige + * Fenster des Window-Managers ermitteln sollen, + * dass direkt unterhalb des Root-Fensters liegt. + * Ergebnis: + * besagtes zu suchendes Fenster, dass die Dekoration enthaelt (hoffentlich + * nur echte Bruesseler Spitze!) + */ +static Window GetDecorationWindow(XmComboBoxWidget w) +{ + Window Root, Parent, AWindow; + Window *Children; + unsigned int NumChildren; + + Parent = XtWindow((Widget) w); + /* Suche nach dem Dekorationsfenster des Window-Managers */ + do { + AWindow = Parent; + XQueryTree(XtDisplay((Widget) w), AWindow, + &Root, &Parent, &Children, &NumChildren); + XFree((char *) Children); + } while ( Parent != Root ); + return AWindow; +} /* GetDecorationWindow */ + +/* -------------------------------------------------------------------- + * Eine Combo-Box aus dem Wege raeumen... + * Momentan muessen wir hier nur den Cursor wieder los werden sowie + * eventuell reservierte Pixmaps. + * Ups -- natuerlich muss auch wieder der Callback entfernt werden, + * der noch an der Shell haengt. + */ +static void Destroy(XmComboBoxWidget w) +{ +/* fprintf(stderr, "Destroy: %08X\n", w->core.window);*/ + if ( w->combobox.ConvertBitmapToPixmap ) + XFreePixmap(XtDisplay((Widget) w), + w->combobox.LabelPixmap); + if ( w->combobox.ConvertBitmapToPixmapInsensitive ) + XFreePixmap(XtDisplay((Widget) w), + w->combobox.LabelInsensitivePixmap); + if ( w->combobox.PendingFocusOut ) + XtRemoveWorkProc(w->combobox.WorkProcID); + XtRemoveEventHandler(w->combobox.MyNextShell, + StructureNotifyMask | FocusChangeMask, + True, (XtEventHandler) ShellCallback, + (XtPointer) w); +} /* Destroy */ + +/* --------------------------------------------------------------------------- + * Ueberpruefe, ob fuer die Ressource "DropDownOffset" ein gueltiger Wert vom + * Benutzer angegeben wurde. Diese Ressource gibt an, wie weit die Drop-Down- + * Liste nach rechts gegenueber dem Eingabefeld eingerueckt sein soll. Wenn + * hierfuer ein negativer Wert angegeben ist, so berechne statt dessen einen + * Standardwert: dieser entspricht der Breite der Pfeilschaltflaeche, was + * optisch ganz gut wirkt (jedenfall nach meinem Dafuerhalten). + */ +static void CheckDropDownOffset(XmComboBoxWidget w) +{ + if ( w->combobox.DropDownOffset < 0 ) { + XtWidgetGeometry ArrowGeom; + + XtQueryGeometry(w->combobox.ArrowCtrl, NULL, &ArrowGeom); + w->combobox.DropDownOffset = ArrowGeom.width; + } +} /* CheckDropDownOffset */ + +/* -------------------------------------------------------------------- + * Berechne die voreinzustellende Groesse, die diese Combo-Box be- + * sitzen muss, um ausreichenden Raum fuer das Eingabefeld und den + * Pfeil rechts daneben zur Verfuegung zu stellen. Bei einer + * editierbaren Combo-Box ist zwischen dem Eingabefeld und dem Pfeil + * noch ein Angst-Rasen von der halben Breite eines Pfeiles vorhanden. + * Wird das Listenfeld staendig dargestellt, so entfallen sowohl Pfeil + * als auch der Angstrasen, dafuer muss aber die Hoehe des Listenfelds + * beruecksichtigt werden. + */ +static void DefaultGeometry(XmComboBoxWidget w, + Dimension *TotalWidth, + Dimension *TotalHeight, + Dimension *EditCtrlWidth, + Dimension *LabelCtrlWidth) +{ + XtWidgetGeometry EditGeom, ArrowGeom, LabelGeom, ListGeom; + + XtQueryGeometry(w->combobox.EditCtrl, NULL, &EditGeom); + XtQueryGeometry(w->combobox.ArrowCtrl, NULL, &ArrowGeom); + XtQueryGeometry(w->combobox.LabelCtrl, NULL, &LabelGeom); + + /* + * Soll die Pfeilschaltflaeche quadratisch, praktisch, gut sein? + */ + if ( w->combobox.SquareArrow ) + ArrowGeom.width = ArrowGeom.height; + else + ArrowGeom.width = (ArrowGeom.height * 4) / 5; + + /* + * Zuerst einmal ein paar einfache Werte ermitteln und zurueckgeben... + */ + *TotalHeight = EditGeom.height; + *EditCtrlWidth = EditGeom.width; + *LabelCtrlWidth = LabelGeom.width; + + /* + * Ermittele nun die Breite, welche die Combobox benoetigt. Je nach- + * dem, ob das Eingabefeld oder die Liste breiter sind, wird der + * entsprechende Wert genommen. Diese Auswahl zwischen der Breite von + * Eingabefeld und Liste findet aber nur statt, wenn die Liste auch + * wirklich staendig sichtbar ist. Waehrend der Initialisierung hat + * allerdings XmNcolumns, so dass in diesem Moment die List nicht + * mehr die Breite kontrollieren kann! + */ + if ( w->combobox.StaticList ) { + /* + * Beachte: Frage nicht die Listbox, sondern das ScrolledWindow, + * in welchem die Liste eingebettet ist. + */ + CheckDropDownOffset(w); + XtQueryGeometry(XtParent(w->combobox.ListCtrl), NULL, &ListGeom); + if ( w->combobox.InInit ) { + *TotalWidth = EditGeom.width; + } else { + if ( EditGeom.width < (Dimension) + (ListGeom.width + w->combobox.DropDownOffset) ) + *TotalWidth = ListGeom.width + w->combobox.DropDownOffset; + else + *TotalWidth = EditGeom.width; + } + *TotalHeight += ListGeom.height; + } else { + /* + * Das Listenfeld interessiert uns hier nicht. Degegen sollte noch + * die Breite fuer den Pfeil und ein evtl. Angstrasen beachtet + * werden. + */ + *TotalWidth = EditGeom.width + ArrowGeom.width; + if ( w->combobox.Editable && w->combobox.ArrowSpacingOn ) + *TotalWidth += ArrowGeom.width/2; + } + + /* + * Vergiss nicht, auch noch ein evtl. sichtbares Schriftfeld zu berueck- + * sichtigen! + */ + if ( w->combobox.ShowLabel ) + *TotalWidth += LabelGeom.width; + +} /* DefaultGeometry */ + +/* -------------------------------------------------------------------- + * Anhand eines Widgets ermittele darueber die Screennummer desjenigen + * Screens, auf dem das Widget erscheint. + * Parameter: + * w betroffenes Widget. + * Ergebnis: + * Nummer desjenigen Screens, auf dem das Widget angezeigt wird. + */ +static int WidgetToScreen(Widget w) +{ + Screen *screen; + Display *display; + int NumScreens, i; + + screen = XtScreen(w); NumScreens = ScreenCount(XtDisplay(w)); + display = DisplayOfScreen(screen); + for ( i = 0; i < NumScreens; ++i ) + if ( ScreenOfDisplay(display, i) == screen ) + return i; + XtError("WidgetToScreen: data structures are destroyed."); +} /* WidgetToScreen */ + +/* -------------------------------------------------------------------- + * Positioniere die DropDown-Liste (soweit sie natuerlich auch momentan + * sichtbar ist) so auf dem Bildschirm, dass sie sich unterhalb des + * Eingabefeldes anschliesst. + */ +static void DoDropDownLayout(XmComboBoxWidget w) +{ + Position abs_x, abs_y; + Dimension ArrowWidth, ListWidth, ListHeight; + Dimension ScreenHeight, LabelWidth; + Window Decoration; + XWindowChanges WindowChanges; + + /* + * etwa nicht sichtbar ?!! Oder etwa immer sichtbar ?!! + * Dann sind wir jetzt sofort fertig. + */ + if ( !w->combobox.ListVisible || w->combobox.StaticList ) return; + /* + * Finde zuerst einmal heraus, wo wir uns denn auf dem Bildschirm be- + * finden sollen... Beachte dabei auch, dass eventuell die Liste zu schmal + * werden koennte und gib' ihr dann ggf. eine Mindestbreite, damit es + * keinen core-Dump gibt. + */ + XtVaGetValues(w->combobox.ArrowCtrl, XmNwidth, &ArrowWidth, NULL); + XtTranslateCoords((Widget) w, 0, w->core.height, &abs_x, &abs_y); + CheckDropDownOffset(w); + ListWidth = w->core.width - w->combobox.DropDownOffset - 2; + abs_x += w->combobox.DropDownOffset; + if ( w->combobox.ShowLabel ) { + XtVaGetValues(w->combobox.LabelCtrl, XmNwidth, &LabelWidth, NULL); + ListWidth -= LabelWidth; + abs_x += LabelWidth; + } + if ( ListWidth < 20 ) ListWidth = 20; + XtVaGetValues(XtParent(w->combobox.ListCtrl), XmNheight, &ListHeight, NULL); + /* + * Hier ueberpruefen wir noch, ob die Liste unten aus dem Bildschirm + * herausfallen wuerde. In dem Fall klappen wir die Liste oberhalb des + * Eingabefeldes auf. + */ + ScreenHeight = DisplayHeight(XtDisplay((Widget) w), + WidgetToScreen((Widget) w)); + if ( abs_y + ListHeight + 2 > ScreenHeight ) { + int y; + + y = ((int) abs_y) - ListHeight - w->core.height - 1; + if ( y < 0 ) y = 0; + abs_y = (Position) y; + } + XtConfigureWidget(w->combobox.PopupShell, + abs_x, abs_y, ListWidth, ListHeight, 1); + /* + * So...das hier dient der Kosmetik: hier sorgen wir dafuer, dass die + * Liste auch wirklich immer direkt ueber der ComboBox innerhalb des + * Fensterstapels schwebt. Siehe dazu auch die Erlaeuterungen und An- + * merkungen in GetDecorationWindow(). + */ + if ( XtIsRealized((Widget) w) ) { + WindowChanges.sibling = GetDecorationWindow(w); + WindowChanges.stack_mode = Above; + XReconfigureWMWindow(XtDisplay((Widget) w), + XtWindow(w->combobox.PopupShell), + WidgetToScreen(w->combobox.PopupShell), + CWSibling | CWStackMode, &WindowChanges); + } +} /* DoDropDownLayout */ + +/* -------------------------------------------------------------------- + * Naja... diese Routine scheint ja bereits zu einer Institution beim + * Schreiben von Composite-Widgets geworden zu sein. + * + * Hier beim ComboBox-Widget ist die Aufgabe ziemlich einfach: es + * genuegt, die Eingabezeile und den Pfeil-Button entsprechend inner- + * halb des ComboBox-Widgets zu plazieren. Seit allerdings noch das + * Textlabel hinzukommt, wird's langsam aufwendiger. Nun ja - da sich + * das Listenfeld wahlweise auch statisch einblenden laesst, ist nun + * noch mehr zu beruecksichtigen, wenn die Kinder-Widgets an ihre + * Plaetze geschoben werden. + */ +static void DoLayout(XmComboBoxWidget w) +{ + Dimension EditCtrlWidth, ArrowCtrlWidth, LabelCtrlWidth; + Dimension ComboBoxHeight; + Dimension BorderWidth; + Dimension HighlightThickness; + Position EditX; + + XtVaGetValues(w->combobox.ArrowCtrl, + XmNheight, &ArrowCtrlWidth, NULL); + if ( !w->combobox.SquareArrow ) + ArrowCtrlWidth = (ArrowCtrlWidth * 4) / 5; + XtVaGetValues(w->combobox.LabelCtrl, + XmNwidth, &LabelCtrlWidth, NULL); + + /* + * In Abhaengigkeit davon, ob die ComboBox editierbar ist und ob das + * Listenfeld staendig sichtbar sein soll, hier die Breite einzelner + * Widgets bestimmen. + */ + if ( w->combobox.StaticList ) { + ComboBoxHeight = w->combobox.EditCtrl->core.height; + EditCtrlWidth = w->core.width; + } else { + ComboBoxHeight = w->core.height; + EditCtrlWidth = w->core.width - ArrowCtrlWidth; + if ( w->combobox.Editable && w->combobox.ArrowSpacingOn ) + EditCtrlWidth -= ArrowCtrlWidth/2; + } + /* Beruecksichtige noch ein evtl. ebenfalls anzuzeigendes Schriftfeld + * neben dem Eingabefeld. + */ + if ( w->combobox.ShowLabel ) { + EditX = LabelCtrlWidth; + EditCtrlWidth -= LabelCtrlWidth; + } else + EditX = 0; + if ( EditCtrlWidth < 20 ) EditCtrlWidth = 20; +/* Plaziere nun das Eingabefeld... */ + XtVaGetValues(w->combobox.EditCtrl, + XmNborderWidth, &BorderWidth, + XmNhighlightThickness, &HighlightThickness, + NULL); + XtConfigureWidget(w->combobox.EditCtrl, + EditX, 0, + EditCtrlWidth, ComboBoxHeight, BorderWidth); +/* ...und nun den Pfeil... */ + XtVaGetValues(w->combobox.ArrowCtrl, + XtNborderWidth, &BorderWidth, NULL); + XtConfigureWidget(w->combobox.ArrowCtrl, + w->core.width-ArrowCtrlWidth, HighlightThickness, + ArrowCtrlWidth, + ComboBoxHeight - 2 * HighlightThickness, + BorderWidth); +/* ...und ggf. das Textlabel. */ + if ( w->combobox.ShowLabel ) { + XtVaGetValues(w->combobox.LabelCtrl, + XmNborderWidth, &BorderWidth, + NULL); + XtConfigureWidget(w->combobox.LabelCtrl, + 0, 0, + LabelCtrlWidth, ComboBoxHeight, + BorderWidth); + } +/* Falls da noch die Liste herumgurkt... */ + if ( w->combobox.StaticList ) { + Dimension Width, Height; + + if ( w->core.height > ComboBoxHeight ) + Height = w->core.height - ComboBoxHeight; + else + Height = 10; + + if ( w->core.width > (Dimension)(ArrowCtrlWidth + EditX) ) + Width = w->core.width - ArrowCtrlWidth - EditX; + else + Width = 10; + + XtConfigureWidget(XtParent(w->combobox.ListCtrl), + EditX + ArrowCtrlWidth, ComboBoxHeight, Width, Height, 0); + } else if ( w->combobox.ListVisible ) + DoDropDownLayout(w); +} /* DoLayout */ + +/* -------------------------------------------------------------------- + * Pappi fragt nach, wie gross wir denn sein wollen. + * Die hier benutzte Vorgehensweise zur Ermittlung der Groesse: + * Sobald der Vater uns eine Breite (oder aber Hoehe) vorschlaegt, + * die fuer uns eigentlich zu klein ist, meckern wir und schlagen + * die von uns benoetigte Breite (Hoehe) vor. + * Soweit also zur Theorie... leider sieht es beispielsweise das + * Motif Form-Widget ueberhaupt nicht ein, uns auch nur ein einziges + * Mal nach unseren Wuenschen zu fragen! Damit es bei derart unum- + * gaenglichen Widgets dann doch noch geht, muss ChangedManaged die + * Kohlen wieder aus dem Feuer holen mit einer Sondertour. + * Parameter: + * *Request Vom Vater vorgeschlagene Geometrie + * Ergebnis: + * *Reply Unsere Antwort auf die vorgeschlagene Geometrie + * sowie XtGeometryYes oder XtGeometryAlmost, je nachdem, wie gut + * uns Pappis Vorschlag in den Kram passt. + */ +static XtGeometryResult QueryGeometry(XmComboBoxWidget w, + XtWidgetGeometry *Request, + XtWidgetGeometry *Reply) +{ + XtGeometryResult result = XtGeometryYes; + Dimension minW, minH, editW, labelW; + +/* Elternteil will nichts weiter aendern, also ist uns das + * recht so. + */ + Request->request_mode &= CWWidth | CWHeight; + if ( Request->request_mode == 0 ) return result; + + DefaultGeometry(w, &minW, &minH, &editW, &labelW); + +/* Ueberpruefe, ob uns das in der Breite passt, was Pappi moechte... */ + if ( Request->request_mode & CWWidth ) { + if ( Request->width < minW ) { +/* Wenn Pappi uns etwas vorschlaegt, was im wahrsten Sinne des Wortes + * vorn und hinten nicht reicht, dann versuchen wir ihn entsprechend + * zu korrigieren. ("Versuchen" deshalb, weil er diesen Vorschlag auch + * voellig ignorieren kann.) + */ + result = XtGeometryAlmost; + Reply->width = minW; + Reply->request_mode |= CWWidth; + } + } +/* Die ganze Chose nun noch vertikal */ + if ( Request->request_mode & CWHeight ) { + if ( Request->height < minH ) { + result = XtGeometryAlmost; + Reply->height = minH; + Reply->request_mode |= CWHeight; + } + } + return result; +} /* QueryGeometry */ + +/* -------------------------------------------------------------------- + * Die Groesse des ComboBox-Widgets hat sich veraendert und deshalb + * mussen alle Kinder neu positioniert werden. + * Letzten Endes laeuft hier alles auf ein ordinaeres DoLayout() + * hinaus, um die Kinder umher zu schieben. + * Parameter: + * w Die bereits hinlaenglich bekannte Instanz dieses + * Widgets + */ +static void Resize(XmComboBoxWidget w) +{ + DoLayout(w); +} /* Resize */ + +/* -------------------------------------------------------------------- + * Dieses Widget hat sich in irgendeiner Form bewegt (und das nicht + * nur relativ zum Vater, sondern moeglicherweise auch der Vater + * selbst!) bzw. die Shell, in der sich irgendwo unsere Combo-Box + * befindet, hat soeben den Fokus verschusselt und kann ihn nicht + * mehr wiederfinden. Daneben kann es auch sein, dass die Shell + * ikonisiert wurde. (Welch' Vielfalt! Dieses ist hier halt eine + * multifunktionale Routine.) + * + * Parameter: + * w Die naechste Shell in Reichweite ueber unserer + * Combo-Box. + * cbw Diese Combo-Box. + * event ^ auf den Event, enthaelt genauerere Informationen + * (naja... sieht so aus, als ob Motif hier auch + * schon 'mal Schrott 'reinpackt...) + * ContDispatch Auf True setzen, damit dieser Event noch weiter- + * gereicht wird an all' die anderen, die auch noch + * mithoeren. + */ +static void ShellCallback(Widget w, XtPointer pClientData, + XEvent *event, Boolean *ContDispatch) +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData; + + switch ( event->type ) { + case ConfigureNotify: + case CirculateNotify: + DoDropDownLayout((XmComboBoxWidget) cbw); + break; + case FocusOut: + LOG3("ShellCallback: FocusOut, mode: %i, detail: %i\n", + (int)event->xfocus.mode, (int)event->xfocus.detail); + if ( cbw->combobox.Persistent ) + cbw->combobox.IgnoreFocusOut = True; + else if ( (event->xfocus.mode == NotifyGrab) && + cbw->combobox.ListVisible ) + cbw->combobox.IgnoreFocusOut = True; + break; + case UnmapNotify: + ShowHideDropDownList((XmComboBoxWidget) cbw, + event, False); + break; + } + *ContDispatch = True; +} /* ShellCallback */ + +/* -------------------------------------------------------------------- + * Diese Routine sorgt dafuer, dass die Liste nicht irrtuemlich bei + * manchen Window Managern vom Bildschirm genommen wird, bloss weil + * diese der OverrideShell den Tastaturfocus schenken bzw. diesen + * dem Combo-Box-Widget wegnehmen, sobald der Mauszeiger in die Liste + * bewegt wird. + */ +static void OverrideShellCallback(Widget w, XtPointer pClientData, + XEvent *event, Boolean *ContDispatch) + +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData; + switch ( event->type ) { + case EnterNotify: + LOG2("OverrideShellCallback: EnterNotify, PendingFO: %s\n", + cbw->combobox.PendingFocusOut ? "True" : "False"); + if ( cbw->combobox.PendingFocusOut ) + cbw->combobox.IgnoreFocusOut = True; + if ( cbw->combobox.TwmHandlingOn ) + cbw->combobox.PendingOverrideInOut = True; + break; + case LeaveNotify: + LOG("OverrideShellCallback: LeaveNotify\n"); + if ( cbw->combobox.TwmHandlingOn ) + cbw->combobox.PendingOverrideInOut = True; + break; + } +} /* OverrideShellCallback */ + +/* -------------------------------------------------------------------- + * Ha! Anscheinend kann man das Problem mit der einklappenden Liste, + * sobald man den Arrow-Button anklickt, doch loesen! Allerdings geht + * das auch nur von hinten durch die Brust in's Auge. Hier war die + * Reihenfolge der Events bislang das Problem: Klickt man den Arrow- + * Button an, so verliert das Eingabefeld den Focus, dann wird leider + * schon die WorkProc aktiviert und laesst die Liste verschwinden. + * Danach erst kommt der Arrow-Button-Callback an die Reihe. Um dieses + * Dilemma doch noch zu loesen, wird hier darauf gelauert, wann und + * welcher LeaveNotify kommt. Klickt der Benutzer den Pfeil an, so + * kommt hier noch rechtzeitig ein LeaveNotify vorbei, der aber durch + * einen Grab ausgeloest wurde. Und das ist eben nur beim Anklicken + * der Fall. Damit wissen wir, das der FocusOut getrost ignoriert + * werden darf. + * Puhhh -- ist das ein kompliziertes Chaos. + * Uebrigends...auch wenn manche Befehle zuerst ueberfluessig er- + * scheinen...sie sind erforderlich, damit die ComboBox auch mit unter- + * schiedlichen Window Managern zurechtkommt! + */ +static void ArrowCrossingCallback(Widget w, XtPointer pClientData, + XEvent *event, Boolean *ContDispatch) + +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData; + switch ( event->type ) { + case LeaveNotify: + LOG2("ArrowCrossingCallback: LeaveNotify, mode: %i\n", + event->xcrossing.mode); + if ( event->xcrossing.mode == NotifyGrab ) + cbw->combobox.IgnoreFocusOut = True; + else + cbw->combobox.IgnoreFocusOut = False; + break; + } +} /* ArrowCrossingCallback */ + +/* -------------------------------------------------------------------- + * Alle Hilfeaufrufe innerhalb der Kinder gehen an das eigentliche + * Combo-Box-Widget weiter, so dass auch hier nach aussen hin die + * Kinder-Widgets nicht in Erscheinung treten. + */ +static void HelpCallback(Widget w, XtPointer cbw, XtPointer CallData) +{ + XtCallCallbacks((Widget) cbw, XmNhelpCallback, CallData); +} /* HelpCallback */ + +/* -------------------------------------------------------------------- + * Wenn der Benutzer im Eingabefeld osfActivate drueckt, dann dieses + * Ereignis offiziell bekanntgeben. + */ +static void ActivateCallback(Widget w, XtPointer cbw, XtPointer CallData) +{ + XtCallCallbacks((Widget) cbw, XmNactivateCallback, CallData); +} /* ActivateCallback */ + +/* -------------------------------------------------------------------- + * Ein Kind moechte sein Groesse veraendern und fragt deshalb hier bei + * uns an. + * Parameter: + * w Naja... + * *Request Vorschlag des Kindes + * Ergebnis: + * *Reply Unsere Antwort darauf + * XtGeometryNo, da es uns bislang grundsaetzlich nie passt, es sei + * denn, es ist das Label... Naja, jetzt darf auch schon einmal das + * Listenfeld quengeln (aber nur, wenn es staendig sichtbar ist, + * ansonsten wird es nicht beruecksichtigt!). + */ +static XtGeometryResult GeometryManager(Widget w, + XtWidgetGeometry *Request, + XtWidgetGeometry *Reply) +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w); + XtGeometryResult Result = XtGeometryNo; + + /* + * Falls das Listenfeld statisch dargestellt wird, muessen wir seine + * Wuensche doch beruecksichtigen. Was fuer ein Aufwand... + */ + if ( (w == XtParent(cbw->combobox.ListCtrl)) && cbw->combobox.StaticList ) { + Dimension TotalWidth, TotalHeight, EditWidth, LabelWidth; + XtWidgetGeometry MyRequest, YourReply, EditGeom; + + XtQueryGeometry(cbw->combobox.EditCtrl, NULL, &EditGeom); + DefaultGeometry(cbw, &TotalWidth, &TotalHeight, + &EditWidth, &LabelWidth); + CheckDropDownOffset(cbw); + + if ( Request->request_mode && CWWidth ) + if ( (Dimension)(LabelWidth + cbw->combobox.DropDownOffset + + Request->width) > TotalWidth ) + TotalWidth = LabelWidth + cbw->combobox.DropDownOffset + + Request->width; + + if ( Request->request_mode && CWHeight ) + TotalHeight = EditGeom.height + Request->height; + /* + * Bastele nun eine Anfrage an Pappi zusammen und geh' ihm damit auf den + * Keks. Wenn er zustimmt, ist sofort alles gut, wir muessen dann nur + * noch das Layout aufpolieren, damit das Listenfeld die neue Groesse + * bekommt. Wenn Pappi nur halb zustimmt, akzeptieren wir das und fragen + * ihn damit noch einmal.... + */ + MyRequest.request_mode = CWWidth | CWHeight; + MyRequest.width = TotalWidth; + MyRequest.height = TotalHeight; + Result = XtMakeGeometryRequest((Widget) cbw, &MyRequest, &YourReply); + if ( Result == XtGeometryAlmost ) { + MyRequest.width = YourReply.width; + MyRequest.height = YourReply.height; + Result = XtMakeGeometryRequest((Widget) cbw, &MyRequest, &YourReply); + } + if ( Result == XtGeometryYes ) + DoLayout(cbw); + } else + /* + * Ansonsten darf nur noch das Schriftfeld Ansprueche anmelden. + */ + if ( w != cbw->combobox.LabelCtrl ) + return XtGeometryNo; /* Was ICH hier vorgegeben habe, gilt! */ + else if ( cbw->combobox.ShowLabel ) { /* Naja, 'mal schauen! */ + Dimension TotalWidth, TotalHeight, EditWidth, LabelWidth; + XtWidgetGeometry MyRequest; + + if ( Request->request_mode & CWWidth ) { + DefaultGeometry(cbw, &TotalWidth, &TotalHeight, + &EditWidth, &LabelWidth); + TotalWidth = TotalWidth - LabelWidth + + Request->width; + + MyRequest.request_mode = CWWidth; + MyRequest.width = TotalWidth; + Result = XtMakeGeometryRequest((Widget) cbw, &MyRequest, NULL); + + if ( Result == XtGeometryYes ) + DoLayout(cbw); + } + } + return Result; +} /* GeometryManager */ + +/* -------------------------------------------------------------------- + * Hier werden auf Wunsch diejenigen Farben, die bei der Combo-Box neu + * gesetzt wurden, an alle Kinder weitergegeben. + */ +#define BOTTOMSHADOWCOLOR 0x0001 +#define TOPSHADOWCOLOR 0x0002 +#define FOREGROUND 0x0004 +#define BACKGROUND 0x0008 + +static struct { String Resource; int Flag; } + ColorResources[] = { + { XmNbottomShadowColor, BOTTOMSHADOWCOLOR }, + { XmNtopShadowColor, TOPSHADOWCOLOR }, + { XmNforeground, FOREGROUND }, + { XmNbackground, BACKGROUND } + }; + +static UpdateColors(XmComboBoxWidget w, int flags) +{ + Pixel Color; + int i, size = XtNumber(ColorResources); + Widget ScrolledWin, ScrollBar; + + ScrolledWin = XtParent(w->combobox.ListCtrl); + XtVaGetValues(ScrolledWin, XmNverticalScrollBar, &ScrollBar, NULL); + for ( i=0; icombobox.ListCtrl, + ColorResources[i].Resource, Color, NULL); + XtVaSetValues(ScrolledWin, + ColorResources[i].Resource, Color, NULL); + XtVaSetValues(ScrollBar, + ColorResources[i].Resource, Color, NULL); + XtVaSetValues(w->combobox.EditCtrl, + ColorResources[i].Resource, Color, NULL); + XtVaSetValues(w->combobox.LabelCtrl, + ColorResources[i].Resource, Color, NULL); + XtVaSetValues(w->combobox.ArrowCtrl, + ColorResources[i].Resource, Color, NULL); + if ( ColorResources[i].Flag & BACKGROUND ) + XtVaSetValues(ScrollBar, XmNtroughColor, Color, NULL); + } + + return 1; +} /* UpdateColors */ + +/* -------------------------------------------------------------------- + * Liste aller vorgespiegelten Resourcen, die automatisch verarbeitet + * werden koennen, ohne weiter darueber nachdenken zu muessen... + */ +typedef enum { EDITCTRL, LISTCTRL, LABELCTRL } CHILDCTRL; +typedef enum { RO, RW, RWS, RWL, RWI, RWIGNORE } aUniqueName; +typedef struct { + String rsc; + CHILDCTRL ctrl; +/* enum { RO, RW, RWS, RWL, RWI, RWIGNORE } dir; */ + aUniqueName dir; + /* nur lesen, lesen&schreiben, lesen&schreiben spezial, + lesen&schreiben label, lesen&schreiben items */ +} MIRROR; + +/* Alle mit !!! gekennzeichneten Eintraege werden auf die richtigen + * Namen des entsprechenden Widgets umgesetzt. + */ +static MIRROR MirroredResources[] = { + { XmNitems, LISTCTRL, RWI }, /* Urgs! */ + { XmNitemCount, LISTCTRL, RWIGNORE }, /* dto. */ + { XmNlistMarginHeight, LISTCTRL, RW }, + { XmNlistMarginWidth, LISTCTRL, RW }, + { XmNlistSpacing, LISTCTRL, RW }, + { XmNstringDirection, LISTCTRL, RO }, /* Naja? */ + { XmNtopItemPosition, LISTCTRL, RO }, + + { XmNblinkRate, EDITCTRL, RW }, + { XmNcolumns, EDITCTRL, RW }, + { XmNcursorPosition, EDITCTRL, RW }, + { XmNcursorPositionVisible, EDITCTRL, RW }, + { XmNmarginHeight, EDITCTRL, RW }, + { XmNmarginWidth, EDITCTRL, RW }, + { XmNmaxLength, EDITCTRL, RW }, + { XmNselectThreshold, EDITCTRL, RW }, + { XmNvalue, EDITCTRL, RWS }, + + { XmNalignment, LABELCTRL, RW }, + { XmNmnemonic, LABELCTRL, RW }, + { XmNmnemonicCharSet, LABELCTRL, RW }, + { XmNlabelPixmap, LABELCTRL, RW }, + { XmNlabelInsensitivePixmap, LABELCTRL, RW }, + { XmNlabelString, LABELCTRL, RW }, + { XmNlabelType, LABELCTRL, RW }, + { XmNlabelMarginBottom, LABELCTRL, RWL }, /* !!! */ + { XmNlabelMarginHeight, LABELCTRL, RWL }, /* !!! */ + { XmNlabelMarginLeft, LABELCTRL, RWL }, /* !!! */ + { XmNlabelMarginRight, LABELCTRL, RWL }, /* !!! */ + { XmNlabelMarginTop, LABELCTRL, RWL }, /* !!! */ + { XmNlabelMarginWidth, LABELCTRL, RWL }, /* !!! */ + { XmNlabelFontList, LABELCTRL, RWL }, /* !!! */ +}; + +typedef struct { + char *from, *to; +} TRANSFORMATION; +static TRANSFORMATION Transformations[] = { + { XmNlabelMarginBottom, XmNmarginBottom }, + { XmNlabelMarginHeight, XmNmarginHeight }, + { XmNlabelMarginLeft, XmNmarginLeft }, + { XmNlabelMarginRight, XmNmarginRight }, + { XmNlabelMarginTop, XmNmarginTop }, + { XmNlabelMarginWidth, XmNmarginWidth }, + { XmNlabelFontList, XmNfontList }, +}; + +/* -------------------------------------------------------------------- + * Sobald irgendeine Resource veraendert wird, erfolgt der Aufruf + * hierin als Benachrichtigung, einmal nach dem rechten zu sehen. + * Parameter: + * current Kopie der Widget-Instanz, bevor irgendwelche + * Resourcen veraendert oder set_values()-Methoden + * aufgerufen wurden. + * req Kopie der Widget-Instanz, aber bereits mit den + * durch XtSetValues veraenderten Werten + * new aktuellster Zustand der Widget-Instanz mit + * veraenderten Werten (entweder durch XtSetValues + * oder set_values()-Methoden der Superklasse) + * args Argumentenliste beim Aufruf von XtSetValues() + * NumArgs Anzahl der Argumente in der Liste + * Ergebnis: + * True, falls Widget neu gezeichnet werden soll. + */ +static Boolean SetValues(XmComboBoxWidget current, XmComboBoxWidget req, + XmComboBoxWidget newW, + ArgList args, Cardinal *NumArgs) +{ + Boolean Update = False; + int i, j, MirrorSize = XtNumber(MirroredResources); + int k, TransformationSize = XtNumber(Transformations); + Arg arg; + int Flags; + +/* + * Alle Resourcen, die nicht mehr nach dem Erstellen der Widget-Instanz + * veraendert werden koennen. + */ + newW->combobox.Editable = current->combobox.Editable; + newW->combobox.ListCtrl = current->combobox.ListCtrl; + newW->combobox.EditCtrl = current->combobox.EditCtrl; + newW->combobox.LabelCtrl = current->combobox.LabelCtrl; + newW->combobox.SelectionPolicy = current->combobox.SelectionPolicy; + newW->combobox.ListSizePolicy = current->combobox.ListSizePolicy; + newW->combobox.StaticList = current->combobox.StaticList; + +/* + * Kontrolliere nun alle Resourcen, die sich veraendert haben koennten + * und gebe die neuen Einstellungen entsprechend weiter... + * + * Hat sich der Sensitive-Zustand veraendert? Dann muessen wir hier dafuer + * sorgen, dass alle Kinder ebenfalls den neuen Zustand annehmen. + */ + if ( current->core.sensitive != newW->core.sensitive ) { + XtSetSensitive(newW->combobox.ListCtrl, newW->core.sensitive); + XtSetSensitive(newW->combobox.EditCtrl, newW->core.sensitive); + XtSetSensitive(newW->combobox.ArrowCtrl, newW->core.sensitive); + XtSetSensitive(newW->combobox.ListCtrl, newW->core.sensitive); + if ( !newW->core.sensitive ) + ShowHideDropDownList(newW, NULL, False); + } +/* + * Die ScrollBarPolicy kann nur dann geaendert werden, wenn das Listenfeld + * dauerhaft dargestellt wird. + */ + if ( newW->combobox.ScrollBarDisplayPolicy != + current->combobox.ScrollBarDisplayPolicy ) + if ( newW->combobox.StaticList ) + XtVaSetValues(newW->combobox.ListCtrl, + XmNscrollBarDisplayPolicy, newW->combobox.ScrollBarDisplayPolicy, + NULL); + else + XtWarning( +"XmComboBox: ScrollBarDisplayPolicy can not be changed when StaticList == False." + ); +/* Anzahl der in der Liste gleichzeitig darstellbaren Eintraege */ + if ( current->combobox.VisibleItemCount != + newW->combobox.VisibleItemCount ) { + XtVaSetValues(newW->combobox.ListCtrl, + XmNvisibleItemCount, newW->combobox.VisibleItemCount, + NULL); + Update = True; + } + if ( current->combobox.AutomaticSelection != + newW->combobox.AutomaticSelection ) + XtVaSetValues(newW->combobox.ListCtrl, + XmNautomaticSelection, newW->combobox.AutomaticSelection, + NULL); + +/* + * benutzter Font: hier erhalten Liste und Eingabefeld jeweils die + * gleiche Fontliste, wohingegen das Label getrennt behandelt wird. + * Das macht auch Sinn, denn Liste und Eingabefeld beinhalten gleich- + * artigen Text, so dass hier auch tunlichst der gleiche Font zu + * benutzen ist. + */ + if ( current->combobox.Font != newW->combobox.Font ) { + XtVaSetValues(newW->combobox.ListCtrl, + XmNfontList, newW->combobox.Font, NULL); + XtVaSetValues(newW->combobox.EditCtrl, + XmNfontList, newW->combobox.Font, NULL); + Update = True; + } + + Flags = 0; + if ( newW->manager.top_shadow_color != + current->manager.top_shadow_color ) Flags |= TOPSHADOWCOLOR; + if ( newW->manager.bottom_shadow_color != + current->manager.bottom_shadow_color ) Flags |= BOTTOMSHADOWCOLOR; + if ( newW->manager.foreground != + current->manager.foreground ) Flags |= FOREGROUND; + if ( newW->core.background_pixel != + current->core.background_pixel ) Flags |= BACKGROUND; + if ( Flags ) { UpdateColors(newW, Flags); Update = True; } + + + if ( newW->combobox.ArrowCursor != current->combobox.ArrowCursor ) { + if ( newW->combobox.ListVisible ) + XDefineCursor(XtDisplay(newW->combobox.PopupShell), + XtWindow(newW->combobox.PopupShell), + newW->combobox.ArrowCursor); + } +/* Hier werden die vorgespiegelten Resourcen verwaltet, die in + * Wirklichkeit zu einem unserer Kinder gehoeren. + */ + for ( i = 0; i < *NumArgs; i++ ) { +/* Ist es eine vorgespiegelte Resource ? Wenn ja, dann leite die + * Anfrage an das entsprechende Kind-Widget weiter. + */ + for ( j = 0; j < MirrorSize; j++ ) { + if ( (strcmp(args[i].name, MirroredResources[j].rsc) == 0) ) { + switch ( MirroredResources[j].dir ) { + case RW: /* schreibender Zugriff erlaubt */ + XtSetValues(MirroredResources[j].ctrl == LISTCTRL ? + newW->combobox.ListCtrl : + (MirroredResources[j].ctrl == EDITCTRL ? + newW->combobox.EditCtrl : + newW->combobox.LabelCtrl), + &(args[i]), 1); + break; + case RWS: /* schreibender Zugriff unter Kontrolle */ + if ( strcmp(args[i].name, XmNvalue) == 0 ) { + if ( newW->combobox.Editable ) + XtSetValues(newW->combobox.EditCtrl, + &(args[i]), 1); + } + break; + case RWL: /* Transformation in andere Resource beim + Label-Widget */ + for ( k = 0; k < TransformationSize; k++ ) + if ( strcmp(args[i].name, Transformations[k].from) == 0 ) { + arg.value = args[i].value; + arg.name = Transformations[k].to; + XtSetValues(newW->combobox.LabelCtrl, + &arg, 1); + break; + } + break; + case RWIGNORE: /* Zugriff auf XmNitemCount */ + /* Wird von XmNitems erledigt! */ + break; + case RWI: /* Zugriff auf XmNitems */ + for ( k = 0; k < *NumArgs; k++ ) + if ( strcmp(args[k].name, XmNitemCount) == 0 ) { + Arg MyArgs[2]; + + MyArgs[0].name = XmNitems; + MyArgs[0].value = args[i].value; + MyArgs[1].name = XmNitemCount; + MyArgs[1].value = args[k].value; + XtSetValues(newW->combobox.ListCtrl, + args, 2); + /*XtVaSetValues(newW->combobox.ListCtrl, + XmNitems, args[i].value, + XmNitemCount, args[k].value, + NULL);*/ + break; + } + break; + case RO: + break; + } /* case write mode */ + goto ScanForNextResource; + } /* if entry found */ + } /* for every mirrored entry */ + ScanForNextResource: ; + } /* for every Arg */ + + if ( (newW->combobox.SquareArrow != current->combobox.SquareArrow) || + (newW->combobox.ArrowSpacingOn != current->combobox.ArrowSpacingOn) ) { + Update = False; + DoLayout(newW); + } + + return Update; +} /* SetValues */ + +/* -------------------------------------------------------------------- + * Werden irgendwelche Resourcen abgefragt, so muessen wir hier erst + * noch vor der Rueckkehr zum Frager klaeren, ob davon eine Resource + * betroffen ist, die nur vorgespiegelt ist, da sie eigentlich einem + * der Widgets gehoert, die von uns hier verwaltet werden, um daraus + * eine ordentliche Combo-Box zu machen. + * Parameter: + * w Widget-Instanz + * args Abgefragte Resourcen + * NumArgs Anzahl der abgefragten Resourcen + */ +static void GetValuesAlmost(XmComboBoxWidget w, ArgList args, + Cardinal *NumArgs) +{ + int i, j, MirrorSize = XtNumber(MirroredResources); + int k, TransformationSize = XtNumber(Transformations); + Arg arg; + + for ( i = 0; i < *NumArgs; i++ ) { +/* Ist es eine vorgespiegelte Resource ? Wenn ja, dann leite die + * Anfrage an das entsprechende Kind-Widget weiter. + */ + for ( j = 0; j < MirrorSize; j++ ) { + if ( strcmp(args[i].name, MirroredResources[j].rsc) == 0 ) { + switch ( MirroredResources[j].dir ) { + case RO: + case RW: + case RWS: + case RWI: + XtGetValues(MirroredResources[j].ctrl == LISTCTRL ? + w->combobox.ListCtrl : + MirroredResources[j].ctrl == EDITCTRL ? + w->combobox.EditCtrl : + w->combobox.LabelCtrl, + &(args[i]), 1); + break; + case RWL: /* Umzuleitende Resource bei Label-Widget */ + for ( k = 0; k < TransformationSize; k++ ) + if ( strcmp(args[i].name, Transformations[k].from) == 0 ) { + arg.value = args[i].value; + arg.name = Transformations[k].to; + XtGetValues(w->combobox.LabelCtrl, + (ArgList) &arg, 1); + break; + } + break; + } /* case read mode */ + } /* if entry found */ + } /* for every mirrored entry */ + } /* for every Arg */ +} /* GetValuesAlmost */ + +/* -------------------------------------------------------------------- + * Zeige beziehungsweise verstecke die Drop-Down-Liste der Combo-Box. + * Falls die Liste bereits den entsprechenden Zustand hat, geht's + * sofort zum Aufrufer zurueck. + * Parameter: + * w Her Royal Majesty ComboBox + * Show True, falls anzuzeigen, andernfalls False + */ +static void ShowHideDropDownList(XmComboBoxWidget w, XEvent *event, + Boolean Show) +{ + XmComboBoxDropDownCallbackStruct info; + + if ( w->combobox.StaticList || + (Show == w->combobox.ListVisible) ) return; + w->combobox.ListVisible = Show; + if ( Show ) { /* Klapp' die Liste aus! */ + DoDropDownLayout(w); + info.reason = XmCR_SHOW_LIST; + info.event = event; + XtCallCallbacks((Widget) w, XmNdropDownCallback, + (XtPointer) &info); + XDefineCursor(XtDisplay(w->combobox.PopupShell), + XtWindow(w->combobox.PopupShell), + w->combobox.ArrowCursor); + XtPopup(w->combobox.PopupShell, XtGrabNone); + XtVaSetValues(w->combobox.ArrowCtrl, + XmNarrowDirection, XmARROW_UP, NULL); + } else { /* Klapp' die Liste wieder ein... */ + XtPopdown(w->combobox.PopupShell); + XtVaSetValues(w->combobox.ArrowCtrl, + XmNarrowDirection, XmARROW_DOWN, NULL); + info.reason = XmCR_HIDE_LIST; + info.event = event; + XtCallCallbacks((Widget) w, XmNdropDownCallback, + (XtPointer) &info); + } +} /* ShowHideDropDownList */ + +/* -------------------------------------------------------------------- + * Hier laeuft die Nachricht auf, dass der Pfeil ausgeloest wurde... + * (Daraufhin sollte die Liste aus- oder eingeklappt werden) + * ...oder dass der Benutzer da draussen auf der anderen Seite der + * Mattscheibe den Pfeil bereits anklickte ohne aber bereits losge- + * gelassen zu haben. Bereits hier bekommt das Eingabefeld den Fokus + * vor den Latz geknallt, denn sonst kann es passieren, dass zwar die + * Liste ausgeklappt ist, aber das Eingabefeld noch keinen Tastatur- + * fokus erhalten hat. Das sollte aber nicht so sein, denn es ist dann + * keine konsequente Tastaturbedienung. + */ +static void ArrowCallback(Widget w, XtPointer pClientData, + XmAnyCallbackStruct *info) +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w); + + switch ( info->reason ) { + case XmCR_ARM: + LOG("ArrowCallback: XmCR_ARM\n"); + XmProcessTraversal(cbw->combobox.EditCtrl, XmTRAVERSE_CURRENT); + if ( cbw->combobox.TwmHandlingOn && cbw->combobox.ListVisible ) + cbw->combobox.IgnoreFocusOut = True; + break; + case XmCR_ACTIVATE: + XmProcessTraversal(cbw->combobox.EditCtrl, XmTRAVERSE_CURRENT); + ShowHideDropDownList(cbw, info->event, + (Boolean)(!cbw->combobox.ListVisible)); + break; + } +} /* ArrowCallback */ + +/* -------------------------------------------------------------------- + * Diese Benachrichtigung moechte uns nur mitteilen, dass wir soeben + * den Fokus verloren haben (Ohhhh!) Sollte allerdings der Fokus nur + * aus dem Grunde perdue sein, dass der Anwender den Mauszeiger ausser- + * halb des Applikationsfensters plaziert hat, so koennen wir diese + * Nachricht uebergehen. Erst wenn der Fokus an ein anderes Widget in + * unserer Applikation verlorenging, muessen wir auf diese Information + * reagieren. + * Und jetzt zu noch einem total beknackten Problem - alles nur wegen + * Motif und den diversen Window-Managern (bspw. olwm)... Leider kommt + * beim FocusOut kein richtiger Hinweis auf den tatsaechlichen Event, + * der dieses Callback ausloeste -- warum liefert denn dann Motif ueber- + * haupt noch den Event???? Und ueberhauupt, die Geschichte mit dem + * Fokus ist schon der reinste Horror. Aktueller Ausweg: wenn wir die + * Benachrichtigung ueber den Focusabgang bekommen, registrieren wir + * eine Work-Prozedur, die, sobald der Rechner wieder Luft hat, auf- + * gerufen wird. Sie kann dann nachschauen, ob nicht inzwischen die + * OverrideShell den Focus bekahm. Wenn ja, koennen wir den FocusOut + * uebergehen, ansonsten muessen wir ihn beruecksichtigen. + * -- Ist das eine ^@#$^*(#$^&! (Meine gute Erziehung hindert mich + * daran, diesen Begriff hier zu nennen.) + */ +static Boolean DelayedFocusOutWorkProc(XtPointer pClientData) +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData; + LOG2("DelayedFocusOutWorkProc: IgnoreFocusOut: %s\n", + cbw->combobox.IgnoreFocusOut ? "True" : "False"); + if ( !cbw->combobox.IgnoreFocusOut ) + ShowHideDropDownList(cbw, &(cbw->combobox.xevent), False); + cbw->combobox.IgnoreFocusOut = False; + cbw->combobox.PendingFocusOut = False; + return True; /* diese Routine wird nicht mehr benoetigt. */ +} /* DelayedFocusOutWorkProc */ + +static void EditFocusCallback(Widget w, XtPointer pClientData, + XmAnyCallbackStruct *info) +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w); + + if ( cbw->combobox.StaticList ) return; + + if ( info->reason == XmCR_LOSING_FOCUS ) { + LOG2("EditFocusCallback: PendingFocusOut: %s, ", + cbw->combobox.PendingFocusOut ? "True" : "False"); + LOG3("mode: %i, detail: %i, ", (int)info->event->xcrossing.mode, + (int)info->event->xcrossing.detail); + LOG2("PendingOverrideInOut: %s\n", + cbw->combobox.PendingOverrideInOut ? "True" : "False"); + if ( !cbw->combobox.PendingFocusOut && + !cbw->combobox.PendingOverrideInOut ) { + /* Normalerweise duerfen aber keine NULL-Events hier + * vorbeikommen...aber man weiss ja nie so genau und + * sicher ist sicher. Defensiv programmieren! + */ + if ( info->event ) + cbw->combobox.xevent = *info->event; + cbw->combobox.WorkProcID = XtAppAddWorkProc( + XtWidgetToApplicationContext((Widget) cbw), + (XtWorkProc) DelayedFocusOutWorkProc, + (XtPointer) cbw); + cbw->combobox.PendingFocusOut = True; + } + cbw->combobox.PendingOverrideInOut = False; + } +} /* EditFocusCallback */ + +/* -------------------------------------------------------------------- + * Hier wird der angegebene Eintrag in der Listbox der Combo-Box + * markiert und zudem in den sichtbaren Bereich gerollt, sollte er + * sich ausserhalb des dargestellten Bereichs der Liste befinden. + * Parameter: + * w Die Combo-Box (ueblicher Parameter) + * Index Index des neu zu markierenden Eintrages. + * Notify Schickt Mitteilung via Callback + * Ergebnis: + * Index des markierten Eintrages oder 0, falls die Listbox leer + * war und deshalb auch kein Eintrag markiert werden konnte. + */ +static int SetSelectionPos(XmComboBoxWidget w, int Index, Boolean Notify) +{ + Widget ListBox = w->combobox.ListCtrl; + int ItemCount; /* Anzahl Eintraege in Listbox */ + int TopItem, VisibleItems; + + XtVaGetValues(ListBox, XmNitemCount, &ItemCount, + XmNtopItemPosition, &TopItem, + XmNvisibleItemCount, &VisibleItems, + NULL); + if ( Index < 1 ) Index = 1; + if ( Index > ItemCount ) Index = ItemCount; + if ( Index != 0 && ItemCount != 0 ) { + if ( Index < TopItem ) + XmListSetPos(ListBox, Index); + if ( Index >= TopItem + VisibleItems ) + XmListSetBottomPos(ListBox, Index); + XmListSelectPos(ListBox, Index, Notify); + return Index; + } else + return 0; +} /* SetSelectionPos */ + +/* -------------------------------------------------------------------- + * Diese Routine kuemmert sich darum, denjenigen Eintrag aus der List- + * box mit der angegebenen Nummer herauszufischen und an die Eingabe- + * zeile zu uebergeben. Dabei wird der Index auf den Eintrag auto- + * matisch auf den zulaessigen Bereich begrenzt. Zugleich wird auch + * noch der angegebene Eintrag in der Listbox markiert. + */ +static void TransferToEditCtrl(XmComboBoxWidget w, int SelectionIndex, + Boolean MayWipeOut) +{ + Widget ListBox = w->combobox.ListCtrl; + XmStringTable Items; + char *pItemText; + + XtVaGetValues(ListBox, XmNitems, &Items, NULL); + + if ( MayWipeOut && + (SelectionIndex == w->combobox.LastSelection) && + (w->combobox.SelectionPolicy == XmSINGLE_SELECT) ) { + SelectionIndex = 0; + } + + if ( (SelectionIndex == 0) && + (w->combobox.SelectionPolicy == XmSINGLE_SELECT) ) { + XmListDeselectAllItems(w->combobox.ListCtrl); + w->combobox.PassVerification = True; + XmTextFieldSetString(w->combobox.EditCtrl, ""); + } else { + SelectionIndex = SetSelectionPos(w, SelectionIndex, False); + if ( SelectionIndex > 0 ) { + XmStringGetLtoR(Items[SelectionIndex-1], + XmSTRING_DEFAULT_CHARSET, &pItemText); + w->combobox.PassVerification = True; + XmTextFieldSetString(w->combobox.EditCtrl, pItemText); + XtFree(pItemText); + } + } + w->combobox.LastSelection = SelectionIndex; +} /* TransferToEditCtrl */ + +/* -------------------------------------------------------------------- + * Alle registrierten Callbacks bei Anwahl eines neuen Eintrages in + * der Listbox aktivieren. + */ +static void CallSelectionCBL(XmComboBoxWidget w, XEvent *Event) +{ + int index; + + index = XmComboBoxGetSelectedPos((Widget) w); + /* + * Wenn momentan KEIN Eintrag selektiert ist, dann rufe den neuen + * XmNunselectionCallback auf! + */ + if ( index == 0 ) { + XmComboBoxUnselectionCallbackStruct info; + + info.reason = XmCR_UNSELECT; + info.event = Event; + XtCallCallbacks((Widget) w, XmNunselectionCallback, (XtPointer) &info); + } else { + /* + * Ansonsten den ueblichen SelectionCallback! + */ + XmComboBoxSelectionCallbackStruct info; + XmStringTable Items; + + info.reason = w->combobox.SelectionPolicy == XmSINGLE_SELECT ? + XmCR_SINGLE_SELECT : XmCR_BROWSE_SELECT; + info.event = Event; + info.index = index; + XtVaGetValues(w->combobox.ListCtrl, XmNitems, &Items, NULL); + info.value = Items[info.index-1]; + XtCallCallbacks((Widget) w, XmNselectionCallback, (XtPointer) &info); + } +} /* CallSelectionCBL */ + +/* -------------------------------------------------------------------- + * Hier laeuft das Tastatur-Management fuer die ComboBox zusammen. + * ACHTUNG: Der 'w'-Parameter wird nur benoetigt, um das eigentliche + * ComboBox-Widget zu ermitteln. Er muss daher die ID eines direkten + * Kinds der ComboBox enthalten! + */ +static void CBoxManager(Widget w, XEvent *Event, String *params, + Cardinal *num_params) +{ + XmComboBoxWidget cbw; + Widget ListBox; + int *SelectionList; + int SelectionCount; + int SelectionIndex; /* Wer denn nun markiert wird... */ + int ItemCount; /* Anzahl Eintraege in Listbox */ + int VisibleItems; /* Hoehe der Liste in Eintraegen */ + char opt; + + /* + * Nur wenn eine der Translationen page-up und page-down direkt im + * Listenfeld ausgeloest wurden, wird auch als "w" die Liste ueber- + * geben. Bei allen anderen Faellen ist dieses zumeist das TextField. + */ + if ( XtClass(w) == xmListWidgetClass ) + cbw = (XmComboBoxWidget) XtParent(XtParent(w)); + else + cbw = (XmComboBoxWidget) XtParent(w); + ListBox = cbw->combobox.ListCtrl; + + switch ( *(params[0]) ) { +/* -------------------------------------------------------------------- + * Klappe die Liste auf Wunsch des Benutzers aus oder wieder ein. + */ + case 's': /* show-hide-list */ + ShowHideDropDownList(cbw, Event, + (Boolean)(!cbw->combobox.ListVisible)); + break; + case 'h': /* hide-list */ + ShowHideDropDownList(cbw, Event, False); + break; +/* -------------------------------------------------------------------- + * Hier werden die Bewegungen in der Listbox behandelt. + */ + case 'u': /* up */ + case 'd': /* down */ + case 't': /* top */ + case 'b': /* bottom */ + case 'p': /* page-up/page-down */ + opt = *(params[0]); + XtVaGetValues(ListBox, XmNitemCount, &ItemCount, + XmNvisibleItemCount, &VisibleItems, NULL); + if ( XmListGetSelectedPos(ListBox, + &SelectionList, &SelectionCount) ) { + SelectionIndex = *SelectionList; + XtFree((char *)SelectionList); + switch ( opt ) { + case 'u': SelectionIndex--; break; + case 'd': SelectionIndex++; break; + case 't': SelectionIndex = 1; break; + case 'b': SelectionIndex = ItemCount; break; + case 'p': if ( *(params[0]+5) == 'u' ) + SelectionIndex -= VisibleItems; + else + SelectionIndex += VisibleItems; + break; + } + } else { /* momentan noch kein Eintrag in der Liste ausgewaehlt */ + if ( opt == 'b' ) SelectionIndex = ItemCount; + else SelectionIndex = 1; /* nun ersten Eintrag nehmen */ + } + TransferToEditCtrl(cbw, SelectionIndex, False); + CallSelectionCBL(cbw, Event); + break; +/* -------------------------------------------------------------------- + * Der Benutzer hat die Eingabetaste gedrueckt oder einen Eintrag in + * der Listbox angeklickt. + */ + case 'a': /* Return = activate */ + case 'S': /* Selection */ + if ( !cbw->combobox.StaticList && !cbw->combobox.ListVisible ) break; + XtVaGetValues(ListBox, XmNitemCount, &ItemCount, NULL); + if ( ItemCount == 0 ) break; + if ( XmListGetSelectedPos(ListBox, + &SelectionList, &SelectionCount) ) { + SelectionIndex = *SelectionList; + XtFree((char *)SelectionList); + } else { + if ( cbw->combobox.SelectionPolicy != XmSINGLE_SELECT ) + SelectionIndex = 1; + else + SelectionIndex = 0; + } + + TransferToEditCtrl(cbw, SelectionIndex, + *(params[0]) == 'S'); + CallSelectionCBL(cbw, Event); + ShowHideDropDownList(cbw, Event, (Boolean) + (*(params[0]) == 'S' ? True : False)); + break; +/* -------------------------------------------------------------------- + * Der Benutzer hat die ESC-Taste gedrueckt. Ist die Liste zu diesem + * Zeitpunkt noch ausgeklappt, so wird sie einfach nur eingeklappt und + * weiter passiert nichts. Ist die Liste jedoch eingeklappt, so wird + * das ESC an die normale Action-Routine des Eingabefeldes weiter- + * gegeben, damit damit bspw. Dialog u.a. abgebrochen werden koennen. + */ + case 'c': /* Cancel */ + if ( cbw->combobox.ListVisible ) + ShowHideDropDownList(cbw, Event, False); + else + XtCallActionProc(cbw->combobox.EditCtrl, + "process-cancel", Event, NULL, 0); + break; +/* -------------------------------------------------------------------- + * Wenn es erlaubt ist, dass auch einmal kein Eintrag in einer ComboBox + * mit nicht editierbarem Eingabefeld ausgewaehlt ist, dann darf der + * Anwender mittels osfDelete den aktuellen Eintrag deselektieren. + */ + case 'w': /* wipe */ + if ( cbw->combobox.SelectionPolicy == XmSINGLE_SELECT ) { + TransferToEditCtrl(cbw, 0, True); + CallSelectionCBL(cbw, Event); + } + break; +/* -------------------------------------------------------------------- + * Dummy-Operation + */ + case 'n': /* no-operation */ + break; + } +} /* CBoxManager */ + +/* -------------------------------------------------------------------- + * Der Benutzer hat einen Eintrag in der Listbox angeklickt. Der Ein- + * fachkeit halber wird einfach nur ein Druecken der Eingabetaste + * simuliert. + */ +static void ListSelectionCallback(Widget w, XtPointer pClientData, + XmAnyCallbackStruct *info) +{ + String paramsMouse[1] = { "a" }, paramsKeyboard[1] = { "S" }; + Cardinal NumParams = 1; + XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData; +/* + * Wurde der Event durch die Tastatur oder einen Mausklick + * ausgeloest? Wenn es ein Mausklick auf das Listenfeld war und es + * sich um ein staendig angezeigtes Listenfeld einer nicht editierbaren + * ComboBox handelt, dann gib' dem Eingabefeld den Tastaturfokus. + */ + if ( info->event == NULL ) + CBoxManager(cbw->combobox.EditCtrl, info->event, + paramsKeyboard, &NumParams); + else { + CBoxManager(cbw->combobox.EditCtrl, info->event, + paramsMouse, &NumParams); + if ( !cbw->combobox.StaticList || + (cbw->combobox.StaticList && !cbw->combobox.Editable) ) + XmProcessTraversal(cbw->combobox.EditCtrl, + XmTRAVERSE_CURRENT); + } +} /* ListSelectionCallback */ + +/* -------------------------------------------------------------------- + * Nach einem Doppelklick innerhalb des Listenfelds wird diese Routine + * aufgerufen. Zunaechst einmal wird ganz normal wie bei einem ein- + * fachen Anklicken vorgegangen, danach aber noch der ein spezieller + * Callback aufgerufen. + */ +static void ListDefaultActionCallback(Widget w, XtPointer pClientData, + XmAnyCallbackStruct *OldInfo) +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData; + XmComboBoxDefaultActionCallbackStruct info; + XmStringTable Items; + + ListSelectionCallback(w, pClientData, OldInfo); + info.reason = XmCR_DEFAULT_ACTION; + info.event = OldInfo->event; + info.index = XmComboBoxGetSelectedPos((Widget) cbw); + XtVaGetValues(cbw->combobox.ListCtrl, XmNitems, &Items, NULL); + info.value = Items[info.index-1]; + XtCallCallbacks((Widget) cbw, XmNdefaultActionCallback, (XtPointer) &info); +} /* ListDefaultActionCallback */ + + +/* -------------------------------------------------------------------- + * Ohweh!! Diese Routine wurde erforderlich, um XmNautomaticSelection + * zu unterstuetzen. Denn wenn der Benutzer in der Liste herumsucht und + * automaticSelection 'True' ist, kommt kein Callback-Aufruf mehr, wenn + * die Maustaste losgelassen wird. Und damit wuessten wir sonst nicht, + * wann die Liste einzuklappen ist! Irgendwie wird das alles mit der + * Zeit immer konfuser und aufwendiger. Wenn das Chaos gequantelt + * sein sollte, dann muss das Chaos-Quant (sog. 'Chaotonen') aber jede + * Menge Chaos transportieren!!! + */ +static void Button1UpInList(Widget w, XtPointer pClientData, + XEvent *Event, Boolean *ContDispatch) +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) pClientData; + + if ( Event->xbutton.button == Button1 ) { + if ( cbw->combobox.AutomaticSelection ) + ShowHideDropDownList(cbw, Event, False); + } +} /* Button1UpInList */ + +/* -------------------------------------------------------------------- + * Sobald sich irgendetwas im Eingabefeld veraenderte, kommt das + * TextField-Widget zuerst zu uns gelaufen, um sich unser Okay zu + * holen. Bei einer nicht editierbaren Combo-Box wird hierueber die + * Schnellsuche realisiert. + */ +static void EditVerifyCallback(Widget w, XtPointer pClientData, + XmTextVerifyCallbackStruct *info) +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w); + +/* + * Sollte gerade dem Eingabefeld Text aus der Listbox einverleibt + * werden, so duerfen wir hier darueber natuerlich nicht meckern, + * sondern unser <> dazu geben. (D.h. in diesem Fall haben wir + * kein Recht, zu intervenieren.) + */ + if ( cbw->combobox.PassVerification ) { + cbw->combobox.PassVerification = False; + info->doit = True; + return; + } +/* + * Ist es eine Combo-Box, in die kein Text vom Benutzer eingegeben + * werden kann, so wird bei der Eingabe von Zeichen die Schnellsuche + * ausgeloest. + */ + if ( !cbw->combobox.Editable ) { + Widget ListBox = cbw->combobox.ListCtrl; + char WarpCharLow, WarpCharHigh; + XmString Item; + XmStringTable Items; + int *SelectionList; + int SelectionCount; + int i, ItemCount, Start, End; + char *pItem; + Boolean Ignore; + + info->doit = False; + if ( (info->text == NULL ) || + (info->text->length == 0 ) ) return; /* Hoppala! */ +/* + * Nun aus dem Zeichen einen String (Motif-like) basteln und + * in der Listbox danach auf die Suche gehen. + */ + if ( info->text->length > 1 ) { + /* Das ist nun endweder ein normaler Paste, oder aber + * das Ergebnis einer Drag'n'Drop-Operation. + */ + Item = XmStringCreateSimple(info->text->ptr); + XmComboBoxSelectItem((Widget) cbw, Item, True); + XmStringFree(Item); + } else { + /* Ansonsten soll nur eine Schnellsuche ausgefuehrt + * werden, der entsprechende Buchstabe ist das einzige + * Zeichen im dem Callback uebergebenen Text. + */ + WarpCharLow = tolower(*(info->text->ptr)); + WarpCharHigh = toupper(WarpCharLow); + + XtVaGetValues(ListBox, XmNitemCount, &ItemCount, + XmNitems, &Items, + NULL); + if ( ItemCount < 1 ) return; + /* Ermittele, wo's los geht mit der Suche... */ + if ( XmListGetSelectedPos(ListBox, + &SelectionList, &SelectionCount) ) { + Start = *SelectionList; i = Start + 1; + XtFree((char *)SelectionList); + } else i = Start = 1; + + if ( i > ItemCount ) i = 1; + Ignore = True; + while ( i != Start || Ignore ) { + Ignore = False; + XmStringGetLtoR(Items[i-1], XmSTRING_DEFAULT_CHARSET, + &pItem); + if ( (strchr(pItem, WarpCharLow ) == pItem) || + (strchr(pItem, WarpCharHigh) == pItem) ) { + XtFree(pItem); + TransferToEditCtrl(cbw, i, False); + CallSelectionCBL(cbw, info->event); + break; + } + XtFree(pItem); + if ( ++i > ItemCount ) i = 1; + } + } + } else { +/* + * Wenn das Eingabefeld editierbar ist, dann fragen wir ueber die Callbacks + * nach, ob es genehm ist, den neuen Text einzufuegen. + */ + XtCallCallbacks((Widget) cbw, XmNmodifyVerifyCallback, + (XtPointer) info); + } +} /* EditVerifyCallback */ + +/* -------------------------------------------------------------------- + * Dieser Callback wird immer dann aufgerufen, wenn in einer ComboBox + * mit einem veraenderlichem Eingabefeld der Eingabetext veraendert + * wurde. In diesem Fall suchen wir hier nach einem passenden gleich- + * lautenden Eintrag. Wenn wir einen finden, heben wir ihn in der Liste + * sogleich hervor, ansonsten ist kein Eintrag hervorgehoben. + */ +static void EditChangedCallback(Widget w, XtPointer pClientDate, + XmAnyCallbackStruct *info) +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w); + XmStringTable Items; + int ItemCount, i; + XmString EditStr; + String EditLine; + + /* + * Zuerst nach einem passenden Eintrag zum Eingabefeld in der Liste + * suchen... + */ + XtVaGetValues(cbw->combobox.EditCtrl, XmNvalue, &EditLine, NULL); + XtVaGetValues(cbw->combobox.ListCtrl, + XmNitemCount, &ItemCount, + XmNitems, &Items, + NULL); + EditStr = XmStringCreateSimple(EditLine); + XtVaSetValues(cbw->combobox.ListCtrl, XmNselectedItemCount, 0, NULL); + if ( ItemCount < 1 ) return; + for ( i = 0; i < ItemCount; i++ ) + if ( XmStringCompare(Items[i], EditStr) ) { + SetSelectionPos(cbw, i+1, False); + break; + } + XmStringFree(EditStr); + /* + * Zum Abschluss noch den Callback aufrufen... + */ + XtCallCallbacks((Widget) cbw, XmNvalueChangedCallback, (XtPointer) info); +} /* EditChangedCallback */ + +/* -------------------------------------------------------------------- + * Dieser Callback wird immer dann aufgerufen, wenn in einer ComboBox + * mit einem veraenderlichem Eingabefeld der Cursor bewegt wurde. + * Dieser Callback ist nur fuer echte Fans von Callbacks da... + */ +static void MotionVerifyCallback(Widget w, XtPointer pClientDate, + XmTextVerifyCallbackStruct *info) +{ + XmComboBoxWidget cbw = (XmComboBoxWidget) XtParent(w); + + XtCallCallbacks((Widget) cbw, XmNmotionVerifyCallback, (XtPointer) info); +} /* MotionVerifyCallback */ + +/* -------------------------------------------------------------------- + * Bastele einen vollstaendigen Namens- und Klassenbezeichner anhand + * des angegebenen Widgets zusammen. + */ +static void MakeNameAndClass(Widget w, char *NameBuff, char *ClassBuff) +{ + Widget Parent = XtParent(w); + + if ( Parent ) MakeNameAndClass(Parent, NameBuff, ClassBuff); + if ( XtIsSubclass(w, applicationShellWidgetClass) ) { + /* Wenn wir ganz oben angekommen sind, holen wir uns den + * Namen und die Klasse der Applikation selbst und nicht die + * des Widgets. + */ + String AppName, AppClass; + XtGetApplicationNameAndClass( + XtDisplayOfObject(w), &AppName, &AppClass); + strcpy(NameBuff, AppName); + strcpy(ClassBuff, AppClass); + } else { + /* Ansonsten sind wir noch mitten irgendwo in der Hierarchie + * und besorgen uns den Namen und die Klasse dieses Widgets + */ + strcat(NameBuff, "."); + strcat(NameBuff, XtName(w)); + strcat(ClassBuff, "."); + strcat(ClassBuff, ((CoreClassRec *) XtClass(w))->core_class.class_name); + } +} /* MakeNameAndClass */ + +/* -------------------------------------------------------------------- + * Eine einzelne Resource aus der Datenbank herausholen. Diese Resource + * kommt im Allgemeinen immer als String zurueck und muss daher erst + * noch in das gewuenschte Zielformat konvertiert werden. + */ +static Boolean FetchResource(Widget w, + char *FullName, char *FullClass, + char *RscName, char *RscClass, + XrmValue *RscValue, + String *RepresentationType) +{ + Boolean ok; + char *EndOfName = FullName + strlen(FullName); + char *EndOfClass = FullClass + strlen(FullClass); + + strcat(FullName, "."); strcat(FullName, RscName); + strcat(FullClass, "."); strcat(FullClass, RscClass); + ok = XrmGetResource( + XtDatabase(XtDisplayOfObject(w)), + FullName, FullClass, RepresentationType, RscValue); + /* Wieder den alten Namens- und Klassenrumpf herstellen */ + *EndOfName = 0; *EndOfClass = 0; + return ok; +} /* FetchResource */ + +/* -------------------------------------------------------------------- + * Nun folgen diejenigen Routinen, mit denen die Konvertierung in das + * gewuenschte Zielformat einer Resource moeglich ist. + * Verfuegbar: + * String --> Int + * String --> Short + * String XmPIXMAP / XmSTRING --> unsigned char + * String --> Dimension + * String --> XmString + * String --> XmStringTable + * String --> XmFontList + * String --> Pixmap (genauer: Bitmap) + * String --> String + * String --> KeySym + */ +static Boolean FetchIntResource(Widget w, + char *FullName, char *FullClass, + char *RscName, char *RscClass, + int *pInt) +{ + XrmValue RscValue, RscDest; + String RepresentationType; + + if ( FetchResource(w, FullName, FullClass, + RscName, RscClass, + &RscValue, &RepresentationType) ) { + RscDest.size = sizeof(int); + RscDest.addr = (caddr_t) pInt; + if ( XtConvertAndStore(w, RepresentationType, &RscValue, + XtRInt, &RscDest) ) + return True; + } + return False; +} /* FetchIntResource */ + +static Boolean FetchShortResource(Widget w, + char *FullName, char *FullClass, + char *RscName, char *RscClass, + short *pShort) +{ + XrmValue RscValue, RscDest; + String RepresentationType; + + if ( FetchResource(w, FullName, FullClass, + RscName, RscClass, + &RscValue, &RepresentationType) ) { + RscDest.size = sizeof(short); + RscDest.addr = (caddr_t) pShort; + if ( XtConvertAndStore(w, RepresentationType, &RscValue, + XtRShort, &RscDest) ) + return True; + } + return False; +} /* FetchShortResource */ + +static Boolean FetchLabelTypeResource(Widget w, + char *FullName, char *FullClass, + char *RscName, char *RscClass, + unsigned char *pUChar) +{ + XrmValue RscValue, RscDest; + String RepresentationType; + int AInt; + + if ( FetchResource(w, FullName, FullClass, + RscName, RscClass, + &RscValue, &RepresentationType) ) { + if ( strcasecmp((char *) RscValue.addr, "XmPIXMAP") == 0 ) + *pUChar = XmPIXMAP; + else + *pUChar = XmSTRING; + return True; + } + return False; +} /* FetchLabelTypeResource */ + +static Boolean FetchDimensionResource(Widget w, + char *FullName, char *FullClass, + char *RscName, char *RscClass, + Dimension *pDimension) +{ + XrmValue RscValue, RscDest; + String RepresentationType; + + if ( FetchResource(w, FullName, FullClass, + RscName, RscClass, + &RscValue, &RepresentationType) ) { + RscDest.size = sizeof(Dimension); + RscDest.addr = (caddr_t) pDimension; + if ( XtConvertAndStore(w, RepresentationType, &RscValue, + XtRDimension, &RscDest) ) + return True; + } + return False; +} /* FetchDimensionResource */ + +static Boolean FetchStringResource(Widget w, + char *FullName, char *FullClass, + char *RscName, char *RscClass, + String *pString) +{ + XrmValue RscValue; + String RepresentationType; + + if ( FetchResource(w, FullName, FullClass, + RscName, RscClass, + &RscValue, &RepresentationType) ) { + *pString = (char *) RscValue.addr; + return True; + } + return False; +} /* FetchStringResource */ + +static Boolean FetchKeySymResource(Widget w, + char *FullName, char *FullClass, + char *RscName, char *RscClass, + KeySym *pKeySym) +{ + XrmValue RscValue, RscDest; + String RepresentationType; + + if ( FetchResource(w, FullName, FullClass, + RscName, RscClass, + &RscValue, &RepresentationType) ) { + RscDest.size = sizeof(KeySym); + RscDest.addr = (caddr_t) pKeySym; + if ( XtConvertAndStore(w, RepresentationType, &RscValue, + XmRKeySym, &RscDest) ) + return True; + } + return False; +} /* FetchKeySymResource */ + +static Boolean FetchXmStringResource(Widget w, + char *FullName, char *FullClass, + char *RscName, char *RscClass, + XmString *pString) +{ + XrmValue RscValue; + String RepresentationType; + + if ( FetchResource(w, FullName, FullClass, + RscName, RscClass, + &RscValue, &RepresentationType) ) { + *pString = XmCvtCTToXmString((char *) RscValue.addr); + return True; + } + return False; +} /* FetchXmStringResource */ + +static Boolean FetchXmStringTableResource(Widget w, + char *FullName, char *FullClass, + char *RscName, char *RscClass, + XmStringTable *pStringTable, + int *pTableSize) +{ + XrmValue RscValue; + String RepresentationType; + String TmpList, p, pStart; + int Entries, Entry; + + if ( FetchResource(w, FullName, FullClass, + RscName, RscClass, + &RscValue, &RepresentationType) ) { + /* + * Zuerst eine Kopie erzeugen und dann daraus die Liste + * zusammenbasteln. + */ + TmpList = XtNewString((String)RscValue.addr); + if ( TmpList == NULL ) return False; + if ( *TmpList == 0 ) { XtFree(TmpList); return False; } + /* Ermittele, wieviele Eintrage in der Liste sind und + * erstelle dann daraus die Liste. + */ + Entries = 1; p = TmpList; + while ( *p ) + if ( *p++ == ',' ) ++Entries; + *pStringTable = (XmStringTable) + XtMalloc(Entries * sizeof(XmString)); + + p = TmpList; + for ( Entry = 0; Entry < Entries; ++Entry ) { + pStart = p; + while ( (*p != 0) && (*p != ',') ) ++p; + *p++ = 0; + (*pStringTable)[Entry] = (XmString) + XmStringCreateSimple(pStart); + } + /* Hier geht ausnahmsweise einmal Rueckgabe vor + * Entschaedigung... hey, das war doch nur ein + * (wenn auch ziemlich miserabler) Scherz + */ + XtFree(TmpList); + *pTableSize = Entries; + return True; + } + return False; +} /* FetchXmStringTableResource */ + +static Boolean FetchXmFontListResource(Widget w, + char *FullName, char *FullClass, + char *RscName, char *RscClass, + XmFontList *pFontList) +{ + XrmValue RscValue, RscDest; + String RepresentationType; + + if ( FetchResource(w, FullName, FullClass, + RscName, RscClass, + &RscValue, &RepresentationType) ) { + RscDest.size = sizeof(XmFontList); + RscDest.addr = (caddr_t) pFontList; + if ( XtConvertAndStore(w, RepresentationType, &RscValue, + XmRFontList, &RscDest) ) + return True; + } + return False; +} /* FetchXmFontListResource */ + +static Boolean FetchPixmapResource(Widget w, + char *FullName, char *FullClass, + char *RscName, char *RscClass, + Pixmap *pPixmap) +{ + XrmValue RscValue, RscDest; + String RepresentationType; + + if ( FetchResource(w, FullName, FullClass, + RscName, RscClass, + &RscValue, &RepresentationType) ) { + RscDest.size = sizeof(Pixmap); + RscDest.addr = (caddr_t) pPixmap; + if ( XtConvertAndStore(w, RepresentationType, &RscValue, + XtRBitmap, &RscDest) ) + return True; + } + return False; +} /* FetchPixmapResource */ + +/* -------------------------------------------------------------------- + * Waehrend der Initialisierung alle gespiegelten Resourcen, fuer die + * Eintraege in der Resourcen-Datenbank existieren an die passenden + * Kinder-Widgets weiterleiten. Der Trick an der Sache: wir setzen + * die betroffenen Resourcen vie XtSetValues mit uns selbst als Ziel. + * Dadurch bekommt SetValues die Arbeit aufgehalst, die Resourcen den + * richtigen Kindern zuzuordnen... + */ + +#define RInt 0 +#define RShort 1 +#define RLType 2 +#define RDimension 3 +#define RXmString 4 +#define RPixmap 5 +#define RXmFontList 6 +#define RKeySym 7 +#define RString 8 +#define RXmStringTable 9 +#define RXmItemCount 10 + + +typedef struct +{ + String Name, Class; + + int Converter; + +} RESOURCEMIRROR; + +static RESOURCEMIRROR ResourceMirror[] = { + { XmNblinkRate, XmCBlinkRate, RInt, }, + { XmNcolumns, XmCColumns, RShort, }, + { XmNmaxLength, XmCMaxLength, RInt, }, + { XmNmarginHeight, XmCMarginHeight, RDimension }, + { XmNmarginWidth, XmCMarginWidth, RDimension }, + { XmNselectThreshold, XmCSelectThreshold, RInt }, + + { XmNlistMarginHeight, XmCListMarginHeight, RDimension }, + { XmNlistMarginWidth, XmCListMarginWidth, RDimension }, + { XmNlistSpacing, XmCListSpacing, RDimension }, + { XmNitems, XmCItems, RXmStringTable }, + { XmNitemCount, XmCItemCount, RXmItemCount }, + + { XmNmnemonic, XmCMnemonic, RKeySym }, + { XmNmnemonicCharSet, XmCMnemonicCharSet, RString }, + { XmNlabelString, XmCLabelString, RXmString }, + { XmNlabelMarginBottom, XmCLabelMarginBottom, RDimension }, + { XmNlabelMarginHeight, XmCLabelMarginHeight, RDimension }, + { XmNlabelMarginLeft, XmCLabelMarginLeft, RDimension }, + { XmNlabelMarginRight, XmCLabelMarginRight, RDimension }, + { XmNlabelMarginTop, XmCLabelMarginTop, RDimension }, + { XmNlabelMarginWidth, XmCLabelMarginWidth, RDimension }, + { XmNlabelPixmap, XmCLabelPixmap, RPixmap }, + { XmNlabelInsensitivePixmap, XmCLabelInsensitivePixmap, RPixmap }, + { XmNlabelType, XmCLabelType, RLType }, + { XmNlabelFontList, XmCLabelFontList, RXmFontList }, +}; + +static void InitMirrorResources(XmComboBoxWidget w) +{ + char FullName[1024], FullClass[1024]; + int AInt, TableSize; + short AShort; + unsigned char AUChar; + Dimension ADimension; + XmString AXmString; + XmStringTable AStringTable; + Pixmap APixmap; + XmFontList AFontList; + XrmValue RscValue; + String AString; + KeySym AKeySym; + int i, size = XtNumber(ResourceMirror); + + FullName[0] = 0; FullClass[0] = 0; + MakeNameAndClass((Widget) w, FullName, FullClass); + + for ( i=0; i < size; i++ ) { + switch ( ResourceMirror[i].Converter ) { + case RInt: + if ( FetchIntResource((Widget) w, + FullName, FullClass, + ResourceMirror[i].Name, ResourceMirror[i].Class, + &AInt) ) + XtVaSetValues((Widget) w, ResourceMirror[i].Name, + AInt, NULL); + break; + case RXmItemCount: + if ( FetchIntResource((Widget) w, + FullName, FullClass, + ResourceMirror[i].Name, ResourceMirror[i].Class, + &AInt) && ( AInt != 0) ) + XtVaSetValues((Widget) w, ResourceMirror[i].Name, + AInt, NULL); + break; + case RShort: + if ( FetchShortResource((Widget) w, + FullName, FullClass, + ResourceMirror[i].Name, ResourceMirror[i].Class, + &AShort) ) + XtVaSetValues((Widget) w, ResourceMirror[i].Name, + AShort, NULL); + break; + case RLType: + if ( FetchLabelTypeResource((Widget) w, + FullName, FullClass, + ResourceMirror[i].Name, ResourceMirror[i].Class, + &AUChar) ) + XtVaSetValues((Widget) w, ResourceMirror[i].Name, + AUChar, NULL); + break; + case RDimension: + if ( FetchDimensionResource((Widget) w, + FullName, FullClass, + ResourceMirror[i].Name, ResourceMirror[i].Class, + &ADimension) ) + XtVaSetValues((Widget) w, ResourceMirror[i].Name, + ADimension, NULL); + break; + case RXmString: + if ( FetchXmStringResource((Widget) w, + FullName, FullClass, + ResourceMirror[i].Name, ResourceMirror[i].Class, + &AXmString) ) + XtVaSetValues((Widget) w, ResourceMirror[i].Name, + AXmString, NULL); + break; + case RXmStringTable: + if ( FetchXmStringTableResource((Widget) w, + FullName, FullClass, + ResourceMirror[i].Name, ResourceMirror[i].Class, + &AStringTable, &TableSize) ) { + XtVaSetValues((Widget) w, + XmNitems, (XtPointer) AStringTable, + XmNitemCount, TableSize, NULL); + } + break; + case RKeySym: + if ( FetchKeySymResource((Widget) w, + FullName, FullClass, + ResourceMirror[i].Name, ResourceMirror[i].Class, + &AKeySym) ) + XtVaSetValues((Widget) w, ResourceMirror[i].Name, + AKeySym, NULL); + break; + case RString: + if ( FetchStringResource((Widget) w, + FullName, FullClass, + ResourceMirror[i].Name, ResourceMirror[i].Class, + &AString) ) + XtVaSetValues((Widget) w, ResourceMirror[i].Name, + AString, NULL); + break; + case RPixmap: + if ( FetchPixmapResource((Widget) w, + FullName, FullClass, + ResourceMirror[i].Name, ResourceMirror[i].Class, + &APixmap) ) { + XtVaSetValues((Widget) w, ResourceMirror[i].Name, + APixmap, NULL); + if ( strcmp(ResourceMirror[i].Name, XmNlabelPixmap) == 0 ) + w->combobox.ConvertBitmapToPixmap = True; + else + w->combobox.ConvertBitmapToPixmapInsensitive = True; + } + break; + case RXmFontList: + if ( FetchXmFontListResource((Widget) w, + FullName, FullClass, + ResourceMirror[i].Name, ResourceMirror[i].Class, + &AFontList) ) + XtVaSetValues((Widget) w, ResourceMirror[i].Name, + AFontList, NULL); + break; + } + } +} /* InitMirrorResources */ + +/* -------------------------------------------------------------------- + * Wandelt ein 1-Bit tiefes Bitmap in ein n-Bit tiefes Pixmap um, dass + * die gleiche Tiefe besitzt, wie der Bildschirm, auf dem das Pixmap + * spaeter erscheinen soll. + */ +static Pixmap BitmapToPixmap(XmComboBoxWidget w, + String Resource, GC ColorGC) +{ + Pixmap LabelPixmap, LabelBitmap; + Display *display = XtDisplay(w); + Window root; + int PixX, PixY; + unsigned int PixW, PixH, PixBW, PixDepth; + + XtVaGetValues(w->combobox.LabelCtrl, Resource, &LabelBitmap, NULL); + XGetGeometry(display, LabelBitmap, &root, + &PixX, &PixY, &PixW, &PixH, &PixBW, &PixDepth); + LabelPixmap = XCreatePixmap( + display, RootWindowOfScreen(XtScreen(w)), + PixW, PixH, + (w->combobox.LabelCtrl)->core.depth); + XCopyPlane(display, LabelBitmap, LabelPixmap, + ColorGC, 0, 0, PixW, PixH, 0, 0, 1); + XtVaSetValues(w->combobox.LabelCtrl, Resource, LabelPixmap, NULL); + XFreePixmap(display, LabelBitmap); + return LabelPixmap; +} /* BitmapToPixmap */ + +/* -------------------------------------------------------------------- + * Alles initialisieren, sobald das Widget eingerichtet wird. Das sagt + * sich hier so einfach, ist es aber *definitiv* nicht!!!! + */ +static void Initialize(Widget request, XmComboBoxWidget newW, + ArgList wargs, Cardinal *ArgCount) +{ + Dimension width, height, dummy; + Widget w; + Arg args[10]; + int n = 0; + XmString xmstr; + Pixel BackgroundColor; + +/* + * Da zu allem Ueberfluss die einzelnen Instanzen einer XmComboBox + * auf verschiedenen Displays auftauchen koennen, wird hier: + * 1. pro Widget ein eigener Cursor erzeugt (benoetigt fuer die Liste) + * 2. pro Widget (hier = pro Applikation) die benoetigte Action-Routine + * registiert. Doppelte Registrierung macht dem Toolkit nichts aus, da es + * dann eine evtl. aeltere Definition loescht. + */ + XtAppAddActions(XtWidgetToApplicationContext((Widget) newW), + actions, XtNumber(actions)); + +/* Allgemeine Initialisierungen... */ + newW->combobox.ConvertBitmapToPixmap = False; + newW->combobox.ConvertBitmapToPixmapInsensitive = False; + + newW->combobox.LastSelection = 0; + + newW->combobox.InInit = True; + +/* + * Das folgende Problem mit der Kontrolle, ob sich das Widget absolut auf + * dem Bildschirm verschoben hat, trifft uns nur, wenn die Liste nicht + * dauernd auf dem Bildschirm erscheint: + * Lass' dich benachrichtigen, sobald dieses Widget in irgendeiner + * Form bewegt wird -- und sei es nur, dass das gesamte Applikations- + * fenster umhergeschoben wurde. Um die Benachrichtigung ueberhaupt + * zu erreichen, ist es erforderlich, sich benachrichtigen zu lassen, + * sobald die naechste Shell (oder ein Nachkomme) im Widget-Instanzen- + * Baum verschoben wurde. + */ + if ( !newW->combobox.StaticList ) { + w = (Widget) newW; + while ( !XtIsSubclass(w, shellWidgetClass) ) + w = XtParent(w); + newW->combobox.MyNextShell = w; + XtAddEventHandler(w, + StructureNotifyMask | FocusChangeMask, + False, (XtEventHandler) ShellCallback, + (XtPointer) newW); + } + +/* Richte nun alle zu diesem Widget gehoerenden Kinder ein, als da + * waeren: + * 1 x editierbares Eingabefeld + * 1 x ein Pfeil nach unten + * 1 x ein Schriftfeld + */ + newW->combobox.EditCtrl = XtVaCreateManagedWidget( + "edit", xmTextFieldWidgetClass, (Widget) newW, + XmNverifyBell, False, + NULL); + XtAddCallback(newW->combobox.EditCtrl, + XmNlosingFocusCallback, + (XtCallbackProc) EditFocusCallback, NULL); + XtAddCallback(newW->combobox.EditCtrl, + XmNmodifyVerifyCallback, + (XtCallbackProc) EditVerifyCallback, NULL); + XtAddCallback(newW->combobox.EditCtrl, + XmNvalueChangedCallback, + (XtCallbackProc) EditChangedCallback, NULL); + XtAddCallback(newW->combobox.EditCtrl, + XmNhelpCallback, + (XtCallbackProc) HelpCallback, + (XtPointer) newW); + XtAddCallback(newW->combobox.EditCtrl, + XmNactivateCallback, + (XtCallbackProc) ActivateCallback, + (XtPointer) newW); + if ( newW->combobox.Editable ) + XtAddCallback(newW->combobox.EditCtrl, + XmNmotionVerifyCallback, + (XtCallbackProc) MotionVerifyCallback, + (XtPointer) newW); +/* Neue Translations fuer das Eingabefeld aufnehmen */ + XtOverrideTranslations(newW->combobox.EditCtrl, + NewEditTranslations); + if ( !newW->combobox.Editable ) { + XtOverrideTranslations(newW->combobox.EditCtrl, + NewEditTranslationsNE); + XtVaSetValues(newW->combobox.EditCtrl, + XmNcursorPositionVisible, False, NULL); + } +#ifdef NODRAGNDROP + XtOverrideTranslations(newW->combobox.EditCtrl, + NewListTranslations); /* Btn2Dwn aus! */ +#endif + +/* --- */ + newW->combobox.ArrowCtrl = XtVaCreateManagedWidget( + "arrow", xmArrowButtonWidgetClass, (Widget) newW, + XmNarrowDirection, XmARROW_DOWN, + XmNtraversalOn, False, + XmNnavigationType, XmNONE, + XmNborderWidth, 0, + XmNhighlightThickness, 0, + NULL); + XmRemoveTabGroup(newW->combobox.ArrowCtrl); + if ( newW->combobox.StaticList ) { + XtVaSetValues(newW->combobox.ArrowCtrl, + XmNmappedWhenManaged, False, NULL); + } else { + XtAddEventHandler(newW->combobox.ArrowCtrl, + EnterWindowMask | LeaveWindowMask, + False, (XtEventHandler) ArrowCrossingCallback, + (XtPointer) newW); + XtAddCallback(newW->combobox.ArrowCtrl, + XmNactivateCallback, + (XtCallbackProc) ArrowCallback, NULL); + XtAddCallback(newW->combobox.ArrowCtrl, + XmNarmCallback, + (XtCallbackProc) ArrowCallback, NULL); + XtAddCallback(newW->combobox.ArrowCtrl, + XmNhelpCallback, + (XtCallbackProc) HelpCallback, + (XtPointer) newW); + } + +/* --- */ + newW->combobox.LabelCtrl = XtVaCreateWidget( + "label", xmLabelWidgetClass, (Widget) newW, + XmNstringDirection, newW->manager.string_direction, + NULL); + if ( newW->combobox.ShowLabel ) { + XtManageChild((Widget) newW->combobox.LabelCtrl); + XtAddCallback(newW->combobox.LabelCtrl, + XmNhelpCallback, + (XtCallbackProc) HelpCallback, + (XtPointer) newW); + } + +/* + * Zuerst noch die Shell erzeugen, die so einfach mir nichts dir nichts + * frei auf dem Bildschirm herumschweben kann und damit das Ausklappen + * der Liste erst ermoeglicht -- und uns allerhand Scherereien bereitet! + * War das ein bloeder Fehler in Motif 1.2! Diese Version vertraegt ab- + * solut keine ShellWidgetClass noch overrideShellWidgetClass!!!! Naja, + * mit einer vendorShellWidgetClass laesst sich aber exakt der gleiche + * Effekt erreichen. NEU: vor allem funktioniert dann endlich auch + * Drag'n'Drop!!! + * Noch neuer: Wenn die Liste dauerhaft angezeigt werden muss, entfaellt + * diese Shell zwangslaeufig. Dann ist das Listenfeld ein direktes Kind + * der ComboBox. + */ + if ( !newW->combobox.StaticList ) { + newW->combobox.PopupShell = XtVaCreateWidget( + "combobox_shell", vendorShellWidgetClass, (Widget) newW, + XmNoverrideRedirect, True, + XmNsaveUnder, False, + XmNallowShellResize, True, + NULL); + XtAddEventHandler(newW->combobox.PopupShell, + EnterWindowMask | LeaveWindowMask, + False, (XtEventHandler) OverrideShellCallback, + (XtPointer) newW); + } else { + /* + * Sieht ja pervers nach einer Rekursion aus...daher: OBACHT! + */ + newW->combobox.PopupShell = (Widget) newW; + } + +/* + * Nun kommt die Drop-Down-Liste an die Reihe. Die Liste muss dabei + * mit einer Convenience-Funktion erstellt werden, damit ein Rollbalken + * 'dran ist und das Ganze wird dann in eine Override-Shell gepackt. + * Nicht zu vergessen ist der XtManageChild-Aufruf, damit die Liste + * sofort nach dem Aufklappen der Shell sichtbar wird. + */ + XtSetArg(args[n], XmNselectionPolicy, newW->combobox.SelectionPolicy); n++; + + if ( !newW->combobox.StaticList ) { + /* + * Es gibt halt so eine ganze Reihe von Einstellungen, die koennen nicht + * veraendert werden, wenn das Listenfeld nur bei Bedarf ausgeklappt wird. + */ + XtSetArg(args[n], XmNhighlightThickness, 0); n++; + } + XtSetArg(args[n], XmNlistSizePolicy, + newW->combobox.ListSizePolicy); n++; + XtSetArg(args[n], XmNscrollBarDisplayPolicy, + newW->combobox.ScrollBarDisplayPolicy); n++; + + XtSetArg(args[n], XmNautomaticSelection, + newW->combobox.AutomaticSelection); n++; + XtSetArg(args[n], XmNvisibleItemCount, + newW->combobox.VisibleItemCount); n++; + newW->combobox.ListCtrl = XmCreateScrolledList( + newW->combobox.PopupShell, "list", + args, n); + +/* + * Fuer den Fall, dass die Liste in einer eigenen Shell steckt und daher frei + * auf dem Bildschirm herumschweben kann, sollten wir sicherheitshalber die + * Tastaturbedienung (Fokus) abschalten, um Probleme zu vermeiden (jedenfalls + * hoffentlich...!) + */ + if ( !newW->combobox.StaticList ) { + XtVaSetValues(newW->combobox.ListCtrl, + XmNtraversalOn, False, NULL); + XtVaSetValues(XtParent(newW->combobox.ListCtrl), + XmNtraversalOn, False, NULL); + } else { + if ( !newW->combobox.Editable ) { + XtVaSetValues(XtParent(newW->combobox.ListCtrl), + XmNtraversalOn, False, NULL); + XmRemoveTabGroup(newW->combobox.ListCtrl); + } + } + + XtManageChild(newW->combobox.ListCtrl); + XtAddCallback(newW->combobox.ListCtrl, + XmNsingleSelectionCallback, + (XtCallbackProc) ListSelectionCallback, + (XtPointer) newW); + XtAddCallback(newW->combobox.ListCtrl, + XmNbrowseSelectionCallback, + (XtCallbackProc) ListSelectionCallback, + (XtPointer) newW); + XtAddCallback(newW->combobox.ListCtrl, + XmNdefaultActionCallback, + (XtCallbackProc) ListDefaultActionCallback, + (XtPointer) newW); + XtAddCallback(newW->combobox.ListCtrl, + XmNhelpCallback, + (XtCallbackProc) HelpCallback, + (XtPointer) newW); + + XtAddEventHandler(newW->combobox.ListCtrl, + ButtonReleaseMask, + False, (XtEventHandler) Button1UpInList, + (XtPointer) newW); + +#ifdef NODRAGNDROP + XtOverrideTranslations(newW->combobox.ListCtrl, + NewListTranslations); +#endif + if ( newW->combobox.StaticList && newW->combobox.Editable ) + XtOverrideTranslations(newW->combobox.ListCtrl, + NewListTranslationsE); + +/* Jetzt wird es dann erst richtig spannend... Zuerst alle evtl. + * in der Resource-Datenbank abgelegten Resourcen an die Kinder + * weitergeben. Danach die uebergebenen Parameter ebenfalls an + * die Kinder weiterreichen und schliesslich das Layout ermitteln. + */ + InitMirrorResources(newW); + UpdateColors(newW, -1); + SetValues(newW, newW, newW, wargs, ArgCount); + + if ( newW->combobox.ConvertBitmapToPixmap ) + newW->combobox.LabelPixmap = + BitmapToPixmap(newW, XmNlabelPixmap, + ((XmLabelRec *) newW->combobox.LabelCtrl)-> + label.normal_GC); + if ( newW->combobox.ConvertBitmapToPixmapInsensitive ) + newW->combobox.LabelInsensitivePixmap = + BitmapToPixmap(newW, XmNlabelInsensitivePixmap, + ((XmLabelRec *) newW->combobox.LabelCtrl)-> + label.insensitive_GC); + + DefaultGeometry(newW, &width, &height, &dummy, &dummy); + if ( newW->core.width == 0 ) + newW->core.width = width; + if ( newW->core.height == 0 ) + newW->core.height = height; + +/* + * Falls wir keine Fontliste besitzen, dann nehmen wir die von + * dem Eingabefeld... + */ + if ( newW->combobox.Font == NULL ) { + XtVaGetValues(newW->combobox.EditCtrl, + XmNfontList, &newW->combobox.Font, NULL); + XtVaSetValues(newW->combobox.ListCtrl, + XmNfontList, newW->combobox.Font, NULL); + } else { + XtVaSetValues(newW->combobox.ListCtrl, + XmNfontList, newW->combobox.Font, NULL); + XtVaSetValues(newW->combobox.EditCtrl, + XmNfontList, newW->combobox.Font, NULL); + } + +/* + * Initialisiere alle Statusflaggen, die mit diesem unseligen Focus- + * problem zu tun haben... + */ + newW->combobox.ListVisible = False; + newW->combobox.IgnoreFocusOut = False; + newW->combobox.PendingFocusOut = False; + newW->combobox.PendingOverrideInOut = False; + + newW->combobox.PassVerification = False; + +/* + * Jooa... bei der OSF pennen die wohl komplett?! Zusammen mit Form- + * Widgets gibt das wohl immer Aerger...daher hier ein DoLayout() + * aufrufen, damit Eingabefeld und Pfeil sowie das Listenfeld an der + * richtigen Stelle sitzen! + */ + DoLayout(newW); +/* + * Endlich fertig mit der Initialisierung. Das hier ist aber auch + * wirklich viel Arbeit fuer so ein Widget! + */ + newW->combobox.InInit = False; +} /* Initialize */ + +/* -------------------------------------------------------------------- + * Diese Funktionen bitte nur im aeussersten Notfall benutzen, da sie + * die Abstraktion dieser neuen Klasse umgehen und Informationen ueber + * den internen Aufbau voraussetzen. + */ +Widget XmComboBoxGetEditWidget(Widget w) +{ + return ((XmComboBoxWidget) w)->combobox.EditCtrl; +} /* XmComboBoxGetEditWidget */ + +Widget XmComboBoxGetListWidget(Widget w) +{ + return ((XmComboBoxWidget) w)->combobox.ListCtrl; +} /* XmComboBoxGetListWidget */ + +Widget XmComboBoxGetLabelWidget(Widget w) +{ + return ((XmComboBoxWidget) w)->combobox.LabelCtrl; +} /* XmComboBoxGetLabelWidget */ + + +/* -------------------------------------------------------------------- + * Sobald sich im Listenfeld Eintraege veraenderten, sei es, dass sie + * geloescht wurden, sei es, dass sie veraendert wurden, so muss hier + * gegebenenfalls auch der Text im Eingabefeld angepasst werden. + * Letzteres betrifft aber nur Combo-Boxen mit nicht editierbarem + * Eingabefeld. In jedem Fall wird aber bei jeder Combo-Box-Type in + * dem Fall, dass ein Eintrag geloescht wird, der darauffolgende + * Eintrag markiert. Eigentlich ist dieses nur eine nette Geste + * gegenueber dem Benutzer... + * + * Parameter: + * w Combo-Box-Widget + * Index Index auf denjenigen Eintrag der sich geaendert + * hat, oder der geloescht wurde. + * Deleted Zeigt an, ob der Eintrag geloescht wurde (True) + * oder sich nur veraenderte (False) + */ +static UpdateComboBox(XmComboBoxWidget w, int Index, Boolean Deleted) +{ + int OldIndex, ItemCount; + + OldIndex = XmComboBoxGetSelectedPos((Widget) w); + if ( OldIndex == Index ) { +/* Es betrifft den Eintrag, der auch momentan ausgewaehlt ist. + * Sollte er geloescht werden, so nimm' (soweit vorhanden) den + * naechsten Eintrag, wurde er ausgetauscht, so lass ihn ausge- + * waehlt. + */ + if ( Deleted ) { + XtVaGetValues(w->combobox.ListCtrl, + XmNitemCount, &ItemCount, NULL); + if ( ItemCount != 0 ) { + if ( Index >= ItemCount ) Index = ItemCount; + /* Markieren des Eintrags, ohne jedoch jetzt schon + * den Eintrag in die Eingabezeile zu kopieren. + */ + SetSelectionPos(w, Index, False); + } + } + } +/* Das Problem betrifft uns nur bei nicht editierbaren Combo-Boxen + * im vollen Umfang. Denn dann muss auch der Text im Eingabefeld + * veraendert werden. + */ + if ( !w->combobox.Editable ) { + TransferToEditCtrl(w, Index, False); + } + + return 1; +} /* UpdateComboBox */ + + +/* -------------------------------------------------------------------- + * Die Eintragsposition finden, an der der Eintrag sortiert stehen + * muesste. Naja, es wurde ja 'mal langsam Zeit, diese Routine etwas + * aufzupolieren, damit sie schneller wird. + */ +static int FindSortedItemPos(XmComboBoxWidget w, XmString item) +{ + Widget ListBox = w->combobox.ListCtrl; + XmStringTable Items; + int ItemCount, index, Left, Right, Result; + char *pItemText, *pCompareText; + Boolean ExternSort; + XmComboBoxSortingCallbackStruct data; + + XtVaGetValues(ListBox, XmNitems, &Items, + XmNitemCount, &ItemCount, NULL); + if ( ItemCount == 0 ) return 1; + + /* + * Moechte das Programm die Kontrolle ueber den Sortiervorgang + * uebernehmen? Dann bereite alles vor... + */ + ExternSort = XtHasCallbacks((Widget) w, XmNsortingCallback) == + XtCallbackHasSome; + if ( ExternSort ) { + data.reason = XmCR_SORTING; + data.event = NULL; + data.operation = XmOP_INIT; + data.item = item; + XtCallCallbacks((Widget) w, XmNsortingCallback, (XtPointer) &data); + } else + XmStringGetLtoR(item, XmSTRING_DEFAULT_CHARSET, &pCompareText); + + Left = 0; Right = ItemCount - 1; + do { + index = (Left + Right) / 2; + if ( ExternSort ) { + data.operation = XmOP_COMPARE; + data.item = Items[index]; + data.result = 1; + XtCallCallbacks((Widget) w, XmNsortingCallback, (XtPointer) &data); + Result = data.result; + } else { + XmStringGetLtoR(Items[index], XmSTRING_DEFAULT_CHARSET, &pItemText); + Result = strcmp(pCompareText, pItemText); + XtFree(pItemText); + } + if ( Result < 0 ) Right = index - 1; + else if ( Result > 0 ) Left = index + 1; + } while ( (Result != 0) && (Left <= Right) ); + + /* + * Nach Gebrauch wieder alles aufraeumen (bei einer externen Sortierung + * muss das das Programm uebernehmen!) + */ + if ( ExternSort ) { + data.operation = XmOP_DONE; + XtCallCallbacks((Widget) w, XmNsortingCallback, (XtPointer) &data); + } else + XtFree(pCompareText); + + if ( Result < 0 ) + return index + 1; /* Beachte, dass Indizes mit 1 beginnen! */ + else + return index + 2; /* Beachte, dass Indizes mit 1 beginnen! */ +} /* FindSortedItemPos */ + +/* -------------------------------------------------------------------- + * Kontrolliere, ob es sich ueberhaupt um eine Combo-Box (bzw. einen + * hypothetischen Nachkommen) handelt -- ansonsten mecker kraeftig + * herum! + * Ergebnis: + * True, falls wir hier ein falsches Widget untergejubelt bekommen! + */ +static Boolean CheckComboBox(Widget w, char *pFuncName) +{ + char buff[256]; + char *pWName; + +#if (XmVersion >= 2000) + return False; /* temporary workaround */ +#else + if ( XmIsComboBox(w) ) return False; + pWName = XrmQuarkToString(w->core.xrm_name); + sprintf(buff, +"Warning: %s called on widget named %s beeing \ +not a descendant of class XmComboBox!", + pFuncName, pWName); + XtWarning(buff); + return True; +#endif +} /* CheckComboBox */ + +/* -------------------------------------------------------------------- + * Saemtliche Interface-Routinen zur Combo-Box + */ +/* Zunaechst alles fuer die Listbox */ +#define ListBox (((XmComboBoxWidget) w)->combobox.ListCtrl) +#define EditBox (((XmComboBoxWidget) w)->combobox.EditCtrl) +#define ComboBox ((XmComboBoxWidget) w) + +/* !!! + * So angepasst, dass bei doppelt auftretenden Eintraegen, der + * alte Eintrag weiterhin markiert bleibt. Diese Massnahme soll + * eigentlich nur verhindern, dass zufaellig zwei Eintraege + * markiert sind, falls nach der Anwahl eines Eintrages ein zweiter + * gleichlautender Eintrag hinzugefuegt wurde. + * Was hier die reine Lehre (oder war das die Leere?) anbetrifft: + * in einer Combo-Box sollten sich sowieso nie gleichlautende + * Eintraege befinden, da sie dort unsinnig sind und den Benutzer + * nur verwirren... + */ +void XmComboBoxAddItem(Widget w, XmString item, int pos) +{ + int OldIndex = XmComboBoxGetSelectedPos(w); + + if ( CheckComboBox(w, "XmComboBoxAddItem") ) return; + if ( ComboBox->combobox.Sorted ) + pos = FindSortedItemPos(ComboBox, item); + XmListAddItem(ListBox, item, pos); + if ( OldIndex != XmComboBoxGetSelectedPos(w) ) + /* Hier SetSelectionPos() statt XmComboBoxSelectPos(), + * da der Text nicht in das Eingabefeld uebertragen werden + * soll! + */ + SetSelectionPos(ComboBox, OldIndex, False); +} /* XmComboBoxAddItem */ +/* !!! + * Hier gilt das bereits oben gesagte (siehe XmComboBoxAddItem). + * Bei sortierten Listboxen wird die Sortierung beim Gebrauch dieser + * Funktion zerstoert! + */ +void XmComboBoxAddItems(Widget w, XmString *items, int item_count, int pos) +{ + int OldIndex = XmComboBoxGetSelectedPos(w); + + if ( CheckComboBox(w, "XmComboBoxAddItems") ) return; + XmListAddItems(ListBox, items, item_count, pos); + if ( OldIndex != XmComboBoxGetSelectedPos(w) ) + /* Siehe Anmerkung in XmComboBoxAddItem */ + SetSelectionPos(ComboBox, OldIndex, False); +} /* XmComboBoxAddItems */ + +void XmComboBoxAddItemUnselected(Widget w, XmString item, int pos) +{ XmListAddItemUnselected(ListBox, item, pos); } + +/* !!! + * Da bei den folgenden Routinen jeweils ein oder mehrere Eintraege + * geloescht oder veraendert werden, muss gegebenefalls das Eingabe- + * feld bei nicht editierbaren Combo-Boxen auf Vordermann gebracht + * werden. + */ +void XmComboBoxDeleteItem(Widget w, XmString item) +{ + int Index = XmListItemPos(ListBox, item); + + if ( CheckComboBox(w, "XmComboBoxDeleteItem") ) return; + if ( Index ) XmComboBoxDeletePos(w, Index); +} /* XmComboBoxDeleteItem */ + +void XmComboBoxDeleteItems(Widget w, XmString *items, int item_count) +{ + int i; + + if ( CheckComboBox(w, "XmComboBoxDeleteItems") ) return; + for ( i = 0; i < item_count; i++ ) + XmListDeleteItem(w, items[i]); +} /* XmComboBoxDeleteItems */ + +void XmComboBoxDeletePos(Widget w, int pos) +{ + int OldIndex = XmComboBoxGetSelectedPos(w); + + if ( CheckComboBox(w, "XmComboBoxDeletePos") ) return; + XmListDeletePos(ListBox, pos); + if ( pos == OldIndex ) UpdateComboBox(ComboBox, pos, True); +} /* XmComboBoxDeletePos */ + +void XmComboBoxDeleteItemsPos(Widget w, int item_count, int pos) +{ + int i; + + if ( CheckComboBox(w, "XmComboBoxDeleteItemsPos") ) return; + for ( i = 0; i < item_count; i++ ) + XmComboBoxDeletePos(w, pos++); +} /* XmComboBoxDeleteItemsPos */ + +void XmComboBoxDeleteAllItems(Widget w) +{ + if ( CheckComboBox(w, "XmComboBoxAllDeleteItems") ) return; + XmListDeleteAllItems(ListBox); + UpdateComboBox(ComboBox, 0, True); +} /* XmComboBoxDeleteAllItems */ + +/* !!! + * Werden Eintraege ausgetauscht, so heisst es fuer uns, auch hierbei + * auf der Hut zu sein. + */ +void XmComboBoxReplaceItems(Widget w, XmString *old_items, int item_count, XmString *new_items) +{ + if ( CheckComboBox(w, "XmComboBoxReplaceItems") ) return; + XmListReplaceItems(ListBox, old_items, item_count, new_items); + UpdateComboBox(ComboBox, XmComboBoxGetSelectedPos(w), False); +} /* XmComboBoxReplaceItems */ + +void XmComboBoxReplaceItemsPos(Widget w, XmString *new_items, int item_count, int position) +{ + int OldIndex = XmComboBoxGetSelectedPos(w); + + if ( CheckComboBox(w, "XmComboBoxReplaceItemsPos") ) return; + XmListReplaceItemsPos(ListBox, new_items, item_count, position); + if ( (OldIndex >= position) && (OldIndex < position + item_count) ) + UpdateComboBox(ComboBox, OldIndex, False); +} /* XmComboBoxReplaceItemsPos */ + +Boolean XmComboBoxItemExists(Widget w, XmString item) +{ + if ( CheckComboBox(w, "XmComboBoxItemExists") ) return False; + return XmListItemExists(ListBox, item); +} /* XmComboBoxItemExists */ + +int XmComboBoxItemPos(Widget w, XmString item) +{ + if ( CheckComboBox(w, "XmComboBoxItemPos") ) return 0; + return XmListItemPos(ListBox, item); +} /* XmComboBoxItemPos */ + +Boolean XmComboBoxGetMatchPos(Widget w, XmString item, int **pos_list, int *pos_count) +{ + if ( CheckComboBox(w, "XmComboBoxGetMatchPos") ) return False; + return XmListGetMatchPos(ListBox, item, pos_list, pos_count); +} /* XmComboBoxGetMatchPos */ + +/* !!! + * Sobald ein anderer Eintrag in der Listbox ausgewaehlt werden soll, + * muessen wir hier helfend eingreifen. + */ +void XmComboBoxSelectPos(Widget w, int pos, Boolean notify) +{ + int index; + + if ( CheckComboBox(w, "XmComboBoxSelectPos") ) return; + index = SetSelectionPos(ComboBox, pos, notify); + if ( index ) TransferToEditCtrl(ComboBox, index, False); +} /* XmComboBoxSelectPos */ + +/* !!! + * dto. analog zu XmComboBoxSelectPos, nur statt des Index wird der + * Eintragstext angegeben, um einen Eintrag in der Listbox zu + * markieren. + */ +void XmComboBoxSelectItem(Widget w, XmString item, Boolean notify) +{ + int index; + + if ( CheckComboBox(w, "XmComboBoxSelectItem") ) return; + XmListSelectItem(ListBox, item, notify); + index = SetSelectionPos(ComboBox, XmComboBoxGetSelectedPos(w), False); + if ( index ) TransferToEditCtrl(ComboBox, index, False); +} /* XmComboBoxSelectItem */ + +/* !!! + * Geaendert gegenueber dem ListBox-Pendant! Da in einer Combo-Box die + * Liste nur maximal einen ausgewaehlten Eintrag besitzt, macht die + * 'alte' Funktionalitaet von XmListGetSelectedPos ziemlich wenig Sinn. + * Die neue Routine liefert statt dessen direkt den Index des aus- + * gewaehlten Eintrages oder 0 zurueck. + */ +int XmComboBoxGetSelectedPos(Widget w) +{ + int *SelectionList, SelectionCount, SelectionIndex; + + if ( CheckComboBox(w, "XmComboBoxGetSelectedPos") ) return 0; + if ( XmListGetSelectedPos(ListBox, + &SelectionList, &SelectionCount) ) { + SelectionIndex = *SelectionList; + XtFree((char *)SelectionList); + } else SelectionIndex = 0; + return SelectionIndex; +} /* XmComboBoxGetSelectedPos */ + + + +void XmComboBoxClearSelection(Widget w, Time time) +{ + XmTextFieldClearSelection(EditBox, time); +} /* XmComboBoxClearSelection */ + +Boolean XmComboBoxCopy(Widget w, Time time) +{ + return XmTextFieldCopy(EditBox, time); +} /* XmComboBoxCopy */ + +Boolean XmComboBoxCut(Widget w, Time time) +{ + return XmTextFieldCut(EditBox, time); +} /* XmComboBoxCut */ + +XmTextPosition XmComboBoxGetInsertionPosition(Widget w) +{ + return XmTextFieldGetInsertionPosition(EditBox); +} /* XmComboBoxGetInsertionPosition */ + +XmTextPosition XmComboBoxGetLastPosition(Widget w) +{ + return XmTextFieldGetLastPosition(EditBox); +} /* XmComboBoxGetLastPosition */ + +int XmComboBoxGetMaxLength(Widget w) +{ + return XmTextFieldGetMaxLength(EditBox); +} /* XmComboBoxGetMaxLength */ + +char * XmComboBoxGetSelection(Widget w) +{ + return XmTextFieldGetSelection(EditBox); +} /* XmComboBoxGetSelection */ + +Boolean XmComboBoxGetSelectionPosition(Widget w, XmTextPosition *left, + XmTextPosition *right) +{ + return XmTextFieldGetSelectionPosition(EditBox, left, right); +} /* XmComboBoxGetSelectionPosition */ + +char * XmComboBoxGetString(Widget w) +{ + return XmTextFieldGetString(EditBox); +} /* XmComboBoxGetString */ + +void XmComboBoxInsert(Widget w, XmTextPosition position, char *value) +{ + XmTextFieldInsert(EditBox, position, value); +} /* XmComboBoxInsert */ + +Boolean XmComboBoxPaste(Widget w) +{ + return XmTextFieldPaste(EditBox); +} /* XmComboBoxPaste */ + +Boolean XmComboBoxRemove(Widget w) +{ + return XmTextFieldRemove(EditBox); +} /* XmComboBoxRemove */ + +void XmComboBoxReplace(Widget w, XmTextPosition from_pos, + XmTextPosition to_pos, char *value) +{ + XmTextFieldReplace(EditBox, from_pos, to_pos, value); +} /* XmComboBoxReplace */ + +void XmComboBoxSetAddMode(Widget w, Boolean state) +{ + XmTextFieldSetAddMode(EditBox, state); +} /* XmComboBoxSetAddMode */ + +void XmComboBoxSetHighlight(Widget w, XmTextPosition left, + XmTextPosition right, XmHighlightMode mode) +{ + XmTextFieldSetHighlight(EditBox, left, right, mode); +} /* XmComboBoxSetHighlight */ + +void XmComboBoxSetInsertionPosition(Widget w, XmTextPosition position) +{ + XmTextFieldSetInsertionPosition(EditBox, position); +} /* XmComboBoxSetInsertionPosition */ + +void XmComboBoxSetMaxLength(Widget w, int max_length) +{ + XmTextFieldSetMaxLength(EditBox, max_length); +} /* XmComboBoxSetMaxLength */ + +void XmComboBoxSetSelection(Widget w, XmTextPosition first, + XmTextPosition last, Time time) +{ + XmTextFieldSetSelection(EditBox, first, last, time); +} /* XmComboBoxSetSelection */ + +void XmComboBoxSetString(Widget w, char *value) +{ +/* Liebe OSF...ihr ^&*#%$*&)*(@$(*^(*&%# habt doch einen ziemlich gemeinen + * Fehler in XmTextFieldSetString() drin... wenn man einen leeren String + * (also "") angiebt, gibt's nur noch Aerger, wenn man spaeter wieder an + * den Inhalt des Eingabefeldes heranwill. + */ + if ( (value == NULL) || (*value == 0) ) + XtVaSetValues(w, XmNvalue, "", NULL); + else + XmTextFieldSetString(EditBox, value); +} /* XmComboBoxSetString */ + +void XmComboBoxShowPosition(Widget w, XmTextPosition position) +{ + XmTextFieldShowPosition(EditBox, position); +} /* XmComboBoxShowPosition */ + +/* + * Loescht einen evtl. noch ausgewaehlten Eintrag in einer Combo Box, + * wenn diese eine SelectionPolicy von XmSINGLE_SELECT hat. + */ +void XmComboBoxClearItemSelection(Widget w) +{ + int index; + + if ( CheckComboBox(w, "XmComboBoxClearItemSelection") ) return; + + /* + * Wenn bereits kein Eintrag markiert ist, dann loeschen wir nur noch + * eben das Eingabefeld. + */ + index = XmComboBoxGetSelectedPos(w); + if ( index == 0 ) { + XmComboBoxSetString(w, ""); + } else { + /* + * Ansonsten aktuellen Eintrag entsorgen (wie bei der Methode wipe-out) + */ + TransferToEditCtrl(ComboBox, 0, True); + CallSelectionCBL(ComboBox, NULL); + } +} /* XmComboBoxClearItemSelection */ + +/* Die Drop-Down-Liste ein oder ausklappen */ +void XmComboBoxShowList(Widget w) +{ + if ( CheckComboBox(w, "XmComboBoxShowList") ) return; + ShowHideDropDownList((XmComboBoxWidget) w, NULL, False); +} /* XmComboBoxShowList */ + +void XmComboBoxHideList(Widget w) +{ + if ( CheckComboBox(w, "XmComboBoxHideList") ) return; + ShowHideDropDownList((XmComboBoxWidget) w, NULL, True); +} /* XmComboBoxShowList */ + +/* + * Naja, ich komm' ja doch nicht um diese olle Funktion herum... + */ +Widget XmCreateComboBox(Widget parent, String name, ArgList arglist, + Cardinal argcount) +{ + return XtCreateWidget(name, xmComboBoxWidgetClass, parent, + arglist, argcount); +} /* XmCreateComboBox */ + +/* Ende von ComboBox.c */ diff --git a/src/motif/xmcombo/xmcombo.h b/src/motif/xmcombo/xmcombo.h new file mode 100644 index 0000000000..3a7a10a447 --- /dev/null +++ b/src/motif/xmcombo/xmcombo.h @@ -0,0 +1,223 @@ +/* + * ComboBox.h - Das schon lange schmerzlich vermisste Combo-Box- + * Widget -- nun endlich auf fuer Motif! + * + * Letzte Modifikation: 04.10.1995 Revisionsstand: 1.32a + * + * (c) 1993, 1994 Harald Albrecht + * Institut fuer Geometrie und Praktische Mathematik + * RWTH Aachen, Germany + * albrecht@igpm.rwth-aachen.de + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program (see the file COPYING for more details); + * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, + * Cambridge, MA 02139, USA. + * + */ +#ifndef __ComboBoxWidget_h +#define __ComboBoxWidget_h + +#include + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define XmNselectionCallback "selectionCallback" +#define XmCSelectionCallback "SelectionCallback" +#define XmNunselectionCallback "unselectionCallback" +#define XmCUnselectionCallback "UnselectionCallback" +#define XmNdropDownCallback "dropDownCallback" +#define XmCDropDownCallback "DropDownCallback" + +#define XmNdropDownCursor "dropDownCursor" +#define XmCDropDownCursor "DropDownCursor" + +/* ICH GLAUB' ES JA EINFACH NICHT! DIESE @#$!%^ BEI DER OSF HABEN + * DOCH TATSAECHLICH VERGESSEN, DASS DIE EINTRAEGE IN DER LISTBOX + * VIELLEICHT AUCH SORTIERT SEIN SOLLEN -- MUSS MAN DENN ALLES + * SELBST MACHEN?! + */ +#define XmNsorted "sorted" +#define XmCSorted "Sorted" +#define XmNsortingCallback "sortingCallback" +#define XmCSortingCallback "SortingCallback" + +#define XmNstaticList "staticList" +#define XmCStaticList "StaticList" + +#define XmNsquareArrow "squareArrow" +#define XmCSquareArrow "SquareArrow" +#define XmNarrowSpacingOn "arrowSpacingOn" +#define XmCArrowSpacingOn "ArrowSpacingOn" + +/* + * Wie verhaeltsich die Liste, wenn der Focus verloren geht, sobald + * der Mauszeiger aus dem Dialog herausbewegt wird? + */ +#define XmNpersistentDropDown "persistentDropDown" +#define XmCPersistentDropDown "PersistentDropDown" +#define XmNtwmHandlingOn "twmHandlingOn" +#define XmCTwmHandlingOn "TwmHandlingOn" +/* + * alles fuer das Label... + */ +#define XmNshowLabel "showLabel" +#define XmCShowLabel "ShowLabel" +#define XmNdropDownOffset "dropDownOffset" +#define XmCDropDownOffset "DropDownOffset" + +#define XmNlabelMarginBottom "labelMarginBottom" +#define XmCLabelMarginBottom "LabelMarginBottom" +#define XmNlabelMarginHeight "labelMarginHeight" +#define XmCLabelMarginHeight "LabelMarginHeight" +#define XmNlabelMarginLeft "labelMarginLeft" +#define XmCLabelMarginLeft "LabelMarginLeft" +#define XmNlabelMarginRight "labelMarginRight" +#define XmCLabelMarginRight "LabelMarginRight" +#define XmNlabelMarginTop "labelMarginTop" +#define XmCLabelMarginTop "LabelMarginTop" +#define XmNlabelMarginWidth "labelMarginWidth" +#define XmCLabelMarginWidth "LabelMarginWidth" + +/* Callback reasons: (part. predefined) + * + * XmCR_SINGLE_SELECT user selected item in the list + */ + +typedef struct { + int reason; /* Grund */ + XEvent *event; /* Ausloesender Event */ + XmString value; /* Ausgewaehlter Eintrag */ + int index; /* Index dieses Eintrages */ +} XmComboBoxSelectionCallbackStruct,XmComboBoxDefaultActionCallbackStruct; + +typedef struct { + int reason; + XEvent *event; + Boolean doit; + Position currInsert, newInsert; + Position startPos, endPos; + XmTextBlock text; +} XmComboBoxTextVerifyCallbackStruct, *XmComboBoxTextVerifyPtr; + +/* Callback reasons: new + * + * XmCR_SHOW_LIST list is dropping down + * XmCR_HIDE_LIST list is getting hidden + * + * XmCR_UNSELECT unselecting item from list or osfDelete + */ +#define XmCR_SHOW_LIST 4200 /* ten times "42", that should */ +#define XmCR_HIDE_LIST 4201 /* explain everything of live... */ +#define XmCR_UNSELECT 4202 +typedef struct { + int reason; /* Grund */ + XEvent *event; /* Ausloesender Event */ +} XmComboBoxDropDownCallbackStruct, XmComboBoxUnselectionCallbackStruct; + +#define XmCR_SORTING 4203 +#define XmOP_INIT 1 +#define XmOP_DONE 2 +#define XmOP_COMPARE 3 +typedef struct { + int reason; + XEvent *event; /* IMMER NULL!! */ + int operation; + void *item_internal; + XmString item; + int result; +} XmComboBoxSortingCallbackStruct, *XmComboBoxSortingPtr; + +/* Alle Funktionen, um auf die Liste der Combo-Box zuzugreifen. + * Bitte immer diese Funktionen dazu benutzen und nicht direkt + * auf das entsprechende Widget in der Combo-Box zugreifen! + * Aus diesem Grunde sind auch nicht alle Funktionen einer Listbox + * verfuegbar, da sich einige Funktionen mit der Verwaltung der + * Combo-Box beissen wuerden. + */ +extern void XmComboBoxAddItem(Widget w, XmString item, int pos); +extern void XmComboBoxAddItems(Widget w, XmString *items, int item_count, int pos); +extern void XmComboBoxAddItemUnselected(Widget w, XmString item, int pos); +extern void XmComboBoxDeleteItem(Widget w, XmString item); +extern void XmComboBoxDeleteItems(Widget w, XmString *items, int item_count); +extern void XmComboBoxDeletePos(Widget w, int pos); +extern void XmComboBoxDeleteItemsPos(Widget w, int item_count, int pos); +extern void XmComboBoxDeleteAllItems(Widget w); +extern void XmComboBoxReplaceItems(Widget w, XmString *old_items, int item_count, XmString *new_items); +extern void XmComboBoxReplaceItemsPos(Widget w, XmString *new_items, int item_count, int position); +extern Boolean XmComboBoxItemExists(Widget w, XmString item); +extern int XmComboBoxItemPos(Widget w, XmString item); +extern Boolean XmComboBoxGetMatchPos(Widget w, XmString item, int **pos_list, int *pos_count); +extern void XmComboBoxSelectPos(Widget w, int pos, Boolean notify); +extern void XmComboBoxSelectItem(Widget w, XmString item, Boolean notify); +/* Etwas anders als bei der Listbox, da es sowieso nur einen ausge- + * waehlten Eintrag in der Listbox geben kann! + * Liefert Index des ausgewaehlten Eintrages oder 0. + */ +extern int XmComboBoxGetSelectedPos(Widget w); +extern void XmComboBoxClearItemSelection(Widget w); +/* + * Nun alle Funktionen, die auf das Eingabefeld zugreifen... + * Auch hier gilt wieder, es gibt 'was auf die Finger, wenn jemand + * versucht, direkt auf das Eingabefeld direkt zuzugreifen! + */ +extern void XmComboBoxClearSelection(Widget w, Time time); +extern Boolean XmComboBoxCopy(Widget w, Time time); +extern Boolean XmComboBoxCut(Widget w, Time time); +extern XmTextPosition XmComboBoxGetInsertionPosition(Widget w); +extern XmTextPosition XmComboBoxGetLastPosition(Widget w); +extern int XmComboBoxGetMaxLength(Widget w); +extern char * XmComboBoxGetSelection(Widget w); +extern Boolean XmComboBoxGetSelectionPosition(Widget w, XmTextPosition *left, + XmTextPosition *right); +extern char * XmComboBoxGetString(Widget w); +extern void XmComboBoxInsert(Widget w, XmTextPosition position, char *value); +extern Boolean XmComboBoxPaste(Widget w); +extern Boolean XmComboBoxRemove(Widget w); +extern void XmComboBoxReplace(Widget w, XmTextPosition from_pos, + XmTextPosition to_pos, char *value); +extern void XmComboBoxSetAddMode(Widget w, Boolean state); +extern void XmComboBoxSetHighlight(Widget w, XmTextPosition left, + XmTextPosition right, XmHighlightMode mode); +extern void XmComboBoxSetInsertionPosition(Widget w, XmTextPosition position); +extern void XmComboBoxSetMaxLength(Widget w, int max_length); +extern void XmComboBoxSetSelection(Widget w, XmTextPosition first, + XmTextPosition last, Time time); +extern void XmComboBoxSetString(Widget w, char *value); +extern void XmComboBoxShowPosition(Widget w, XmTextPosition position); + +extern WidgetClass xmComboBoxWidgetClass; /* Die Klasse hoechstselbst */ + +#ifndef XmIsComboBox +#define XmIsComboBox(w) XtIsSubclass(w, xmComboBoxWidgetClass) +#endif /* XmIsComboBox */ + +typedef struct _XmComboBoxClassRec *XmComboBoxWidgetClass; +typedef struct _XmComboBoxRec *XmComboBoxWidget; + +extern Widget XmCreateComboBox(Widget parent, String name, ArgList arglist, + Cardinal argcount); + +/* PLEASE do not use this functions if you really not need to do so !!! */ +extern Widget XmComboBoxGetEditWidget(Widget w); +extern Widget XmComboBoxGetListWidget(Widget w); +extern Widget XmComboBoxGetLabelWidget(Widget w); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* __ComboBoxWidget_h */ +/* Ende von ComboBox.h */ diff --git a/src/msw/makefile.g95 b/src/msw/makefile.g95 index 073d3883cc..3428239c56 100644 --- a/src/msw/makefile.g95 +++ b/src/msw/makefile.g95 @@ -258,7 +258,7 @@ $(COMMDIR)/y_tab.$(OBJSUFF): $(COMMDIR)/y_tab.c $(COMMDIR)/lex_yy.c # problems with lex_yy.c. See also note about LEX_SCANNER # above. $(COMMDIR)/lex_yy.c: $(COMMDIR)/lexer.l - $(LEX) $(COMMDIR)/lexer.l > $(COMMDIR)/lex_yy.c + $(LEX) -o$(COMMDIR)/lex_yy.c $(COMMDIR)/lexer.l # sed -e "s/BUFSIZ/5000/g" < lex.yy.c | \ # sed -e "s/yyoutput(c)/void yyoutput(c)/g" | \ -- 2.45.2