1 /* Part of XPCE --- The SWI-Prolog GUI toolkit
2
3 Author: Jan Wielemaker and Anjo Anjewierden
4 E-mail: jan@swi.psy.uva.nl
5 WWW: http://www.swi.psy.uva.nl/projects/xpce/
6 Copyright (c) 1985-2002, University of Amsterdam
7 All rights reserved.
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12
13 1. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16 2. Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <h/kernel.h>
36 #include <h/graphics.h>
37 #include <h/text.h>
38
39 static Int normalise_index(ListBrowser, Int);
40 static status clearSelectionListBrowser(ListBrowser);
41 static status ChangeItemListBrowser(ListBrowser, DictItem);
42 static status ChangedListBrowser(ListBrowser);
43 static status geometryListBrowser(ListBrowser, Int, Int, Int, Int);
44 static status deselectListBrowser(ListBrowser, DictItem);
45 static status showLabelListBrowser(ListBrowser, BoolObj);
46 static status selectListBrowser(ListBrowser, DictItem);
47 static status scrollUpListBrowser(ListBrowser, Int);
48 static status scrollDownListBrowser(ListBrowser, Int);
49 static status extendPrefixListBrowser(ListBrowser);
50
51 #define swap(x, y) { int z; z=x; x=y; y=z; }
52
53 /********************************
54 * CREATE *
55 ********************************/
56
57 static status
initialiseListBrowser(ListBrowser lb,Dict dict,Int w,Int h)58 initialiseListBrowser(ListBrowser lb, Dict dict, Int w, Int h)
59 { int fw, fh, iw, ih;
60
61 if ( isDefault(dict) )
62 dict = newObject(ClassDict, EAV);
63
64 if ( notNil(dict->browser) )
65 return errorPce(lb, NAME_alreadyShown, dict, dict->browser);
66
67 assign(lb, size, newObject(ClassSize, EAV));
68 copySize(lb->size, getClassVariableValueObject(lb, NAME_size));
69 if ( notDefault(w) ) assign(lb->size, w, w);
70 if ( notDefault(h) ) assign(lb->size, h, h);
71
72 initialiseDevice((Device) lb);
73
74 assign(lb, pen, getClassVariableValueObject(lb, NAME_pen));
75 assign(lb, dict, dict);
76 assign(dict, browser, lb);
77 assign(lb, status, NAME_inactive);
78 assign(lb, key_binding, newObject(ClassKeyBinding, NIL,
79 NAME_listBrowser, EAV));
80 assign(lb, select_message, NIL);
81 assign(lb, open_message, NIL);
82 assign(lb, cancel_message, NIL);
83 assign(lb, multiple_selection, OFF);
84 assign(lb, selection, NIL);
85 assign(lb, start, ZERO);
86 assign(lb, search_string, NIL);
87 assign(lb, search_origin, ZERO);
88 assign(lb, search_hit, toInt(-1));
89 assign(lb, label_text, NIL);
90 assign(lb, styles, newObject(ClassSheet, EAV));
91 assign(lb, selection_style, getClassVariableValueObject(lb,
92 NAME_selectionStyle));
93
94 lb->start_cell = NIL;
95
96 assign(lb, font, getClassVariableValueObject(lb, NAME_font));
97 fw = valInt(getExFont(lb->font));
98 fh = valInt(getHeightFont(lb->font));
99 iw = valInt(lb->size->w) * fw + 2 * TXT_X_MARGIN;
100 ih = valInt(lb->size->h) * fh + 2 * TXT_Y_MARGIN;
101
102 assign(lb, image, newObject(ClassTextImage, lb, toInt(iw), toInt(ih), EAV));
103 assign(lb->image, wrap, NAME_none);
104 assign(lb, scroll_bar, newObject(ClassScrollBar, lb, NAME_vertical, EAV));
105
106 send(lb->image, NAME_cursor, getClassVariableValueObject(lb, NAME_cursor), EAV);
107 send(lb->image, NAME_set,
108 lb->scroll_bar->area->w, ZERO, DEFAULT, toInt(ih), EAV);
109 displayDevice(lb, lb->scroll_bar, DEFAULT);
110 displayDevice(lb, lb->image, DEFAULT);
111 if ( notNil(lb->scroll_bar) )
112 iw += valInt(getMarginScrollBar(lb->scroll_bar));
113
114 doSetGraphical(lb, DEFAULT, DEFAULT, toInt(iw), toInt(ih));
115
116 succeed;
117 }
118
119
120 static status
unlinkListBrowser(ListBrowser lb)121 unlinkListBrowser(ListBrowser lb)
122 { if ( notNil(lb->dict) )
123 { assign(lb->dict, browser, NIL);
124 assign(lb, dict, NIL);
125 }
126
127 return unlinkDevice((Device) lb);
128 }
129
130
131 static Any
lbReceiver(ListBrowser lb)132 lbReceiver(ListBrowser lb)
133 { if ( instanceOfObject(lb->device, ClassBrowser) )
134 return lb->device;
135
136 return lb;
137 }
138
139 /*******************************
140 * REDRAW *
141 *******************************/
142
143 static status
RedrawAreaListBrowser(ListBrowser lb,Area a)144 RedrawAreaListBrowser(ListBrowser lb, Area a)
145 { Any obg = r_background(getClassVariableValueObject(lb, NAME_background));
146
147 RedrawAreaDevice((Device)lb, a);
148 if ( lb->pen != ZERO )
149 { int x, y, w, h;
150 int th = valInt(lb->image->area->y);
151
152 initialiseDeviceGraphical(lb, &x, &y, &w, &h);
153 y += th;
154 h -= th;
155
156 if ( h > 0 )
157 { r_thickness(valInt(lb->pen));
158 r_dash(lb->texture);
159
160 r_box(x, y, w, h, 0, NIL);
161 }
162 }
163
164 r_background(obg);
165
166 succeed;
167 }
168
169 /*******************************
170 * LOAD/SAVE *
171 *******************************/
172
173 static status
storeListBrowser(ListBrowser lb,FileObj file)174 storeListBrowser(ListBrowser lb, FileObj file)
175 { return storeSlotsObject(lb, file);
176 }
177
178
179 static status
loadListBrowser(ListBrowser lb,IOSTREAM * fd,ClassDef def)180 loadListBrowser(ListBrowser lb, IOSTREAM *fd, ClassDef def)
181 { TRY(loadSlotsObject(lb, fd, def));
182
183 if ( isNil(lb->status) )
184 assign(lb, status, NAME_inactive);
185
186 lb->start_cell = NIL;
187
188 succeed;
189 }
190
191
192 /********************************
193 * LABEL *
194 ********************************/
195
196 static status
labelListBrowser(ListBrowser lb,Name lbl)197 labelListBrowser(ListBrowser lb, Name lbl)
198 { showLabelListBrowser(lb, ON);
199
200 send(lb->label_text, NAME_string, lbl, EAV);
201 geometryListBrowser(lb, DEFAULT, DEFAULT, DEFAULT, DEFAULT);
202
203 succeed;
204 }
205
206
207 static Name
getLabelListBrowser(ListBrowser lb)208 getLabelListBrowser(ListBrowser lb)
209 { if ( notNil(lb->label_text) )
210 answer(getValueCharArray((CharArray) lb->label_text->string));
211
212 fail;
213 }
214
215
216 static status
showLabelListBrowser(ListBrowser lb,BoolObj val)217 showLabelListBrowser(ListBrowser lb, BoolObj val)
218 { if ( isNil(lb->label_text) )
219 { if ( val == ON )
220 { assign(lb, label_text,
221 newObject(ClassText, GetLabelNameName(lb->name), NAME_left,
222 getClassVariableValueObject(lb, NAME_labelFont), EAV));
223 marginText(lb->label_text, lb->area->w, NAME_clip);
224 displayDevice(lb, lb->label_text, DEFAULT);
225 return geometryListBrowser(lb, DEFAULT, DEFAULT,
226 add(lb->image->area->x, lb->image->area->w),
227 lb->image->area->h);
228 } else
229 succeed;
230 }
231
232 if ( lb->label_text->displayed != val )
233 { DisplayedGraphical(lb->label_text, val);
234 return geometryListBrowser(lb, DEFAULT, DEFAULT, DEFAULT, DEFAULT);
235 }
236
237 succeed;
238 }
239
240
241 static BoolObj
getShowLabelListBrowser(ListBrowser lb)242 getShowLabelListBrowser(ListBrowser lb)
243 { if ( notNil(lb->label_text) )
244 answer(lb->label_text->displayed);
245
246 answer(OFF);
247 }
248
249
250 /*******************************
251 * TYPING *
252 *******************************/
253
254 static status
statusListBrowser(ListBrowser lb,Name stat)255 statusListBrowser(ListBrowser lb, Name stat)
256 { if ( lb->status != stat )
257 { Elevation z;
258
259 assign(lb, status, stat);
260
261 /* avoid unnecessary flickering (hack) */
262 if ( !((z = getClassVariableValueObject(lb->image, NAME_elevation)) &&
263 notNil(z)) )
264 { penGraphical((Graphical) lb->image,
265 stat == NAME_active ? add(lb->pen, ONE) : lb->pen);
266 }
267 }
268
269 succeed;
270 }
271
272
273 static status
nextListBrowser(ListBrowser lb)274 nextListBrowser(ListBrowser lb)
275 { return send(lb->device, NAME_advance, lb, EAV);
276 }
277
278
279 static status
extendPrefixOrNextListBrowser(ListBrowser lb)280 extendPrefixOrNextListBrowser(ListBrowser lb)
281 { if ( notNil(lb->search_string) )
282 { StringObj ext = lb->search_string;
283
284 extendPrefixListBrowser(lb);
285 if ( lb->search_string != ext )
286 succeed;
287 }
288
289 return nextListBrowser(lb);
290 }
291
292
293 static status
WantsKeyboardFocusListBrowser(ListBrowser lb)294 WantsKeyboardFocusListBrowser(ListBrowser lb)
295 { if ( notNil(lb->dict) &&
296 getSizeChain(lb->dict->members) != ZERO )
297 succeed;
298
299 fail;
300 }
301
302
303 /********************************
304 * SCROLLBAR *
305 ********************************/
306
307 static Int
getViewListBrowser(ListBrowser lb)308 getViewListBrowser(ListBrowser lb)
309 { answer(div(getViewTextImage(lb->image), toInt(BROWSER_LINE_WIDTH)));
310 }
311
312
313 static Int
getLengthListBrowser(ListBrowser lb)314 getLengthListBrowser(ListBrowser lb)
315 { answer(notNil(lb->dict) ? lb->dict->members->size : ZERO);
316 }
317
318
319 /********************************
320 * GEOMETRY *
321 ********************************/
322
323 static status
geometryListBrowser(ListBrowser lb,Int x,Int y,Int w,Int h)324 geometryListBrowser(ListBrowser lb, Int x, Int y, Int w, Int h)
325 { int ix, iw, sw, iy, ih;
326 int pen = valInt(lb->pen);
327
328 if ( isDefault(w) || isDefault(h) )
329 computeBoundingBoxDevice((Device)lb);
330
331 if ( isDefault(x) ) x = lb->area->x;
332 if ( isDefault(y) ) y = lb->area->y;
333 if ( isDefault(w) ) w = lb->area->w;
334 if ( isDefault(h) ) h = lb->area->h;
335
336 if ( valInt(w) < 50 ) w = toInt(50);
337 if ( valInt(h) < 20 ) h = toInt(20);
338
339 sw = isNil(lb->scroll_bar) ? 0 : valInt(getMarginScrollBar(lb->scroll_bar));
340 iw = valInt(w) - abs(sw);
341
342 { int fw = valInt(getExFont(lb->font));
343 int fh = valInt(getHeightFont(lb->font));
344
345 assign(lb->size, w, toInt((iw - 2 * TXT_X_MARGIN)/fw));
346 assign(lb->size, h, toInt((valInt(h) - 2 * TXT_Y_MARGIN)/fh));
347 }
348
349 ix = (sw < 0 ? -sw : 0);
350 if ( getShowLabelListBrowser(lb) == ON )
351 { send(lb->label_text, NAME_set, ZERO, ZERO, w, EAV);
352 iy = valInt(lb->label_text->area->h) - pen;
353 } else
354 { iy = 0;
355 }
356 ih = valInt(h) - iy;
357
358 send(lb->image, NAME_set, toInt(ix), toInt(iy), toInt(iw), toInt(ih), EAV);
359 if ( notNil(lb->scroll_bar) )
360 placeScrollBar(lb->scroll_bar, (Graphical) lb->image);
361
362 return geometryDevice((Device) lb, x, y, DEFAULT, DEFAULT);
363 }
364
365
366 static status
SizeListBrowser(ListBrowser lb,Size size)367 SizeListBrowser(ListBrowser lb, Size size)
368 { return doSetGraphical(lb, DEFAULT, DEFAULT, size->w, size->h);
369 }
370
371
372 status
requestGeometryListBrowser(ListBrowser lb,Int x,Int y,Int w,Int h)373 requestGeometryListBrowser(ListBrowser lb, Int x, Int y, Int w, Int h)
374 { PceWindow v;
375
376 if ( notDefault(w) )
377 { w = mul(w, getExFont(lb->font));
378 if ( notNil(lb->scroll_bar) )
379 w = add(w, getMarginScrollBar(lb->scroll_bar));
380 w = add(w, toInt(2 * TXT_X_MARGIN));
381 }
382
383 if ( notDefault(h) )
384 { h = mul(h, getHeightFont(lb->font));
385 h = add(h, toInt(2 * TXT_Y_MARGIN));
386 }
387
388 if ( instanceOfObject(v = lbReceiver(lb), ClassWindow) )
389 { int b = (valInt(v->tile->border) + valInt(v->pen)) * 2;
390
391 if ( notDefault(w) )
392 w = add(w, toInt(b));
393 if ( notDefault(h) )
394 h = add(h, toInt(b));
395
396 requestGeometryWindow(v, x, y, w, h);
397 } else
398 requestGeometryGraphical(lb, x, y, w, h);
399
400 succeed;
401 }
402
403
404 Size
getSizeListBrowser(ListBrowser lb)405 getSizeListBrowser(ListBrowser lb)
406 { answer(lb->size);
407 }
408
409
410 static Int
getWidthListBrowser(ListBrowser lb)411 getWidthListBrowser(ListBrowser lb)
412 { answer(lb->size->w);
413 }
414
415
416 static Int
getHeightListBrowser(ListBrowser lb)417 getHeightListBrowser(ListBrowser lb)
418 { answer(lb->size->h);
419 }
420
421 /********************************
422 * FETCH *
423 ********************************/
424
425 static Dict current_dict; /* Currently displayed dict */
426 static Cell current_cell; /* Cell of this item */
427 static int current_item; /* Index of current name */
428 static int current_index; /* Current location */
429 static PceString current_name; /* Working on this name */
430 static int current_search; /* search feedback */
431 static unsigned char current_atts; /* Attributes for it */
432 static FontObj current_font; /* Current font */
433 static Colour current_colour; /* Current colour */
434 static Any current_background; /* Current background */
435 static Image current_image; /* Image to flag line */
436
437 static void
compute_current(ListBrowser lb)438 compute_current(ListBrowser lb)
439 { if ( notNil(current_cell) )
440 { DictItem di = (DictItem) current_cell->value;
441 CharArray label = getLabelDictItem(di);
442 Style style;
443
444 assert(valInt(di->index) == current_item);
445 current_name = (label ? &label->data : (PceString) NULL);
446
447 if ( notDefault(di->style) &&
448 (style = getValueSheet(lb->styles, di->style)) )
449 { current_font = style->font;
450 current_colour = style->colour;
451 current_background = style->background;
452 current_atts = style->attributes;
453 current_image = style->icon;
454
455 if ( isDefault(current_font) )
456 current_font = lb->font;
457 } else
458 { current_font = lb->font;
459 current_colour = DEFAULT;
460 current_background = DEFAULT;
461 current_atts = 0;
462 current_image = NIL;
463 }
464
465 if ( selectedListBrowser(lb, di) )
466 { if ( isDefault(lb->selection_style) )
467 current_atts ^= TXT_HIGHLIGHTED;
468 else
469 { current_atts |= lb->selection_style->attributes;
470 if ( notDefault(lb->selection_style->font) )
471 current_font = lb->selection_style->font;
472 if ( notDefault(lb->selection_style->colour) )
473 current_colour = lb->selection_style->colour;
474 if ( notDefault(lb->selection_style->background) )
475 current_background = lb->selection_style->background;
476 }
477 }
478
479 if ( di->index == lb->search_hit )
480 { current_search = lb->search_string->data.s_size;
481 } else
482 current_search = 0;
483 } else
484 { current_name = NULL; /* past the end */
485 current_atts = 0;
486 current_font = lb->font;
487 current_colour = DEFAULT;
488 current_background = DEFAULT;
489 current_image = NIL;
490 }
491 }
492
493
494 static Cell
find_cell_dict(Dict dict,Int item)495 find_cell_dict(Dict dict, Int item)
496 { if ( notNil(dict) )
497 { Cell cell;
498
499 for_cell(cell, dict->members)
500 if ( ((DictItem) cell->value)->index == item )
501 return cell;
502 }
503
504 return NIL;
505 }
506
507
508 static void
seek_list_browser(Any obj,long int index)509 seek_list_browser(Any obj, long int index)
510 { ListBrowser lb = obj;
511 int item = index / BROWSER_LINE_WIDTH;
512 Dict d = lb->dict;
513
514 if ( isNil(d) )
515 return;
516
517 if ( item != current_item || d != current_dict )
518 { if ( item < current_item || d != current_dict )
519 { current_cell = find_cell_dict(lb->dict, toInt(item));
520 assert(current_cell != NULL);
521 current_dict = d;
522 } else
523 { for( ; item > current_item && notNil(current_cell); current_item++ )
524 current_cell = current_cell->next;
525 assert(current_cell != NULL);
526 }
527
528 current_item = item;
529
530 compute_current(lb);
531 }
532
533 current_index = index;
534 }
535
536
537 static long
scan_list_browser(Any obj,long int from,int dir,int how,int category,int * eof)538 scan_list_browser(Any obj, long int from, int dir,
539 int how, int category, int *eof)
540 { ListBrowser lb = obj;
541 int item = from / BROWSER_LINE_WIDTH;
542
543 assert(dir > 0 && how == TEXT_SCAN_FOR && category == EL);
544
545 *eof = (isNil(lb->dict) ||
546 ((item + 1 >= valInt(lb->dict->members->size)) ? TRUE : FALSE));
547
548 return (item + 1) * BROWSER_LINE_WIDTH - 1;
549 }
550
551
552 static long
fetch_list_browser(Any obj,TextChar tc)553 fetch_list_browser(Any obj, TextChar tc)
554 { ListBrowser lb = obj;
555 int index = current_index;
556 int pos = current_index++ % BROWSER_LINE_WIDTH;
557
558 if ( current_name )
559 { int len = current_name->s_size;
560
561 if ( pos <= len )
562 { if ( pos == 0 )
563 { if ( notNil(current_image) )
564 { tc->value.image = current_image;
565 tc->type = CHAR_IMAGE;
566 } else
567 { tc->value.image = NULL_IMAGE;
568 tc->type = CHAR_IMAGE;
569 }
570 } else
571 { tc->value.c = str_fetch(current_name, pos-1);
572 tc->type = CHAR_ASCII;
573 }
574 } else /* if ( pos == len+1 ) */
575 { tc->value.c = '\n';
576 tc->type = CHAR_ASCII;
577 current_index = ((index / BROWSER_LINE_WIDTH) + 1) * BROWSER_LINE_WIDTH;
578 }
579 } else
580 { tc->value.c = EOB;
581 tc->type = CHAR_ASCII;
582 }
583
584 tc->font = current_font;
585 tc->attributes = current_atts;
586 tc->colour = current_colour;
587 tc->background = current_background;
588 tc->index = index;
589
590 if ( pos > 0 && pos <= current_search )
591 { Style s = getClassVariableValueObject(lb, NAME_isearchStyle);
592
593 if ( s && notDefault(s) )
594 { tc->attributes |= s->attributes;
595 if ( notDefault(s->font) ) tc->font = s->font;
596 if ( notDefault(s->colour) ) tc->colour = s->colour;
597 if ( notDefault(s->background) ) tc->background = s->background;
598 } else
599 tc->attributes ^= TXT_HIGHLIGHTED;
600 }
601
602 return current_index;
603 }
604
605 static void
rewind_list_browser(Any obj)606 rewind_list_browser(Any obj)
607 { ListBrowser lb = (ListBrowser) obj;
608 DictItem di;
609
610 assign(lb, start, normalise_index(lb, lb->start));
611
612 if ( isNil(lb->start_cell) ||
613 !isProperObject((di = lb->start_cell->value)) ||
614 di->index != lb->start )
615 lb->start_cell = find_cell_dict(lb->dict, lb->start);
616
617 current_cell = lb->start_cell;
618 current_item = valInt(lb->start);
619 current_dict = lb->dict;
620 compute_current(lb);
621 }
622
623
624 static SeekFunction
getSeekFunctionListBrowser(ListBrowser lb)625 getSeekFunctionListBrowser(ListBrowser lb)
626 { DEBUG(NAME_SeekFunction,
627 Cprintf("seek_list_browser = 0x%p\n", seek_list_browser));
628 answer(seek_list_browser);
629 }
630
631
632 static ScanFunction
getScanFunctionListBrowser(ListBrowser lb)633 getScanFunctionListBrowser(ListBrowser lb)
634 { answer(scan_list_browser);
635 }
636
637
638 static FetchFunction
getFetchFunctionListBrowser(ListBrowser lb)639 getFetchFunctionListBrowser(ListBrowser lb)
640 { answer(fetch_list_browser);
641 }
642
643
644 static MarginFunction
getMarginFunctionListBrowser(ListBrowser lb)645 getMarginFunctionListBrowser(ListBrowser lb)
646 { answer((MarginFunction) NULL);
647 }
648
649
650 static RewindFunction
getRewindFunctionListBrowser(ListBrowser lb)651 getRewindFunctionListBrowser(ListBrowser lb)
652 { answer(rewind_list_browser);
653 }
654
655
656
657 /********************************
658 * REDRAW *
659 ********************************/
660
661 static status
computeListBrowser(ListBrowser lb)662 computeListBrowser(ListBrowser lb)
663 { if ( notNil(lb->request_compute) )
664 { computeTextImage(lb->image);
665 requestComputeGraphical(lb->scroll_bar, DEFAULT); /* TBD: where to put? */
666 return computeDevice(lb);
667 }
668
669 succeed;
670 }
671
672
673 static Int
normalise_index(ListBrowser lb,Int index)674 normalise_index(ListBrowser lb, Int index)
675 { Int size = (notNil(lb->dict) ? lb->dict->members->size : ZERO);
676
677 if ( valInt(index) >= valInt(size) )
678 index = sub(size, ONE);
679
680 if ( valInt(index) < 0 )
681 return ZERO;
682
683 return index;
684 }
685
686
687 /********************************
688 * SEARCHING *
689 ********************************/
690
691 static StringObj
getExtendPrefixDict(Dict dict,CharArray pref,BoolObj ign_case)692 getExtendPrefixDict(Dict dict, CharArray pref, BoolObj ign_case)
693 { LocalString(common, pref->data.s_iswide, LINESIZE);
694 Cell cell;
695 int hit = FALSE;
696
697 common->s_size = 0;
698
699 for_cell(cell, dict->members)
700 { DictItem di = cell->value;
701 CharArray c = getLabelDictItem(di);
702 PceString name;
703
704 if ( !c )
705 continue;
706
707 name = &c->data;
708 if ( name->s_size > LINESIZE ||
709 name->s_iswide != common->s_iswide ) /* TBD */
710 continue;
711
712 if ( ign_case == OFF )
713 { if ( str_prefix(name, &pref->data) )
714 { if ( !hit++ )
715 str_cpy(common, name);
716 else
717 common->s_size = str_common_length(common, name);
718 }
719 } else
720 { if ( str_icase_prefix(name, &pref->data) )
721 { if ( !hit++ )
722 { str_cpy(common, name);
723 str_downcase(common, 0, common->s_size);
724 } else
725 common->s_size = str_icase_common_length(common, name);
726 }
727 }
728 }
729
730 answer(StringToString(common));
731 }
732
733
734 static status
extendPrefixListBrowser(ListBrowser lb)735 extendPrefixListBrowser(ListBrowser lb)
736 { if ( notNil(lb->dict) )
737 { StringObj ext;
738
739 ext = getExtendPrefixDict(lb->dict,
740 isNil(lb->search_string)
741 ? (CharArray) CtoName("")
742 : (CharArray) lb->search_string,
743 getClassVariableValueObject(lb,
744 NAME_searchIgnoreCase));
745
746 assign(lb, search_string, ext);
747 executeSearchListBrowser(lb);
748 }
749
750 succeed;
751 }
752
753
754 static status
extendToCurrentListBrowser(ListBrowser lb)755 extendToCurrentListBrowser(ListBrowser lb)
756 { if ( notNil(lb->search_string) )
757 { DictItem di;
758
759 if ( notNil(lb->dict) && (di=getFindIndexDict(lb->dict, lb->search_hit)) )
760 { assign(lb, search_string,
761 newObject(ClassString, name_procent_s, getLabelDictItem(di), EAV));
762 return executeSearchListBrowser(lb);
763 }
764 }
765
766 fail;
767 }
768
769
770 static status
cancelSearchListBrowser(ListBrowser lb)771 cancelSearchListBrowser(ListBrowser lb)
772 { DictItem di;
773
774 assign(lb, caret, NIL);
775 assign(lb, search_string, NIL);
776 assign(lb, search_origin, ZERO);
777 if ( valInt(lb->search_hit) >= 0 )
778 { if ( notNil(lb->dict) && (di=getFindIndexDict(lb->dict, lb->search_hit)) )
779 ChangeItemListBrowser(lb, di);
780 assign(lb, search_hit, toInt(-1));
781 }
782
783 succeed;
784 }
785
786
787 status
executeSearchListBrowser(ListBrowser lb)788 executeSearchListBrowser(ListBrowser lb)
789 { DictItem di;
790
791 if ( isNil(lb->dict) ||
792 !(di=getFindPrefixDict(lb->dict, lb->search_string,
793 lb->search_origin,
794 getClassVariableValueObject(lb,
795 NAME_searchIgnoreCase))))
796 fail;
797
798 if ( valInt(lb->search_hit) >= 0 )
799 { DictItem old = getFindIndexDict(lb->dict, lb->search_hit);
800
801 if ( old != FAIL )
802 ChangeItemListBrowser(lb, old);
803 }
804 assign(lb, search_hit, di->index);
805 normaliseListBrowser(lb, di);
806 return ChangeItemListBrowser(lb, di);
807 }
808
809
810 static status
repeatSearchListBrowser(ListBrowser lb,Int chr,EventObj ev)811 repeatSearchListBrowser(ListBrowser lb, Int chr, EventObj ev)
812 { if ( notNil(lb->search_string) )
813 { Int oldorg = lb->search_origin;
814
815 assign(lb, search_origin, add(lb->search_hit, ONE));
816 if ( !executeSearchListBrowser(lb) )
817 { assign(lb, search_origin, oldorg);
818 fail;
819 }
820 succeed;
821 }
822
823 fail;
824 }
825
826
827 static status
backwardDeleteCharListBrowser(ListBrowser lb)828 backwardDeleteCharListBrowser(ListBrowser lb)
829 { StringObj ss = lb->search_string;
830
831 if ( notNil(ss) )
832 { int size = valInt(getSizeCharArray(ss));
833
834 if ( size > 1 )
835 { deleteString(ss, toInt(size-1), DEFAULT);
836 return executeSearchListBrowser(lb);
837 }
838
839 cancelSearchListBrowser(lb);
840 }
841
842 fail;
843 }
844
845
846 static status
insertSelfListBrowser(ListBrowser lb,Int times,Int chr)847 insertSelfListBrowser(ListBrowser lb, Int times, Int chr)
848 { wint_t c;
849
850 if ( isDefault(times) )
851 times = ONE;
852
853 if ( isDefault(chr) )
854 { EventObj ev = EVENT->value;
855
856 if ( instanceOfObject(ev, ClassEvent) && isAEvent(ev, NAME_printable) )
857 c = valInt(getIdEvent(ev));
858 else
859 return errorPce(lb, NAME_noCharacter);
860 } else
861 c = valInt(chr);
862
863 { LocalString(s, c <= 0xff ? FALSE : TRUE, valInt(times));
864 int i;
865
866 for(i=0; i<valInt(times); )
867 str_store(s, i++, c);
868
869 if ( isNil(lb->search_string) )
870 { assign(lb, search_string, StringToString(s));
871 if ( getClassVariableValueObject(lb, NAME_clearSelectionOnSearch) == ON )
872 clearSelectionListBrowser(lb);
873 } else
874 { if ( !instanceOfObject(lb->search_string, ClassString) )
875 assign(lb, search_string,
876 newObject(ClassString, name_procent_s, lb->search_string, EAV));
877 str_insert_string(lb->search_string, DEFAULT, s);
878 }
879
880 if ( !executeSearchListBrowser(lb) )
881 { StringObj ss = lb->search_string;
882 int size = valInt(getSizeCharArray(ss));
883
884 if ( size > 1 )
885 deleteString(ss, toInt(size-1), DEFAULT);
886 else
887 cancelSearchListBrowser(lb);
888
889 fail;
890 }
891 }
892
893 succeed;
894 }
895
896
897 static status
enterListBrowser(ListBrowser lb)898 enterListBrowser(ListBrowser lb)
899 { DictItem di;
900
901 if ( isNil(lb->dict) )
902 fail;
903
904 if ( (di=getFindIndexDict(lb->dict, lb->search_hit)) )
905 { send(lb, NAME_changeSelection, NAME_set, di, EAV);
906 return forwardListBrowser(lb, NAME_open);
907 }
908
909 return forwardListBrowser(lb, NAME_open);
910 }
911
912 /********************************
913 * EVENT HANDLING *
914 ********************************/
915
916
917 status
typedListBrowser(ListBrowser lb,EventId id)918 typedListBrowser(ListBrowser lb, EventId id)
919 { return typedKeyBinding(lb->key_binding, id, lbReceiver(lb));
920 }
921
922
923 DictItem
getDictItemListBrowser(ListBrowser lb,EventObj ev)924 getDictItemListBrowser(ListBrowser lb, EventObj ev)
925 { if ( insideEvent(ev, (Graphical)lb->image) )
926 { Int where = getIndexTextImage(lb->image, ev);
927
928 if ( where && notNil(lb->dict) )
929 answer(getFindIndexDict(lb->dict,
930 toInt(valInt(where)/BROWSER_LINE_WIDTH)));
931 }
932
933 fail;
934 }
935
936
937 Any
selectBrowserGesture()938 selectBrowserGesture()
939 { static Any g = NULL;
940
941 if ( !g )
942 g = globalObject(NAME_browserSelectGesture, ClassBrowserSelectGesture, EAV);
943
944 return g;
945 }
946
947
948
949 static status
eventListBrowser(ListBrowser lb,EventObj ev)950 eventListBrowser(ListBrowser lb, EventObj ev)
951 { if ( isAEvent(ev, NAME_focus) )
952 { if ( isAEvent(ev, NAME_activateKeyboardFocus) )
953 return send(lb, NAME_status, NAME_active, EAV);
954 if ( isAEvent(ev, NAME_deactivateKeyboardFocus) )
955 { cancelSearchListBrowser(lb);
956 return send(lb, NAME_status, NAME_inactive, EAV);
957 }
958 }
959
960 if ( eventDevice(lb, ev) )
961 succeed;
962
963 if ( isAEvent(ev, NAME_keyboard) )
964 return send(lb, NAME_typed, getIdEvent(ev), EAV);
965
966 if ( mapWheelMouseEvent(ev, lb) )
967 succeed;
968
969 if ( isAEvent(ev, NAME_button) )
970 { DictItem di = getDictItemListBrowser(lb, ev);
971
972 if ( di && notNil(lb->popup) && isAEvent(ev, NAME_msRightDown) )
973 { send(popupGesture(), NAME_context, di, EAV);
974
975 if ( !postEvent(ev, (Graphical) lb, popupGesture()) )
976 send(popupGesture(), NAME_context, NIL, EAV);
977 else
978 succeed;
979 } else
980 return postEvent(ev, (Graphical)lb, selectBrowserGesture());
981 }
982
983 fail;
984 }
985
986 /********************************
987 * EDIT FUNCTIONS *
988 ********************************/
989
990 static status
changeSelectionListBrowser(ListBrowser lb,Name action,DictItem di)991 changeSelectionListBrowser(ListBrowser lb, Name action, DictItem di)
992 { cancelSearchListBrowser(lb);
993
994 if ( action == NAME_cancel )
995 { assign(lb, selection_origin, NIL);
996
997 clearSelectionListBrowser(lb);
998 if ( instanceOfObject(di, ClassChain) )
999 { Cell cell;
1000
1001 for_cell(cell, (Chain)di)
1002 { selectListBrowser(lb, cell->value);
1003 }
1004 } else if ( instanceOfObject(di, ClassDictItem) )
1005 selectListBrowser(lb, di);
1006
1007 if ( instanceOfObject(lb->cancel_message, ClassCode) )
1008 forwardReceiverCode(lb->cancel_message,
1009 lbReceiver(lb),
1010 EAV);
1011
1012 succeed;
1013 }
1014
1015 if ( action != NAME_clear && isDefault(di) )
1016 return errorPce(di, NAME_unexpectedType, nameToType(NAME_dictItem));
1017
1018 if ( action == NAME_set )
1019 { clearSelectionListBrowser(lb);
1020 selectListBrowser(lb, di);
1021 assign(lb, selection_origin, di->index);
1022 } else if ( action == NAME_toggle )
1023 { if ( selectedListBrowser(lb, di) )
1024 deselectListBrowser(lb, di);
1025 else
1026 { selectListBrowser(lb, di);
1027 assign(lb, selection_origin, di->index);
1028 }
1029 } else if ( action == NAME_extend )
1030 { if ( isNil(lb->selection) || isNil(lb->selection_origin) )
1031 { selectListBrowser(lb, di);
1032 assign(lb, selection_origin, di->index);
1033 } else
1034 { Chain ch = lb->selection;
1035 Cell cell, c2;
1036 int low, high;
1037
1038 low = valInt(di->index);
1039 high = valInt(lb->selection_origin);
1040 if ( low > high )
1041 swap(low, high);
1042
1043 for_cell_save(cell, c2, ch)
1044 { DictItem di2 = cell->value;
1045
1046 if ( valInt(di2->index) < low || valInt(di2->index) > high )
1047 deselectListBrowser(lb, di2);
1048 }
1049
1050 if ( (cell = find_cell_dict(lb->dict, toInt(low))) )
1051 { for( ; notNil(cell); cell = cell->next )
1052 { DictItem di2 = cell->value;
1053
1054 selectListBrowser(lb, di2);
1055 if ( valInt(di2->index) == high )
1056 break;
1057 }
1058 } else
1059 { clearSelectionListBrowser(lb);
1060 selectListBrowser(lb, di);
1061 assign(lb, selection_origin, di->index);
1062 }
1063 }
1064 } else /* clear */
1065 { clearSelectionListBrowser(lb);
1066 assign(lb, selection_origin, NIL);
1067 }
1068
1069 succeed;
1070 }
1071
1072
1073 status
forwardListBrowser(ListBrowser lb,Name action)1074 forwardListBrowser(ListBrowser lb, Name action)
1075 { if ( notNil(lb->selection) )
1076 { if ( notNil(lb->select_message) )
1077 forwardReceiverCode(lb->select_message, lbReceiver(lb),
1078 lb->selection, EAV);
1079
1080 if ( action == NAME_open )
1081 { if ( notNil(lb->open_message) )
1082 { DisplayObj d = getDisplayGraphical((Graphical)lb);
1083
1084 busyCursorDisplay(d, DEFAULT, DEFAULT);
1085 forwardReceiverCode(lb->open_message, lbReceiver(lb),
1086 lb->selection, EAV);
1087 busyCursorDisplay(d, NIL, DEFAULT);
1088 }
1089 }
1090 }
1091
1092 succeed;
1093 }
1094
1095
1096 /********************************
1097 * SELECTION HANDLING *
1098 ********************************/
1099
1100 status
selectedListBrowser(ListBrowser lb,DictItem di)1101 selectedListBrowser(ListBrowser lb, DictItem di)
1102 { if ( instanceOfObject(lb->selection, ClassChain) )
1103 return memberChain(lb->selection, di);
1104
1105 if ( notNil(lb->selection) && (DictItem) lb->selection == di )
1106 succeed;
1107
1108 fail;
1109 }
1110
1111
1112 static status
deselectListBrowser(ListBrowser lb,DictItem di)1113 deselectListBrowser(ListBrowser lb, DictItem di)
1114 { if ( instanceOfObject(lb->selection, ClassChain) )
1115 { if ( deleteChain(lb->selection, di) )
1116 ChangeItemListBrowser(lb, di);
1117 } else if ( notNil(lb->selection) && (DictItem) lb->selection == di )
1118 { assign(lb, selection, NIL);
1119 ChangeItemListBrowser(lb, di);
1120 }
1121
1122 succeed;
1123 }
1124
1125
1126 static status
selectListBrowser(ListBrowser lb,DictItem di)1127 selectListBrowser(ListBrowser lb, DictItem di)
1128 { if ( selectedListBrowser(lb, di) )
1129 succeed;
1130
1131 if ( lb->multiple_selection == ON )
1132 { appendChain(lb->selection, di);
1133 ChangeItemListBrowser(lb, di);
1134 } else
1135 { if ( notNil(lb->selection) )
1136 deselectListBrowser(lb, lb->selection);
1137 assign(lb, selection, di);
1138 ChangeItemListBrowser(lb, di);
1139 }
1140
1141 succeed;
1142 }
1143
1144
1145 static status
clearSelectionListBrowser(ListBrowser lb)1146 clearSelectionListBrowser(ListBrowser lb)
1147 { if ( instanceOfObject(lb->selection, ClassChain) )
1148 { Chain ch = (Chain) lb->selection;
1149
1150 while( notNil(ch->head) )
1151 deselectListBrowser(lb, ch->head->value);
1152 } else if ( notNil(lb->selection) )
1153 deselectListBrowser(lb, lb->selection);
1154
1155 succeed;
1156 }
1157
1158
1159 status
selectionListBrowser(ListBrowser lb,Any obj)1160 selectionListBrowser(ListBrowser lb, Any obj)
1161 { clearSelectionListBrowser(lb);
1162
1163 if ( instanceOfObject(obj, ClassChain) )
1164 { Chain ch = obj;
1165 Cell cell;
1166
1167 for_cell(cell, ch)
1168 sendv(lb, NAME_select, 1, (Any *)&cell->value);
1169 } else if ( notNil(obj) )
1170 selectListBrowser(lb, obj);
1171
1172 succeed;
1173 }
1174
1175
1176 Any
getSelectionListBrowser(ListBrowser lb)1177 getSelectionListBrowser(ListBrowser lb)
1178 { if ( notNil(lb->selection) )
1179 answer(lb->selection);
1180
1181 fail;
1182 }
1183
1184 /********************************
1185 * SCROLLING *
1186 ********************************/
1187
1188 status
scrollToListBrowser(ListBrowser lb,Int index)1189 scrollToListBrowser(ListBrowser lb, Int index)
1190 { if ( isDefault(index) )
1191 index = (notNil(lb->dict) ? lb->dict->members->size : ZERO);
1192 index = normalise_index(lb, index);
1193
1194 assign(lb, start, index);
1195 return startTextImage(lb->image, mul(index, toInt(BROWSER_LINE_WIDTH)), ZERO);
1196 }
1197
1198
1199 status
normaliseListBrowser(ListBrowser lb,DictItem di)1200 normaliseListBrowser(ListBrowser lb, DictItem di)
1201 { int here = valInt(di->index);
1202 int start, last;
1203
1204 computeListBrowser(lb);
1205 start = valInt(lb->image->start) / BROWSER_LINE_WIDTH;
1206 last = (valInt(lb->image->end) - 1) / BROWSER_LINE_WIDTH;
1207
1208 if ( here >= start && here <= last )
1209 succeed;
1210 if ( here == start-1 )
1211 return scrollDownListBrowser(lb, ONE);
1212 if ( here == last+1 )
1213 return scrollUpListBrowser(lb, ONE);
1214
1215 return scrollToListBrowser(lb,
1216 toInt(here - valInt(getLinesTextImage(lb->image))/2));
1217 }
1218
1219
1220 static status
scrollUpListBrowser(ListBrowser lb,Int arg)1221 scrollUpListBrowser(ListBrowser lb, Int arg)
1222 { Int lines = (isDefault(arg) ? sub(getLinesTextImage(lb->image), ONE) : arg);
1223
1224 if ( isDefault(arg) )
1225 cancelSearchListBrowser(lb);
1226 return scrollToListBrowser(lb, add(lb->start, lines));
1227 }
1228
1229
1230 static status
scrollDownListBrowser(ListBrowser lb,Int arg)1231 scrollDownListBrowser(ListBrowser lb, Int arg)
1232 { Int lines = (isDefault(arg) ? sub(getLinesTextImage(lb->image), ONE) : arg);
1233
1234 if ( isDefault(arg) )
1235 cancelSearchListBrowser(lb);
1236 return scrollToListBrowser(lb, sub(lb->start, lines));
1237 }
1238
1239
1240 static status
recenterListBrowser(ListBrowser lb,Int arg)1241 recenterListBrowser(ListBrowser lb, Int arg)
1242 { cancelSearchListBrowser(lb);
1243
1244 succeed;
1245 }
1246
1247
1248 static status
scrollVerticalListBrowser(ListBrowser lb,Name dir,Name unit,Int amount)1249 scrollVerticalListBrowser(ListBrowser lb, Name dir, Name unit, Int amount)
1250 { if ( unit == NAME_file )
1251 { if ( dir == NAME_goto )
1252 { int size = (isNil(lb->dict) ? 0 : valInt(lb->dict->members->size));
1253 int view = valInt(getLinesTextImage(lb->image));
1254 int h = ((size-view) * valInt(amount)) / 1000;
1255
1256 if ( h < 0 )
1257 h = 0;
1258
1259 scrollToListBrowser(lb, toInt(h));
1260 }
1261 } else if ( unit == NAME_page )
1262 { int d = (valInt(getLinesTextImage(lb->image)) * valInt(amount)) / 1000;
1263
1264 if ( d < 1 )
1265 d = 1;
1266
1267 if ( dir == NAME_forwards )
1268 scrollUpListBrowser(lb, toInt(d));
1269 else
1270 scrollDownListBrowser(lb, toInt(d));
1271 } else if ( unit == NAME_line )
1272 { if ( dir == NAME_forwards )
1273 scrollUpListBrowser(lb, amount);
1274 else
1275 scrollDownListBrowser(lb, amount);
1276 }
1277
1278 succeed;
1279 }
1280
1281
1282 static status
showScrollBarListBrowser(ListBrowser lb,BoolObj show,ScrollBar sb)1283 showScrollBarListBrowser(ListBrowser lb, BoolObj show, ScrollBar sb)
1284 { if ( isDefault(sb) || sb == lb->scroll_bar )
1285 { computeBoundingBoxDevice((Device) lb);
1286 DisplayedGraphical(lb->scroll_bar, show);
1287 geometryListBrowser(lb, DEFAULT, DEFAULT, lb->area->w, lb->area->h);
1288 }
1289
1290 succeed;
1291 }
1292
1293
1294 /*******************************
1295 * LINE UP/DOWN *
1296 *******************************/
1297
1298 static int
onPage(DictItem di,int start,int end)1299 onPage(DictItem di, int start, int end)
1300 { if ( valInt(di->index) >= start &&
1301 valInt(di->index) <= end )
1302 succeed;
1303
1304 fail;
1305 }
1306
1307
1308 static status
nextLineListBrowser(ListBrowser lb,Int lines)1309 nextLineListBrowser(ListBrowser lb, Int lines)
1310 { if ( notNil(lb->dict) )
1311 { int times = isDefault(lines) ? 1 : valInt(lines);
1312 DictItem di = NULL;
1313
1314 if ( times == 0 )
1315 succeed;
1316
1317 if ( valInt(lb->search_hit) >= 0 ) /* Searching */
1318 { Int newi = normalise_index(lb, toInt(valInt(lb->search_hit) + times));
1319
1320 di = getNth0Chain(lb->dict->members, newi);
1321 if ( di )
1322 { CharArray lbl = getLabelDictItem(di);
1323 DictItem di2 = getNth0Chain(lb->dict->members, lb->search_hit);
1324 BoolObj ign_case = getClassVariableValueObject(lb,
1325 NAME_searchIgnoreCase);
1326
1327 ChangeItemListBrowser(lb, di2);
1328
1329 if ( !prefixCharArray(lbl, (CharArray)lb->search_string, ign_case) ||
1330 getSizeCharArray(lb->search_string) == ZERO )
1331 { assign(lb, search_string,
1332 newObject(ClassString, name_procent_s, lbl, EAV));
1333 assign(lb, search_origin, newi);
1334 }
1335 assign(lb, search_hit, newi);
1336 }
1337 } else
1338 { int start = valInt(lb->image->start) / BROWSER_LINE_WIDTH;
1339 int last = (valInt(lb->image->end) - 1) / BROWSER_LINE_WIDTH;
1340 int caret = -1;
1341
1342 if ( notNil(lb->caret) )
1343 { caret = valInt(lb->caret);
1344 } else if ( instanceOfObject(lb->selection, ClassDictItem) )
1345 { if ( onPage(lb->selection, start, last) )
1346 { DictItem di2 = lb->selection;
1347
1348 caret = valInt(di2->index);
1349 }
1350 } else if ( instanceOfObject(lb->selection, ClassChain) )
1351 { Cell cell;
1352
1353 for_cell(cell, (Chain)lb->selection)
1354 { DictItem di2 = cell->value;
1355
1356 if ( onPage(di2, start, last) )
1357 { caret = valInt(di2->index);
1358 break;
1359 }
1360 }
1361 }
1362 if ( caret >= 0 )
1363 caret = valInt(normalise_index(lb, toInt(caret)));
1364 else
1365 caret = start;
1366
1367 caret += times;
1368 caret = valInt(normalise_index(lb, toInt(caret)));
1369 di = getNth0Chain(lb->dict->members, toInt(caret));
1370
1371 if ( di )
1372 { assign(lb, caret, toInt(caret));
1373
1374 if ( lb->multiple_selection == ON &&
1375 instanceOfObject(EVENT->value, ClassEvent) )
1376 { EventObj ev = EVENT->value;
1377
1378 if ( valInt(ev->buttons) & BUTTON_shift )
1379 send(lb, NAME_changeSelection, NAME_extend, di, EAV);
1380 else
1381 send(lb, NAME_changeSelection, NAME_set, di, EAV);
1382 } else
1383 send(lb, NAME_changeSelection, NAME_set, di, EAV);
1384 }
1385 }
1386
1387 if ( di )
1388 { normaliseListBrowser(lb, di);
1389 return ChangeItemListBrowser(lb, di);
1390 }
1391
1392 fail;
1393 }
1394
1395 fail;
1396 }
1397
1398
1399 static status
previousLineListBrowser(ListBrowser lb,Int lines)1400 previousLineListBrowser(ListBrowser lb, Int lines)
1401 { if ( isDefault(lines) )
1402 lines = toInt(-1);
1403 else
1404 lines = neg(lines);
1405
1406 return nextLineListBrowser(lb, lines);
1407 }
1408
1409
1410 /********************************
1411 * ATTRIBUTES *
1412 ********************************/
1413
1414
1415 static status
dictListBrowser(ListBrowser lb,Dict dict)1416 dictListBrowser(ListBrowser lb, Dict dict)
1417 { if ( lb->dict == dict )
1418 succeed;
1419
1420 if ( notNil(dict) && notNil(dict->browser) )
1421 return errorPce(lb, NAME_alreadyShown, dict, dict->browser);
1422
1423 if ( notNil(lb->dict) )
1424 assign(lb->dict, browser, NIL);
1425 assign(lb, dict, dict);
1426 if ( notNil(dict) )
1427 assign(dict, browser, lb);
1428 scrollToListBrowser(lb, ZERO);
1429 lb->start_cell = NIL;
1430
1431 return ChangedListBrowser(lb);
1432 }
1433
1434
1435 static status
fontListBrowser(ListBrowser lb,FontObj font)1436 fontListBrowser(ListBrowser lb, FontObj font)
1437 { if ( lb->font != font )
1438 { assign(lb, font, font);
1439 setGraphical(lb, DEFAULT, DEFAULT, lb->size->w, lb->size->h);
1440 return ChangedListBrowser(lb);
1441 }
1442
1443 succeed;
1444 }
1445
1446
1447 static status
styleListBrowser(ListBrowser lb,Name name,Style style)1448 styleListBrowser(ListBrowser lb, Name name, Style style)
1449 { valueSheet(lb->styles, name, style);
1450 ChangedListBrowser(lb);
1451
1452 succeed;
1453 }
1454
1455
1456 static status
selectionStyleListBrowser(ListBrowser lb,Style style)1457 selectionStyleListBrowser(ListBrowser lb, Style style)
1458 { if ( lb->selection_style != style )
1459 { assign(lb, selection_style, style);
1460 ChangedListBrowser(lb);
1461 }
1462
1463 succeed;
1464 }
1465
1466
1467 static status
multipleSelectionListBrowser(ListBrowser lb,BoolObj val)1468 multipleSelectionListBrowser(ListBrowser lb, BoolObj val)
1469 { if ( lb->multiple_selection != val )
1470 { if ( val == ON )
1471 { if ( isNil(lb->selection) )
1472 assign(lb, selection, newObject(ClassChain, EAV));
1473 else
1474 assign(lb, selection, newObject(ClassChain, lb->selection, EAV));
1475 } else
1476 { if ( emptyChain(lb->selection) )
1477 { assign(lb, selection, NIL);
1478 } else
1479 { Cell cell;
1480 int start = TRUE;
1481
1482 for_cell(cell, (Chain)lb->selection)
1483 { if ( start )
1484 start = FALSE;
1485 else
1486 deselectListBrowser(lb, cell->value);
1487 }
1488 assign(lb, selection, ((Chain) lb->selection)->head->value);
1489 }
1490 }
1491 assign(lb, multiple_selection, val);
1492 }
1493
1494 succeed;
1495 }
1496
1497 /********************************
1498 * CHANGE NOTIFICATIONS *
1499 ********************************/
1500
1501
1502 static status
DeleteItemListBrowser(ListBrowser lb,DictItem di)1503 DeleteItemListBrowser(ListBrowser lb, DictItem di)
1504 { Int where = mul(di->index, toInt(BROWSER_LINE_WIDTH));
1505
1506 deselectListBrowser(lb, di);
1507 if ( di->index == lb->start && notNil(lb->start_cell) )
1508 lb->start_cell = lb->start_cell->next;
1509 if ( valInt(di->index) <= valInt(lb->start) && lb->start != ZERO )
1510 assign(lb, start, sub(lb->start, ONE));
1511
1512 current_dict = NULL; /* clears cache */
1513 return InsertTextImage(lb->image, where, toInt(-BROWSER_LINE_WIDTH));
1514 }
1515
1516
1517 static status
InsertItemListBrowser(ListBrowser lb,DictItem di)1518 InsertItemListBrowser(ListBrowser lb, DictItem di)
1519 { Int where = mul(di->index, toInt(BROWSER_LINE_WIDTH));
1520
1521 current_dict = NULL; /* clears cache */
1522 return InsertTextImage(lb->image, where, toInt(BROWSER_LINE_WIDTH));
1523 }
1524
1525
1526 static status
ClearListBrowser(ListBrowser lb)1527 ClearListBrowser(ListBrowser lb)
1528 { if ( !isFreeingObj(lb) )
1529 { int size = (isNil(lb->dict) ? 0 : valInt(lb->dict->members->size));
1530
1531 lb->start_cell = NIL;
1532 assign(lb, start, ZERO);
1533
1534 if ( instanceOfObject(lb->selection, ClassChain) )
1535 clearChain(lb->selection);
1536 else
1537 assign(lb, selection, NIL);
1538
1539 current_dict = NULL; /* clears cache */
1540 InsertTextImage(lb->image, ZERO, toInt(size * -BROWSER_LINE_WIDTH));
1541 }
1542
1543 succeed;
1544 }
1545
1546
1547 static status
ChangeItemListBrowser(ListBrowser lb,DictItem di)1548 ChangeItemListBrowser(ListBrowser lb, DictItem di)
1549 { Int from = mul(di->index, toInt(BROWSER_LINE_WIDTH));
1550 Int to = add(from, toInt(BROWSER_LINE_WIDTH));
1551
1552 return ChangedRegionTextImage(lb->image, from, to);
1553 }
1554
1555
1556 static status
ChangedListBrowser(ListBrowser lb)1557 ChangedListBrowser(ListBrowser lb)
1558 { current_dict = NULL; /* clears cache */
1559 ChangedRegionTextImage(lb->image, ZERO, toInt(PCE_MAX_INT));
1560
1561 succeed;
1562 }
1563
1564 /********************************
1565 * DELEGATION *
1566 ********************************/
1567
1568 static status
tabStopsListBrowser(ListBrowser lb,Vector v)1569 tabStopsListBrowser(ListBrowser lb, Vector v)
1570 { return tabStopsTextImage(lb->image, v);
1571
1572 succeed;
1573 }
1574
1575
1576 status
backgroundListBrowser(ListBrowser lb,Any bg)1577 backgroundListBrowser(ListBrowser lb, Any bg)
1578 { return backgroundTextImage(lb->image, bg);
1579
1580 succeed;
1581 }
1582 /* avoid capture by device */
1583
1584 static status
clearListBrowser(ListBrowser lb)1585 clearListBrowser(ListBrowser lb)
1586 { if ( notNil(lb->dict) )
1587 send(lb->dict, NAME_clear, EAV);
1588
1589 succeed;
1590 }
1591
1592
1593 DictItem
getMemberListBrowser(ListBrowser lb,Any key)1594 getMemberListBrowser(ListBrowser lb, Any key)
1595 { if ( notNil(lb->dict) )
1596 answer(getMemberDict(lb->dict, key));
1597
1598 fail;
1599 }
1600
1601
1602 static status
referenceListBrowser(ListBrowser lb,Point ref)1603 referenceListBrowser(ListBrowser lb, Point ref)
1604 { return referenceGraphical((Graphical) lb, ref);
1605 }
1606
1607
1608 /********************************
1609 * VISUAL *
1610 ********************************/
1611
1612 Chain
getContainsListBrowser(ListBrowser lb)1613 getContainsListBrowser(ListBrowser lb)
1614 { if ( notNil(lb->dict) )
1615 answer(answerObject(ClassChain, lb->dict, EAV));
1616
1617 fail;
1618 }
1619
1620
1621 static Any
getMasterListBrowser(ListBrowser lb)1622 getMasterListBrowser(ListBrowser lb)
1623 { if ( instanceOfObject(lb->device, ClassBrowser) )
1624 answer(lb->device);
1625
1626 answer(lb);
1627 }
1628
1629 /*******************************
1630 * CLASS DECLARATION *
1631 *******************************/
1632
1633 /* Type declarations */
1634
1635 static char *T_scrollVertical[] =
1636 { "{forwards,backwards,goto}", "{file,page,line}", "int" };
1637 static char *T_showScrollBar[] =
1638 { "show=[bool]", "which=[scroll_bar]" };
1639 static char *T_changeSelection[] =
1640 { "action={set,toggle,extend,clear,cancel}",
1641 "context=[dict_item|chain]" };
1642 static char *T_initialise[] =
1643 { "dict=[dict]", "width=[int]", "height=[int]" };
1644 static char *T_style[] =
1645 { "style_name=name", "style=style" };
1646 static char *T_insertSelf[] =
1647 { "times=[int]", "character=[char]" };
1648 static char *T_xADintD_yADintD_widthADintD_heightADintD[] =
1649 { "x=[int]", "y=[int]", "width=[int]", "height=[int]" };
1650
1651 /* Instance Variables */
1652
1653 static vardecl var_listBrowser[] =
1654 { SV(NAME_dict, "dict*", IV_GET|IV_STORE, dictListBrowser,
1655 NAME_delegate, "Associated dict object (table of items)"),
1656 IV(NAME_image, "text_image", IV_GET,
1657 NAME_components, "TextImage used to display textlines"),
1658 IV(NAME_scrollBar, "scroll_bar", IV_GET,
1659 NAME_components, "Scrollbar used to scroll window"),
1660 IV(NAME_labelText, "text*", IV_GET,
1661 NAME_components, "Text object that displays the label"),
1662 SV(NAME_status, "{active,inactive}", IV_GET|IV_STORE, statusListBrowser,
1663 NAME_event, "Handle typing?"),
1664 IV(NAME_keyBinding, "key_binding", IV_BOTH,
1665 NAME_accelerator, "Key binding table"),
1666 SV(NAME_selection, "chain|member:dict_item*", IV_NONE|IV_STORE,
1667 selectionListBrowser,
1668 NAME_selection, "Selected items"),
1669 SV(NAME_selectionStyle, "[style]", IV_GET|IV_STORE,
1670 selectionStyleListBrowser,
1671 NAME_appearance, "Style for selection feedback"),
1672 SV(NAME_multipleSelection, "bool", IV_GET|IV_STORE, multipleSelectionListBrowser,
1673 NAME_selection, "If @on, multiple items may be selected"),
1674 IV(NAME_selectMessage, "code*", IV_BOTH,
1675 NAME_action, "Send on left-click on item"),
1676 IV(NAME_openMessage, "code*", IV_BOTH,
1677 NAME_action, "Send on keyboard selection or double click"),
1678 IV(NAME_cancelMessage, "code*", IV_BOTH,
1679 NAME_action, "Send on drag-select with `up' outside browser"),
1680 IV(NAME_popup, "popup*", IV_BOTH,
1681 NAME_menu, "Associated popup menu"),
1682 SV(NAME_font, "font", IV_GET|IV_STORE, fontListBrowser,
1683 NAME_appearance, "Font for displayed items"),
1684 IV(NAME_styles, "sheet", IV_GET,
1685 NAME_appearance, "Name --> style mapping"),
1686 IV(NAME_size, "characters=size", IV_GET,
1687 NAME_area, "Size in characters/lines"),
1688 IV(NAME_start, "int", IV_GET,
1689 NAME_scroll, "Object on top-row of display"),
1690 IV(NAME_searchOrigin, "int", IV_NONE,
1691 NAME_search, "Start of incremental search"),
1692 IV(NAME_searchHit, "int", IV_NONE,
1693 NAME_search, "Current hit"),
1694 IV(NAME_searchString, "char_array*", IV_NONE,
1695 NAME_search, "Current search string"),
1696 IV(NAME_caret, "int*", IV_NONE,
1697 NAME_keyboard, "Location for ->next_line"),
1698 IV(NAME_selectionOrigin, "int*", IV_NONE,
1699 NAME_keyboard, "Origin for ->change_selection: extend"),
1700 IV(NAME_startCell, "alien:Cell", IV_NONE,
1701 NAME_cache, "Cell reference to top-row of display")
1702 };
1703
1704 /* Send Methods */
1705
1706 static senddecl send_listBrowser[] =
1707 { SM(NAME_compute, 0, NULL, computeListBrowser,
1708 DEFAULT, "Recompute the image"),
1709 SM(NAME_geometry, 4, T_xADintD_yADintD_widthADintD_heightADintD, geometryListBrowser,
1710 DEFAULT, "Resize the text_image"),
1711 SM(NAME_initialise, 3, T_initialise, initialiseListBrowser,
1712 DEFAULT, "Create from dict, width and height"),
1713 SM(NAME_requestGeometry, 4, T_xADintD_yADintD_widthADintD_heightADintD, requestGeometryListBrowser,
1714 DEFAULT, "Map size to character units"),
1715 SM(NAME_unlink, 0, NULL, unlinkListBrowser,
1716 DEFAULT, "Unlink from dict and device"),
1717 SM(NAME_typed, 1, "event_id", typedListBrowser,
1718 NAME_accelerator, "Handle typed character"),
1719 SM(NAME_showLabel, 1, "show=bool", showLabelListBrowser,
1720 NAME_appearance, "Show/unshow the label"),
1721 SM(NAME_style, 2, T_style, styleListBrowser,
1722 NAME_appearance, "Set style associated with name"),
1723 SM(NAME_tabStops, 1, "vector*", tabStopsListBrowser,
1724 NAME_appearance, "Set tab-stops (pixels)"),
1725 SV(NAME_background, 1, "[colour|pixmap]", backgroundListBrowser,
1726 NAME_appearance, "Background colour"),
1727 SM(NAME_Size, 1, "pixels=size", SizeListBrowser,
1728 NAME_area, "Set size in pixels (trap window resize)"),
1729 SM(NAME_extendPrefixOrNext, 0, NULL, extendPrefixOrNextListBrowser,
1730 NAME_caret, "->extend_prefix or ->next"),
1731 SM(NAME_next, 0, NULL, nextListBrowser,
1732 NAME_caret, "Move caret to next item (`device ->advance')"),
1733 SM(NAME_reference, 1, "point", referenceListBrowser,
1734 NAME_dialogItem, "Set reference as dialog_item"),
1735 SM(NAME_clear, 0, NULL, clearListBrowser,
1736 NAME_edit, "Remove all items from the associated dict"),
1737 SM(NAME_WantsKeyboardFocus, 0, NULL, WantsKeyboardFocusListBrowser,
1738 NAME_event, "Test if ready to accept input (non-empty)"),
1739 SM(NAME_event, 1, "event", eventListBrowser,
1740 NAME_event, "Handle arbitrary event"),
1741 SM(NAME_label, 1, "name", labelListBrowser,
1742 NAME_label, "Set the name of the label"),
1743 SM(NAME_ChangeItem, 1, "dict_item", ChangeItemListBrowser,
1744 NAME_repaint, "Handle changed item from dict"),
1745 SM(NAME_Clear, 0, NULL, ClearListBrowser,
1746 NAME_repaint, "Handle clear from dict"),
1747 SM(NAME_DeleteItem, 1, "dict_item", DeleteItemListBrowser,
1748 NAME_repaint, "Handle deleted item from dict"),
1749 SM(NAME_InsertItem, 1, "dict_item", InsertItemListBrowser,
1750 NAME_repaint, "Handle inserted item from dict"),
1751 SM(NAME_normalise, 1, "member:dict_item", normaliseListBrowser,
1752 NAME_scroll, "Make specified item visible"),
1753 SM(NAME_scrollDown, 1, "[int]", scrollDownListBrowser,
1754 NAME_scroll, "Scroll lines down (default one window)"),
1755 SM(NAME_scrollTo, 1, "[int]", scrollToListBrowser,
1756 NAME_scroll, "Make nth-1 item start of window"),
1757 SM(NAME_scrollUp, 1, "[int]", scrollUpListBrowser,
1758 NAME_scroll, "Scroll lines up (default one window)"),
1759 SM(NAME_recenter, 1, "[int]", recenterListBrowser,
1760 NAME_scroll, "Recenter current line (to be implemented)"),
1761 SM(NAME_scrollVertical, 3, T_scrollVertical, scrollVerticalListBrowser,
1762 NAME_scroll, "Handle scroll_bar request"),
1763 SM(NAME_showScrollBar, 2, T_showScrollBar, showScrollBarListBrowser,
1764 NAME_scroll, "Control visibility of the <-scroll_bar"),
1765 SM(NAME_nextLine, 1, "[int]", nextLineListBrowser,
1766 NAME_selection, "Set selection to next item"),
1767 SM(NAME_previousLine, 1, "[int]", previousLineListBrowser,
1768 NAME_selection, "Set selection to previous item"),
1769 SM(NAME_backwardDeleteChar, 0, NULL, backwardDeleteCharListBrowser,
1770 NAME_search, "Undo last search extension"),
1771 SM(NAME_cancelSearch, 0, NULL, cancelSearchListBrowser,
1772 NAME_search, "Cancel the current search operation"),
1773 SM(NAME_enter, 0, NULL, enterListBrowser,
1774 NAME_search, "Select current item as double-click"),
1775 SM(NAME_extendPrefix, 0, NULL, extendPrefixListBrowser,
1776 NAME_search, "Extend search with common part"),
1777 SM(NAME_extendToCurrent, 0, NULL, extendToCurrentListBrowser,
1778 NAME_search, "Extend search to current item"),
1779 SM(NAME_insertSelf, 2, T_insertSelf, insertSelfListBrowser,
1780 NAME_search, "Start/Continue incremental search"),
1781 SM(NAME_keyboardQuit, 0, NULL, cancelSearchListBrowser,
1782 NAME_search, "Equivalent to ->cancel_search"),
1783 SM(NAME_repeatSearch, 0, NULL, repeatSearchListBrowser,
1784 NAME_search, "Repeat with same string"),
1785 SM(NAME_changeSelection, 2, T_changeSelection, changeSelectionListBrowser,
1786 NAME_selection, "Hook in selection management"),
1787 SM(NAME_deselect, 1, "member:dict_item", deselectListBrowser,
1788 NAME_selection, "Unselect (remove from selection) item"),
1789 SM(NAME_select, 1, "member:dict_item", selectListBrowser,
1790 NAME_selection, "Select (add to selection) item"),
1791 SM(NAME_selected, 1, "member:dict_item", selectedListBrowser,
1792 NAME_selection, "Test if item is selected")
1793 };
1794
1795 /* Get Methods */
1796
1797 static getdecl get_listBrowser[] =
1798 { GM(NAME_contains, 0, "chain", NULL, getContainsListBrowser,
1799 DEFAULT, "Dict visualised"),
1800 GM(NAME_master, 0, "device", NULL, getMasterListBrowser,
1801 DEFAULT, "Principal visual I'm part of (self or browser)"),
1802 GM(NAME_selection, 0, "chain|dict_item", NULL, getSelectionListBrowser,
1803 DEFAULT, "Current value of selection"),
1804 GM(NAME_showLabel, 0, "bool", NULL, getShowLabelListBrowser,
1805 NAME_appearance, "Bool indicating if label is visible"),
1806 GM(NAME_height, 0, "characters=int", NULL, getHeightListBrowser,
1807 NAME_area, "Height in character units"),
1808 GM(NAME_width, 0, "characters=int", NULL, getWidthListBrowser,
1809 NAME_area, "Width in character units"),
1810 GM(NAME_dictItem, 1, "dict_item", "event", getDictItemListBrowser,
1811 NAME_event, "DictItem on which event occurred"),
1812 GM(NAME_FetchFunction, 0, "alien:FetchFunction", NULL, getFetchFunctionListBrowser,
1813 NAME_internal, "Pointer to C-function to fetch char"),
1814 GM(NAME_MarginFunction, 0, "alien:MarginFunction", NULL, getMarginFunctionListBrowser,
1815 NAME_internal, "Pointer to C-function to fetch margins"),
1816 GM(NAME_RewindFunction, 0, "alien:RewindFunction", NULL, getRewindFunctionListBrowser,
1817 NAME_internal, "Pointer to C-function to rewind object"),
1818 GM(NAME_ScanFunction, 0, "alien:ScanFunction", NULL, getScanFunctionListBrowser,
1819 NAME_internal, "Pointer to C-function to scan for char-type"),
1820 GM(NAME_SeekFunction, 0, "alien:SeekFunction", NULL, getSeekFunctionListBrowser,
1821 NAME_internal, "Pointer to C-function to seek to position"),
1822 GM(NAME_label, 0, "name", NULL, getLabelListBrowser,
1823 NAME_label, "Current value of the label"),
1824 GM(NAME_member, 1, "dict_item", "any", getMemberListBrowser,
1825 NAME_member, "DictItem with given key"),
1826 GM(NAME_length, 0, "int", NULL, getLengthListBrowser,
1827 NAME_scroll, "Length of contents (for scroll_bar)"),
1828 GM(NAME_view, 0, "int", NULL, getViewListBrowser,
1829 NAME_scroll, "Length of view (for scroll_bar)")
1830 };
1831
1832 /* Resources */
1833
1834 static classvardecl rc_listBrowser[] =
1835 { RC(NAME_background, "colour|pixmap", "white",
1836 "Colour/fill pattern of the background"),
1837 RC(NAME_clearSelectionOnSearch, "bool", "@on",
1838 "@on: clear selection when searching"),
1839 RC(NAME_cursor, "cursor", "right_ptr",
1840 "Default cursor"),
1841 RC(NAME_font, "font", "normal",
1842 "Default font"),
1843 RC(NAME_isearchStyle, "[style]",
1844 UXWIN("when(@colour_display,\n"
1845 " style(background := green),\n"
1846 " style(background:= @grey25_image))",
1847 "@_isearch_style"),
1848 "Style for incremental search"),
1849 RC(NAME_labelFont, "font", "bold",
1850 "Font used to display the label"),
1851 RC(NAME_pen, "0..", "1",
1852 "Thickness of box around list_browser"),
1853 RC(NAME_searchIgnoreCase, "bool", "@on",
1854 "@on: ignore case when searching"),
1855 RC(NAME_selectionStyle, "[style]",
1856 UXWIN("when(@colour_display,\n"
1857 " style(background := black, colour := white),\n"
1858 " style(highlight := @on))",
1859 "@_select_style"),
1860 "Style object for <-selection"),
1861 RC(NAME_size, "size", "size(15,10)",
1862 "Default size in `characters x lines'")
1863 };
1864
1865 /* Class Declaration */
1866
1867 static Name listBrowser_termnames[] = { NAME_dict, NAME_width, NAME_height };
1868
1869 ClassDecl(listBrowser_decls,
1870 var_listBrowser, send_listBrowser, get_listBrowser, rc_listBrowser,
1871 3, listBrowser_termnames,
1872 "$Rev$");
1873
1874
1875 status
makeClassListBrowser(Class class)1876 makeClassListBrowser(Class class)
1877 { declareClass(class, &listBrowser_decls);
1878
1879 setLoadStoreFunctionClass(class, loadListBrowser, storeListBrowser);
1880 setRedrawFunctionClass(class, RedrawAreaListBrowser);
1881 delegateClass(class, NAME_dict);
1882
1883 succeed;
1884 }
1885
1886