home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 mARCH / PCWK3A99.iso / Linux / DDD331 / DDD-3_1_.000 / DDD-3_1_ / ddd-3.1.1 / ddd / ComboBox.C < prev    next >
C/C++ Source or Header  |  1998-06-28  |  15KB  |  494 lines

  1. // $Id: ComboBox.C,v 1.9 1998/06/28 16:59:10 zeller Exp $ -*- C++ -*-
  2. // Create a combo box
  3.  
  4. // Copyright (C) 1998 Technische Universitaet Braunschweig, Germany.
  5. // Written by Andreas Zeller <zeller@ips.cs.tu-bs.de>.
  6. // 
  7. // This file is part of DDD.
  8. // 
  9. // DDD is free software; you can redistribute it and/or
  10. // modify it under the terms of the GNU General Public
  11. // License as published by the Free Software Foundation; either
  12. // version 2 of the License, or (at your option) any later version.
  13. // 
  14. // DDD is distributed in the hope that it will be useful,
  15. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17. // See the GNU General Public License for more details.
  18. // 
  19. // You should have received a copy of the GNU General Public
  20. // License along with DDD -- see the file COPYING.
  21. // If not, write to the Free Software Foundation, Inc.,
  22. // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23. // 
  24. // DDD is the data display debugger.
  25. // For details, see the DDD World-Wide-Web page, 
  26. // `http://www.cs.tu-bs.de/softech/ddd/',
  27. // or send a mail to the DDD developers <ddd@ips.cs.tu-bs.de>.
  28.  
  29. char ComboBox_rcsid[] = 
  30.     "$Id: ComboBox.C,v 1.9 1998/06/28 16:59:10 zeller Exp $";
  31.  
  32. #ifdef __GNUG__
  33. #pragma implementation
  34. #endif
  35.  
  36. // #define as 0 to rely exclusively on our replacement routines
  37. // #define USE_XM_COMBOBOX 0
  38.  
  39. #include "ComboBox.h"
  40.  
  41. #include "bool.h"
  42. #include "frame.h"
  43. #include "charsets.h"
  44. #include "verify.h"
  45. #include "wm.h"
  46. #include "TimeOut.h"
  47.  
  48. #include <Xm/Xm.h>
  49. #include <Xm/ArrowB.h>
  50. #include <Xm/TextF.h>
  51. #include <Xm/List.h>
  52. #include <Xm/Frame.h>
  53. #include <Xm/Form.h>
  54. #include <X11/Shell.h>
  55. #include <X11/cursorfont.h>
  56.  
  57. // Whether to use XmComboBox
  58. #ifndef USE_XM_COMBOBOX
  59. #if XmVersion >= 2000
  60. #define USE_XM_COMBOBOX 1
  61. #else
  62. #define USE_XM_COMBOBOX 0
  63. #endif
  64. #endif
  65.  
  66. #if USE_XM_COMBOBOX
  67. #include <Xm/ComboBox.h>
  68. #endif
  69.  
  70.  
  71. //-----------------------------------------------------------------------
  72. // ComboBox helpers
  73. //-----------------------------------------------------------------------
  74.  
  75. struct ComboBoxInfo
  76. {
  77.     Widget top;            // The top-level window
  78.     Widget text;        // The text to be updated
  79.     Widget button;        // The arrow button
  80.     Widget list;        // The list to select from
  81.     Widget shell;        // The shell that contains the list
  82.     XtIntervalId timer;        // The timer that controls popup time
  83.     bool popped_up;        // True iff the combo box is popped up
  84.  
  85.     ComboBoxInfo()
  86.     : top(0), text(0), button(0), list(0), shell(0), 
  87.       timer(0), popped_up(false)
  88.     {}
  89. };
  90.  
  91.  
  92. #if !USE_XM_COMBOBOX
  93. // Make sure menu stays on top.  This prevents conflicts with
  94. // auto-raise windows which would otherwise hide menu panels.
  95. static void AutoRaiseEH(Widget w, XtPointer, XEvent *event, Boolean *)
  96. {
  97.  
  98.     if (event->type != VisibilityNotify)
  99.     return;
  100.  
  101.     switch (event->xvisibility.state)
  102.     {
  103.     case VisibilityFullyObscured:
  104.     case VisibilityPartiallyObscured:
  105.     XRaiseWindow(XtDisplay(w), frame(w));
  106.     break;
  107.     }
  108. }
  109.  
  110. static void CloseWhenActivatedCB(XtPointer client_data, XtIntervalId *id)
  111. {
  112.     ComboBoxInfo *info = (ComboBoxInfo *)client_data;
  113.     
  114.     assert(*id == info->timer);
  115.     (void) id;
  116.  
  117.     info->timer = 0;
  118. }
  119.  
  120. static void PopdownComboListCB(Widget, XtPointer client_data, XtPointer)
  121. {
  122.     ComboBoxInfo *info = (ComboBoxInfo *)client_data;
  123.  
  124.     XtVaSetValues(info->button, XmNarrowDirection, XmARROW_DOWN, NULL);
  125.     XtPopdown(info->shell);
  126.     info->popped_up = false;
  127. }
  128.  
  129. static void PopupComboListCB(Widget w, XtPointer client_data, 
  130.                  XtPointer call_data)
  131. {
  132.     ComboBoxInfo *info = (ComboBoxInfo *)client_data;
  133.  
  134.     if (info->popped_up)
  135.     {
  136.     PopdownComboListCB(w, client_data, call_data);
  137.     return;
  138.     }
  139.  
  140.     // Get size and position
  141.     Position top_x, top_y;
  142.     XtTranslateCoords(info->top, 0, 0, &top_x, &top_y);
  143.  
  144.     Dimension top_height = 0;
  145.     Dimension top_width  = 0;
  146.     XtVaGetValues(info->top, XmNheight, &top_height,
  147.           XmNwidth, &top_width, NULL);
  148.  
  149.     XtWidgetGeometry size;
  150.     size.request_mode = CWHeight;
  151.     XtQueryGeometry(XtParent(info->list), NULL, &size);
  152.  
  153.     Position x       = top_x;
  154.     Position y       = top_y + top_height;
  155.     Dimension width  = top_width;
  156.     Dimension height = size.height;
  157.  
  158.     XtVaSetValues(info->shell, XmNx, x, XmNy, y, 
  159.           XmNwidth, width, XmNheight, height, NULL);
  160.  
  161.  
  162.     // Popup shell
  163.     XtPopup(info->shell, XtGrabNone);
  164.     raise_shell(info->shell);
  165.     info->popped_up = true;
  166.  
  167.     // Unmanage horizontal scrollbar
  168.     Widget horizontal_scrollbar = 0;
  169.     XtVaGetValues(XtParent(info->list), XmNhorizontalScrollBar, 
  170.           &horizontal_scrollbar, NULL);
  171.     if (horizontal_scrollbar != 0)
  172.     XtUnmanageChild(horizontal_scrollbar);
  173.  
  174.     XtVaSetValues(info->button, XmNarrowDirection, XmARROW_UP, NULL);
  175.  
  176.     static Cursor cursor = XCreateFontCursor(XtDisplay(info->shell), XC_arrow);
  177.     XDefineCursor(XtDisplay(info->shell), XtWindow(info->shell), cursor);
  178.  
  179.     // If we release the button within the next 250ms, keep the menu open.
  180.     // Otherwise, pop it down again.
  181.     if (info->timer != 0)
  182.     XtRemoveTimeOut(info->timer);
  183.     info->timer = 
  184.     XtAppAddTimeOut(XtWidgetToApplicationContext(info->shell), 250,
  185.             CloseWhenActivatedCB, XtPointer(info));
  186. }
  187.  
  188. static void ActivatePopdownComboListCB(Widget w, XtPointer client_data, 
  189.                        XtPointer call_data)
  190. {
  191.     ComboBoxInfo *info = (ComboBoxInfo *)client_data;
  192.     if (info->timer == 0)
  193.     PopdownComboListCB(w, client_data, call_data);
  194. }
  195.  
  196. #endif // !USE_XM_COMBOBOX
  197.  
  198.  
  199. static void RefreshComboTextCB(Widget w, XtPointer client_data,
  200.                    XtPointer call_data)
  201. {
  202.     (void) w;            // Use it
  203.  
  204.     XmListCallbackStruct *cbs = (XmListCallbackStruct *)call_data;
  205.     ComboBoxInfo *info = (ComboBoxInfo *)client_data;
  206.  
  207.     XmString item = cbs->item;
  208.     String item_s;
  209.     XmStringGetLtoR(item, CHARSET_TT, &item_s);
  210.     XmTextFieldSetString(info->text, item_s);
  211.     XtFree(item_s);
  212.  
  213.     XmTextPosition last_pos = XmTextFieldGetLastPosition(info->text);
  214.     XmTextFieldSetInsertionPosition(info->text, last_pos);
  215.     XmTextFieldShowPosition(info->text, 0);
  216.     XmTextFieldShowPosition(info->text, last_pos);
  217.  
  218. #if !USE_XM_COMBOBOX
  219.     PopdownComboListCB(w, client_data, call_data);
  220. #endif
  221. }
  222.  
  223.  
  224. //-----------------------------------------------------------------------
  225. // ComboBox access
  226. //-----------------------------------------------------------------------
  227.  
  228. // Access ComboBox members
  229. Widget ComboBoxList(Widget text)
  230. {
  231.     XtPointer userData;
  232.     XtVaGetValues(text, XmNuserData, &userData, NULL);
  233.     ComboBoxInfo *info = (ComboBoxInfo *)userData;
  234.     return info->list;
  235. }
  236.  
  237. Widget ComboBoxText(Widget text)
  238. {
  239.     return text;
  240. }
  241.  
  242. Widget ComboBoxButton(Widget text)
  243. {
  244.     XtPointer userData;
  245.     XtVaGetValues(text, XmNuserData, &userData, NULL);
  246.     ComboBoxInfo *info = (ComboBoxInfo *)userData;
  247.     return info->button;
  248. }
  249.  
  250. Boolean ComboBoxIsSimple(Widget text)
  251. {
  252.     return ComboBoxButton(text) != 0;
  253. }
  254.  
  255. Widget ComboBoxTop(Widget text)
  256. {
  257.     XtPointer userData;
  258.     XtVaGetValues(text, XmNuserData, &userData, NULL);
  259.     ComboBoxInfo *info = (ComboBoxInfo *)userData;
  260.     return info->top;
  261. }
  262.  
  263.  
  264. // Set items
  265. void ComboBoxSetList(Widget text, const StringArray& items)
  266. {
  267.     Widget list = ComboBoxList(text);
  268.  
  269.     // Check for value change
  270.     XmStringTable old_items;
  271.     int old_items_count = 0;
  272.  
  273.     XtVaGetValues(list,
  274.           XmNitemCount, &old_items_count,
  275.           XmNitems,     &old_items,
  276.           NULL);
  277.  
  278.     int i;
  279.     if (old_items_count == items.size())
  280.     {
  281.     for (i = 0; i < items.size(); i++)
  282.     {
  283.         String _old_item;
  284.         XmStringGetLtoR(old_items[i], CHARSET_TT, &_old_item);
  285.         string old_item(_old_item);
  286.         XtFree(_old_item);
  287.  
  288.         if (old_item != items[i])
  289.         break;
  290.     }
  291.  
  292.     if (i >= items.size())
  293.     {
  294.         // All elements are equal
  295.         return;
  296.     }
  297.     }
  298.  
  299.     // Set new values
  300.     XmStringTable xmlist = 
  301.     XmStringTable(XtMalloc(items.size() * sizeof(XmString)));
  302.  
  303.     for (i = 0; i < items.size(); i++)
  304.     xmlist[i] = XmStringCreateLtoR(items[i], CHARSET_TT);
  305.  
  306.     XtVaSetValues(list,
  307.           XmNitems,     xmlist,
  308.           XmNitemCount, items.size(),
  309.           NULL);
  310.  
  311.     for (i = 0; i < items.size(); i++)
  312.     XmStringFree(xmlist[i]);
  313.  
  314.     // It seems XMLIST is already owned by LIST
  315.     // XtFree((char *)xmlist);
  316. }
  317.  
  318.  
  319. //-----------------------------------------------------------------------
  320. // ComboBox creation
  321. //-----------------------------------------------------------------------
  322.  
  323. // Create a combo box
  324. Widget CreateComboBox(Widget parent, String name, ArgList _args, Cardinal _arg)
  325. {
  326.     ArgList args = new Arg[_arg + 10];
  327.     Cardinal arg = 0;
  328.  
  329.     ComboBoxInfo *info = new ComboBoxInfo;
  330.  
  331.     arg = 0;
  332.     XtSetArg(args[arg], XmNshadowType, XmSHADOW_IN); arg++;
  333.     XtSetArg(args[arg], XmNmarginWidth,        0); arg++;
  334.     XtSetArg(args[arg], XmNmarginHeight,       0); arg++;
  335.     XtSetArg(args[arg], XmNborderWidth,        0); arg++;
  336.     XtSetArg(args[arg], XmNhighlightThickness, 0); arg++;
  337.     info->top = verify(XmCreateFrame(parent, "frame", args, arg));
  338.     XtManageChild(info->top);
  339.  
  340.     arg = 0;
  341.     XtSetArg(args[arg], XmNmarginWidth,        0); arg++;
  342.     XtSetArg(args[arg], XmNmarginHeight,       0); arg++;
  343.     XtSetArg(args[arg], XmNborderWidth,        0); arg++;
  344.     XtSetArg(args[arg], XmNhighlightThickness, 0); arg++;
  345.     Widget form = verify(XmCreateForm(info->top, "form", args, arg));
  346.     XtManageChild(form);
  347.  
  348. #if USE_XM_COMBOBOX
  349.     // ComboBoxes in OSF/Motif 2.0 sometimes resize themselves without
  350.     // apparent reason.  Prevent this by constraining them in a form.
  351.     arg = 0;
  352.     XtSetArg(args[arg], XmNleftAttachment,     XmATTACH_FORM); arg++;
  353.     XtSetArg(args[arg], XmNrightAttachment,    XmATTACH_FORM); arg++;
  354.     XtSetArg(args[arg], XmNtopAttachment,      XmATTACH_FORM); arg++;
  355.     XtSetArg(args[arg], XmNbottomAttachment,   XmATTACH_FORM); arg++;
  356.     XtSetArg(args[arg], XmNresizable,          False);         arg++;
  357.     for (Cardinal i = 0; i < _arg; i++)
  358.     args[arg++] = _args[i];
  359.     Widget combo = verify(XmCreateDropDownComboBox(form, name, args, arg));
  360.     XtManageChild(combo);
  361.  
  362.     arg = 0;
  363.     XtSetArg(args[arg], XmNshadowThickness, 0); arg++;
  364.     XtSetArg(args[arg], XmNhighlightThickness, 0); arg++;
  365.     XtSetArg(args[arg], XmNborderWidth, 0); arg++;
  366.     XtSetArg(args[arg], XmNmarginWidth, 0); arg++;
  367.     XtSetArg(args[arg], XmNmarginHeight, 0); arg++;
  368.     XtSetValues(combo, args, arg);
  369.  
  370.     info->text = XtNameToWidget(combo, "*Text");
  371.     arg = 0;
  372.     XtSetArg(args[arg], XmNshadowThickness, 0); arg++;
  373.     XtSetValues(info->text, args, arg);
  374.  
  375.     info->list = XtNameToWidget(combo, "*List");
  376.     arg = 0;
  377.     XtSetArg(args[arg], XmNshadowThickness,    2); arg++;
  378.     XtSetArg(args[arg], XmNhighlightThickness, 0); arg++;
  379.     XtSetValues(info->list, args, arg);
  380.  
  381.     info->shell = info->list;
  382.     while (!XtIsShell(info->shell))
  383.     info->shell = XtParent(info->shell);
  384.  
  385.     // Set form size explicitly.
  386.     XtWidgetGeometry size;
  387.     size.request_mode = CWHeight | CWWidth;
  388.     XtQueryGeometry(combo, NULL, &size);
  389.     XtVaSetValues(form, XmNheight, size.height, XmNwidth, size.width, NULL);
  390.  
  391.     // Set frame size explicitly, too
  392.     Dimension shadow_thickness;
  393.     XtVaGetValues(info->top, XmNshadowThickness, &shadow_thickness, NULL);
  394.     XtVaSetValues(info->top, XmNheight, size.height + shadow_thickness * 2, 
  395.           XmNwidth, size.width + shadow_thickness * 2, NULL);
  396. #else
  397.     arg = 0;
  398.     XtSetArg(args[arg], XmNborderWidth,        0);     arg++;
  399.     XtSetArg(args[arg], XmNhighlightThickness, 0);     arg++;
  400.     XtSetArg(args[arg], XmNshadowThickness,    0);     arg++;
  401.     XtSetArg(args[arg], XmNresizable,          False); arg++;
  402.     for (Cardinal i = 0; i < _arg; i++)
  403.     args[arg++] = _args[i];
  404.     info->text = verify(XmCreateTextField(form, name, args, arg));
  405.     XtManageChild(info->text);
  406.  
  407.     Pixel foreground;
  408.     XtVaGetValues(parent, XmNbackground, &foreground, 0);
  409.  
  410.     arg = 0;
  411.     XtSetArg(args[arg], XmNarrowDirection,     XmARROW_DOWN);  arg++;
  412.     XtSetArg(args[arg], XmNborderWidth,        0);             arg++;
  413.     XtSetArg(args[arg], XmNforeground,         foreground);    arg++;
  414.     XtSetArg(args[arg], XmNhighlightThickness, 0);             arg++;
  415.     XtSetArg(args[arg], XmNshadowThickness,    0);             arg++;
  416.     XtSetArg(args[arg], XmNresizable,          False);         arg++;
  417.     XtSetArg(args[arg], XmNrightAttachment,    XmATTACH_FORM); arg++;
  418.     XtSetArg(args[arg], XmNtopAttachment,      XmATTACH_FORM); arg++;
  419.     XtSetArg(args[arg], XmNbottomAttachment,   XmATTACH_FORM); arg++;
  420.     info->button = XmCreateArrowButton(form, "comboBoxArrow", args, arg);
  421.     XtManageChild(info->button);
  422.  
  423.     XtVaSetValues(info->text,
  424.           XmNleftAttachment,   XmATTACH_FORM,
  425.           XmNrightAttachment,  XmATTACH_WIDGET,
  426.           XmNrightWidget,      info->button,
  427.           XmNtopAttachment,    XmATTACH_FORM,
  428.           XmNbottomAttachment, XmATTACH_FORM,
  429.           NULL);
  430.  
  431.     XtAddCallback(info->button, XmNarmCallback,
  432.           PopupComboListCB, XtPointer(info));
  433.     XtAddCallback(info->button, XmNactivateCallback,
  434.           ActivatePopdownComboListCB, XtPointer(info));
  435.  
  436.     XtAddCallback(info->text, XmNvalueChangedCallback,
  437.           PopdownComboListCB, XtPointer(info));
  438.     XtAddCallback(info->text, XmNactivateCallback,
  439.           PopdownComboListCB, XtPointer(info));
  440.  
  441.     Widget shell = parent;
  442.     while (!XtIsShell(shell))
  443.     shell = XtParent(shell);
  444.  
  445.     XtAddCallback(shell, XmNpopdownCallback,
  446.           PopdownComboListCB, XtPointer(info));
  447.  
  448.     arg = 0;
  449.     XtSetArg(args[arg], XmNborderWidth, 0); arg++;
  450.     info->shell = XtCreatePopupShell("comboBoxShell", 
  451.                      overrideShellWidgetClass,
  452.                      parent, args, arg);
  453.  
  454.     XtAddEventHandler(info->shell, VisibilityChangeMask, False,
  455.               AutoRaiseEH, XtPointer(0));
  456.  
  457.     arg = 0;
  458.     XtSetArg(args[arg], XmNhighlightThickness, 0); arg++;
  459.     info->list = XmCreateScrolledList(info->shell, "list", args, arg);
  460.     XtManageChild(info->list);
  461.  
  462.     // Set form size explicitly.
  463.     XtWidgetGeometry size;
  464.     size.request_mode = CWHeight | CWWidth;
  465.     XtQueryGeometry(info->text, NULL, &size);
  466.     XtVaSetValues(form, XmNheight, size.height, XmNwidth, size.width, NULL);
  467.  
  468.     // Set frame size explicitly, too
  469.     Dimension shadow_thickness;
  470.     XtVaGetValues(info->top, XmNshadowThickness, &shadow_thickness, NULL);
  471.     XtVaSetValues(info->top, XmNheight, size.height + shadow_thickness * 2, 
  472.           XmNwidth, size.width + shadow_thickness * 2, NULL);
  473. #endif
  474.  
  475.     // Give shell a little more border
  476.     XtVaSetValues(info->shell, XmNborderWidth, 1, NULL);
  477.  
  478.     // Store ComboBox info in text field
  479.     XtVaSetValues(info->text, XmNuserData, XtPointer(info), NULL);
  480.  
  481.     // Synchronize text and list
  482.     XtAddCallback(info->list, XmNbrowseSelectionCallback,
  483.           RefreshComboTextCB, XtPointer(info));
  484.     XtAddCallback(info->list, XmNsingleSelectionCallback,
  485.           RefreshComboTextCB, XtPointer(info));
  486.     XtAddCallback(info->list, XmNmultipleSelectionCallback,
  487.           RefreshComboTextCB, XtPointer(info));
  488.     XtAddCallback(info->list, XmNextendedSelectionCallback,
  489.           RefreshComboTextCB, XtPointer(info));
  490.  
  491.     delete[] args;
  492.     return info->text;
  493. }
  494.