Mercurial > kinput2.yaz
comparison lib/CandPanel.c @ 0:92745d501b9a
initial import from kinput2-v3.1
author | Yoshiki Yazawa <yaz@honeyplanet.jp> |
---|---|
date | Mon, 08 Mar 2010 04:44:30 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:92745d501b9a |
---|---|
1 #ifndef lint | |
2 static char *rcsid = "$Id: CandPanel.c,v 1.11 1994/04/22 04:26:22 ishisone Rel $"; | |
3 #endif | |
4 /* | |
5 * Copyright (c) 1990 Software Research Associates, Inc. | |
6 * | |
7 * Permission to use, copy, modify, and distribute this software and its | |
8 * documentation for any purpose and without fee is hereby granted, provided | |
9 * that the above copyright notice appear in all copies and that both that | |
10 * copyright notice and this permission notice appear in supporting | |
11 * documentation, and that the name of Software Research Associates not be | |
12 * used in advertising or publicity pertaining to distribution of the | |
13 * software without specific, written prior permission. Software Research | |
14 * Associates makes no representations about the suitability of this software | |
15 * for any purpose. It is provided "as is" without express or implied | |
16 * warranty. | |
17 * | |
18 * Author: Makoto Ishisone, Software Research Associates, Inc., Japan | |
19 */ | |
20 | |
21 #include <X11/IntrinsicP.h> | |
22 #include <X11/StringDefs.h> | |
23 #include "CandPanelP.h" | |
24 #include "ConvDisp.h" | |
25 | |
26 static XtResource resources[] = { | |
27 #define offset(field) XtOffset(CandidatePanelWidget, cpanel.field) | |
28 { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), | |
29 offset(foreground), XtRString, XtDefaultForeground }, | |
30 { XtNhorizontalSpacing, XtCSpacing, XtRDimension, sizeof(Dimension), | |
31 offset(hspace), XtRString, "6" }, | |
32 { XtNverticalSpacing, XtCSpacing, XtRDimension, sizeof(Dimension), | |
33 offset(vspace), XtRString, "4" }, | |
34 { XtNlist, XtCList, XtRPointer, sizeof(ICString*), | |
35 offset(list), XtRImmediate, NULL }, | |
36 { XtNnumStrings, XtCNumStrings, XtRInt, sizeof(int), | |
37 offset(nstrings), XtRImmediate, 0 }, | |
38 { XtNdefaultWidth, XtCDefaultWidth, XtRDimension, sizeof(Dimension), | |
39 offset(defaultwidth), XtRString, "400" }, | |
40 { XtNcurrentItem, XtCCurrentItem, XtRInt, sizeof(int), | |
41 offset(current), XtRImmediate, 0 }, | |
42 { XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor), | |
43 offset(cursor), XtRImmediate, (XtPointer)None }, | |
44 { XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer), | |
45 offset(callback), XtRCallback, NULL }, | |
46 #undef offset | |
47 }; | |
48 | |
49 static void Move(/* Widget, XEvent*, String*, Cardinal* */); | |
50 static void Set(/* Widget, XEvent*, String*, Cardinal* */); | |
51 static void Notify(/* Widget, XEvent*, String*, Cardinal* */); | |
52 | |
53 static XtActionsRec actions[] = { | |
54 { "move", Move }, | |
55 { "set", Set }, | |
56 { "select", Notify }, | |
57 }; | |
58 | |
59 static char translations[] = | |
60 "<Btn1Down>: set() select()\n\ | |
61 <Key>Up: move(up)\n\ | |
62 <Key>Down: move(down)\n\ | |
63 <Key>Left: move(left)\n\ | |
64 <Key>Right: move(right)"; | |
65 | |
66 static void Initialize(), Destroy(); | |
67 static void Realize(); | |
68 static void Redisplay(); | |
69 static void Resize(); | |
70 static Boolean SetValues(); | |
71 static XtGeometryResult QueryGeometry(); | |
72 static void InsertChild(); | |
73 | |
74 static void GetInvGC(); | |
75 static int MaxWidth(); | |
76 static void ComputeSize(); | |
77 static void Layout(); | |
78 static void ToggleHighlight(); | |
79 | |
80 static CompositeClassExtensionRec CompositeExtension = { | |
81 /* next_extension */ NULL, | |
82 /* record_type */ NULLQUARK, | |
83 /* version */ XtCompositeExtensionVersion, | |
84 /* record_size */ sizeof(CompositeClassExtensionRec), | |
85 /* accept_objects */ True, | |
86 }; | |
87 | |
88 CandidatePanelClassRec candidatePanelClassRec = { | |
89 { /* core fields */ | |
90 /* superclass */ (WidgetClass) &compositeClassRec, | |
91 /* class_name */ "CandidatePanel", | |
92 /* widget_size */ sizeof(CandidatePanelRec), | |
93 /* class_initialize */ NULL, | |
94 /* class_part_initialize */ NULL, | |
95 /* class_inited */ FALSE, | |
96 /* initialize */ Initialize, | |
97 /* initialize_hook */ NULL, | |
98 /* realize */ Realize, | |
99 /* actions */ actions, | |
100 /* num_actions */ XtNumber(actions), | |
101 /* resources */ resources, | |
102 /* num_resources */ XtNumber(resources), | |
103 /* xrm_class */ NULLQUARK, | |
104 /* compress_motion */ TRUE, | |
105 /* compress_exposure */ TRUE, | |
106 /* compress_enterleave */ TRUE, | |
107 /* visible_interest */ FALSE, | |
108 /* destroy */ Destroy, | |
109 /* resize */ Resize, | |
110 /* expose */ Redisplay, | |
111 /* set_values */ SetValues, | |
112 /* set_values_hook */ NULL, | |
113 /* set_values_almost */ XtInheritSetValuesAlmost, | |
114 /* get_values_hook */ NULL, | |
115 /* accept_focus */ NULL, | |
116 /* version */ XtVersion, | |
117 /* callback_private */ NULL, | |
118 /* tm_table */ translations, | |
119 /* query_geometry */ QueryGeometry, | |
120 /* display_accelerator */ XtInheritDisplayAccelerator, | |
121 /* extension */ NULL | |
122 }, | |
123 { /* composite fields */ | |
124 /* geometry_manager */ NULL, | |
125 /* change_managed */ NULL, | |
126 /* insert_child */ InsertChild, | |
127 /* delete_child */ XtInheritDeleteChild, | |
128 /* extension */ (XtPointer)&CompositeExtension, | |
129 }, | |
130 { /* candidatepanel fields */ | |
131 /* empty */ 0 | |
132 } | |
133 }; | |
134 | |
135 WidgetClass candidatePanelWidgetClass = (WidgetClass)&candidatePanelClassRec; | |
136 | |
137 /* ARGSUSED */ | |
138 static void | |
139 Initialize(req, new, args, num_args) | |
140 Widget req; | |
141 Widget new; | |
142 ArgList args; | |
143 Cardinal *num_args; | |
144 { | |
145 CandidatePanelWidget cpw = (CandidatePanelWidget)new; | |
146 | |
147 cpw->cpanel.displayobj = NULL; | |
148 GetInvGC(cpw); | |
149 } | |
150 | |
151 static void | |
152 Destroy(w) | |
153 Widget w; | |
154 { | |
155 CandidatePanelWidget cpw = (CandidatePanelWidget)w; | |
156 | |
157 if (cpw->cpanel.invgc != NULL) XtReleaseGC(w, cpw->cpanel.invgc); | |
158 } | |
159 | |
160 static void | |
161 Realize(w, mask, value) | |
162 Widget w; | |
163 XtValueMask *mask; | |
164 XSetWindowAttributes *value; | |
165 { | |
166 CandidatePanelWidget cpw = (CandidatePanelWidget)w; | |
167 CompositeWidgetClass super = (CompositeWidgetClass)XtClass(w)->core_class.superclass; | |
168 String params[1]; | |
169 Cardinal num_params; | |
170 | |
171 if (cpw->cpanel.displayobj == NULL) { | |
172 params[0] = XtClass(w)->core_class.class_name; | |
173 num_params = 1; | |
174 XtAppErrorMsg(XtWidgetToApplicationContext(w), | |
175 "childError", "number", "WidgetError", | |
176 "%s: has no child (ConvDisplayObject)", | |
177 params, &num_params); | |
178 } | |
179 | |
180 if (cpw->cpanel.cursor != None) { | |
181 *mask |= CWCursor; | |
182 value->cursor = cpw->cpanel.cursor; | |
183 } | |
184 | |
185 (*super->core_class.realize)(w, mask, value); | |
186 } | |
187 | |
188 /* ARGSUSED */ | |
189 static void | |
190 Redisplay(w, ev, region) | |
191 Widget w; | |
192 XEvent *ev; | |
193 Region region; | |
194 { | |
195 CandidatePanelWidget cpw = (CandidatePanelWidget)w; | |
196 Widget dispobj = cpw->cpanel.displayobj; | |
197 XExposeEvent *event = (XExposeEvent *)ev; | |
198 ICString *list = cpw->cpanel.list; | |
199 int cwidth, cheight, hspace, vspace; | |
200 int c0, c1, r0, r1; | |
201 int row, col; | |
202 int idx; | |
203 int x, y; | |
204 | |
205 if (list == NULL || dispobj == NULL) return; | |
206 | |
207 cwidth = cpw->cpanel.maxwidth; | |
208 cheight = cpw->cpanel.fontheight; | |
209 hspace = cpw->cpanel.hspace; | |
210 vspace = cpw->cpanel.vspace; | |
211 | |
212 c0 = (event->x + hspace - hspace / 2) / (cwidth + hspace); | |
213 c1 = (event->x + event->width - 1 - hspace / 2) / (cwidth + hspace) + 1; | |
214 if (c1 > cpw->cpanel.ncolumns) c1 = cpw->cpanel.ncolumns; | |
215 | |
216 r0 = (event->y + vspace - vspace / 2) / (cheight + vspace); | |
217 r1 = (event->y + event->height - 1 - vspace / 2) / (cheight + vspace) + 1; | |
218 if (r1 > cpw->cpanel.nrows) r1 = cpw->cpanel.nrows; | |
219 | |
220 for (row = r0; row < r1; row++) { | |
221 y = (cheight + vspace) * row + vspace / 2; | |
222 for (col = c0; col < c1; col++) { | |
223 x = (cwidth + hspace) * col + hspace / 2; | |
224 idx = row * cpw->cpanel.ncolumns + col; | |
225 if (idx >= cpw->cpanel.nstrings) return; | |
226 if (idx == cpw->cpanel.current) { | |
227 XClearArea(XtDisplay(w), XtWindow(w), x, y, | |
228 (unsigned int)cwidth, (unsigned int)cheight, | |
229 False); | |
230 } | |
231 CDDrawString(dispobj, w, list + idx, 0, -1, x, y); | |
232 if (idx == cpw->cpanel.current) { | |
233 ToggleHighlight(cpw, idx); | |
234 } | |
235 } | |
236 } | |
237 } | |
238 | |
239 static void | |
240 Resize(w) | |
241 Widget w; | |
242 { | |
243 CandidatePanelWidget cpw = (CandidatePanelWidget)w; | |
244 | |
245 Layout(cpw, False, False); | |
246 } | |
247 | |
248 /* ARGSUSED */ | |
249 static Boolean | |
250 SetValues(cur, req, wid, args, num_args) | |
251 Widget cur; | |
252 Widget req; | |
253 Widget wid; | |
254 ArgList args; | |
255 Cardinal *num_args; | |
256 { | |
257 CandidatePanelWidget old = (CandidatePanelWidget)cur; | |
258 CandidatePanelWidget new = (CandidatePanelWidget)wid; | |
259 Boolean redisplay = False; | |
260 Boolean listspecified = False; | |
261 int i; | |
262 | |
263 if (new->cpanel.displayobj == NULL) return False; | |
264 | |
265 for (i = 0; i < *num_args; i++) { | |
266 if (!strcmp(args[i].name, XtNlist)) { | |
267 listspecified = True; | |
268 break; | |
269 } | |
270 } | |
271 | |
272 if (new->cpanel.foreground != old->cpanel.foreground || | |
273 new->core.background_pixel != old->core.background_pixel) { | |
274 XtVaSetValues(new->cpanel.displayobj, | |
275 XtNforeground, new->cpanel.foreground, | |
276 XtNbackground, new->core.background_pixel, | |
277 NULL); | |
278 redisplay = True; | |
279 } | |
280 | |
281 if (listspecified || | |
282 new->cpanel.list != old->cpanel.list || | |
283 new->cpanel.nstrings != old->cpanel.nstrings) { | |
284 /* compute maximum pixel width of the list items */ | |
285 new->cpanel.maxwidth = MaxWidth(new); | |
286 } | |
287 | |
288 if (listspecified || | |
289 new->cpanel.list != old->cpanel.list || | |
290 new->cpanel.nstrings != old->cpanel.nstrings || | |
291 new->cpanel.hspace != old->cpanel.hspace || | |
292 new->cpanel.vspace != old->cpanel.vspace || | |
293 new->cpanel.defaultwidth != old->cpanel.defaultwidth) { | |
294 Layout(new, True, True); | |
295 redisplay = True; | |
296 } | |
297 | |
298 if (new->cpanel.current != old->cpanel.current && | |
299 !redisplay && XtIsRealized(wid)) { | |
300 ToggleHighlight(new, old->cpanel.current); | |
301 ToggleHighlight(new, new->cpanel.current); | |
302 } | |
303 | |
304 if (new->cpanel.cursor != old->cpanel.cursor && XtIsRealized(wid)) { | |
305 XDefineCursor(XtDisplay(wid), XtWindow(wid), new->cpanel.cursor); | |
306 } | |
307 | |
308 return redisplay; | |
309 } | |
310 | |
311 static XtGeometryResult | |
312 QueryGeometry(w, req, ret) | |
313 Widget w; | |
314 XtWidgetGeometry *req; | |
315 XtWidgetGeometry *ret; | |
316 { | |
317 Dimension width, height; | |
318 Dimension owidth, oheight; | |
319 | |
320 ret->request_mode = 0; | |
321 | |
322 if ((req->request_mode & (CWWidth | CWHeight)) == 0) return XtGeometryYes; | |
323 | |
324 width = (req->request_mode & CWWidth) ? req->width : w->core.width; | |
325 height = (req->request_mode & CWHeight) ? req->height : w->core.height; | |
326 | |
327 owidth = width; | |
328 oheight = height; | |
329 ComputeSize((CandidatePanelWidget)w, | |
330 (req->request_mode & CWWidth) != 0, | |
331 (req->request_mode & CWHeight) != 0, | |
332 &width, &height); | |
333 ret->request_mode = CWWidth | CWHeight; | |
334 ret->width = width; | |
335 ret->height = height; | |
336 | |
337 if (width != owidth || height != oheight) return XtGeometryAlmost; | |
338 | |
339 return XtGeometryYes; | |
340 } | |
341 | |
342 static void | |
343 InsertChild(w) | |
344 Widget w; | |
345 { | |
346 CandidatePanelWidget cpw = (CandidatePanelWidget)XtParent(w); | |
347 CompositeWidgetClass super = (CompositeWidgetClass)XtClass(cpw)->core_class.superclass; | |
348 String params[1]; | |
349 Cardinal num_params; | |
350 | |
351 if (!XtIsSubclass(w, convDisplayObjectClass)) { | |
352 params[0] = XtClass(cpw)->core_class.class_name; | |
353 num_params = 1; | |
354 XtAppErrorMsg(XtWidgetToApplicationContext(w), | |
355 "childError", "class", "WidgetError", | |
356 "%s: child must be subclass of ConvDisplayObject", | |
357 params, &num_params); | |
358 } | |
359 if (cpw->composite.num_children != 0) { | |
360 params[0] = XtClass(cpw)->core_class.class_name; | |
361 num_params = 1; | |
362 XtAppErrorMsg(XtWidgetToApplicationContext(w), | |
363 "childError", "number", "WidgetError", | |
364 "%s: can only take one child", | |
365 params, &num_params); | |
366 } | |
367 | |
368 (*super->composite_class.insert_child)(w); | |
369 | |
370 cpw->cpanel.displayobj = w; | |
371 cpw->cpanel.fontheight = CDLineHeight(w, (Position *)NULL); | |
372 | |
373 #ifdef notdef | |
374 { | |
375 Pixel fg, bg; | |
376 XtVaGetValues(w, XtNforeground, &fg, XtNbackground, &bg, NULL); | |
377 GetInvGC(cpw, fg, bg); | |
378 } | |
379 #endif | |
380 | |
381 if (cpw->cpanel.list != NULL) { | |
382 cpw->cpanel.maxwidth = MaxWidth(cpw); | |
383 Layout(cpw, cpw->core.width == 0, cpw->core.height == 0); | |
384 } | |
385 } | |
386 | |
387 static void | |
388 GetInvGC(cpw) | |
389 CandidatePanelWidget cpw; | |
390 { | |
391 XGCValues values; | |
392 | |
393 values.function = GXinvert; | |
394 values.plane_mask = cpw->cpanel.foreground ^ cpw->core.background_pixel; | |
395 cpw->cpanel.invgc = XtGetGC((Widget)cpw, GCFunction|GCPlaneMask, &values); | |
396 } | |
397 | |
398 /* ARGSUSED */ | |
399 static void | |
400 Move(w, ev, args, num_args) | |
401 Widget w; | |
402 XEvent *ev; | |
403 String *args; | |
404 Cardinal *num_args; | |
405 { | |
406 int dir; | |
407 | |
408 if (*num_args < 1) return; | |
409 | |
410 if (!strcmp(*args, "left") || !strcmp(*args, "Left")) { | |
411 dir = ICMoveLeft; | |
412 } else if (!strcmp(*args, "right") || !strcmp(*args, "Right")) { | |
413 dir = ICMoveRight; | |
414 } else if (!strcmp(*args, "up") || !strcmp(*args, "Up")) { | |
415 dir = ICMoveUp; | |
416 } else if (!strcmp(*args, "down") || !strcmp(*args, "Down")) { | |
417 dir = ICMoveDown; | |
418 } else { | |
419 XtAppWarning(XtWidgetToApplicationContext(w), | |
420 "CandidatePanel: unknown direction"); | |
421 return; | |
422 } | |
423 | |
424 CPanelMoveCurrent(w, dir); | |
425 } | |
426 | |
427 /* ARGSUSED */ | |
428 static void | |
429 Set(w, ev, args, num_args) | |
430 Widget w; | |
431 XEvent *ev; | |
432 String *args; | |
433 Cardinal *num_args; | |
434 { | |
435 CandidatePanelWidget cpw = (CandidatePanelWidget)w; | |
436 XButtonEvent *event = (XButtonEvent *)ev; | |
437 int cwidth, cheight, hspace, vspace; | |
438 int x, y; | |
439 int row, col; | |
440 int newidx; | |
441 | |
442 cwidth = cpw->cpanel.maxwidth; | |
443 cheight = cpw->cpanel.fontheight; | |
444 hspace = cpw->cpanel.hspace; | |
445 vspace = cpw->cpanel.vspace; | |
446 | |
447 x = event->x - hspace / 2; | |
448 col = x / (cwidth + hspace); | |
449 if (col >= cpw->cpanel.ncolumns || (x % (cwidth + hspace)) > cwidth) return; | |
450 | |
451 y = event->y - vspace / 2; | |
452 row = y / (cheight + vspace); | |
453 if (row >= cpw->cpanel.nrows || (y % (cheight + vspace)) > cheight) return; | |
454 | |
455 newidx = col + cpw->cpanel.ncolumns * row; | |
456 if (newidx >= cpw->cpanel.nstrings) return; | |
457 | |
458 CPanelSetCurrent(w, newidx); | |
459 } | |
460 | |
461 /* ARGSUSED */ | |
462 static void | |
463 Notify(w, ev, args, num_args) | |
464 Widget w; | |
465 XEvent *ev; | |
466 String *args; | |
467 Cardinal *num_args; | |
468 { | |
469 CandidatePanelWidget cpw = (CandidatePanelWidget)w; | |
470 | |
471 XtCallCallbackList(w, cpw->cpanel.callback, | |
472 (XtPointer)cpw->cpanel.current); | |
473 } | |
474 | |
475 static int | |
476 MaxWidth(cpw) | |
477 CandidatePanelWidget cpw; | |
478 { | |
479 Widget dispobj = cpw->cpanel.displayobj; | |
480 ICString *list = cpw->cpanel.list; | |
481 int maxwidth; | |
482 int i; | |
483 | |
484 maxwidth = 0; | |
485 for (i = 0; i < cpw->cpanel.nstrings; i++) { | |
486 int w = CDStringWidth(dispobj, list + i, 0, -1); | |
487 if (w > maxwidth) maxwidth = w; | |
488 } | |
489 | |
490 return maxwidth; | |
491 } | |
492 | |
493 static void | |
494 ComputeSize(cpw, resizex, resizey, width_inout, height_inout) | |
495 CandidatePanelWidget cpw; | |
496 int resizex; | |
497 int resizey; | |
498 Dimension *width_inout; | |
499 Dimension *height_inout; | |
500 { | |
501 int nrows, ncolumns; | |
502 int width, height; | |
503 | |
504 if (cpw->cpanel.displayobj == NULL || cpw->cpanel.nstrings == 0) return; | |
505 | |
506 width = *width_inout; | |
507 height = *height_inout; | |
508 | |
509 if (resizex) { | |
510 if (resizey) { | |
511 int maxheight = HeightOfScreen(XtScreen((Widget)cpw)); | |
512 | |
513 /* use defaultwidth */ | |
514 ncolumns = cpw->cpanel.defaultwidth / | |
515 (cpw->cpanel.maxwidth + cpw->cpanel.hspace); | |
516 if (ncolumns > cpw->cpanel.nstrings) ncolumns = cpw->cpanel.nstrings; | |
517 if (ncolumns <= 0) ncolumns = 1; | |
518 nrows = (cpw->cpanel.nstrings + ncolumns - 1) / ncolumns; | |
519 width = (cpw->cpanel.maxwidth + cpw->cpanel.hspace) * ncolumns; | |
520 height = (cpw->cpanel.fontheight + cpw->cpanel.vspace) * nrows; | |
521 /* | |
522 * If the computed height exceeds display height, | |
523 * expand width so that the entire window fits into the display. | |
524 */ | |
525 if (height > maxheight) { | |
526 /* compute maximum number of rows */ | |
527 nrows = maxheight / (cpw->cpanel.fontheight + cpw->cpanel.vspace); | |
528 if (nrows <= 0) nrows = 1; | |
529 ncolumns = (cpw->cpanel.nstrings + nrows - 1) / nrows; | |
530 if (ncolumns > cpw->cpanel.nstrings) { | |
531 ncolumns = cpw->cpanel.nstrings; | |
532 } | |
533 /* re-compute correct number of rows */ | |
534 nrows = (cpw->cpanel.nstrings + ncolumns - 1) / ncolumns; | |
535 width = (cpw->cpanel.maxwidth + cpw->cpanel.hspace) * ncolumns; | |
536 height = (cpw->cpanel.fontheight + cpw->cpanel.vspace) * nrows; | |
537 } | |
538 } else { | |
539 /* use specified height */ | |
540 nrows = height / (cpw->cpanel.fontheight + cpw->cpanel.vspace); | |
541 if (nrows <= 0) nrows = 1; | |
542 ncolumns = (cpw->cpanel.nstrings + nrows - 1) / nrows; | |
543 if (ncolumns > cpw->cpanel.nstrings) ncolumns = cpw->cpanel.nstrings; | |
544 width = (cpw->cpanel.maxwidth + cpw->cpanel.hspace) * ncolumns; | |
545 } | |
546 } else { | |
547 ncolumns = width / (cpw->cpanel.maxwidth + cpw->cpanel.hspace); | |
548 if (ncolumns <= 0) ncolumns = 1; | |
549 nrows = (cpw->cpanel.nstrings + ncolumns - 1) / ncolumns; | |
550 if (resizey) { | |
551 height = (cpw->cpanel.fontheight + cpw->cpanel.vspace) * nrows; | |
552 } | |
553 } | |
554 cpw->cpanel.ncolumns = ncolumns; | |
555 cpw->cpanel.nrows = nrows; | |
556 *width_inout = width; | |
557 *height_inout = height; | |
558 } | |
559 | |
560 static void | |
561 Layout(cpw, resizex, resizey) | |
562 CandidatePanelWidget cpw; | |
563 int resizex; | |
564 int resizey; | |
565 { | |
566 Dimension width, height; | |
567 Dimension owidth, oheight; | |
568 XtGeometryResult re; | |
569 | |
570 if (cpw->cpanel.displayobj == NULL) return; | |
571 | |
572 width = cpw->core.width; | |
573 height = cpw->core.height; | |
574 ComputeSize(cpw, resizex, resizey, &width, &height); | |
575 | |
576 if (width != cpw->core.width || height != cpw->core.height) { | |
577 owidth = width; | |
578 oheight = height; | |
579 re = XtMakeResizeRequest((Widget)cpw, owidth, oheight, &width, &height); | |
580 switch (re) { | |
581 case XtGeometryYes: | |
582 /* no problem */ | |
583 break; | |
584 case XtGeometryNo: | |
585 width = cpw->core.width; | |
586 height = cpw->core.height; | |
587 ComputeSize(cpw, False, False, &width, &height); | |
588 break; | |
589 case XtGeometryAlmost: | |
590 ComputeSize(cpw, | |
591 width != owidth, | |
592 height != oheight, | |
593 &width, &height); | |
594 re = XtMakeResizeRequest((Widget)cpw, width, height, &width, &height); | |
595 switch (re) { | |
596 case XtGeometryYes: | |
597 break; | |
598 case XtGeometryNo: | |
599 width = cpw->core.width; | |
600 height = cpw->core.height; | |
601 ComputeSize(cpw, False, False, &width, &height); | |
602 break; | |
603 case XtGeometryAlmost: | |
604 ComputeSize(cpw, False, False, &width, &height); | |
605 (void)XtMakeResizeRequest((Widget)cpw, width, height, &width, &height); | |
606 } | |
607 } | |
608 } | |
609 } | |
610 | |
611 static void | |
612 ToggleHighlight(cpw, idx) | |
613 CandidatePanelWidget cpw; | |
614 int idx; | |
615 { | |
616 int row, col; | |
617 int x, y; | |
618 int width; | |
619 | |
620 if (idx < 0 || cpw->cpanel.nstrings <= idx) return; | |
621 | |
622 col = idx % cpw->cpanel.ncolumns; | |
623 row = idx / cpw->cpanel.ncolumns; | |
624 x = (cpw->cpanel.maxwidth + cpw->cpanel.hspace) * col + | |
625 cpw->cpanel.hspace / 2; | |
626 y = (cpw->cpanel.fontheight + cpw->cpanel.vspace) * row + | |
627 cpw->cpanel.vspace / 2; | |
628 width = CDStringWidth(cpw->cpanel.displayobj, cpw->cpanel.list + idx, | |
629 0, -1); | |
630 | |
631 XFillRectangle(XtDisplay(cpw), XtWindow(cpw), cpw->cpanel.invgc, x, y, | |
632 (unsigned int)width, (unsigned int)cpw->cpanel.fontheight); | |
633 } | |
634 | |
635 | |
636 /* | |
637 * Public Functions | |
638 */ | |
639 | |
640 void | |
641 CPanelSetList(w, list, nstrings, current, resize) | |
642 Widget w; | |
643 ICString *list; | |
644 int nstrings; | |
645 int current; | |
646 int resize; | |
647 { | |
648 CandidatePanelWidget cpw = (CandidatePanelWidget)w; | |
649 | |
650 if (list != NULL) { | |
651 cpw->cpanel.list = list; | |
652 cpw->cpanel.nstrings = nstrings; | |
653 if (current < 0) current = 0; | |
654 if (current >= nstrings) current = nstrings - 1; | |
655 cpw->cpanel.current = current; | |
656 } | |
657 | |
658 if (cpw->cpanel.displayobj == NULL) return; | |
659 | |
660 cpw->cpanel.fontheight = CDLineHeight(cpw->cpanel.displayobj, | |
661 (Position *)NULL); | |
662 /* compute maximum pixel width of the list items */ | |
663 cpw->cpanel.maxwidth = MaxWidth(cpw); | |
664 Layout(cpw, resize, resize); | |
665 | |
666 if (XtIsRealized(w)) XClearWindow(XtDisplay(w), XtWindow(w)); | |
667 } | |
668 | |
669 void | |
670 CPanelSetCurrent(w, idx) | |
671 Widget w; | |
672 int idx; | |
673 { | |
674 CandidatePanelWidget cpw = (CandidatePanelWidget)w; | |
675 | |
676 if (idx < 0 || cpw->cpanel.nstrings <= idx) return; | |
677 | |
678 if (idx == cpw->cpanel.current) return; | |
679 | |
680 if (cpw->cpanel.displayobj != NULL && XtIsRealized(w)) { | |
681 ToggleHighlight(cpw, cpw->cpanel.current); | |
682 ToggleHighlight(cpw, idx); | |
683 } | |
684 cpw->cpanel.current = idx; | |
685 } | |
686 | |
687 void | |
688 CPanelMoveCurrent(w, dir) | |
689 Widget w; | |
690 int dir; | |
691 { | |
692 CandidatePanelWidget cpw = (CandidatePanelWidget)w; | |
693 int newidx; | |
694 int row, col; | |
695 int nstrings = cpw->cpanel.nstrings; | |
696 | |
697 if (nstrings <= 0) return; | |
698 | |
699 col = cpw->cpanel.current % cpw->cpanel.ncolumns; | |
700 row = cpw->cpanel.current / cpw->cpanel.ncolumns; | |
701 | |
702 switch (dir) { | |
703 case ICMoveLeft: | |
704 if ((newidx = cpw->cpanel.current - 1) < 0) newidx = nstrings - 1; | |
705 break; | |
706 case ICMoveRight: | |
707 if ((newidx = cpw->cpanel.current + 1) >= nstrings) newidx = 0; | |
708 break; | |
709 case ICMoveUp: | |
710 case ICMovePrevPage: | |
711 if (--row < 0) row = cpw->cpanel.nrows - 1; | |
712 newidx = row * cpw->cpanel.ncolumns + col; | |
713 if (newidx >= nstrings) newidx -= cpw->cpanel.ncolumns; | |
714 break; | |
715 case ICMoveDown: | |
716 case ICMoveNextPage: | |
717 if (++row >= cpw->cpanel.nrows) row = 0; | |
718 newidx = row * cpw->cpanel.ncolumns + col; | |
719 if (newidx >= nstrings) newidx = col; | |
720 break; | |
721 case ICMoveLeftMost: | |
722 newidx = row * cpw->cpanel.ncolumns; | |
723 break; | |
724 case ICMoveRightMost: | |
725 newidx = (row + 1) * cpw->cpanel.ncolumns - 1; | |
726 if (newidx >= cpw->cpanel.nstrings) newidx = cpw->cpanel.nstrings - 1; | |
727 break; | |
728 case ICMoveFirst: | |
729 newidx = 0; | |
730 break; | |
731 case ICMoveLast: | |
732 newidx = cpw->cpanel.nstrings - 1; | |
733 break; | |
734 } | |
735 | |
736 CPanelSetCurrent(w, newidx); | |
737 } |