home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d3xx / d386 / xlispstat.lha / XLispStat / src3.lzh / UNIX / X11listitem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-07-30  |  18.1 KB  |  632 lines

  1. /* X11listitem - list items for X11 dialogs                            */
  2. /* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney                  */
  3. /* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz    */
  4. /* You may give out copies of this software; for conditions see the    */
  5. /* file COPYING included with this distribution.                       */
  6.  
  7. /***********************************************************************/
  8. /**                                                                   **/
  9. /**                    General Includes and Definitions               **/
  10. /**                                                                   **/
  11. /***********************************************************************/
  12.  
  13. #include <X11/Xlib.h>
  14. #include <X11/Xutil.h>
  15. #include <X11/Xos.h>
  16.  
  17. #include "dialogs.h"
  18.  
  19. extern Display *StX11Display();
  20. extern Point DialogStringSize();
  21. extern LVAL StX11ItemObject();
  22. extern char *checkstring();
  23.  
  24. typedef struct {
  25.   unsigned long fore, back;
  26. } ColorPair;
  27.  
  28. extern LVAL s_internals;
  29.  
  30. extern LVAL coerce_to_vector();
  31.  
  32. /***********************************************************************/
  33. /**                                                                   **/
  34. /**                        Global Variables                           **/
  35. /**                                                                   **/
  36. /***********************************************************************/
  37.  
  38. /* configuration parameters - should be set using the defaults database */
  39. extern XFontStruct *DialogFont;
  40. extern unsigned long DialogBorderColor;
  41. extern ColorPair DialogC;
  42. extern unsigned int list_border_width;
  43. extern int min_button_width;
  44.  
  45. extern GC DialogGC, DialogRGC;
  46.  
  47. extern XContext ObjectContext, ListFieldContext;
  48.  
  49. /***********************************************************************/
  50. /**                                                                   **/
  51. /**                           List Items                              **/
  52. /**                                                                   **/
  53. /***********************************************************************/
  54.  
  55. # define LIST_TEXT_PATTERN "MMMMMMMMMMMMMMM"
  56. # define LIST_LEAD 5
  57. # define LIST_PAD 15
  58. # define MAX_LIST_ROWS 12
  59. # define SCROLL_WIDTH 20
  60. # define DOUBLE_CLICK_TIME 1000
  61. # define DOUBLE_CLICK_MOVE 10
  62.  
  63. /***********************************************************************/
  64. /**                                                                   **/
  65. /**                     Double Click Detection                        **/
  66. /**                                                                   **/
  67. /***********************************************************************/
  68.  
  69. static int click_x, click_y, click_inited = FALSE;
  70. static Time click_time;
  71. Window click_win;
  72.  
  73. static is_double_click(report)
  74.      XEvent *report;
  75. {
  76.   int result, x, y, del_x, del_y, del_time;
  77.   Time time;
  78.   Window win;
  79.   
  80.   x = report->xbutton.x;
  81.   y = report->xbutton.y;
  82.   time = report->xbutton.time;
  83.   win = report->xbutton.window;
  84.   if (click_inited) {
  85.     del_x = (click_x < x) ? x - click_x : click_x - x;
  86.     del_y = (click_y < y) ? y - click_y : click_y - y;
  87.     del_time = (click_time < time) ? time - click_time : click_time - time;
  88.     result = (click_win == win
  89.           && del_x < DOUBLE_CLICK_MOVE 
  90.           && del_y < DOUBLE_CLICK_MOVE 
  91.           && del_time < DOUBLE_CLICK_TIME) ? TRUE : FALSE;
  92.   }
  93.   else result = FALSE;
  94.  
  95.   click_inited = ! result;
  96.   click_x = x;
  97.   click_y = y;
  98.   click_time = time;
  99.   click_win = win;
  100.  
  101.   return(result);
  102. }
  103.  
  104. /***********************************************************************/
  105. /**                                                                   **/
  106. /**                    Basic Size Calculations                        **/
  107. /**                                                                   **/
  108. /***********************************************************************/
  109.  
  110. static Point data_size(data)
  111.      LVAL data;
  112. {
  113.   Point sz;
  114.   if (listp(data)) { 
  115.     sz.v = llength(data); 
  116.     sz.h = 1;
  117.   }
  118.   else if (simplevectorp(data)) {
  119.     sz.v = getsize(data);
  120.     sz.h = 1;
  121.   }
  122.   else if (matrixp(data)) {
  123.     sz.v = getfixnum(getelement(displacedarraydim(data), 0));
  124.     sz.h = getfixnum(getelement(displacedarraydim(data), 1));
  125.   }
  126.   else xlerror("bad list item data", data);
  127.   return(sz);
  128. }
  129.  
  130. static Point cell_size()
  131. {
  132.   Point cellsz;
  133.  
  134.   cellsz = DialogStringSize(LIST_TEXT_PATTERN);
  135.   cellsz.v += LIST_LEAD;
  136.   cellsz.h += LIST_PAD;
  137.   return(cellsz);
  138. }
  139.  
  140. static max_cols(item)
  141.      LVAL item;
  142. {
  143.   LVAL columns = slot_value(item, s_columns);
  144.  
  145.   return((fixp(columns)) ? getfixnum(columns) : 1);
  146. }
  147.  
  148. /***********************************************************************/
  149. /**                                                                   **/
  150. /**                        Index Conversion                           **/
  151. /**                                                                   **/
  152. /***********************************************************************/
  153.  
  154. static field_index(dpy, win, vdims, ddims, offset)
  155.      Display *dpy;
  156.      Window win;
  157.      Point vdims, ddims, offset;
  158. {
  159.   int vis_index, index;
  160.   Point vpoint, dpoint;
  161.  
  162.   if (XFindContext(dpy, win, ListFieldContext, &vis_index) != 0)
  163.     xlfail("could not find field index");
  164.   vis_index--; /* needed to avoid storing a zero - confuses som X's */
  165.  
  166.   vpoint.v = vis_index / vdims.h;
  167.   vpoint.h = vis_index % vdims.h;
  168.   dpoint.v = offset.v + vpoint.v;
  169.   dpoint.h = offset.h + vpoint.h;
  170.   index = dpoint.v * ddims.h + dpoint.h;
  171.  
  172.   return(index);
  173. }
  174.  
  175. /***********************************************************************/
  176. /**                                                                   **/
  177. /**                  Internal Data Represenation                      **/
  178. /**                                                                   **/
  179. /***********************************************************************/
  180.  
  181. make_internals(item)
  182.      LVAL item;
  183. {
  184.   LVAL internals, data;
  185.   int cols, num_fields;
  186.   Point dsize, vsize;
  187.   
  188.   data = slot_value(item, s_list_data);
  189.   cols = max_cols(item);
  190.   dsize = data_size(data);
  191.   vsize.h = (dsize.h > cols) ? cols : dsize.h;
  192.   vsize.v = (dsize.v > MAX_LIST_ROWS) ? MAX_LIST_ROWS : dsize.v;
  193.   num_fields = vsize.h * vsize.v;
  194.  
  195.   internals = newvector(8);
  196.   set_slot_value(item, s_internals, internals);
  197.   setelement(internals, 0, PointToList(vsize));
  198.   setelement(internals, 1, PointToList(dsize));
  199.   setelement(internals, 2, (listp(data)) ? coerce_to_vector(data) : data);
  200.   setelement(internals, 3, newvector(num_fields));
  201.   setelement(internals, 4, integer_list_2(0, 0));
  202.   setelement(internals, 5, NIL);
  203.   setelement(internals, 6, NIL);
  204.   setelement(internals, 7, NIL);
  205. }
  206.  
  207. static Point visible_dims(internals)
  208.      LVAL internals;
  209. {
  210.   return(ListToPoint(getelement(internals, 0)));
  211. }
  212.  
  213. static Point data_dims(internals)
  214.      LVAL internals;
  215. {
  216.   return(ListToPoint(getelement(internals, 1)));
  217. }
  218.  
  219. static LVAL get_data(internals)
  220.      LVAL internals;
  221. {
  222.   return(getelement(internals, 2));
  223. }
  224.  
  225. static LVAL get_fields(internals)
  226.      LVAL internals;
  227. {
  228.   return(getelement(internals, 3));
  229. }
  230.  
  231. static Point get_offset(internals)
  232.      LVAL internals;
  233. {
  234.   return(ListToPoint(getelement(internals, 4)));
  235. }
  236.  
  237. set_offset(internals, offset)
  238.      LVAL internals;
  239.      Point offset;
  240. {
  241.   setelement(internals, 4, PointToList(offset));
  242. }
  243.  
  244. static LVAL get_selection(internals)
  245.      LVAL internals;
  246. {
  247.   return(getelement(internals, 5));
  248. }
  249.  
  250. static selection_index(internals)
  251.      LVAL internals;
  252. {
  253.   LVAL sel = get_selection(internals);
  254.   Point ddims, psel;
  255.  
  256.   if (sel == NIL) return(-1);
  257.   else if (fixp(sel)) return(getfixnum(sel));
  258.   else {
  259.     ddims = data_dims(internals);
  260.     psel = ListToPoint(sel);
  261.     return(ddims.h * psel.h + psel.v);
  262.   }
  263. }
  264.  
  265. static set_selection(item, val, index, use_val)
  266.      LVAL item, val;
  267.      int index, use_val;
  268. {
  269.   Point ddims, p;
  270.   LVAL internals;
  271.  
  272.   internals = slot_value(item, s_internals);
  273.   if (use_val) setelement(internals, 5, val);
  274.   else if (vectorp(get_data(internals))) 
  275.     setelement(internals, 5, cvfixnum((FIXTYPE) index));
  276.   else {
  277.     ddims = data_dims(internals);
  278.     p.h = index / ddims.h;
  279.     p.v = index % ddims.h;
  280.     setelement(internals, 5, PointToList(p));
  281.   }
  282.   draw_fields(item);
  283. }    
  284.  
  285. static set_vscroll(internals, w, has)
  286.      LVAL internals;
  287.      Window w;
  288.      int has;
  289. {
  290.   setelement(internals, 6, (has) ? cvfixnum((FIXTYPE) w) : NIL);
  291. }
  292.  
  293. static set_hscroll(internals, w, has)
  294.      LVAL internals;
  295.      Window w;
  296.      int has;
  297. {
  298.   setelement(internals, 7, (has) ? cvfixnum((FIXTYPE) w) : NIL);
  299. }
  300.  
  301. static has_vscroll(internals)
  302.      LVAL internals;
  303. {
  304.   return(getelement(internals, 6) != NIL);
  305. }
  306.  
  307. static has_hscroll(internals)
  308.      LVAL internals;
  309. {
  310.   return(getelement(internals, 7) != NIL);
  311. }
  312.  
  313. static Window get_vscroll(internals)
  314.      LVAL internals;
  315. {
  316.   LVAL val = getelement(internals, 6);
  317.   return(fixp(val) ? (Window) getfixnum(val) : None);
  318. }
  319.  
  320. static Window get_hscroll(internals)
  321.      LVAL internals;
  322. {
  323.   LVAL val = getelement(internals, 7);
  324.   return(fixp(val) ? (Window) getfixnum(val) : None);
  325. }
  326.  
  327. /***********************************************************************/
  328. /**                                                                   **/
  329. /**                       Drawing Routines                            **/
  330. /**                                                                   **/
  331. /***********************************************************************/
  332.  
  333. static draw_field_content(dpy, win, text, reversed)
  334.      Display *dpy;
  335.      Window win;
  336.      char *text;
  337.      int reversed;
  338. {
  339.   Point ssz;
  340.   int x, y, len;
  341.   GC gc;
  342.   unsigned long color;
  343.  
  344.   gc = (reversed) ? DialogRGC : DialogGC;
  345.   color = (reversed) ? DialogC.fore : DialogC.back;
  346.  
  347.   XSetWindowBackground(dpy, win, color);
  348.   XClearWindow(dpy, win);
  349.   ssz = DialogStringSize(text);
  350.   x = LIST_PAD / 2;
  351.   y = LIST_LEAD / 2 + DialogFont->max_bounds.ascent;
  352.   len = strlen(text);
  353.   XDrawString(dpy, win, gc, x, y, text, len);
  354.   XSetWindowBackground(dpy, win, DialogC.back);
  355. }
  356.  
  357. static draw_fields(item)
  358.      LVAL item;
  359. {
  360.   Display *dpy = StX11Display();
  361.   Window win;
  362.   LVAL fields, internals, data;
  363.   Point vdims, ddims, offset;
  364.   char *text;
  365.   int sel, i, j, k, index, num_fields;
  366.  
  367.   internals = slot_value(item, s_internals);
  368.   data = arraydata(get_data(internals));
  369.   fields = get_fields(internals);
  370.   vdims = visible_dims(internals);
  371.   ddims = data_dims(internals);
  372.   offset = get_offset(internals);
  373.   sel = selection_index(internals);
  374.   num_fields = getsize(fields);
  375.  
  376.   for (i = 0, k = 0; i < vdims.v; i++) {
  377.     for (j = 0; j < vdims.h && k < num_fields; j++, k++) {
  378.       win = getfixnum(getelement(fields, k));
  379.       index = (i + offset.v) * ddims.h + j + offset.h;
  380.       text = checkstring(getelement(data, index));
  381.       draw_field_content(dpy, win, text, sel == index);
  382.     }
  383.   }
  384. }
  385.  
  386. /***********************************************************************/
  387. /**                                                                   **/
  388. /**                        Event Handlers                             **/
  389. /**                                                                   **/
  390. /***********************************************************************/
  391.  
  392. static LVAL field_handler(report, modal)
  393.      XEvent report;
  394.      int modal;
  395. {
  396.   Display *dpy = StX11Display();
  397.   Window win;
  398.   LVAL item, internals, data;
  399.   LVAL result = NIL;
  400.   Point vdims, ddims, offset;
  401.   char *text;
  402.   int sel, index;
  403.  
  404.   win = report.xany.window;
  405.   item = StX11ItemObject(dpy, win);
  406.   internals = slot_value(item, s_internals);
  407.   data = arraydata(get_data(internals));
  408.   vdims = visible_dims(internals);
  409.   ddims = data_dims(internals);
  410.   offset = get_offset(internals);
  411.   sel = selection_index(internals);
  412.  
  413.   if (item != NIL) {
  414.     switch (report.type) {
  415.     case Expose:
  416.       index = field_index(dpy, win, vdims, ddims, offset);
  417.       text = checkstring(getelement(data, index));
  418.       draw_field_content(dpy, win, text, sel == index);
  419.       break;
  420.     case ButtonPress:
  421.       index = field_index(dpy, win, vdims, ddims, offset);
  422.       set_selection(item, NIL, index, FALSE);
  423.       if (is_double_click(&report)) 
  424.         send_message_1L(item, sk_do_action, s_true);
  425.       else 
  426.     send_message(item, sk_do_action);
  427.       break;
  428.     default: 
  429.       break;
  430.     }
  431.   }
  432.   return(result);
  433. }
  434.  
  435. static scroll_action(item, s, which, x, y)
  436.      LVAL item;
  437.      Window s;
  438.      int which, x, y;
  439. {
  440.   int is_h_scroll, val, max, page, pos, inc;
  441.   Point size, offset, ddims, vdims, cellsz;
  442.   LVAL internals;
  443.   Window hscroll, vscroll;
  444.   double side;
  445.  
  446.   internals = slot_value(item, s_internals);
  447.   offset = get_offset(internals);
  448.   ddims = data_dims(internals);
  449.   vdims = visible_dims(internals);
  450.   cellsz = cell_size();
  451.   size.v = vdims.v * cellsz.v;
  452.   size.h = vdims.h * cellsz.h;
  453.   hscroll = get_hscroll(internals);
  454.   vscroll = get_vscroll(internals);
  455.  
  456.   is_h_scroll = (s == hscroll) ? TRUE : FALSE;
  457.   val = (is_h_scroll) ? offset.h : offset.v;
  458.   max = (is_h_scroll) ? ddims.h : ddims.v;
  459.   page = (is_h_scroll) ? vdims.h : vdims.v;
  460.   side = (is_h_scroll) ? size.h : size.v;
  461.   pos = (is_h_scroll) ? x * (max / side) : y * (max / side);
  462.   inc = 1;
  463.     
  464.   switch (which) {
  465.   case 'M': val = pos;  break;
  466.   case 'L': val += inc; break;
  467.   case 'R': val -= inc; break;
  468.   }
  469.   if (val + page > max) val = max - page;
  470.   if (val < 0) val = 0;
  471.  
  472.   if (is_h_scroll) offset.h = val;
  473.   else offset.v = val;
  474.   set_offset(internals, offset);
  475.   draw_fields(item);
  476.   if (hscroll != None) AdjustScrollBar(hscroll, offset.h, vdims.h, ddims.h);
  477.   if (vscroll != None) AdjustScrollBar(vscroll, offset.v, vdims.v, ddims.v);
  478. }
  479.  
  480. /***********************************************************************/
  481. /**                                                                   **/
  482. /**                       Public Routines                             **/
  483. /**                                                                   **/
  484. /***********************************************************************/
  485.  
  486. DialogListGetDefaultSize(item, width, height)
  487.      LVAL item;
  488.      int *width, *height;
  489. {
  490.   LVAL data = slot_value(item, s_list_data);
  491.   Point sz, cellsz;
  492.   int cols, m, n;
  493.  
  494.   cellsz = cell_size();
  495.  
  496.   cols = max_cols(item);
  497.   sz = data_size(data);
  498.   m = sz.v;
  499.   n = sz.h;
  500.  
  501.   *height = (m <= MAX_LIST_ROWS) ? m * cellsz.v : MAX_LIST_ROWS * cellsz.v;
  502.   *width = (n <= cols) ? n * cellsz.h : cols * cellsz.h;
  503.   if (m > MAX_LIST_ROWS) *width +=  SCROLL_WIDTH;
  504.   if (n > cols) *height += SCROLL_WIDTH;
  505. }
  506.  
  507. InstallListItem(win, item) 
  508.      Window win;
  509.      LVAL item;
  510. {
  511.   Display *dpy = StX11Display();
  512.   Point loc, vsize, size, cellsz, dsize;
  513.   Window panel, newfield, scroll;
  514.   LVAL s_window_id = xlenter("WINDOW-ID"), internals, fields;
  515.   int num_fields, i, j, k;
  516.  
  517.   make_internals(item);
  518.  
  519.   internals = slot_value(item, s_internals);
  520.   cellsz = cell_size();
  521.   loc = ListToPoint(slot_value(item, s_location));
  522.   vsize = visible_dims(internals);
  523.   dsize = data_dims(internals);
  524.   size.v = vsize.v * cellsz.v;
  525.   size.h = vsize.h * cellsz.h;
  526.   fields = get_fields(internals);
  527.   num_fields = getsize(fields);
  528.  
  529.   panel = XCreateSimpleWindow(dpy, win, loc.h, loc.v, size.h, size.v,
  530.                   list_border_width,
  531.                   DialogBorderColor, DialogC.back);
  532.   
  533.   set_slot_value(item, s_window_id, cvfixnum((FIXTYPE) panel));
  534.   
  535.   if (XSaveContext(dpy, panel, ObjectContext, (XContext) item) != 0)
  536.     xlfail("could not install object in window");
  537.  
  538.   if (dsize.h > vsize.h) {
  539.     InstallScrollBar(win, item, loc.h, loc.v + size.v, size.h, SCROLL_WIDTH,
  540.              &scroll, scroll_action);
  541.     set_hscroll(internals, scroll, TRUE);
  542.     AdjustScrollBar(scroll, 0, vsize.h, dsize.h);
  543.   }
  544.   if (dsize.v > vsize.v) {
  545.     InstallScrollBar(win, item, loc.h + size.h, loc.v, SCROLL_WIDTH, size.v,
  546.              &scroll, scroll_action);
  547.     set_vscroll(internals, scroll, TRUE);
  548.     AdjustScrollBar(scroll, 0, vsize.v, dsize.v);
  549.   }
  550.  
  551.   for (i = 0, k = 0; i < vsize.v; i++) {
  552.     for (j = 0; j < vsize.h && k < num_fields; j++, k++) {
  553.       newfield = XCreateSimpleWindow(dpy, panel, cellsz.h * j, cellsz.v * i,
  554.                      cellsz.h, cellsz.v, 0,
  555.                      DialogBorderColor, DialogC.back);
  556.  
  557.       XSelectInput(dpy, newfield, ExposureMask | ButtonPressMask);
  558.       install_dialog_item_handler(dpy, newfield, field_handler, item);
  559.       if (XSaveContext(dpy, newfield, ObjectContext, (XContext) item) != 0)
  560.     xlfail("could not install object in window");
  561.  
  562.       /* add 1 to index to avoid confusing context manager with zeros */
  563.       if (XSaveContext(dpy, newfield, ListFieldContext, (k + 1)) != 0)
  564.     xlfail("could not install field index in window");
  565.       setelement(fields, k, cvfixnum((FIXTYPE) newfield));
  566.     }
  567.   }
  568.   XMapSubwindows(dpy, panel);
  569. }
  570.  
  571. DeleteListItem(win, item) 
  572.      Window win;
  573.      LVAL item;
  574. {
  575.   Display *dpy = StX11Display();
  576.   Window panel, thefield;
  577.   LVAL s_window_id = xlenter("WINDOW-ID"), internals, fields;
  578.   int k, num_fields;
  579.  
  580.   panel = (Window) getfixnum(slot_value(item, s_window_id));
  581.   internals = slot_value(item, s_internals);
  582.   fields = get_fields(internals);
  583.  
  584.   num_fields = getsize(fields);
  585.   for (k = 0; k < num_fields; k++) {
  586.     thefield = getfixnum(getelement(fields, k));
  587.     delete_dialog_item_handler(dpy, thefield);
  588.     if (XDeleteContext(dpy, thefield, ObjectContext) != 0)
  589.       xlfail("cound not delete object context");
  590.     if (XDeleteContext(dpy, thefield, ListFieldContext) != 0)
  591.       xlfail("cound not delete list field context");
  592.     setelement(fields, k, NIL);
  593.   }
  594.  
  595.   if (has_hscroll(internals)) DeleteScrollBar(get_hscroll(internals));
  596.   if (has_vscroll(internals)) DeleteScrollBar(get_vscroll(internals));
  597.  
  598.   if (XDeleteContext(dpy, panel, ObjectContext) != 0)
  599.     xlfail("cound not delete object context");
  600.   set_slot_value(item, s_window_id, NIL);
  601. }
  602.  
  603. DialogListItemSetText(item, index, text)
  604.      LVAL item, index;
  605.      char *text;
  606. {
  607.   LVAL internals, data;
  608.   Point p, ddims;
  609.   int i;
  610.  
  611.   internals = slot_value(item, s_internals);
  612.   data = arraydata(get_data(internals));
  613.   if (fixp(index)) i = getfixnum(index);
  614.   else {
  615.     p = ListToPoint(index);
  616.     ddims = data_dims(internals);
  617.     i = p.v * ddims.h + p.h;
  618.   }
  619.   if (0 <= i && i < getsize(data))
  620.     setelement(data, i, cvstring(text));
  621.   else xlerror("index out of range", index);
  622.   draw_fields(item);
  623. }
  624.  
  625. LVAL DialogListItemSelection(item, set, index) 
  626.      LVAL item, index;
  627.      int set;
  628. {
  629.   if (set) set_selection(item, index, 0, TRUE);
  630.   return(get_selection(slot_value(item, s_internals)));
  631. }
  632.