Mercurial > kinput2.yaz
view 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 |
line wrap: on
line source
#ifndef lint static char *rcsid = "$Id: CandPanel.c,v 1.11 1994/04/22 04:26:22 ishisone Rel $"; #endif /* * Copyright (c) 1990 Software Research Associates, Inc. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Software Research Associates not be * used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. Software Research * Associates makes no representations about the suitability of this software * for any purpose. It is provided "as is" without express or implied * warranty. * * Author: Makoto Ishisone, Software Research Associates, Inc., Japan */ #include <X11/IntrinsicP.h> #include <X11/StringDefs.h> #include "CandPanelP.h" #include "ConvDisp.h" static XtResource resources[] = { #define offset(field) XtOffset(CandidatePanelWidget, cpanel.field) { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), offset(foreground), XtRString, XtDefaultForeground }, { XtNhorizontalSpacing, XtCSpacing, XtRDimension, sizeof(Dimension), offset(hspace), XtRString, "6" }, { XtNverticalSpacing, XtCSpacing, XtRDimension, sizeof(Dimension), offset(vspace), XtRString, "4" }, { XtNlist, XtCList, XtRPointer, sizeof(ICString*), offset(list), XtRImmediate, NULL }, { XtNnumStrings, XtCNumStrings, XtRInt, sizeof(int), offset(nstrings), XtRImmediate, 0 }, { XtNdefaultWidth, XtCDefaultWidth, XtRDimension, sizeof(Dimension), offset(defaultwidth), XtRString, "400" }, { XtNcurrentItem, XtCCurrentItem, XtRInt, sizeof(int), offset(current), XtRImmediate, 0 }, { XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor), offset(cursor), XtRImmediate, (XtPointer)None }, { XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer), offset(callback), XtRCallback, NULL }, #undef offset }; static void Move(/* Widget, XEvent*, String*, Cardinal* */); static void Set(/* Widget, XEvent*, String*, Cardinal* */); static void Notify(/* Widget, XEvent*, String*, Cardinal* */); static XtActionsRec actions[] = { { "move", Move }, { "set", Set }, { "select", Notify }, }; static char translations[] = "<Btn1Down>: set() select()\n\ <Key>Up: move(up)\n\ <Key>Down: move(down)\n\ <Key>Left: move(left)\n\ <Key>Right: move(right)"; static void Initialize(), Destroy(); static void Realize(); static void Redisplay(); static void Resize(); static Boolean SetValues(); static XtGeometryResult QueryGeometry(); static void InsertChild(); static void GetInvGC(); static int MaxWidth(); static void ComputeSize(); static void Layout(); static void ToggleHighlight(); static CompositeClassExtensionRec CompositeExtension = { /* next_extension */ NULL, /* record_type */ NULLQUARK, /* version */ XtCompositeExtensionVersion, /* record_size */ sizeof(CompositeClassExtensionRec), /* accept_objects */ True, }; CandidatePanelClassRec candidatePanelClassRec = { { /* core fields */ /* superclass */ (WidgetClass) &compositeClassRec, /* class_name */ "CandidatePanel", /* widget_size */ sizeof(CandidatePanelRec), /* class_initialize */ NULL, /* class_part_initialize */ NULL, /* class_inited */ FALSE, /* initialize */ Initialize, /* initialize_hook */ NULL, /* realize */ Realize, /* actions */ actions, /* num_actions */ XtNumber(actions), /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ TRUE, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ Destroy, /* resize */ Resize, /* expose */ Redisplay, /* set_values */ SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback_private */ NULL, /* tm_table */ translations, /* query_geometry */ QueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ NULL }, { /* composite fields */ /* geometry_manager */ NULL, /* change_managed */ NULL, /* insert_child */ InsertChild, /* delete_child */ XtInheritDeleteChild, /* extension */ (XtPointer)&CompositeExtension, }, { /* candidatepanel fields */ /* empty */ 0 } }; WidgetClass candidatePanelWidgetClass = (WidgetClass)&candidatePanelClassRec; /* ARGSUSED */ static void Initialize(req, new, args, num_args) Widget req; Widget new; ArgList args; Cardinal *num_args; { CandidatePanelWidget cpw = (CandidatePanelWidget)new; cpw->cpanel.displayobj = NULL; GetInvGC(cpw); } static void Destroy(w) Widget w; { CandidatePanelWidget cpw = (CandidatePanelWidget)w; if (cpw->cpanel.invgc != NULL) XtReleaseGC(w, cpw->cpanel.invgc); } static void Realize(w, mask, value) Widget w; XtValueMask *mask; XSetWindowAttributes *value; { CandidatePanelWidget cpw = (CandidatePanelWidget)w; CompositeWidgetClass super = (CompositeWidgetClass)XtClass(w)->core_class.superclass; String params[1]; Cardinal num_params; if (cpw->cpanel.displayobj == NULL) { params[0] = XtClass(w)->core_class.class_name; num_params = 1; XtAppErrorMsg(XtWidgetToApplicationContext(w), "childError", "number", "WidgetError", "%s: has no child (ConvDisplayObject)", params, &num_params); } if (cpw->cpanel.cursor != None) { *mask |= CWCursor; value->cursor = cpw->cpanel.cursor; } (*super->core_class.realize)(w, mask, value); } /* ARGSUSED */ static void Redisplay(w, ev, region) Widget w; XEvent *ev; Region region; { CandidatePanelWidget cpw = (CandidatePanelWidget)w; Widget dispobj = cpw->cpanel.displayobj; XExposeEvent *event = (XExposeEvent *)ev; ICString *list = cpw->cpanel.list; int cwidth, cheight, hspace, vspace; int c0, c1, r0, r1; int row, col; int idx; int x, y; if (list == NULL || dispobj == NULL) return; cwidth = cpw->cpanel.maxwidth; cheight = cpw->cpanel.fontheight; hspace = cpw->cpanel.hspace; vspace = cpw->cpanel.vspace; c0 = (event->x + hspace - hspace / 2) / (cwidth + hspace); c1 = (event->x + event->width - 1 - hspace / 2) / (cwidth + hspace) + 1; if (c1 > cpw->cpanel.ncolumns) c1 = cpw->cpanel.ncolumns; r0 = (event->y + vspace - vspace / 2) / (cheight + vspace); r1 = (event->y + event->height - 1 - vspace / 2) / (cheight + vspace) + 1; if (r1 > cpw->cpanel.nrows) r1 = cpw->cpanel.nrows; for (row = r0; row < r1; row++) { y = (cheight + vspace) * row + vspace / 2; for (col = c0; col < c1; col++) { x = (cwidth + hspace) * col + hspace / 2; idx = row * cpw->cpanel.ncolumns + col; if (idx >= cpw->cpanel.nstrings) return; if (idx == cpw->cpanel.current) { XClearArea(XtDisplay(w), XtWindow(w), x, y, (unsigned int)cwidth, (unsigned int)cheight, False); } CDDrawString(dispobj, w, list + idx, 0, -1, x, y); if (idx == cpw->cpanel.current) { ToggleHighlight(cpw, idx); } } } } static void Resize(w) Widget w; { CandidatePanelWidget cpw = (CandidatePanelWidget)w; Layout(cpw, False, False); } /* ARGSUSED */ static Boolean SetValues(cur, req, wid, args, num_args) Widget cur; Widget req; Widget wid; ArgList args; Cardinal *num_args; { CandidatePanelWidget old = (CandidatePanelWidget)cur; CandidatePanelWidget new = (CandidatePanelWidget)wid; Boolean redisplay = False; Boolean listspecified = False; int i; if (new->cpanel.displayobj == NULL) return False; for (i = 0; i < *num_args; i++) { if (!strcmp(args[i].name, XtNlist)) { listspecified = True; break; } } if (new->cpanel.foreground != old->cpanel.foreground || new->core.background_pixel != old->core.background_pixel) { XtVaSetValues(new->cpanel.displayobj, XtNforeground, new->cpanel.foreground, XtNbackground, new->core.background_pixel, NULL); redisplay = True; } if (listspecified || new->cpanel.list != old->cpanel.list || new->cpanel.nstrings != old->cpanel.nstrings) { /* compute maximum pixel width of the list items */ new->cpanel.maxwidth = MaxWidth(new); } if (listspecified || new->cpanel.list != old->cpanel.list || new->cpanel.nstrings != old->cpanel.nstrings || new->cpanel.hspace != old->cpanel.hspace || new->cpanel.vspace != old->cpanel.vspace || new->cpanel.defaultwidth != old->cpanel.defaultwidth) { Layout(new, True, True); redisplay = True; } if (new->cpanel.current != old->cpanel.current && !redisplay && XtIsRealized(wid)) { ToggleHighlight(new, old->cpanel.current); ToggleHighlight(new, new->cpanel.current); } if (new->cpanel.cursor != old->cpanel.cursor && XtIsRealized(wid)) { XDefineCursor(XtDisplay(wid), XtWindow(wid), new->cpanel.cursor); } return redisplay; } static XtGeometryResult QueryGeometry(w, req, ret) Widget w; XtWidgetGeometry *req; XtWidgetGeometry *ret; { Dimension width, height; Dimension owidth, oheight; ret->request_mode = 0; if ((req->request_mode & (CWWidth | CWHeight)) == 0) return XtGeometryYes; width = (req->request_mode & CWWidth) ? req->width : w->core.width; height = (req->request_mode & CWHeight) ? req->height : w->core.height; owidth = width; oheight = height; ComputeSize((CandidatePanelWidget)w, (req->request_mode & CWWidth) != 0, (req->request_mode & CWHeight) != 0, &width, &height); ret->request_mode = CWWidth | CWHeight; ret->width = width; ret->height = height; if (width != owidth || height != oheight) return XtGeometryAlmost; return XtGeometryYes; } static void InsertChild(w) Widget w; { CandidatePanelWidget cpw = (CandidatePanelWidget)XtParent(w); CompositeWidgetClass super = (CompositeWidgetClass)XtClass(cpw)->core_class.superclass; String params[1]; Cardinal num_params; if (!XtIsSubclass(w, convDisplayObjectClass)) { params[0] = XtClass(cpw)->core_class.class_name; num_params = 1; XtAppErrorMsg(XtWidgetToApplicationContext(w), "childError", "class", "WidgetError", "%s: child must be subclass of ConvDisplayObject", params, &num_params); } if (cpw->composite.num_children != 0) { params[0] = XtClass(cpw)->core_class.class_name; num_params = 1; XtAppErrorMsg(XtWidgetToApplicationContext(w), "childError", "number", "WidgetError", "%s: can only take one child", params, &num_params); } (*super->composite_class.insert_child)(w); cpw->cpanel.displayobj = w; cpw->cpanel.fontheight = CDLineHeight(w, (Position *)NULL); #ifdef notdef { Pixel fg, bg; XtVaGetValues(w, XtNforeground, &fg, XtNbackground, &bg, NULL); GetInvGC(cpw, fg, bg); } #endif if (cpw->cpanel.list != NULL) { cpw->cpanel.maxwidth = MaxWidth(cpw); Layout(cpw, cpw->core.width == 0, cpw->core.height == 0); } } static void GetInvGC(cpw) CandidatePanelWidget cpw; { XGCValues values; values.function = GXinvert; values.plane_mask = cpw->cpanel.foreground ^ cpw->core.background_pixel; cpw->cpanel.invgc = XtGetGC((Widget)cpw, GCFunction|GCPlaneMask, &values); } /* ARGSUSED */ static void Move(w, ev, args, num_args) Widget w; XEvent *ev; String *args; Cardinal *num_args; { int dir; if (*num_args < 1) return; if (!strcmp(*args, "left") || !strcmp(*args, "Left")) { dir = ICMoveLeft; } else if (!strcmp(*args, "right") || !strcmp(*args, "Right")) { dir = ICMoveRight; } else if (!strcmp(*args, "up") || !strcmp(*args, "Up")) { dir = ICMoveUp; } else if (!strcmp(*args, "down") || !strcmp(*args, "Down")) { dir = ICMoveDown; } else { XtAppWarning(XtWidgetToApplicationContext(w), "CandidatePanel: unknown direction"); return; } CPanelMoveCurrent(w, dir); } /* ARGSUSED */ static void Set(w, ev, args, num_args) Widget w; XEvent *ev; String *args; Cardinal *num_args; { CandidatePanelWidget cpw = (CandidatePanelWidget)w; XButtonEvent *event = (XButtonEvent *)ev; int cwidth, cheight, hspace, vspace; int x, y; int row, col; int newidx; cwidth = cpw->cpanel.maxwidth; cheight = cpw->cpanel.fontheight; hspace = cpw->cpanel.hspace; vspace = cpw->cpanel.vspace; x = event->x - hspace / 2; col = x / (cwidth + hspace); if (col >= cpw->cpanel.ncolumns || (x % (cwidth + hspace)) > cwidth) return; y = event->y - vspace / 2; row = y / (cheight + vspace); if (row >= cpw->cpanel.nrows || (y % (cheight + vspace)) > cheight) return; newidx = col + cpw->cpanel.ncolumns * row; if (newidx >= cpw->cpanel.nstrings) return; CPanelSetCurrent(w, newidx); } /* ARGSUSED */ static void Notify(w, ev, args, num_args) Widget w; XEvent *ev; String *args; Cardinal *num_args; { CandidatePanelWidget cpw = (CandidatePanelWidget)w; XtCallCallbackList(w, cpw->cpanel.callback, (XtPointer)cpw->cpanel.current); } static int MaxWidth(cpw) CandidatePanelWidget cpw; { Widget dispobj = cpw->cpanel.displayobj; ICString *list = cpw->cpanel.list; int maxwidth; int i; maxwidth = 0; for (i = 0; i < cpw->cpanel.nstrings; i++) { int w = CDStringWidth(dispobj, list + i, 0, -1); if (w > maxwidth) maxwidth = w; } return maxwidth; } static void ComputeSize(cpw, resizex, resizey, width_inout, height_inout) CandidatePanelWidget cpw; int resizex; int resizey; Dimension *width_inout; Dimension *height_inout; { int nrows, ncolumns; int width, height; if (cpw->cpanel.displayobj == NULL || cpw->cpanel.nstrings == 0) return; width = *width_inout; height = *height_inout; if (resizex) { if (resizey) { int maxheight = HeightOfScreen(XtScreen((Widget)cpw)); /* use defaultwidth */ ncolumns = cpw->cpanel.defaultwidth / (cpw->cpanel.maxwidth + cpw->cpanel.hspace); if (ncolumns > cpw->cpanel.nstrings) ncolumns = cpw->cpanel.nstrings; if (ncolumns <= 0) ncolumns = 1; nrows = (cpw->cpanel.nstrings + ncolumns - 1) / ncolumns; width = (cpw->cpanel.maxwidth + cpw->cpanel.hspace) * ncolumns; height = (cpw->cpanel.fontheight + cpw->cpanel.vspace) * nrows; /* * If the computed height exceeds display height, * expand width so that the entire window fits into the display. */ if (height > maxheight) { /* compute maximum number of rows */ nrows = maxheight / (cpw->cpanel.fontheight + cpw->cpanel.vspace); if (nrows <= 0) nrows = 1; ncolumns = (cpw->cpanel.nstrings + nrows - 1) / nrows; if (ncolumns > cpw->cpanel.nstrings) { ncolumns = cpw->cpanel.nstrings; } /* re-compute correct number of rows */ nrows = (cpw->cpanel.nstrings + ncolumns - 1) / ncolumns; width = (cpw->cpanel.maxwidth + cpw->cpanel.hspace) * ncolumns; height = (cpw->cpanel.fontheight + cpw->cpanel.vspace) * nrows; } } else { /* use specified height */ nrows = height / (cpw->cpanel.fontheight + cpw->cpanel.vspace); if (nrows <= 0) nrows = 1; ncolumns = (cpw->cpanel.nstrings + nrows - 1) / nrows; if (ncolumns > cpw->cpanel.nstrings) ncolumns = cpw->cpanel.nstrings; width = (cpw->cpanel.maxwidth + cpw->cpanel.hspace) * ncolumns; } } else { ncolumns = width / (cpw->cpanel.maxwidth + cpw->cpanel.hspace); if (ncolumns <= 0) ncolumns = 1; nrows = (cpw->cpanel.nstrings + ncolumns - 1) / ncolumns; if (resizey) { height = (cpw->cpanel.fontheight + cpw->cpanel.vspace) * nrows; } } cpw->cpanel.ncolumns = ncolumns; cpw->cpanel.nrows = nrows; *width_inout = width; *height_inout = height; } static void Layout(cpw, resizex, resizey) CandidatePanelWidget cpw; int resizex; int resizey; { Dimension width, height; Dimension owidth, oheight; XtGeometryResult re; if (cpw->cpanel.displayobj == NULL) return; width = cpw->core.width; height = cpw->core.height; ComputeSize(cpw, resizex, resizey, &width, &height); if (width != cpw->core.width || height != cpw->core.height) { owidth = width; oheight = height; re = XtMakeResizeRequest((Widget)cpw, owidth, oheight, &width, &height); switch (re) { case XtGeometryYes: /* no problem */ break; case XtGeometryNo: width = cpw->core.width; height = cpw->core.height; ComputeSize(cpw, False, False, &width, &height); break; case XtGeometryAlmost: ComputeSize(cpw, width != owidth, height != oheight, &width, &height); re = XtMakeResizeRequest((Widget)cpw, width, height, &width, &height); switch (re) { case XtGeometryYes: break; case XtGeometryNo: width = cpw->core.width; height = cpw->core.height; ComputeSize(cpw, False, False, &width, &height); break; case XtGeometryAlmost: ComputeSize(cpw, False, False, &width, &height); (void)XtMakeResizeRequest((Widget)cpw, width, height, &width, &height); } } } } static void ToggleHighlight(cpw, idx) CandidatePanelWidget cpw; int idx; { int row, col; int x, y; int width; if (idx < 0 || cpw->cpanel.nstrings <= idx) return; col = idx % cpw->cpanel.ncolumns; row = idx / cpw->cpanel.ncolumns; x = (cpw->cpanel.maxwidth + cpw->cpanel.hspace) * col + cpw->cpanel.hspace / 2; y = (cpw->cpanel.fontheight + cpw->cpanel.vspace) * row + cpw->cpanel.vspace / 2; width = CDStringWidth(cpw->cpanel.displayobj, cpw->cpanel.list + idx, 0, -1); XFillRectangle(XtDisplay(cpw), XtWindow(cpw), cpw->cpanel.invgc, x, y, (unsigned int)width, (unsigned int)cpw->cpanel.fontheight); } /* * Public Functions */ void CPanelSetList(w, list, nstrings, current, resize) Widget w; ICString *list; int nstrings; int current; int resize; { CandidatePanelWidget cpw = (CandidatePanelWidget)w; if (list != NULL) { cpw->cpanel.list = list; cpw->cpanel.nstrings = nstrings; if (current < 0) current = 0; if (current >= nstrings) current = nstrings - 1; cpw->cpanel.current = current; } if (cpw->cpanel.displayobj == NULL) return; cpw->cpanel.fontheight = CDLineHeight(cpw->cpanel.displayobj, (Position *)NULL); /* compute maximum pixel width of the list items */ cpw->cpanel.maxwidth = MaxWidth(cpw); Layout(cpw, resize, resize); if (XtIsRealized(w)) XClearWindow(XtDisplay(w), XtWindow(w)); } void CPanelSetCurrent(w, idx) Widget w; int idx; { CandidatePanelWidget cpw = (CandidatePanelWidget)w; if (idx < 0 || cpw->cpanel.nstrings <= idx) return; if (idx == cpw->cpanel.current) return; if (cpw->cpanel.displayobj != NULL && XtIsRealized(w)) { ToggleHighlight(cpw, cpw->cpanel.current); ToggleHighlight(cpw, idx); } cpw->cpanel.current = idx; } void CPanelMoveCurrent(w, dir) Widget w; int dir; { CandidatePanelWidget cpw = (CandidatePanelWidget)w; int newidx; int row, col; int nstrings = cpw->cpanel.nstrings; if (nstrings <= 0) return; col = cpw->cpanel.current % cpw->cpanel.ncolumns; row = cpw->cpanel.current / cpw->cpanel.ncolumns; switch (dir) { case ICMoveLeft: if ((newidx = cpw->cpanel.current - 1) < 0) newidx = nstrings - 1; break; case ICMoveRight: if ((newidx = cpw->cpanel.current + 1) >= nstrings) newidx = 0; break; case ICMoveUp: case ICMovePrevPage: if (--row < 0) row = cpw->cpanel.nrows - 1; newidx = row * cpw->cpanel.ncolumns + col; if (newidx >= nstrings) newidx -= cpw->cpanel.ncolumns; break; case ICMoveDown: case ICMoveNextPage: if (++row >= cpw->cpanel.nrows) row = 0; newidx = row * cpw->cpanel.ncolumns + col; if (newidx >= nstrings) newidx = col; break; case ICMoveLeftMost: newidx = row * cpw->cpanel.ncolumns; break; case ICMoveRightMost: newidx = (row + 1) * cpw->cpanel.ncolumns - 1; if (newidx >= cpw->cpanel.nstrings) newidx = cpw->cpanel.nstrings - 1; break; case ICMoveFirst: newidx = 0; break; case ICMoveLast: newidx = cpw->cpanel.nstrings - 1; break; } CPanelSetCurrent(w, newidx); }