|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: S T
Length: 34682 (0x877a) Types: TextFile Names: »ScrollList.c«
└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89 └─⟦e10a7c8ba⟧ »./UNRELEASED/xgdb.tar.Z« └─⟦ae30648b5⟧ └─⟦this⟧ »./ScrollList.c«
\f #ifndef lint static char rcsid[] = "$Header: ScrollList.c,v 1.1 89/07/05 15:35:14 hubbard Exp $"; #endif /* This is the scrollList widget. It's basically a modification of * Chris Peterson's List widget that allows the list to be viewed * with a scrollbar and to optionally keep the highlighted region * visible. The second feature was the driving reason behind this * widget. I'm not sure that I consider this generally usable. * We also support stippling of individual items, where the List widget * only supports stippling the entire list via the XtNsensitive attribute. * * Jordan Hubbard * * Based on List widget by: * Chris D. Peterson * MIT - Project Athena * * $Log: ScrollList.c,v $ * Revision 1.1 89/07/05 15:35:14 hubbard * Initial revision * * */ /*********************************************************** Copyright 1988 by Digital Equipment Corporation, Maynard, Massachusetts, and the Massachusetts Institute of Technology, Cambridge, Massachusetts. All Rights Reserved 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 names of Digital or MIT not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. And furthermore, blah blah blah blah blah blah blah and blah. ******************************************************************/ /* * scrollList.c - Scrolling List widget (widget with optional scrollbar) * */ #include "IntrinsicP.h" #include <stdio.h> #include <ctype.h> #include "Xos.h" #include "Xmu.h" #include "Cardinals.h" #include "StringDefs.h" #include "Scroll.h" #include "Command.h" #include "ScrollLstP.h" /* * Default Translation table. */ static char defaultTranslations[] = "<Btn1Down>: Set()\n\ <Btn1Up>: Notify()"; /**************************************************************** * * Full class record constant * ****************************************************************/ /* Private Data */ #define offset(field) XtOffset(ScrollListWidget, field) static XtResource resources[] = { {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), offset(list.foreground), XtRString, "XtDefaultForeground"}, {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor), offset(simple.cursor), XtRString, "left_ptr"}, {XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), offset(list.font),XtRString, "XtDefaultFont"}, {XtNlist, XtCList, XtRPointer, sizeof(char **), offset(list.list), XtRString, NULL}, {XtNdefaultColumns, XtCColumns, XtRInt, sizeof(int), offset(list.default_cols), XtRImmediate, (caddr_t)2}, {XtNlongest, XtCLongest, XtRInt, sizeof(int), offset(list.longest), XtRImmediate, (caddr_t)0}, {XtNnumberStrings, XtCNumberStrings, XtRInt, sizeof(int), offset(list.nitems), XtRImmediate, (caddr_t)0}, {XtNpasteBuffer, XtCBoolean, XtRBoolean, sizeof(Boolean), offset(list.paste), XtRString, (caddr_t) "False"}, {XtNforceColumns, XtCColumns, XtRBoolean, sizeof(Boolean), offset(list.force_cols), XtRString, (caddr_t) "False"}, {XtNrepositionOnHilite, XtCBoolean, XtRBoolean, sizeof(Boolean), offset(list.repositionOnHilite), XtRString, (caddr_t) "False"}, {XtNscrollVertical, XtCBoolean, XtRBoolean, sizeof(Boolean), offset(list.scrollVertical), XtRString, (caddr_t) "False"}, {XtNverticalList, XtCBoolean, XtRBoolean, sizeof(Boolean), offset(list.vertical_cols), XtRString, (caddr_t) "False"}, {XtNinternalWidth, XtCWidth, XtRDimension, sizeof(Dimension), offset(list.internal_width), XtRImmediate, (caddr_t)4}, {XtNinternalHeight, XtCHeight, XtRDimension, sizeof(Dimension), offset(list.internal_height), XtRImmediate, (caddr_t)2}, {XtNcolumnSpacing, XtCSpacing, XtRDimension, sizeof(Dimension), offset(list.column_space), XtRImmediate, (caddr_t)6}, {XtNrowSpacing, XtCSpacing, XtRDimension, sizeof(Dimension), offset(list.row_space), XtRImmediate, (caddr_t)2}, {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t), offset(list.callback), XtRCallback, NULL}, }; static void Initialize(); static void Realize(); static void Resize(); static void Redisplay(); static void ResetList(); static void CreateScrollbar(); static void ChangeHeight(); static Boolean Layout(); static XtGeometryResult PreferredGeom(); static Boolean SetValues(); static void Notify(), Set(), Unset(); static XtActionsRec actions[] = { {"Notify", Notify}, {"Set", Set}, {"Unset", Unset}, {NULL,NULL} }; ScrollListClassRec scrollListClassRec = { /* Core Fields */ /* superclass */ (WidgetClass)&simpleClassRec, /* class_name */ "ScrollList", /* widget_size */ sizeof(ScrollListRec), /* 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 */ NULL, /* 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 */ defaultTranslations, /* query_geometry */ PreferredGeom, /* accelerators */ XtInheritDisplayAccelerator, /* extension */ NULL, }; WidgetClass scrollListWidgetClass = (WidgetClass)&scrollListClassRec; /**************************************************************** * * Private Procedures * ****************************************************************/ static void GetGCs(w) Widget w; { XGCValues values; ScrollListWidget lw = (ScrollListWidget) w; values.foreground = lw->list.foreground; values.font = lw->list.font->fid; lw->list.normgc = XtGetGC(w, (unsigned) GCForeground | GCFont, &values); values.foreground = lw->core.background_pixel; lw->list.revgc = XtGetGC(w, (unsigned) GCForeground | GCFont, &values); values.foreground = lw->list.foreground; values.tile = XtGrayPixmap(XtScreen(w)); values.fill_style = FillTiled; lw->list.graygc = XtGetGC(w, (unsigned) GCForeground | GCFont | GCTile | GCFillStyle, &values); } /* Function Name: Initialize * Description: Function that initilizes the widget instance. * Arguments: junk - NOT USED. * new - the new widget. * Returns: none */ /* ARGSUSED */ static void Initialize(junk, new) Widget junk, new; { ScrollListWidget lw = (ScrollListWidget) new; /* * Initialize all private resources. */ GetGCs(new); /* Set row height. */ lw->list.row_height = lw->list.font->max_bounds.ascent + lw->list.font->max_bounds.descent + lw->list.row_space; /* * Default to the name of the widget as the entire list. * Changed on 4/5/89 by jkh to fix a bug where ResetList() was * called too soon. */ if (lw->list.list == NULL) { lw->list.list = &(lw->core.name); lw->list.nitems = 1; lw->list.ncols = 1; } lw->list.stiplist = (Boolean *)NULL; lw->list.is_highlighted = NO_HIGHLIGHT; lw->list.highlight = NO_HIGHLIGHT; if (lw->list.scrollVertical) /* they want a scrollbar */ CreateScrollbar(lw); lw->list.top = 0; ResetList(lw, (lw->core.width == 0), (lw->core.height == 0)); } /* Initialize */ /* * Function: Realize * Description: Checks for the existance of a god. * Arguments: father, son, holy ghost. * Returns: Only HE knows for sure. */ static void Realize(w, valueMask, attributes) Widget w; Mask *valueMask; XSetWindowAttributes *attributes; { ScrollListWidget lw = (ScrollListWidget)w; (*scrollListClassRec.core_class.superclass->core_class.realize) (w, valueMask, attributes); if (lw->list.sbar) { XtRealizeWidget(lw->list.sbar); XtMapWidget(lw->list.sbar); } } /* Realize */ /* Function Name: ResetList * Description: Resets the new list when important things change. * Arguments: w - the widget. * changex, changey - allow the height or width to change? * Returns: none. */ static void ResetList(w, changex, changey) Widget w; Boolean changex, changey; { ScrollListWidget lw = (ScrollListWidget) w; Dimension width = w->core.width; Dimension height = w->core.height; String str; if (lw->list.nitems == 0) /* Get number of items. */ while (lw->list.list[lw->list.nitems] != NULL) lw->list.nitems++; if (lw->list.longest == 0) { /* Get column width. */ int i, len, max; for ( i = 0, max = 0; i < lw->list.nitems; i++) { str = lw->list.list[i]; len = XTextWidth(lw->list.font, str, strlen(str)); if (len > max) max = len; } lw->list.col_width = max; } else lw->list.col_width = lw->list.longest; lw->list.col_width += lw->list.column_space; lw->list.top = 0; if (lw->list.stiplist) XtFree(lw->list.stiplist); lw->list.stiplist = (Boolean *)XtMalloc(lw->list.nitems*sizeof(Boolean)); bzero(lw->list.stiplist, lw->list.nitems * sizeof(Boolean)); if (Layout(w, changex, changey, &width, &height) && XtIsRealized(w)) Redisplay(w, NULL, NULL); } /* Function Name: CvtToItem * Description: Converts Xcoord to item number of item containing that * point. * Arguments: w - the list widget. * xloc, yloc - x location, and y location. * Returns: the item number. */ static int CvtToItem(w, xloc, yloc, item) Widget w; int xloc, yloc; int *item; { int one, another; ScrollListWidget lw = (ScrollListWidget) w; int ret_val = OKAY; if (lw->list.vertical_cols) { one = lw->list.nrows * ((xloc - (int) lw->list.internal_width) / lw->list.col_width); another = (yloc - (int) lw->list.internal_height) / lw->list.row_height; /* If out of range, return minimum possible value. */ if (another >= lw->list.nrows) { another = lw->list.nrows - 1; ret_val = OUT_OF_RANGE; } } else { one = (lw->list.ncols * ((yloc - (int) lw->list.internal_height) / lw->list.row_height)) ; /* If in right margin handle things right. */ another = (xloc - (int) lw->list.internal_width) / lw->list.col_width; if (another >= lw->list.ncols) { another = lw->list.ncols - 1; ret_val = OUT_OF_RANGE; } } if ((xloc < 0) || (yloc < 0)) ret_val = OUT_OF_RANGE; if (one < 0) one = 0; if (another < 0) another = 0; *item = one + another + lw->list.top; if (*item >= lw->list.nitems) return(OUT_OF_RANGE); return(ret_val); } /* Function Name: FindCornerItems. * Description: Find the corners of the rectangle in item space. * Arguments: w - the list widget. * event - the event structure that has the rectangle it it. * ul_ret, lr_ret - the corners ** RETURNED **. * Returns: none. */ FindCornerItems(w, event, ul_ret, lr_ret) Widget w; XEvent * event; int *ul_ret, *lr_ret; { int xloc, yloc; xloc = event->xexpose.x; yloc = event->xexpose.y; CvtToItem(w, xloc, yloc, ul_ret); xloc += event->xexpose.width; yloc += event->xexpose.height; CvtToItem(w, xloc, yloc, lr_ret); } /* Function Name: ItemInRectangle * Description: returns TRUE if the item passed is in the given rectangle. * Arguments: w - the list widget. * ul, lr - corners of the rectangle in item space. * item - item to check. * Returns: TRUE if the item passed is in the given rectangle. */ ItemInRectangle(w, ul, lr, item) Widget w; int ul, lr, item; { ScrollListWidget lw = (ScrollListWidget) w; register int mod_item; int things; if (item < ul || item > lr) return(FALSE); if (lw->list.vertical_cols) things = lw->list.nrows; else things = lw->list.ncols; mod_item = item % things; if ( (mod_item >= ul % things) && (mod_item <= lr % things ) ) return(TRUE); return(FALSE); } /* Function Name: HighlightBackground * Description: paints the color of the background for the given item. * Arguments: w - the widget. * x, y - ul corner of the area item occupies. * item - the item we are dealing with. * gc - the gc that is used to paint this rectangle * Returns: */ HighlightBackground(w, x, y, item, gc) Widget w; int x, y, item; GC gc; { ScrollListWidget lw = (ScrollListWidget) w; int hl_x, hl_y, width, height; hl_x = x - lw->list.column_space/2; width = XTextWidth(lw->list.font, lw->list.list[item], strlen(lw->list.list[item])) + lw->list.column_space; hl_y = y - lw->list.row_space/2; height = lw->list.row_height + lw->list.row_space; XFillRectangle(XtDisplay(w), XtWindow(w), gc, hl_x, hl_y, width, height); } /* Function Name: PaintItemName * Description: paints the name of the item in the appropriate location. * Arguments: w - the list widget. * item - the item to draw. * Returns: none. */ PaintItemName(w, item) Widget w; int item; { char * str; GC gc; int x, y, str_y, top_y; ScrollListWidget lw = (ScrollListWidget) w; if (item >= lw->list.nitems) { XtWarning("ScrollListWidget: Tried to paint an item >= nitems\n"); return; } if (item < 0) return; top_y = lw->list.top * lw->list.row_height; if (lw->list.vertical_cols) { x = lw->list.col_width * (item / lw->list.nrows) + lw->list.internal_width + lw->list.left_margin; y = lw->list.row_height * (item % lw->list.nrows) + lw->list.internal_height; } else { x = lw->list.col_width * (item % lw->list.ncols) + lw->list.internal_width + lw->list.left_margin; y = lw->list.row_height * (item / lw->list.ncols) + lw->list.internal_height; } y -= top_y; str_y = y + lw->list.font->max_bounds.ascent; if (item == lw->list.is_highlighted) { if (item == lw->list.highlight) { gc = lw->list.revgc; HighlightBackground(w, x, y, item, lw->list.normgc); } else { if (XtIsSensitive(w)) gc = lw->list.normgc; else gc = lw->list.graygc; HighlightBackground(w, x, y, item, lw->list.revgc); lw->list.is_highlighted = NO_HIGHLIGHT; } } else { if (item == lw->list.highlight) { if (lw->list.repositionOnHilite && (item < lw->list.top || item >= (lw->list.top + lw->list.n_lines))) { /* recenter */ lw->list.top = item - (lw->list.n_lines / 2); if (lw->list.top < 0) lw->list.top = 0; if (lw->list.sbar) XtScrollBarSetThumb(lw->list.sbar, (float)lw->list.top / (float)lw->list.actual, -1.0); Redisplay(lw, NULL, NULL); return; } gc = lw->list.revgc; HighlightBackground(w, x, y, item, lw->list.normgc); lw->list.is_highlighted = item; } else { if (XtIsSensitive(w)) gc = lw->list.normgc; else gc = lw->list.graygc; } } str = lw->list.list[item]; /* draw it */ if (lw->list.stiplist[item]) gc = lw->list.graygc; XDrawString(XtDisplay(w), XtWindow(w), gc, x, str_y, str, strlen(str)); } /* Handle up/down scrolling */ static void ScrollUpDownProc(w, closure, data) Widget w; caddr_t closure, data; { ScrollListWidget lw = (ScrollListWidget)closure; int position = (int)data; int new_top; float thumb_top; new_top = lw->list.top + (position / lw->list.row_height); if (new_top < 0) new_top = 0; else if (new_top >= (lw->list.actual - lw->list.n_lines)) new_top = (lw->list.actual - lw->list.n_lines) + 1; if (new_top < 0) /* Nothing in the list */ return; thumb_top = (float)((float)new_top / (float)lw->list.actual); XtScrollBarSetThumb(lw->list.sbar, thumb_top, -1.0); if (new_top != lw->list.top) { lw->list.top = new_top; Redisplay(lw, NULL, NULL); } } /* Thumb to a position */ static void ThumbProc(w, closure, percent_ptr) Widget w; caddr_t closure, percent_ptr; { ScrollListWidget lw = (ScrollListWidget)closure; float percent = *(float *)percent_ptr; int new_top; new_top = (int)((percent * (float)lw->list.actual * (float)lw->list.row_height)/(float)lw->list.row_height); lw->list.top = new_top; Redisplay(lw, NULL, NULL); } /* Create a scrollbar for the list widget */ static void CreateScrollbar(lw) ScrollListWidget lw; { Dimension bw; Widget sbar; lw->list.sbar = sbar = XtCreateWidget("scrollbar", scrollbarWidgetClass, lw, NULL, ZERO); XtAddCallback(sbar, XtNscrollProc, ScrollUpDownProc, (caddr_t)lw); XtAddCallback(sbar, XtNjumpProc, ThumbProc, (caddr_t)lw); lw->list.left_margin += sbar->core.width + (bw = sbar->core.border_width); XtMoveWidget(sbar, -(Position)bw, -(Position)bw); } /* * Change the height of the view region, resize the * scrollbar and change scroll metrics. */ static void ChangeHeight(lw, height) ScrollListWidget lw; Dimension height; { float shown; /* resize the scroll bar */ if (lw->list.sbar) { XtResizeWidget(lw->list.sbar, lw->list.sbar->core.width, height, lw->list.sbar->core.border_width); } /* * Figure out new n_lines from new height. */ lw->list.n_lines = (unsigned int)height / lw->list.row_height; /* * What's the actual physical number of lines in the list? */ lw->list.actual = lw->list.nitems / lw->list.ncols; if (!lw->list.actual) /* handle the items < rows case */ lw->list.actual = 1; if (lw->list.sbar) { /* Set the thumb */ if (lw->list.n_lines < 2 || lw->list.nitems < 2 || lw->list.actual <= lw->list.n_lines) shown = 1.0; else shown = (float)((float)lw->list.n_lines / (float)lw->list.actual); XtScrollBarSetThumb(lw->list.sbar, -1.0, shown); } } /* Function Name: Redisplay * Description: Repaints the widget window on expose events. * Arguments: w - the list widget. * event - the expose event for this repaint. * junk - NOT USED. * Returns: */ /* ARGSUSED */ static void Redisplay(w, event, junk) Widget w; XEvent *event; Region junk; { int item; /* an item to work with. */ int ul_item, lr_item; /* corners of items we need to paint. */ int max_viewable; /* last possible item to show */ ScrollListWidget lw = (ScrollListWidget) w; max_viewable = lw->list.top + (lw->list.n_lines * lw->list.ncols); if (event == NULL) { /* repaint all. */ ul_item = lw->list.top; lr_item = lw->list.nrows * lw->list.ncols - 1; XClearWindow(XtDisplay(w), XtWindow(w)); } else FindCornerItems(w, event, &ul_item, &lr_item); for (item = ul_item; (item <= lr_item && item < max_viewable && item < lw->list.nitems) ; item++) if (ItemInRectangle(w, ul_item, lr_item, item)) PaintItemName(w, item); } /* Function Name: PreferredGeom * Description: This tells the parent what size we would like to be * given certain constraints. * Arguments: w - the widget. * intended - what the parent intends to do with us. * requested - what we want to happen. * Returns: none. */ static XtGeometryResult PreferredGeom(w, intended, requested) Widget w; XtWidgetGeometry *intended, *requested; { Dimension width_req, height_req, new_width, new_height; Boolean change; width_req = intended->request_mode & CWWidth; height_req = intended->request_mode & CWHeight; if (width_req) new_width = intended->width; else new_width = w->core.width; if (height_req) new_height = intended->height; else new_height = w->core.height; requested->request_mode = 0; /* * We only care about our height and width. */ if (!width_req && !height_req) { return(XtGeometryYes); } change = Layout(w, !width_req, !height_req, &new_width, &new_height); requested->request_mode |= CWWidth; requested->width = new_width; requested->request_mode |= CWHeight; requested->height = new_height; if (change) return(XtGeometryAlmost); return(XtGeometryYes); } /* Function Name: Resize * Description: resizes the widget, by changing the number of rows and * columns. * Arguments: w - the widget. * Returns: none. */ static void Resize(w) Widget w; { Dimension width, height; width = w->core.width; height = w->core.height; if (Layout(w, FALSE, FALSE, &width, &height)) XtWarning("ScrollListWidget: Unexpected size change in Resize\n"); } /* Function Name: Layout * Description: lays out the item in the list. * Arguments: w - the widget. * xfree, yfree - TRUE if we are free to resize the widget in * this direction. * width, height - the is the current width and height that * we are going to layout the list widget to, * depending on xfree and yfree of course. * * Returns: TRUE if width or height have been changed. */ static Boolean Layout(w, xfree, yfree, width, height) Widget w; Boolean xfree, yfree; Dimension *width, *height; { ScrollListWidget lw = (ScrollListWidget) w; Boolean change = FALSE; /* * If force columns is set then always use number of columns specified * by default_cols. */ if (lw->list.force_cols) { lw->list.ncols = lw->list.default_cols; if (lw->list.ncols <= 0) lw->list.ncols = 1; /* 12/3 = 4 and 10/3 = 4, but 9/3 = 3 */ lw->list.nrows = ((lw->list.nitems - 1) / lw->list.ncols) + 1; if (xfree) { /* If allowed resize width. */ *width = lw->list.ncols * lw->list.col_width + 2 * lw->list.internal_width; change = TRUE; } if (yfree) { /* If allowed resize height. */ *height = (lw->list.nrows * lw->list.row_height) + 2 * lw->list.internal_height; change = TRUE; } if (lw->list.sbar) ChangeHeight(lw, *height); return(change); } /* * If both width and height are free to change the use default_cols * to determine the number columns and set new width and height to * just fit the window. */ if (xfree && yfree) { lw->list.ncols = lw->list.default_cols; if (lw->list.ncols <= 0) lw->list.ncols = 1; lw->list.nrows = ( ( lw->list.nitems - 1) / lw->list.ncols) + 1 ; *width = lw->list.ncols * lw->list.col_width + 2 * lw->list.internal_width; *height = (lw->list.nrows * lw->list.row_height) + 2 * lw->list.internal_height; change = TRUE; } /* * If the width is fixed then use it to determine the number of columns. * If the height is free to move (width still fixed) then resize the height * of the widget to fit the current list exactly. */ else if (!xfree) { lw->list.ncols = (*width - 2 * lw->list.internal_width) / lw->list.col_width; if (lw->list.ncols <= 0) lw->list.ncols = 1; lw->list.nrows = ( ( lw->list.nitems - 1) / lw->list.ncols) + 1 ; if ( yfree ) { *height = (lw->list.nrows * lw->list.row_height) + 2 * lw->list.internal_height; change = TRUE; } } /* * The last case is xfree and !yfree we use the height to determine * the number of rows and then set the width to just fit the resulting * number of columns. */ else if (!yfree) { /* xfree must be TRUE. */ lw->list.nrows = (*height - 2 * lw->list.internal_height) / lw->list.row_height; if (lw->list.nrows <= 0) lw->list.nrows = 1; lw->list.ncols = (( lw->list.nitems - 1 ) / lw->list.nrows) + 1; *width = lw->list.ncols * lw->list.col_width + 2 * lw->list.internal_width; change = TRUE; } if (lw->list.sbar) ChangeHeight(lw, *height); return(change); } /* Function Name: Notify * Description: Notifies the user that a button has been pressed, and * calles the callback, if the XtNpasteBuffer resource * is true then the name of the item is also put in the * X cut buffer ( buf (0) ). * Arguments: w - the widget that the notify occured in. * event - event that caused this notification. * params, num_params - not used. * Returns: none. */ /* ARGSUSED */ static void Notify(w, event, params, num_params) Widget w; XEvent * event; String * params; Cardinal *num_params; { ScrollListWidget lw = ( ScrollListWidget ) w; int item, item_len; XtScrollListReturnStruct ret_value; /* * Find item and if out of range then unhighlight and return. * * If the current item is unhighlighted then the user has aborted the * notify, so unhighlight and return. */ if ( ((CvtToItem(w, event->xbutton.x, event->xbutton.y, &item)) == OUT_OF_RANGE) || (lw->list.highlight != item) ) { XtScrollListUnhighlight(w); return; } item_len = strlen(lw->list.list[item]); if ( lw->list.paste ) /* if XtNpasteBuffer set then paste it. */ XStoreBytes(XtDisplay(w), lw->list.list[item], item_len); /* * Call Callback function. */ ret_value.string = lw->list.list[item]; ret_value.list_index = item; XtCallCallbacks( w, XtNcallback, (caddr_t) &ret_value); } /* Function Name: Unset * Description: unhighlights the current element. * Arguments: w - the widget that the event occured in. * event - not used. * params, num_params - not used. * Returns: none. */ /* ARGSUSED */ static void Unset(w, event, params, num_params) Widget w; XEvent * event; String * params; Cardinal *num_params; { XtScrollListUnhighlight(w); } /* Function Name: Set * Description: Highlights the current element. * Arguments: w - the widget that the event occured in. * event - event that caused this notification. * params, num_params - not used. * Returns: none. */ /* ARGSUSED */ static void Set(w, event, params, num_params) Widget w; XEvent * event; String * params; Cardinal *num_params; { int item; ScrollListWidget lw = (ScrollListWidget) w; if ( (CvtToItem(w, event->xbutton.x, event->xbutton.y, &item)) == OUT_OF_RANGE) XtScrollListUnhighlight(w); /* Unhighlight current item. */ else if ( lw->list.is_highlighted != item ) /* If this item is not */ XtScrollListHighlight(w, item); /* highlighted then do it. */ } /* * Set specified arguments into widget */ /* ARGSUSED */ static Boolean SetValues(current, request, new) Widget current, request, new; { ScrollListWidget cl = (ScrollListWidget) current; ScrollListWidget rl = (ScrollListWidget) request; ScrollListWidget nl = (ScrollListWidget) new; Boolean redraw = FALSE; if ((cl->list.foreground != rl->list.foreground) || (cl->core.background_pixel != rl->core.background_pixel) || (cl->list.font != rl->list.font) ) { XtDestroyGC(cl->list.normgc); XtDestroyGC(cl->list.graygc); XtDestroyGC(cl->list.revgc); GetGCs(new); redraw = TRUE; } if (cl->list.scrollVertical != rl->list.scrollVertical) { if (!rl->list.scrollVertical) { /* remove scroll bar */ nl->list.left_margin -= (cl->list.sbar->core.width + cl->list.sbar->core.border_width); XtDestroyWidget(cl->list.sbar); nl->list.sbar = NULL; } else CreateScrollbar(nl); } /* Reset row height. */ if ((cl->list.row_space != rl->list.row_space) || (cl->list.font != rl->list.font)) nl->list.row_height = nl->list.font->max_bounds.ascent + nl->list.font->max_bounds.descent + nl->list.row_space; if ((cl->core.width != rl->core.width) || (cl->core.height != rl->core.height) || (cl->list.internal_width != rl->list.internal_width) || (cl->list.internal_height != rl->list.internal_height) || (cl->list.column_space != rl->list.column_space) || (cl->list.row_space != rl->list.row_space) || (cl->list.default_cols != rl->list.default_cols) || ( (cl->list.force_cols != rl->list.force_cols) && (rl->list.force_cols != rl->list.ncols) ) || (cl->list.vertical_cols != rl->list.vertical_cols) || (cl->list.longest != rl->list.longest) || (cl->list.nitems != rl->list.nitems) || (cl->list.font != rl->list.font) || (cl->list.list != rl->list.list) ) { ResetList(new, TRUE, TRUE); redraw = TRUE; } if (cl->list.list != rl->list.list) nl->list.highlight = NO_HIGHLIGHT; if ((cl->core.sensitive != rl->core.sensitive) || (cl->core.ancestor_sensitive != rl->core.ancestor_sensitive)) { nl->list.highlight = NO_HIGHLIGHT; redraw = TRUE; } if (!XtIsRealized(current)) return(FALSE); return(redraw); } /* Exported Functions */ /* Function Name: XtScrollListChange. * Description: Changes the list being used and shown. * Arguments: w - the list widget. * list - the new list. * nitems - the number of items in the list. * longest - the length (in Pixels) of the longest element * in the list. * redraw - if TRUE the the list widget will * be redrawn (user may want to defer this for some * reason). * Returns: none. * NOTE: If nitems of longest are <= 0 then they will be calculated. * If nitems is <= 0 then the list needs to be NULL terminated. */ void XtScrollListChange(w, list, nitems, longest, redraw) Widget w; char ** list; int nitems, longest; Boolean redraw; { ScrollListWidget lw = (ScrollListWidget) w; lw->list.list = list; if (nitems <= 0) nitems = 0; lw->list.nitems = nitems; if (longest <= 0) longest = 0; lw->list.longest = longest; ResetList(w, FALSE, FALSE); lw->list.highlight = NO_HIGHLIGHT; lw->list.is_highlighted = NO_HIGHLIGHT; if ( XtIsRealized(w) && redraw) Redisplay(w, NULL, NULL); } /* Function Name: XtScrollListUnhighlight * Description: unlights the current highlighted element. * Arguments: w - the widget. * Returns: none. */ void XtScrollListUnhighlight(w) Widget w; { ScrollListWidget lw = ( ScrollListWidget ) w; lw->list.highlight = NO_HIGHLIGHT; if (lw->list.is_highlighted != NO_HIGHLIGHT) PaintItemName(w, lw->list.is_highlighted); /* unhighlight this one. */ } /* Function Name: XtScrollListHighlight * Description: Highlights the given item. * Arguments: w - the list widget. * item - the item to hightlight. * Returns: none. */ void XtScrollListHighlight(w, item) Widget w; int item; { ScrollListWidget lw = (ScrollListWidget) w; if (XtIsSensitive(w)) { lw->list.highlight = item; if (lw->list.is_highlighted != NO_HIGHLIGHT) PaintItemName(w, lw->list.is_highlighted); /* Unhighlight. */ PaintItemName(w, item); /* HIGHLIGHT this one. */ } } /* Function Name: XtScrollListStipple * Description: stipple the given item. * Arguments: w - the list widget. * item - the item to stipple. * Returns: none. */ void XtScrollListStipple(w, item) Widget w; int item; { ScrollListWidget lw = (ScrollListWidget) w; if (XtIsSensitive(w)) { if (item >= lw->list.nitems) XtWarning("ScrollListWidget: item >= nitems in Stipple\n"); else if (!lw->list.stiplist[item]) { lw->list.stiplist[item] = TRUE; PaintItemName(w, item); } } } /* Function Name: XtScrollListUnStipple * Description: Unstipples the given item. * Arguments: w - the list widget. * item - the item to unstipple. * Returns: none. */ void XtScrollListUnStipple(w, item) Widget w; int item; { ScrollListWidget lw = (ScrollListWidget) w; if (XtIsSensitive(w)) { if (item >= lw->list.nitems) XtWarning("ScrollListWidget: item >= nitems in UnStipple\n"); else if (lw->list.stiplist[item]) { lw->list.stiplist[item] = FALSE; PaintItemName(w, item); } } } /* Function Name: XtScrollListShowCurrent * Description: returns the currently highlighted object. * Arguments: w - the list widget. * Returns: the info about the currently highlighted object. */ XtScrollListReturnStruct *XtScrollListShowCurrent(w) Widget w; { ScrollListWidget lw = (ScrollListWidget)w; static XtScrollListReturnStruct ret_val; ret_val.list_index = lw->list.highlight; if (ret_val.list_index == XT_LIST_NONE) return((XtScrollListReturnStruct *)NULL); else ret_val.string = lw->list.list[ret_val.list_index]; return(&ret_val); }