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. */
7 /***********************************************************************/
9 /** General Includes and Definitions **/
11 /***********************************************************************/
15 extern Display
*StX11Display();
16 extern Point
DialogStringSize();
17 extern LVAL
StX11ItemObject();
18 extern char *checkstring();
21 unsigned long fore
, back
;
24 extern LVAL s_internals
, s_window_id
;
26 /* forward declarations */
27 LOCAL VOID draw_field_content
_((Display
*dpy
, Window win
,
28 char *text
, int reversed
));
29 LOCAL VOID draw_fields
_((LVAL item
));
31 /***********************************************************************/
33 /** Global Variables **/
35 /***********************************************************************/
37 /* configuration parameters - should be set using the defaults database */
38 extern XFontStruct
*DialogFont
;
39 extern unsigned long DialogBorderColor
;
40 extern ColorPair DialogC
;
41 extern unsigned int list_border_width
;
42 extern int min_button_width
;
44 extern GC DialogGC
, DialogRGC
;
46 extern XContext ObjectContext
, ListFieldContext
;
48 /***********************************************************************/
52 /***********************************************************************/
54 # define LIST_TEXT_PATTERN "MMMMMMMMMMMMMMM"
57 # define MAX_LIST_ROWS 12
58 # define SCROLL_WIDTH 20
59 # define DOUBLE_CLICK_TIME 1000
60 # define DOUBLE_CLICK_MOVE 10
62 /***********************************************************************/
64 /** Double Click Detection **/
66 /***********************************************************************/
68 static int click_x
, click_y
, click_inited
= FALSE
;
69 static Time click_time
;
72 static int is_double_click(report
)
75 int result
, x
, y
, del_x
, del_y
, del_time
;
79 x
= report
->xbutton
.x
;
80 y
= report
->xbutton
.y
;
81 time
= report
->xbutton
.time
;
82 win
= report
->xbutton
.window
;
84 del_x
= (click_x
< x
) ? x
- click_x
: click_x
- x
;
85 del_y
= (click_y
< y
) ? y
- click_y
: click_y
- y
;
86 del_time
= (click_time
< time
) ? time
- click_time
: click_time
- time
;
87 result
= (click_win
== win
88 && del_x
< DOUBLE_CLICK_MOVE
89 && del_y
< DOUBLE_CLICK_MOVE
90 && del_time
< DOUBLE_CLICK_TIME
) ? TRUE
: FALSE
;
94 click_inited
= ! result
;
103 /***********************************************************************/
105 /** Basic Size Calculations **/
107 /***********************************************************************/
109 static Point
data_size(data
)
117 else if (matrixp(data
)) {
118 sz
.v
= numrows(data
);
119 sz
.h
= numcols(data
);
121 else xlerror("bad list item data", data
);
125 static Point
cell_size()
129 cellsz
= DialogStringSize(LIST_TEXT_PATTERN
);
130 cellsz
.v
+= LIST_LEAD
;
131 cellsz
.h
+= LIST_PAD
;
135 static int max_cols(item
)
138 LVAL columns
= slot_value(item
, s_columns
);
140 return((fixp(columns
)) ? getfixnum(columns
) : 1);
143 /***********************************************************************/
145 /** Index Conversion **/
147 /***********************************************************************/
149 static int field_index(dpy
, win
, vdims
, ddims
, offset
)
152 Point vdims
, ddims
, offset
;
154 int vis_index
, index
;
155 Point vpoint
, dpoint
;
157 if (XFindContext(dpy
, win
, ListFieldContext
, (caddr_t
*) &vis_index
) != 0)
158 xlfail("could not find field index");
159 vis_index
--; /* needed to avoid storing a zero - confuses som X's */
161 vpoint
.v
= vis_index
/ vdims
.h
;
162 vpoint
.h
= vis_index
% vdims
.h
;
163 dpoint
.v
= offset
.v
+ vpoint
.v
;
164 dpoint
.h
= offset
.h
+ vpoint
.h
;
165 index
= dpoint
.v
* ddims
.h
+ dpoint
.h
;
170 /***********************************************************************/
172 /** Internal Data Represenation **/
174 /***********************************************************************/
176 static VOID
make_internals(item
)
179 LVAL internals
, data
;
180 int cols
, num_fields
;
183 data
= slot_value(item
, s_list_data
);
184 cols
= max_cols(item
);
185 dsize
= data_size(data
);
186 vsize
.h
= (dsize
.h
> cols
) ? cols
: dsize
.h
;
187 vsize
.v
= (dsize
.v
> MAX_LIST_ROWS
) ? MAX_LIST_ROWS
: dsize
.v
;
188 num_fields
= vsize
.h
* vsize
.v
;
190 internals
= newvector(8);
191 set_slot_value(item
, s_internals
, internals
);
192 setelement(internals
, 0, PointToList(vsize
));
193 setelement(internals
, 1, PointToList(dsize
));
194 setelement(internals
, 2,
195 matrixp(data
) ? data
: coerce_to_tvec(data
, s_true
));
196 setelement(internals
, 3, newvector(num_fields
));
197 setelement(internals
, 4, integer_list_2(0, 0));
198 setelement(internals
, 5, NIL
);
199 setelement(internals
, 6, NIL
);
200 setelement(internals
, 7, NIL
);
203 static Point
visible_dims(internals
)
206 return(ListToPoint(getelement(internals
, 0)));
209 static Point
data_dims(internals
)
212 return(ListToPoint(getelement(internals
, 1)));
215 static LVAL
get_data(internals
)
218 return(getelement(internals
, 2));
221 static LVAL
get_fields(internals
)
224 return(getelement(internals
, 3));
227 static Point
get_offset(internals
)
230 return(ListToPoint(getelement(internals
, 4)));
233 static VOID
set_offset(internals
, offset
)
237 setelement(internals
, 4, PointToList(offset
));
240 static LVAL
get_selection(internals
)
243 return(getelement(internals
, 5));
246 static int selection_index(internals
)
249 LVAL sel
= get_selection(internals
);
252 if (sel
== NIL
) return(-1);
253 else if (fixp(sel
)) return(getfixnum(sel
));
255 ddims
= data_dims(internals
);
256 psel
= ListToPoint(sel
);
257 return(ddims
.h
* psel
.h
+ psel
.v
);
261 static VOID
set_selection(item
, val
, index
, use_val
)
268 internals
= slot_value(item
, s_internals
);
269 if (use_val
) setelement(internals
, 5, val
);
270 else if (vectorp(get_data(internals
)))
271 setelement(internals
, 5, cvfixnum((FIXTYPE
) index
));
273 ddims
= data_dims(internals
);
274 p
.h
= index
/ ddims
.h
;
275 p
.v
= index
% ddims
.h
;
276 setelement(internals
, 5, PointToList(p
));
281 static VOID
set_vscroll(internals
, w
, has
)
286 setelement(internals
, 6, (has
) ? cvfixnum((FIXTYPE
) w
) : NIL
);
289 static VOID
set_hscroll(internals
, w
, has
)
294 setelement(internals
, 7, (has
) ? cvfixnum((FIXTYPE
) w
) : NIL
);
297 static int has_vscroll(internals
)
300 return(getelement(internals
, 6) != NIL
);
303 static int has_hscroll(internals
)
306 return(getelement(internals
, 7) != NIL
);
309 static Window
get_vscroll(internals
)
312 LVAL val
= getelement(internals
, 6);
313 return(fixp(val
) ? (Window
) getfixnum(val
) : None
);
316 static Window
get_hscroll(internals
)
319 LVAL val
= getelement(internals
, 7);
320 return(fixp(val
) ? (Window
) getfixnum(val
) : None
);
323 /***********************************************************************/
325 /** Drawing Routines **/
327 /***********************************************************************/
329 LOCAL VOID
draw_field_content(dpy
, win
, text
, reversed
)
340 gc
= (reversed
) ? DialogRGC
: DialogGC
;
341 color
= (reversed
) ? DialogC
.fore
: DialogC
.back
;
343 XSetWindowBackground(dpy
, win
, color
);
344 XClearWindow(dpy
, win
);
345 ssz
= DialogStringSize(text
);
347 y
= LIST_LEAD
/ 2 + DialogFont
->max_bounds
.ascent
;
349 XDrawString(dpy
, win
, gc
, x
, y
, text
, len
);
350 XSetWindowBackground(dpy
, win
, DialogC
.back
);
353 LOCAL VOID
draw_fields(item
)
356 Display
*dpy
= StX11Display();
358 LVAL fields
, internals
, data
;
359 Point vdims
, ddims
, offset
;
361 int sel
, i
, j
, k
, index
, num_fields
;
363 internals
= slot_value(item
, s_internals
);
364 data
= get_data(internals
);
365 if (darrayp(data
)) data
= getdarraydata(data
);
366 fields
= get_fields(internals
);
367 vdims
= visible_dims(internals
);
368 ddims
= data_dims(internals
);
369 offset
= get_offset(internals
);
370 sel
= selection_index(internals
);
371 num_fields
= getsize(fields
);
373 for (i
= 0, k
= 0; i
< vdims
.v
; i
++) {
374 for (j
= 0; j
< vdims
.h
&& k
< num_fields
; j
++, k
++) {
375 win
= getfixnum(gettvecelement(fields
, k
));
376 index
= (i
+ offset
.v
) * ddims
.h
+ j
+ offset
.h
;
377 text
= checkstring(gettvecelement(data
, index
));
378 draw_field_content(dpy
, win
, text
, sel
== index
);
383 /***********************************************************************/
385 /** Event Handlers **/
387 /***********************************************************************/
389 static LVAL
field_handler(report
, modal
)
393 Display
*dpy
= StX11Display();
395 LVAL item
, internals
, data
;
397 Point vdims
, ddims
, offset
;
401 win
= report
.xany
.window
;
402 item
= StX11ItemObject(dpy
, win
);
403 internals
= slot_value(item
, s_internals
);
404 data
= get_data(internals
);
405 if (darrayp(data
)) data
= getdarraydata(data
);
406 vdims
= visible_dims(internals
);
407 ddims
= data_dims(internals
);
408 offset
= get_offset(internals
);
409 sel
= selection_index(internals
);
412 switch (report
.type
) {
414 index
= field_index(dpy
, win
, vdims
, ddims
, offset
);
415 text
= checkstring(gettvecelement(data
, index
));
416 draw_field_content(dpy
, win
, text
, sel
== index
);
419 index
= field_index(dpy
, win
, vdims
, ddims
, offset
);
420 set_selection(item
, NIL
, index
, FALSE
);
421 if (is_double_click(&report
))
422 send_message_1L(item
, sk_do_action
, s_true
);
424 send_message(item
, sk_do_action
);
433 static VOID
scroll_action(item
, s
, which
, x
, y
)
438 int is_h_scroll
, val
, max
, page
, pos
, inc
;
439 Point size
, offset
, ddims
, vdims
, cellsz
;
441 Window hscroll
, vscroll
;
444 internals
= slot_value(item
, s_internals
);
445 offset
= get_offset(internals
);
446 ddims
= data_dims(internals
);
447 vdims
= visible_dims(internals
);
448 cellsz
= cell_size();
449 size
.v
= vdims
.v
* cellsz
.v
;
450 size
.h
= vdims
.h
* cellsz
.h
;
451 hscroll
= get_hscroll(internals
);
452 vscroll
= get_vscroll(internals
);
454 is_h_scroll
= (s
== hscroll
) ? TRUE
: FALSE
;
455 val
= (is_h_scroll
) ? offset
.h
: offset
.v
;
456 max
= (is_h_scroll
) ? ddims
.h
: ddims
.v
;
457 page
= (is_h_scroll
) ? vdims
.h
: vdims
.v
;
458 side
= (is_h_scroll
) ? size
.h
: size
.v
;
459 pos
= (is_h_scroll
) ? x
* (max
/ side
) : y
* (max
/ side
);
463 case 'M': val
= pos
; break;
464 case 'L': val
+= inc
; break;
465 case 'R': val
-= inc
; break;
467 if (val
+ page
> max
) val
= max
- page
;
468 if (val
< 0) val
= 0;
470 if (is_h_scroll
) offset
.h
= val
;
472 set_offset(internals
, offset
);
474 if (hscroll
!= None
) AdjustScrollBar(hscroll
, offset
.h
, vdims
.h
, ddims
.h
);
475 if (vscroll
!= None
) AdjustScrollBar(vscroll
, offset
.v
, vdims
.v
, ddims
.v
);
478 /***********************************************************************/
480 /** Public Routines **/
482 /***********************************************************************/
484 VOID
DialogListGetDefaultSize(item
, width
, height
)
488 LVAL data
= slot_value(item
, s_list_data
);
492 cellsz
= cell_size();
494 cols
= max_cols(item
);
495 sz
= data_size(data
);
499 *height
= (m
<= MAX_LIST_ROWS
) ? m
* cellsz
.v
: MAX_LIST_ROWS
* cellsz
.v
;
500 *width
= (n
<= cols
) ? n
* cellsz
.h
: cols
* cellsz
.h
;
501 if (m
> MAX_LIST_ROWS
) *width
+= SCROLL_WIDTH
;
502 if (n
> cols
) *height
+= SCROLL_WIDTH
;
505 VOID
InstallListItem(win
, item
)
509 Display
*dpy
= StX11Display();
510 Point loc
, vsize
, size
, cellsz
, dsize
;
511 Window panel
, newfield
, scroll
;
512 LVAL internals
, fields
;
513 int num_fields
, i
, j
, k
;
515 make_internals(item
);
517 internals
= slot_value(item
, s_internals
);
518 cellsz
= cell_size();
519 loc
= ListToPoint(slot_value(item
, s_location
));
520 vsize
= visible_dims(internals
);
521 dsize
= data_dims(internals
);
522 size
.v
= vsize
.v
* cellsz
.v
;
523 size
.h
= vsize
.h
* cellsz
.h
;
524 fields
= get_fields(internals
);
525 num_fields
= getsize(fields
);
527 panel
= XCreateSimpleWindow(dpy
, win
, loc
.h
, loc
.v
, size
.h
, size
.v
,
529 DialogBorderColor
, DialogC
.back
);
531 set_slot_value(item
, s_window_id
, cvfixnum((FIXTYPE
) panel
));
533 if (XSaveContext(dpy
, panel
, ObjectContext
, (caddr_t
) item
) != 0)
534 xlfail("could not install object in window");
536 if (dsize
.h
> vsize
.h
) {
537 InstallScrollBar(win
, item
, loc
.h
, loc
.v
+ size
.v
, size
.h
, SCROLL_WIDTH
,
538 &scroll
, scroll_action
);
539 set_hscroll(internals
, scroll
, TRUE
);
540 AdjustScrollBar(scroll
, 0, vsize
.h
, dsize
.h
);
542 if (dsize
.v
> vsize
.v
) {
543 InstallScrollBar(win
, item
, loc
.h
+ size
.h
, loc
.v
, SCROLL_WIDTH
, size
.v
,
544 &scroll
, scroll_action
);
545 set_vscroll(internals
, scroll
, TRUE
);
546 AdjustScrollBar(scroll
, 0, vsize
.v
, dsize
.v
);
549 for (i
= 0, k
= 0; i
< vsize
.v
; i
++) {
550 for (j
= 0; j
< vsize
.h
&& k
< num_fields
; j
++, k
++) {
551 newfield
= XCreateSimpleWindow(dpy
, panel
, cellsz
.h
* j
, cellsz
.v
* i
,
552 cellsz
.h
, cellsz
.v
, 0,
553 DialogBorderColor
, DialogC
.back
);
555 XSelectInput(dpy
, newfield
, ExposureMask
| ButtonPressMask
);
556 install_dialog_item_handler(dpy
, newfield
, field_handler
, item
);
557 if (XSaveContext(dpy
, newfield
, ObjectContext
, (caddr_t
) item
) != 0)
558 xlfail("could not install object in window");
560 /* add 1 to index to avoid confusing context manager with zeros */
561 if (XSaveContext(dpy
, newfield
, ListFieldContext
, (caddr_t
) (k
+ 1)) != 0)
562 xlfail("could not install field index in window");
563 setelement(fields
, k
, cvfixnum((FIXTYPE
) newfield
));
566 XMapSubwindows(dpy
, panel
);
569 VOID
DeleteListItem(win
, item
)
573 Display
*dpy
= StX11Display();
574 Window panel
, thefield
;
575 LVAL internals
, fields
;
578 panel
= (Window
) getfixnum(slot_value(item
, s_window_id
));
579 internals
= slot_value(item
, s_internals
);
580 fields
= get_fields(internals
);
582 num_fields
= getsize(fields
);
583 for (k
= 0; k
< num_fields
; k
++) {
584 thefield
= getfixnum(getelement(fields
, k
));
585 delete_dialog_item_handler(dpy
, thefield
);
586 if (XDeleteContext(dpy
, thefield
, ObjectContext
) != 0)
587 xlfail("could not delete object context");
588 if (XDeleteContext(dpy
, thefield
, ListFieldContext
) != 0)
589 xlfail("could not delete list field context");
590 setelement(fields
, k
, NIL
);
593 if (has_hscroll(internals
)) DeleteScrollBar(get_hscroll(internals
));
594 if (has_vscroll(internals
)) DeleteScrollBar(get_vscroll(internals
));
596 if (XDeleteContext(dpy
, panel
, ObjectContext
) != 0)
597 xlfail("could not delete object context");
598 set_slot_value(item
, s_window_id
, NIL
);
601 VOID
DialogListItemSetText(item
, index
, text
)
608 this is not needed since the matrix in the internals is eq to the
609 one in the list-data slot already modified by the portable part of
610 the code. Besides, this code is wrong since it permutes the intex
614 LVAL internals
, data
;
618 internals
= slot_value(item
, s_internals
);
619 data
= get_data(internals
);
620 if (darrayp(data
)) data
= getdarraydata(data
);
621 if (fixp(index
)) i
= getfixnum(index
);
623 p
= ListToPoint(index
);
624 ddims
= data_dims(internals
);
625 i
= p
.v
* ddims
.h
+ p
.h
;
627 if (0 <= i
&& i
< getsize(data
))
628 settvecelement(data
, i
, cvstring(text
));
629 else xlerror("index out of range", index
);
634 LVAL
DialogListItemSelection(item
, set
, index
)
638 if (set
) set_selection(item
, index
, 0, TRUE
);
639 return(get_selection(slot_value(item
, s_internals
)));