/* * Motif * * Copyright (c) 1987-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these librararies and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "XmI.h" #include #include #include #ifdef VMS #include #else #include #endif #include #include #include #include "TransferI.h" /* for _XmConvertComplete() */ #include #include #include "RepTypeI.h" /************************************************************ * TYPEDEFS AND DEFINES *************************************************************/ #define SUPERCLASS ((WidgetClass) &xmPrimitiveClassRec) #define NO_SELECTION -1 /* There is currently no anchor. */ #define IN_COLUMN_HEADER -2 /* The location is in the header. */ #define ENTIRE_ROW -3 /* perform operation on entire row. */ #define EXTEND (1 << 0) #define TOGGLE (1 << 1) #define OFF_TOP (1 << 2) #define OFF_BOTTOM (1 << 3) #define OFF_LEFT (1 << 4) /* UNUSED BUT RESERVED */ #define OFF_RIGHT (1 << 5) /* UNUSED BUT RESERVED */ #define OUTSIDE_WIDGET (OFF_TOP | OFF_BOTTOM | OFF_LEFT | OFF_RIGHT) #define DELAY_TIME(w) (XtGetMultiClickTime(XtDisplay(w))/3) #define LINE_HEIGHT 2 /* Height of the separator line */ #define HORIZONTAL_SPACE 8 /* horizontal Space between Text and Text. */ #define VERTICAL_SPACE 2 /* Vertical Space between Text and Text. */ #define NoTimeout ((XtIntervalId) 0) /* * DANGER: XmeRenderTableGetDefaultFont is an undocumented * internal MOTIF(tm) function. */ #define GetDefaultFont XmeRenderTableGetDefaultFont /************************************************************ * MACROS *************************************************************/ #define streq(a, b) (((a) != NULL) && ((b) != NULL) && (strcmp((a), (b)) == 0)) #define IsValidPixmap(p) (((p) != None) && ((p) != XmUNSPECIFIED_PIXMAP)) /************************************************************ * GLOBAL DECLARATIONS *************************************************************/ extern Boolean XmeRenderTableGetDefaultFont (XmFontList, XFontStruct **); static Widget global_current_widget; /* static global to hold widget id for qsort. */ /************************************************************ * STATIC FUNCTION DECLARATIONS *************************************************************/ /****************************** * Exported Widget Functions ******************************/ Boolean XmI18ListDoSearch(Widget w, String str, Boolean reset); XmMultiListRowInfo *XmI18ListFindRow(Widget w, String str, int *found_column, Boolean reset, Boolean do_visual); static void ClassInitialize(); static void ClassPartInitialize(WidgetClass w_class); static void Initialize(Widget, Widget, ArgList, Cardinal *); static void Realize(Widget, Mask *, XSetWindowAttributes *); static void Resize(Widget), Redisplay(Widget, XEvent *, Region); static void Destroy(Widget); static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *); /*********************************** * Internal routines. ***********************************/ static void AdjustFirstRowAndCol( XmI18ListWidget ); static void AdjustFirstCol(Widget); static void CalcLocations(Widget); static void CalcColumnInfo(Widget, Boolean); static void SetVisibleSize(Widget, Boolean); static void DisplayList(Widget, short, short, Boolean); static short GetListWidth(Widget); static void HScroll(Widget, short), VScroll(Widget, short); static short CvtPixelValToColNum(Widget, short); static short CvtColNumToPixelVal(Widget, short); static void CvtRowColumnToPosition(Widget, short, short, short *, short *); static void CvtPositionToRowColumn(Widget, short, short, short *, short *); static void ToggleRow(Widget, short), InvertArea(Widget, short, short); static void SelectHeader(Widget, short), DrawSeparator(Widget); static void CreateGCs(Widget), RedrawList(Widget), GetPixmapInfo(Widget); static void DestroyGCs(Widget), Notify(Widget, Boolean); static void ResizeSliders(Widget), SortList(Widget, Boolean); static void SingleClick(XmI18ListWidget); static void MoveListTimeout(XtPointer, XtIntervalId *); static Boolean MakePositionVisible(Widget, short, short, short, int); static void ExtendedSelect(Widget, short); static int IsRowVisible(Widget, short); static int QSortTest(const void *, const void *); static void UnselectRows(Widget, short); static Boolean Search(XmI18ListWidget ilist, XmString xms, int start_row, int start_column, int *found_row, int *found_column); static int FirstSelectedRow(Widget w); static void MakeCellVisible(Widget w, int row, int col); static void CopyColumnTitles(XmI18ListWidget); static void FreeColumnTitles(XmI18ListWidget); static void SelectRow(XmI18ListWidget, int, Boolean, Boolean); static void SelectItems(XmI18ListWidget, XmString, int, Boolean, Boolean); static void CheckSetRenderTable(Widget wid, int offset, XrmValue *value); static void ListConvert(Widget, XtPointer, XmConvertCallbackStruct*); static void ListPreDestProc(Widget, XtPointer, XmDestinationCallbackStruct*); static void CopyToClipboard(Widget, XEvent*, String*, Cardinal*); static void DragDropFinished(Widget, XtPointer, XtPointer); static XmString GetConcatenatedRow(Widget, int); static void ProcessDrag(Widget, XEvent*, String*, Cardinal*); /*********************************** * Actions and Callback function defs. ***********************************/ static void HScrollCallback(Widget, XtPointer, XtPointer); static void VScrollCallback(Widget, XtPointer, XtPointer); static void HSlideLeftArrowCallback(Widget, XtPointer, XtPointer); static void HSlideRightArrowCallback(Widget, XtPointer, XtPointer); static void ButtonDownAction(Widget, XEvent *, String *, Cardinal *); static void ButtonUpOrLeaveAction(Widget, XEvent *, String *, Cardinal *); static void MotionAction(Widget, XEvent *, String *, Cardinal *); /************************************************************ * STATIC DECLARATIONS *************************************************************/ /* * The Translation table routines are getting in the way here. * Since the implicit removal of event disallows using both: * * (2) and button1 * * in the same translation table I have to do all the work myself. */ static char defaultTranslations[] = "~Ctrl ~Shift : ButtonDown()\n\ Ctrl ~Shift : ButtonDown(Toggle)\n\ ~Ctrl Shift : ButtonDown(Extend)\n\ Button1 : Motion()\n\ : ButtonUpOrLeave()\n\ : ProcessDrag()\n\ :c osfInsert: CopyToClipboard()\n\ :osfCopy: CopyToClipboard()"; static XtActionsRec actionsList[] = { {"ButtonDown", ButtonDownAction}, {"ButtonUpOrLeave", ButtonUpOrLeaveAction}, {"Motion", MotionAction}, {"ProcessDrag", ProcessDrag}, {"CopyToClipboard", CopyToClipboard}, }; /* ARGSUSED */ static void SetEntryBackground(Widget w, int offset, XrmValue *value) { XmI18ListWidget ilist = (XmI18ListWidget) w; /* not really used */ value->addr = (XtPointer) &ilist->core.background_pixel; /* * If this function is called, then the value of XmNentryBackground wasn't * set through a resource file specification, so override the current * value of True. If it was set, the value of True stays set in the widget * and the value of the pixel is set through the usual XtRPixel converter. */ XmI18List_entry_background_use(ilist) = False; } static XtResource resources[] = { { XmNnumColumns, XmCNumColumns, XmRShort, sizeof(short), XtOffsetOf(XmI18ListRec, ilist.num_columns), XmRImmediate, (XtPointer) 0 }, { XmNnumRows, XmCNumRows, XmRShort, sizeof(short), XtOffsetOf(XmI18ListRec, ilist.num_rows), XmRImmediate, (XtPointer) 0 }, { XmNselectedColumn, XmCSelectedColumn, XmRShort, sizeof(short), XtOffsetOf(XmI18ListRec, ilist.selected_header), XmRImmediate, (XtPointer) 0 }, { XmNcolumnTitles, XmCColumnTitles, XmRXmStringTable, sizeof(XmString *), XtOffsetOf(XmI18ListRec, ilist.column_titles), XmRImmediate, (XtPointer) NULL }, { XmNentryData, XmCEntryData, XmRPointer, sizeof(XtPointer), XtOffsetOf(XmI18ListRec, ilist.row_data), XmRImmediate, (XtPointer) NULL }, { XmNfirstColumnPixmaps, XmCFirstColumnPixmaps, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmI18ListRec, ilist.first_col_pixmaps), XmRImmediate, (XtPointer) False }, { "pri.vate", "Pri.vate", XmRBoolean, sizeof(Boolean), XtOffsetOf(XmI18ListRec, ilist.check_set_render_table), XmRImmediate, (XtPointer) False }, { XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList), XtOffsetOf(XmI18ListRec, ilist.font_list), XmRCallProc, (XtPointer)CheckSetRenderTable }, { XmNrenderTable, XmCRenderTable, XmRRenderTable, sizeof(XmRenderTable), XtOffsetOf(XmI18ListRec, ilist.font_list), XmRCallProc, (XtPointer)CheckSetRenderTable }, { XmNverticalScrollBar, XmCScrollBar, XmRWidget, sizeof(Widget), XtOffsetOf(XmI18ListRec, ilist.v_bar), XmRImmediate, (XtPointer) NULL }, { XmNhorizontalScrollBar, XmCScrollBar, XmRWidget, sizeof(Widget), XtOffsetOf(XmI18ListRec, ilist.h_bar), XmRImmediate, (XtPointer) NULL }, { XmNfirstRow, XmCFirstLocation, XmRShort, sizeof(short), XtOffsetOf(XmI18ListRec, ilist.first_row), XmRImmediate, (XtPointer) 0 }, { XmNfirstColumn, XmCFirstLocation, XmRShort, sizeof(short), XtOffsetOf(XmI18ListRec, ilist.first_col), XmRImmediate, (XtPointer) 0 }, { XmNdoubleClickCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffsetOf(XmI18ListRec, ilist.double_click), XmRImmediate, (XtPointer) NULL }, { XmNsortFunctions, XmCFunction, XmRFunction, sizeof(Xm18SortFunction **), XtOffsetOf(XmI18ListRec, ilist.sort_functions), XmRImmediate, (XtPointer) NULL }, { XmNselectionPolicy, XmCSelectionPolicy, XmRSelectionPolicy, sizeof(unsigned char), XtOffsetOf(XmI18ListRec, ilist.selection_policy), XmRImmediate, (XtPointer) XmEXTENDED_SELECT }, { XmNsingleSelectionCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffsetOf(XmI18ListRec, ilist.single_select), XmRImmediate, (XtPointer) NULL }, { XmNalignment, XmCAlignment, XmRAlignment, sizeof(unsigned char), XtOffsetOf(XmI18ListRec, ilist.alignment), XmRImmediate, (XtPointer) XmALIGNMENT_BEGINNING }, { XmNstringDirection, XmCStringDirection, XmRStringDirection, sizeof(unsigned char), XtOffsetOf(XmI18ListRec, ilist.string_direction), XmRImmediate, (XtPointer) XmDEFAULT_DIRECTION }, { XmNvisibleItemCount, XmCVisibleItemCount, XmRInt, sizeof(int), XtOffsetOf(XmI18ListRec, ilist.visible_rows), XmRImmediate, (XtPointer) XmMultiList_DEFAULT_VISIBLE_COUNT }, { XmNnewVisualStyle, XmCNewVisualStyle, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmI18ListRec, ilist.new_visual_style), XmRImmediate, (XtPointer) True }, /* process this first; set the value to True */ { "is.entry.background.set", "I.Really.Wonder", XtRBoolean, sizeof(Boolean), XtOffsetOf(XmI18ListRec, ilist.entry_background_use), XmRImmediate, (XtPointer) True }, /* now see if this resource is set in the defaults file */ /* XmNentryBackground currently UNDOCUMENTED */ { XmNentryBackground, XmCBackground, XtRPixel, sizeof(Pixel), XtOffsetOf(XmI18ListRec, ilist.entry_background_pixel), XmRCallProc, (XtPointer) SetEntryBackground } }; XmI18ListClassRec xmI18ListClassRec = { { /* core fields */ /* superclass */ SUPERCLASS, /* class_name */ XM_I18LIST_CLASS_NAME, /* widget_size */ sizeof(XmI18ListRec), /* class_initialize */ ClassInitialize, /* class_part_initialize */ ClassPartInitialize, /* class_inited */ FALSE, /* initialize */ Initialize, /* initialize_hook */ NULL, /* realize */ Realize, /* actions */ actionsList, /* num_actions */ XtNumber(actionsList), /* resources */ (XtResource*)resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ XtExposeCompressMultiple, /* 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 */ defaultTranslations, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ NULL }, { /* Xmprimitive fields */ NULL, /* border_highlight */ NULL, /* border_unhighlight */ XtInheritTranslations, /* translations */ NULL, /* arm_and_activate */ NULL, /* syn resources */ (Cardinal) 0, /* num syn_resources */ NULL /* extension */ }, { /* ICS List fields */ NULL /* extension */ } }; WidgetClass xmI18ListWidgetClass = (WidgetClass)&xmI18ListClassRec; /* Transfer trait record */ static XmConst XmTransferTraitRec ListTransfer = { 0, /* version */ (XmConvertCallbackProc) ListConvert, /* convertProc */ NULL, /* destinationProc */ (XmDestinationCallbackProc) ListPreDestProc, /* destinationPreHookProc */ }; /* * Comment on code structure. * * This code is separated into two separate coordinate spaces. * * The first is the default space defined by pixels and the X Server. * * The second is "input" space that contains all the information * to display in the actual list. This space runs from 0 -> (num_rows - 1) * in the y direction and 0 -> (num_cols - 1) in the x direction. The * input from the application is sent in this space. * * Chris D. Peterson - ICS, Inc. * 10/16/90 */ /************************************************************ * STATIC (EXPORTED) CODE *************************************************************/ /* Function Name: ClassInitialize * Description: Inits class-specific data (offsets) * Arguments: none * Returns: nothing */ static void ClassInitialize() { /* do nothing */ } /* * ClassPartInitialize sets up the fast subclassing for the widget. */ static void #ifdef _NO_PROTO ClassPartInitialize(w_class) WidgetClass w_class ; #else ClassPartInitialize(WidgetClass w_class) #endif /* _NO_PROTO */ { _XmFastSubclassInit (w_class, XmI18LIST_BIT); /* Install transfer trait */ XmeTraitSet((XtPointer)w_class, XmQTtransfer, (XtPointer) &ListTransfer); } /* Function Name: Initialize * Description: Called to initialize information specific * to this widget. * Arguments: req - what was originally requested. * set - what will be created (our superclassed have * already mucked with this) * args, num_args - The arguments passed to * the creation call. * Returns: none. */ /*ARGSUSED*/ static void Initialize(Widget req, Widget set, ArgList args, Cardinal * num_args) { XmI18ListWidget ilist = (XmI18ListWidget) set; XmI18List_column_widths(ilist) = NULL; XmI18List_left_loc(ilist) = 0; XmI18List_state(ilist) = 0; XmI18List_timeout(ilist) = NoTimeout; XmI18List_working_row(ilist) = -1; XmI18List_end(ilist) = XmI18List_anchor(ilist) = NO_SELECTION; XmI18List_time(ilist) = 0L; XmI18List_search_column(ilist) = -1; if (XmI18List_font_list(ilist) == NULL) XmI18List_font_list(ilist) = XmeGetDefaultRenderTable(set, XmTEXT_FONTLIST); CopyColumnTitles(ilist); if (XmI18List_v_bar(ilist) != NULL) { XtAddCallback(XmI18List_v_bar(ilist), XmNvalueChangedCallback, VScrollCallback, (XtPointer) set); XtAddCallback(XmI18List_v_bar(ilist), XmNdragCallback, VScrollCallback, (XtPointer) set); } if (XmI18List_h_bar(ilist) != NULL) { XtAddCallback(XmI18List_h_bar(ilist), XmNvalueChangedCallback, HScrollCallback, (XtPointer) set); XtAddCallback(XmI18List_h_bar(ilist), XmNdragCallback, HScrollCallback, (XtPointer) set); } /* * Add the callbacks to handle left and right arrow selection */ if (XmI18List_h_bar(ilist) != NULL) XtAddCallback(XmI18List_h_bar(ilist), XmNdecrementCallback, HSlideLeftArrowCallback, (XtPointer) set); if (XmI18List_h_bar(ilist) != NULL) XtAddCallback(XmI18List_h_bar(ilist), XmNincrementCallback, HSlideRightArrowCallback, (XtPointer) set); if (XtHeight(req) == 0) { SetVisibleSize(set, (XtWidth(req) == 0)); } /* If layout_direction is set, it overrides string_direction. * If string_direction is set, but not layout_direction, use * string_direction value. * If neither is set, get from parent */ if (XmPrim_layout_direction(ilist) != XmDEFAULT_DIRECTION) { XmI18List_string_direction(ilist) = XmDirectionToStringDirection(XmPrim_layout_direction(ilist)); } else if (XmI18List_string_direction(ilist) != XmDEFAULT_DIRECTION) { XmPrim_layout_direction(ilist) = XmStringDirectionToDirection(XmI18List_string_direction(ilist)); } else { XmPrim_layout_direction(ilist) = _XmGetLayoutDirection(XtParent(set)); XmI18List_string_direction(ilist) = XmDirectionToStringDirection(XmPrim_layout_direction(ilist)); } if (!XmRepTypeValidValue(XmRID_STRING_DIRECTION, XmI18List_string_direction(ilist), set)) { XmI18List_string_direction(ilist) = XmSTRING_DIRECTION_L_TO_R; } } /* Function Name: Realize * Description: Called to realize this widget. * Arguments: w - Extended List Widget to realize. * valueMask, attributes - attributes to use when creating * this widget's window. * Returns: none. * * This overrides the Manager's frobbing with various values. */ static void Realize(Widget w, Mask *valueMask, XSetWindowAttributes * attributes) { XmI18ListWidget ilist = (XmI18ListWidget)w; attributes->bit_gravity = ForgetGravity; *valueMask |= CWBitGravity; CreateGCs(w); SortList(w, False); CalcColumnInfo(w, False); /* get initial left location based on first column resource */ /* have to calculate it because the columns are different widths */ AdjustFirstRowAndCol( ilist ); { XtRealizeProc realize; _XmProcessLock(); realize = xmI18ListWidgetClass->core_class.superclass->core_class.realize; _XmProcessUnlock(); (*realize) (w, valueMask, attributes); } { XtWidgetProc resize; _XmProcessLock(); resize = xmI18ListWidgetClass->core_class.resize; _XmProcessUnlock(); (*resize)(w); } } /* Function Name: SetValues * Description: Called when some widget data needs to be modified on- * the-fly. * Arguments: current - the current (old) widget values. * request - before superclassed have changed things. * set - what will acutally be the new values. * args, num_args - the arguments in the list. * Returns: none * * NOTE: No provision is made for SetValues on the mini-icons. * * Modified: 03/17/92 beth - converted to pixels */ /*ARGSUSED*/ static Boolean SetValues(Widget current, Widget request, Widget set, ArgList args, Cardinal * num_args) { XmI18ListWidget i_old = (XmI18ListWidget)current; XmI18ListWidget i_set = (XmI18ListWidget)set; register int i; Boolean redisplay = False; Boolean recalculate = False; Boolean resort = False; Boolean refreshGCs = False; Boolean readjust = False; Boolean check_pos = False; Boolean copyTitles = False; for (i = 0; i < *num_args; i++) { String name = args[i].name; if (streq(XmNcolumnTitles, name)) { copyTitles = True; redisplay = recalculate = XtIsRealized(set); } if (streq(XmNentryData, name)) { redisplay = recalculate = resort = XtIsRealized(set); } if (streq(XmNsortFunctions, name)) { redisplay = resort = XtIsRealized(set); } if (streq(XmNfirstRow, name) || streq(XmNfirstColumn,name)) { check_pos = True; } if (streq(XmNnumRows, name)) { check_pos = True; /* int num_rows = (XmI18List_num_rows(i_set) - XmI18List_visible_rows(i_set)); check_pos = (XmI18List_first_row(i_set) > ((num_rows < 0) ? 0 : num_rows)); */ } } if ((XmI18List_v_bar(i_set) != XmI18List_v_bar(i_old)) || (XmI18List_h_bar(i_set) != XmI18List_h_bar(i_old))) { XmI18List_v_bar(i_set) = XmI18List_v_bar(i_old); XmI18List_h_bar(i_set) = XmI18List_h_bar(i_old); XmeWarning(current, XmNstaticScrollbarsMsg); } if( XtIsSensitive(current) != XtIsSensitive(set) ) { redisplay = XtIsRealized(set); } if (XmI18List_font_list(i_set) != XmI18List_font_list(i_old)) { refreshGCs = recalculate = redisplay = XtIsRealized(set); } if ((i_set->primitive.foreground != i_old->primitive.foreground) || (i_set->core.background_pixel != i_old->core.background_pixel)) { refreshGCs = redisplay = XtIsRealized(set); } if (XmI18List_selected_header(i_set) != XmI18List_selected_header(i_old)) { resort = redisplay = XtIsRealized(set); } /* XmNvisibleItemCount has been changed... */ if (XmI18List_visible_rows(i_set) != XmI18List_visible_rows(i_old)) { if (XmI18List_visible_rows(i_set) < 1) { XmI18List_visible_rows(i_set) = 1; /* reset value to 1 */ XmeWarning(current, XmNforceGreaterThanZeroMsg); } /* Change height only... */ SetVisibleSize(set, False); } /* * Convert the user desired column to view to pixels * if and only if the entry Data has been specified */ if ( XmI18List_row_data(i_set) != NULL || XmI18List_row_data(i_old) != NULL ) { #ifdef UNUSED_CODE short column; if (XmI18List_first_col(i_set) > XmI18List_num_columns(i_set)) { column = XmI18List_num_columns(i_set) - 1; } else if (XmI18List_first_col(i_set) <= 0) { column = 0; } else { column = XmI18List_first_col(i_set) - 1; } #endif if ((XmI18List_num_rows(i_old) != XmI18List_num_rows(i_set)) || (XmI18List_num_columns(i_old) != XmI18List_num_columns(i_set)) || (XmI18List_row_data(i_set) != XmI18List_row_data(i_old))) { redisplay = recalculate = XtIsRealized(set); } if ((XmI18List_first_col(i_set) != XmI18List_first_col(i_old)) || (XmI18List_first_row(i_set) != XmI18List_first_row(i_old)) || check_pos) { redisplay = readjust = XtIsRealized(set); } } if (XmI18List_entry_background_pixel(i_set) != XmI18List_entry_background_pixel(i_old)) { /* it was explicitly set via XtSetValues, so the user knows about it */ XmI18List_entry_background_use(i_set) = True; redisplay = True; refreshGCs = True; } if (refreshGCs) { DestroyGCs(current); CreateGCs(set); } if (XmI18List_num_columns(i_old) != XmI18List_num_columns(i_set)) { /* CR03506 */ recalculate = redisplay = XtIsRealized(set); } if (copyTitles) { FreeColumnTitles(i_old); CopyColumnTitles(i_set); } if (readjust && !recalculate) { AdjustFirstRowAndCol(i_set); } else if (recalculate) { CalcColumnInfo(set, True); CalcLocations(set); if (!readjust) AdjustFirstCol(set); else AdjustFirstRowAndCol( i_set ); } if (resort) SortList(set, False); return(redisplay); } /* Function Name: Redisplay * Description: This function redraws the list contents. * Arguments: w - the Frame Widget widget. * event - event that caused the exposure. * region - the region containing all the exposures. * Returns: none * * Modified: 03/17/92 beth - converted to pixels */ /*ARGSUSED*/ static void Redisplay(Widget w, XEvent * event, Region region) { XmI18ListWidget ilist = (XmI18ListWidget) w; short num_rows; #ifdef notdef XExposeEvent * exp_event = (XExposeEvent *) &(event->xexpose); #endif num_rows = XmI18List_num_rows(ilist) - XmI18List_first_row(ilist); /* * Just refresh the entire window each time. */ DisplayList(w, XmI18List_first_row(ilist), num_rows, TRUE); ResizeSliders( w ); DrawSeparator(w); } /* Function Name: Resize * Description: Called when this widget has been resized. * Arguments: w - Extended List Widget to realize. * Returns: none. */ static void Resize(Widget w) { if (!XtIsRealized(w)) return; CalcLocations(w); AdjustFirstCol(w); ResizeSliders(w); } /* Function Name: Destroy * Description: Cleans up after the widget. * Arguments: w - the widget. * Returns: none. */ static void Destroy(Widget w) { XmI18ListWidget ilist = (XmI18ListWidget) w; DestroyGCs(w); FreeColumnTitles(ilist); XtFree((XtPointer) XmI18List_column_widths(ilist)); } /************************************************************ * * Callbacks and Action Routines. * ************************************************************/ /************************************************************ * * This Selection code is pretty confusing, but here's the skinny. * * When the first button click comes in we call the single click * call back and remember when it happened. * * If a second click comes we see if multi click time has passed and if * not then we have a double click and should call the proper callback. * * If we move out of the current row then reset the stored time to zero since * we should not call the double click callback. * * The single click timeout takes care of initializing the extended * select code. We know it will be executed before the motion callback * ever does anything interesting because of the action defined in the * previous paragraph. * ************************************************************/ /* Function Name: ButtonDownAction * Description: Called when the user sends a button up to the ilist. * Arguments: w - the ilist widget. * event - the event that caused this action. * params, num_params - action routine parameters. * Returns: none. */ /*ARGSUSED*/ static void ButtonDownAction(Widget w, XEvent *event, String *params, Cardinal *num_params) { short row, col; XmI18ListWidget ilist = (XmI18ListWidget) w; XButtonEvent * bevent = (XButtonEvent *) event; if (*num_params > 1) { XmeWarning(w, XmNbadMotionParamsMsg); return; } if (XmI18List_selection_policy(ilist) != XmSINGLE_SELECT) { XmI18List_state(ilist) &= ~(EXTEND | TOGGLE); /* remove these bits.*/ if (*num_params == 1) { switch (params[0][0]) { case 'e': case 'E': XmI18List_state(ilist) |= EXTEND; /* set extended mode. */ break; case 't': case 'T': XmI18List_state(ilist) |= TOGGLE; /* set extended mode. */ break; default: { _XmWarningMsg(w, XmNbadActionParameters, XmNbadActionParametersMsg, params, 1); } } } } if (event->type != ButtonPress) { static String params[] = { "BtnDown" }; _XmWarningMsg(w, XmNunexpectedEvent, XmNunexpectedEventMsg, params, 1); return; } CvtPositionToRowColumn(w, bevent->x, bevent->y, &row, &col); if (XmI18List_working_row(ilist) != row) { /* * This click not in the same row as the previous one, reset time to * zero so that double click will not fire. */ XmI18List_time(ilist) = 0; } XmI18List_working_row(ilist) = row; XmI18List_working_col(ilist) = col; /* * Invalid row. */ if ((col >= XmI18List_num_columns(ilist)) || (row >= XmI18List_num_rows(ilist))) { XBell(XtDisplay(w), 0); return; } /* * Click in the column headers. No need to deal with double clicks * or extended selections. */ if (XmI18List_working_row(ilist) == IN_COLUMN_HEADER) { SelectHeader((Widget) ilist, XmI18List_working_col(ilist)); return; } else /* reset search column since user selected a new row */ XmI18List_search_column(ilist) = -1; if ((event->xbutton.time - XmI18List_time(ilist)) > XtGetMultiClickTime(XtDisplay(w))) { SingleClick(ilist); } } /* Function Name: ButtonUpOrLeaveAction * Description: Called when the user sends a button up to the ilist. * Arguments: w - the ilist widget. * event - the event that caused this action. * params, num_params - action routine parameters. * Returns: none. */ /*ARGSUSED*/ static void ButtonUpOrLeaveAction(Widget w, XEvent *event, String *params, Cardinal *num_params) { Boolean notify_type; XmI18ListWidget ilist = (XmI18ListWidget) w; if (event->type != ButtonRelease) { static String params[] = { "BtnUp or BtnLeave" }; _XmWarningMsg(w, XmNunexpectedEvent, XmNunexpectedEventMsg, params, 1); return; } /* * Invalid row started selection. */ if ((XmI18List_working_col(ilist) >= XmI18List_num_columns(ilist)) || (XmI18List_working_row(ilist) >= XmI18List_num_rows(ilist))) { return; } /* * Click in a row, need to handle double click. * notify_type == True specifies double click, False is a single click. */ notify_type = ((event->xbutton.time - XmI18List_time(ilist)) <= XtGetMultiClickTime(XtDisplay(w))); Notify(w, notify_type); XmI18List_time(ilist) = event->xbutton.time; /* * Reset all these flags. */ XmI18List_state(ilist) &= ~OUTSIDE_WIDGET; } /* Function Name: MotionAction * Description: Called when the user sends a button up to the ilist. * Arguments: w - the ilist widget. * event - the event that caused this action. * params, num_params - action routine parameters. * Returns: none. */ /*ARGSUSED*/ static void MotionAction(Widget w, XEvent *event, String *params, Cardinal *num_params) { XmI18ListWidget ilist = (XmI18ListWidget) w; XButtonEvent * bevent = (XButtonEvent *) event; short row, col; short y = bevent->y; /* * Invalid row to start selection. */ if ((XmI18List_working_col(ilist) >= XmI18List_num_columns(ilist)) || (XmI18List_working_row(ilist) >= XmI18List_num_rows(ilist))) { return; } if (XmI18List_selection_policy(ilist) == XmSINGLE_SELECT) return; /* Do nothing here... */ CvtPositionToRowColumn(w, bevent->x, y, &row, &col); /* * We have not moved to a new row, or we started in the headers then * do nothing. */ if ((row == XmI18List_working_row(ilist)) || (XmI18List_working_row(ilist) == IN_COLUMN_HEADER)) { return; } /* * Begin reporting motion events. */ if (y < 0) { if (XmI18List_state(ilist) & OFF_TOP) return; /* We are already off the top. */ else XmI18List_state(ilist) |= OFF_TOP; } else XmI18List_state(ilist) &= ~OFF_TOP; /* remove this flag. */ if (y > ((short) w->core.height)) { if (XmI18List_state(ilist) & OFF_BOTTOM) return; /* We are already off the bottom. */ else XmI18List_state(ilist) |= OFF_BOTTOM; } else XmI18List_state(ilist) &= ~OFF_BOTTOM; /* remove this flag. */ if (!(XmI18List_state(ilist) & OUTSIDE_WIDGET)) { /* Not outside widget.*/ if (XmI18List_timeout(ilist) != NoTimeout) { (void) XtRemoveTimeOut(XmI18List_timeout(ilist)); XmI18List_timeout(ilist) = NoTimeout; /* CR03695 */ } ExtendedSelect(w, row); XmI18List_working_row(ilist) = NO_SELECTION; /* set to nothing... */ return; } XmI18List_timeout(ilist) = XtAppAddTimeOut(XtWidgetToApplicationContext(w), DELAY_TIME(w), MoveListTimeout, (XtPointer) w); } /* Function Name: SingleClick * Description: Called to process the single click. * Arguments: ilist - the ilist widget. * Returns: none. */ /*ARGSUSED*/ static void SingleClick(XmI18ListWidget ilist) { if (XmI18List_selection_policy(ilist) == XmSINGLE_SELECT) { /* * Unselect all rows except the working row. */ UnselectRows((Widget) ilist, XmI18List_working_row(ilist)); } else { register short i, last; XmMultiListRowInfo * ptr; last = XmI18List_num_rows(ilist); if (!(XmI18List_state(ilist) & EXTEND)) { XmI18List_end(ilist) = XmI18List_anchor(ilist) = XmI18List_working_row(ilist); if (XmI18List_state(ilist) & TOGGLE) ToggleRow((Widget) ilist, XmI18List_working_row(ilist)); else /* !EXTEND and !TOGGLE */ UnselectRows((Widget) ilist, XmI18List_working_row(ilist)); for (ptr = XmI18List_row_data(ilist), i = 0; i < last; i++, ptr++) ptr->old_sel_state = ptr->selected; } else { short l_first, l_last; if (XmI18List_anchor(ilist) == NO_SELECTION) return; if (XmI18List_end(ilist) < XmI18List_anchor(ilist)) { l_first = XmI18List_end(ilist); l_last = XmI18List_anchor(ilist); } else { l_first = XmI18List_anchor(ilist); l_last = XmI18List_end(ilist); } for (ptr = XmI18List_row_data(ilist), i = 0; i < last; i++, ptr++) { if ((i >= l_first) && (i <= l_last)) ptr->old_sel_state = FALSE; else ptr->old_sel_state = ptr->selected; } if (XmI18List_state(ilist) & EXTEND) ExtendedSelect((Widget) ilist, XmI18List_working_row(ilist)); } } } /* Function Name: MoveListTimeout * Description: Called when enough time passes so that we know it * is time to move the list. * Arguments: w_ptr - the ilist widget. * id - the interval id. * Returns: none. */ /*ARGSUSED*/ static void MoveListTimeout(XtPointer w_ptr, XtIntervalId *id) { short row; int v_inc = 0; Widget w = (Widget) w_ptr; XmI18ListWidget ilist = (XmI18ListWidget) w; if (XmI18List_state(ilist) & OFF_TOP) { /* * Scroll up if top row is not on screen. */ if ((IsRowVisible(w, 0)) != 0) v_inc = -1; } if (XmI18List_state(ilist) & OFF_BOTTOM) { /* * Scroll up if last row is not on screen. */ if ((IsRowVisible(w, XmI18List_num_rows(ilist) - 1)) != 0) v_inc = 1; } if (v_inc == 0) { XmI18List_timeout(ilist) = NoTimeout; /* CR03695 */ return; } VScroll(w, v_inc); ResizeSliders(w); /* Reset the sliders on my scrollbars. */ /* * Get new end point (first or last row on screen). */ if (v_inc < 0) row = XmI18List_first_row(ilist); else { register int i; register int row_height = XmI18List_row_height(ilist); register Dimension h, height = w->core.height; i = XmI18List_first_row(ilist); h = (XmI18List_sep_y(ilist) + VERTICAL_SPACE/2); if(XmI18List_new_visual_style(ilist)) h += ilist->primitive.shadow_thickness; else h += LINE_HEIGHT; /* * This used to be: * for (; h < height; h += row_height, i++) {} * * ... sigh ... */ while(h < height) { h += row_height; i++; } i--; if (i > (XmI18List_num_rows(ilist) - 1)) row = XmI18List_num_rows(ilist) - 1; else row = i; } ExtendedSelect(w, row); /* * And we can do it again... */ XmI18List_timeout(ilist) = XtAppAddTimeOut(XtWidgetToApplicationContext(w), DELAY_TIME(w), MoveListTimeout, (XtPointer) w); } /* Function Name: Notify * Description: Calls the callbacks when a notify should happen. * Arguments: w - the ilist widget. * dclick - is this a double click? * Returns: none. */ static void Notify(Widget w, Boolean dclick) { XmI18ListWidget ilist = (XmI18ListWidget) w; Boolean first = True; static XrmQuark elist_q; int row; if (first) { elist_q = XrmStringToQuark(XM_EXT_18_LIST_CLASS_NAME); first = False; } row = (int) XmI18List_working_row(ilist); /* * If we didn't click on a row, don't call the callbacks */ if(row == IN_COLUMN_HEADER) return; if( (row < XmI18List_num_rows(ilist)) && (XmI18List_working_col(ilist) < XmI18List_num_columns(ilist)) ) { Widget elist = XtParent(XtParent(w)); XtPointer cbdata; if(row >= 0) cbdata = (XtPointer) &(XmI18List_row_data(ilist)[row]); else cbdata = NULL; /* * If my parent is an extended list, then call all callbacks * on its callback list. * * This is a hack to get around a toolkit specification bug. * * Chris D. Peterson (11/25/90) */ if( dclick ) { if( _XmUtilIsSubclassByNameQ(elist, elist_q) ) { XtCallCallbacks(elist, XmNdoubleClickCallback, cbdata); } XtCallCallbackList(w, XmI18List_double_click(ilist), cbdata); } else /* Is Single notify */ { if( _XmUtilIsSubclassByNameQ(elist, elist_q) ) { XtCallCallbacks(elist, XmNsingleSelectionCallback, cbdata); } XtCallCallbackList( w, XmI18List_single_select(ilist), cbdata); } } } /************************************************************ * * Internal routines. * ************************************************************/ /* Function Name: GetListWidth * Description: determines total width of data in list * Arguments: w - Extended List Widget * Returns: total width of data in list */ static short GetListWidth(Widget w) { XmI18ListWidget ilist = (XmI18ListWidget) w; register int i, width; /* * Get maximum width of data to display */ width = HORIZONTAL_SPACE; for (i=0; i < XmI18List_num_columns(ilist); i++) width += XmI18List_column_widths(ilist)[i] + HORIZONTAL_SPACE; return((short) width); } /* Function Name: AdjustFirstCol * Description: Called when this widget has been resized. * Arguments: w - Extended List Widget to realize. * Returns: none. */ static void AdjustFirstCol(Widget w) { XmI18ListWidget ilist = (XmI18ListWidget) w; register int i, extra, width; /* * Determine if the first pixel position is negative or positive */ if ((0 - XmI18List_left_loc(ilist)) >= 0) i = 0 - XmI18List_left_loc(ilist); else i = XmI18List_left_loc(ilist); /* * If the current pixel position (signed positive) plus the core * width of the list is greater than the whole width of the data * being displayed, then we need to adjust the first pixel position */ width = GetListWidth((Widget) ilist); extra = width - (ilist->core.width + i); if (extra < 0) XmI18List_left_loc(ilist) = 0 - (i + extra); } /* Function Name: ExtendedSelect * Description: Handle the extended selection. * Arguments: w - the ilist widget. * row - current row. * extend - extend the selection. * Returns: none */ static void ExtendedSelect(Widget w, short row) { XmI18ListWidget ilist = (XmI18ListWidget) w; register short i, first, last, end, anchor, out_first, out_last; Boolean state; XmMultiListRowInfo * ptr; if (row >= XmI18List_num_rows(ilist)) row = XmI18List_num_rows(ilist) - 1; else if (row < 0) row = 0; end = XmI18List_end(ilist); /* The old non-anchor end point. */ anchor = XmI18List_anchor(ilist); XmI18List_end(ilist) = row; /* New non-anchor end point. */ state = (XmI18List_row_data(ilist) + anchor)->selected; if (XmI18List_anchor(ilist) < end) { out_first = anchor; out_last = end; } else { out_first = end; out_last = anchor; } if (row < out_first) { first = row; last = out_last; out_first = out_last + 1; /* nothing removed from list. */ } else if (row > out_last) { first = out_first; last = row; out_first = out_last + 1; /* nothing removed from list. */ } else { /* between first and last. */ if (out_first == anchor) { first = out_first; last = row; out_first = row + 1; } else { out_last = row - 1; first = row; last = out_last; } } /* * Handle the case of a jump from one side of the anchor to the other. */ if (((end > anchor) && (row < anchor)) || ((end < anchor) && (row > anchor))) { register short t_first, t_last; if ((end > anchor) && (row < anchor)) { t_first = anchor + 1; t_last = end; last = anchor; } else { /* (end < anchor) && (row > anchor) */ first = anchor; t_first = end; t_last = anchor - 1; } /* * Reset all these nodes to their previous state. */ ptr = XmI18List_row_data(ilist) + t_first; for (i = t_first; i <= t_last; i++, ptr++) if (ptr->old_sel_state != ptr->selected) ToggleRow(w, i); } /* * Set all these nodes to the same state as the anchor. */ for (ptr = XmI18List_row_data(ilist) + first,i = first; i <= last;i++, ptr++) if (ptr->selected != state) ToggleRow(w, i); /* * Reset all these nodes to their previous state. */ ptr = XmI18List_row_data(ilist) + out_first; for (i = out_first; i <= out_last;i++, ptr++) { if (ptr->old_sel_state != ptr->selected) ToggleRow(w, i); } } /* Function Name: VScrollCallback * Description: Called by the vert. scrollbar when it has been selected * by the user. * Arguments: w - the scrollbar widget. * client_data - the ilist widget. * call_data - information about where to scroll. * Returns: none */ /*ARGSUSED*/ static void VScrollCallback(Widget w, XtPointer client_data, XtPointer call_data) { XmI18ListWidget ilist = (XmI18ListWidget) client_data; XmScrollBarCallbackStruct * scroll_info; scroll_info = (XmScrollBarCallbackStruct *) call_data; VScroll((Widget) ilist, (short) (scroll_info->value - XmI18List_first_row(ilist))); } /* Function Name: HScrollCallback * Description: Called by the horiz. scrollbar when it * has been selected. * by the user. * Arguments: w - the scrollbar widget. * client_data - the ilist widget. * call_data - information about where to scroll. * Returns: none * * Modified: 03/17/92 beth - converted to pixels */ /*ARGSUSED*/ static void HScrollCallback(Widget w, XtPointer client_data, XtPointer call_data) { XmI18ListWidget ilist = (XmI18ListWidget) client_data; XmScrollBarCallbackStruct *scroll_info; scroll_info = (XmScrollBarCallbackStruct *) call_data; HScroll((Widget)ilist,(short) scroll_info->value); } /* Function Name: HSlideLeftArrowCallback * Description: handles repositioning of the window data according * to how long the user pressed on the left arrow * Arguments: w - the ilist widget. * client_data - the ilist widget. * junk - ***UNUSED*** * Returns: none * * Added: 03/19/92 beth - for conversion to pixels */ /*ARGSUSED*/ static void HSlideLeftArrowCallback(Widget w, XtPointer client_data, XtPointer junk) { XmI18ListWidget ilist = (XmI18ListWidget) client_data; /* * We are either going to left adjust the first visible column * so that the user is able to see the column beginning with the * first pixel or - if the first visible pixel is currently between * columns, then we will shift all columns once to the left, * thereby changing the first visible column. */ /* * Don't bother if we're already as far left as we can go */ if (XmI18List_left_loc(ilist) <= 0) { register int i, begin, end, before = 0; for (i=0; i < XmI18List_num_columns(ilist); i++) { if (i == 0) begin = before = XmI18List_left_loc(ilist); else begin = before + HORIZONTAL_SPACE; end = begin + XmI18List_column_widths(ilist)[i]; if (begin < 0 && end >= 0) { /* * Leftmost column column is partially visible * left adjust it including horizontal spacing */ XmI18List_left_loc(ilist) += 0 - before; break; } else if (begin >= 0 && i > 0) { /* * Shift Leftmost column to the right once */ XmI18List_left_loc(ilist) += 0 - before + HORIZONTAL_SPACE; XmI18List_left_loc(ilist) += XmI18List_column_widths(ilist)[i-1]; break; } before = end; } } else { XmI18List_left_loc(ilist) = 0; } XClearWindow(XtDisplay(ilist), XtWindow(ilist)); DisplayList((Widget) ilist, XmI18List_first_row(ilist), (XmI18List_num_rows(ilist) - XmI18List_first_row(ilist)), TRUE); DrawSeparator((Widget) ilist); ResizeSliders((Widget) ilist); } /* Function Name: HSlideRightArrowCallback * Description: handles repositioning of the window data according * to how long the user pressed on the right arrow * Arguments: w - the ilist widget. * client_data - the ilist widget. * junk - ***UNUSED*** * Returns: none * * Added: 03/19/92 beth - for conversion to pixels */ /*ARGSUSED*/ static void HSlideRightArrowCallback(Widget w, XtPointer client_data, XtPointer junk) { XmI18ListWidget ilist = (XmI18ListWidget) client_data; register int i, width; /* * We are either going to left adjust the last visible column * so that the user is able to see the column beginning with the * first pixel or the entire column - if the last visible pixel * is currently between columns, then we will shift all columns * once to the right, thereby changing the last visible column. */ if ((0 - XmI18List_left_loc(ilist)) >= 0) i = XmI18List_left_loc(ilist); else i = 0 - XmI18List_left_loc(ilist); /* * Don't bother if we're already as far right as we can go */ width = GetListWidth((Widget) ilist); if ((int)width > (int)(i + ilist->core.width)) { register int begin, end, before = 0; for (i=0; i < XmI18List_num_columns(ilist); i++) { if (i == 0) begin = before = XmI18List_left_loc(ilist); else begin = before + HORIZONTAL_SPACE; end = begin + XmI18List_column_widths(ilist)[i]; if ((begin < 0 && end > 0) || (begin >= 0 && i < XmI18List_num_columns(ilist))) { /* * Leftmost column is partially visible * make as much of it visible as possible */ if ((i + 1) == XmI18List_num_columns(ilist)) XmI18List_left_loc(ilist) = 0 - (width - ilist->core.width); else XmI18List_left_loc(ilist) -= end; break; } before = end; } } else { XmI18List_left_loc(ilist) = 0 - (width - ilist->core.width); } XClearWindow(XtDisplay(ilist), XtWindow(ilist)); DisplayList((Widget) ilist, XmI18List_first_row(ilist), (XmI18List_num_rows(ilist) - XmI18List_first_row(ilist)), TRUE); DrawSeparator((Widget) ilist); ResizeSliders((Widget) ilist); } /************************************************************ * * Local Code * ************************************************************/ /* Function Name: CalcLocations * Description: Calculates the locations of the text positions. * Arguments: w - the ext list widget. * Returns: none */ static void CalcLocations(Widget w) { XmI18ListWidget ilist = (XmI18ListWidget) w; if (XmI18List_num_columns(ilist) && XmI18List_column_titles(ilist)) /* CR03506 */ XmI18List_sep_y(ilist) = 2 * VERTICAL_SPACE + XmI18List_title_row_height(ilist); else XmI18List_sep_y(ilist) = 0; /* CR03506 */ if(XmI18List_new_visual_style(ilist)) XmI18List_sep_y(ilist) += ilist->primitive.shadow_thickness; } /* Function Name: DisplayList * Description: Displays the contents of the list. * Arguments: w - the extended list widget. * start_row - the first row to display * num_rows - the number of rows to display * redraw_headers - boolean flag for redrawing * Returns: none * * Modified: 03/17/92 beth - converted to pixels */ static void DisplayList(Widget w, short start_row, short num_rows, Boolean redraw_headers) { XmI18ListWidget ilist = (XmI18ListWidget) w; register int i, j, row_height, title_row_height, y_loc, x_loc; register Position cur_x=0, cur_y, start_y; register short *col_widths, tot_width; XmString ptr; GC gc; Dimension width_unused, text_height; Dimension height = ilist->core.height; Dimension width = ilist->core.width; register short end_row = start_row + num_rows - 1; /* * The start position is always first_col, which * should have been set to the correct value before * calling this routine */ if (XmI18List_left_loc(ilist) >= 0) XmI18List_left_loc(ilist) = HORIZONTAL_SPACE; if (LayoutIsRtoLP(w)) cur_x = width - XmI18List_left_loc(ilist); else cur_x = XmI18List_left_loc(ilist); col_widths = XmI18List_column_widths(ilist); tot_width = GetListWidth((Widget) ilist); /* * Find the row height. */ row_height = XmI18List_row_height(ilist) + VERTICAL_SPACE; title_row_height = XmI18List_title_row_height(ilist) + VERTICAL_SPACE; /* * Find the selected row, and draw in the select bar in the * background color. * * NOTE: this must draw exactly the same rectangle as InvertArea. */ cur_y = (XmI18List_sep_y(ilist) + VERTICAL_SPACE/2 + (start_row - XmI18List_first_row(ilist)) * row_height); if(XmI18List_new_visual_style(ilist)) { cur_y += ilist->primitive.shadow_thickness; } else { cur_y += LINE_HEIGHT; } if (XmI18List_entry_background_use(ilist)) { Dimension height = ilist->core.height; if(XmI18List_new_visual_style(ilist)) height -= ilist->primitive.shadow_thickness; else height -= LINE_HEIGHT; XFillRectangle(XtDisplay(w), XtWindow(w), XmI18List_entry_background_fill_gc(ilist), LayoutIsRtoLP(w) ? -tot_width + XtWidth(w) - XmI18List_left_loc(ilist) + HORIZONTAL_SPACE/2 : XmI18List_left_loc(ilist) - HORIZONTAL_SPACE/2, cur_y, #define MaX(a,b) (a>b?a:b) (unsigned int) MaX(w->core.width,tot_width), #undef MaX (unsigned int) height); } for (i = start_row ; i <= end_row ; i++) { if (XmI18List_row_data(ilist)[i].selected) { XFillRectangle(XtDisplay(w), XtWindow(w), XmI18List_gc(ilist), LayoutIsRtoLP(w) ? -tot_width + XtWidth(w) - XmI18List_left_loc(ilist) + HORIZONTAL_SPACE/2 : XmI18List_left_loc(ilist) - HORIZONTAL_SPACE/2, cur_y, (unsigned int) tot_width, (unsigned int) row_height); } cur_y += row_height; } start_y = ((XmI18List_sep_y(ilist) + VERTICAL_SPACE) + (start_row - XmI18List_first_row(ilist)) * row_height); if(XmI18List_new_visual_style(ilist)) { start_y += ilist->primitive.shadow_thickness; } else { start_y += LINE_HEIGHT; } /* * Draw in the Text and icons. */ for (i = 0; i < XmI18List_num_columns(ilist); i++) { GC entry_gc; if (LayoutIsRtoLP(w)) { if (cur_x < 0) return; else cur_x -= col_widths[i]; } else { if (cur_x > (int) width) return; } if (redraw_headers) { /* * Paint the Column Header */ if ((XmI18List_selected_header(ilist) == i) && (XmI18List_sort_functions(ilist) != NULL)) { if (XtIsSensitive(w)) gc = XmI18List_rev_gc(ilist); else gc = XmI18List_stippled_rev_gc(ilist); y_loc = VERTICAL_SPACE/2; x_loc = cur_x - HORIZONTAL_SPACE/2; XFillRectangle(XtDisplay(w), XtWindow(w), XmI18List_gc(ilist), x_loc, y_loc, (unsigned int) col_widths[i] + HORIZONTAL_SPACE, (unsigned int) title_row_height); } else { if (XtIsSensitive(w)) gc = XmI18List_gc(ilist); else gc = XmI18List_stippled_gc(ilist); } if (XmI18List_column_titles(ilist) != NULL) { ptr = XmI18List_column_titles(ilist)[i]; cur_y = VERTICAL_SPACE; if(XmI18List_new_visual_style(ilist)) cur_y += ilist->primitive.shadow_thickness; XmStringDraw(XtDisplay(w), XtWindow(w), XmI18List_font_list(ilist), ptr, gc, cur_x, cur_y, col_widths[i], XmI18List_alignment(ilist), XmPrim_layout_direction(ilist), NULL); } } /* * Put in the mini icons if this is column 0 and * first_col_pixmaps is true. */ if ( (XmI18List_first_col_pixmaps(ilist)) && (i == 0)) { int pix_y_offset; cur_y = XmI18List_sep_y(ilist) + VERTICAL_SPACE; if(XmI18List_new_visual_style(ilist)) cur_y += ilist->primitive.shadow_thickness; else cur_y += LINE_HEIGHT; for (j = start_row; j <= end_row; j++) { if (IsValidPixmap(XmI18List_row_data(ilist)[j].pixmap)) { if (XmI18List_row_data(ilist)[j].selected) entry_gc = XmI18List_entry_background_rev_gc(ilist); else entry_gc = XmI18List_entry_background_gc(ilist); /* * Copy it in. */ pix_y_offset = (row_height - XmI18List_row_data(ilist)[j].pix_height)/2; if (XmI18List_row_data(ilist)[j].pix_depth == 1 ){ XCopyPlane(XtDisplay(w), XmI18List_row_data(ilist)[j].pixmap, XtWindow(w), entry_gc, 0, 0, XmI18List_row_data(ilist)[j].pix_width, XmI18List_row_data(ilist)[j].pix_height, LayoutIsRtoLP(w) ? width - XmI18List_left_loc(ilist) - XmI18List_row_data(ilist)[j].pix_width : cur_x, cur_y+pix_y_offset, (unsigned long) 1); } else { XCopyArea(XtDisplay(w), XmI18List_row_data(ilist)[j].pixmap, XtWindow(w), entry_gc, 0, 0, XmI18List_row_data(ilist)[j].pix_width, XmI18List_row_data(ilist)[j].pix_height, LayoutIsRtoLP(w) ? width - XmI18List_left_loc(ilist) - XmI18List_row_data(ilist)[j].pix_width : cur_x, cur_y+pix_y_offset ); } } cur_y += row_height; if (cur_y > (int) height) break; } } else { /* * Draw in the row data. */ cur_y = start_y; for (j = start_row; j <= end_row; j++) { if (cur_y > (int) height) break; if (XtIsSensitive(w)) { if (XmI18List_row_data(ilist)[j].selected) entry_gc = XmI18List_entry_background_rev_gc(ilist); else entry_gc = XmI18List_entry_background_gc(ilist); } else { if (XmI18List_row_data(ilist)[j].selected) entry_gc = XmI18List_entry_background_stippled_rev_gc(ilist); else entry_gc = XmI18List_entry_background_stippled_gc(ilist); } ptr = XmI18List_row_data(ilist)[j].values[i]; XmStringExtent(XmI18List_font_list(ilist), ptr, &width_unused, &text_height); /* to center each string within its row */ cur_y += (int)(XmI18List_row_height(ilist) - VERTICAL_SPACE - text_height)/2; XmStringDraw(XtDisplay(w), XtWindow(w), XmI18List_font_list(ilist), ptr, entry_gc, cur_x, cur_y, col_widths[i], XmI18List_alignment(ilist), XmPrim_layout_direction(ilist), NULL); cur_y -= (int)(XmI18List_row_height(ilist) - VERTICAL_SPACE - text_height)/2; cur_y += XmI18List_row_height(ilist) + VERTICAL_SPACE; } } if (LayoutIsRtoLP(w)) cur_x -= HORIZONTAL_SPACE; else cur_x += HORIZONTAL_SPACE + col_widths[i]; } } /* Function Name: DrawSeparator * Description: Draws the line that separates the titles form the * list elements. * Arguments: w - the ilist widget. * Returns: none. */ static void DrawSeparator(Widget w) { XmI18ListWidget ilist = (XmI18ListWidget) w; unsigned int width = ilist->core.width; unsigned int height = XmI18List_sep_y(ilist); GC gc; if (!XmI18List_num_columns(ilist) || !XmI18List_column_titles(ilist)) return; /* CR03506 */ if(XmI18List_new_visual_style(ilist)) { XmeDrawShadows(XtDisplay(w), XtWindow(w), ilist->primitive.top_shadow_GC, ilist->primitive.bottom_shadow_GC, 0, 0, width, height + ilist->primitive.shadow_thickness, ilist->primitive.shadow_thickness, XmSHADOW_OUT); } else { if (XtIsSensitive(w)) gc = XmI18List_gc(ilist); else gc = XmI18List_stippled_gc(ilist); XFillRectangle(XtDisplay(w), XtWindow(w), gc, 0, XmI18List_sep_y(ilist), width, LINE_HEIGHT); } } /* Function Name: CreateGCs * Description: Creates the Graphics contexts. * Arguments: w - the ext list widget. * Returns: none. */ /* Always create the entry_background GCs and always use them, but their ** values may be different depending on whether or not to use the pixel ** (and may be identical to the regular GCs). We don't need new GCs for ** operations that don't use patterning or that don't use the background ** e.g. text/string draw operations. */ static void CreateGCs(Widget w) { XmI18ListWidget ilist = (XmI18ListWidget) w; XtGCMask mask, smask; XGCValues values; Arg args[2]; Cardinal num_args = 0; Pixel temp; Pixmap stipple; XFontStruct *font; stipple = XCreateBitmapFromData(XtDisplay(w), RootWindowOfScreen(XtScreen(w)), gray_bits, gray_width, gray_height); XtSetArg(args[num_args], XmNforeground, &(values.foreground)); num_args++; XtSetArg(args[num_args], XmNbackground, &(values.background)); num_args++; XtGetValues(w, args, num_args); XmeRenderTableGetDefaultFont (XmI18List_font_list(ilist), &font); values.font = font->fid; values.stipple = stipple; values.fill_style = FillStippled; values.graphics_exposures = False; mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures; #ifdef FIX_1381 smask = mask | GCFillStyle; #else smask = mask | GCStipple | GCFillStyle; #endif XmI18List_gc(ilist) = XtGetGC(w, mask, &values); if (XmI18List_entry_background_use(ilist)) { Pixel cache_foreground = values.foreground; values.foreground = XmI18List_entry_background_pixel(ilist); XmI18List_entry_background_fill_gc(ilist) = XtGetGC(w, mask, &values); values.foreground = cache_foreground; } else { /* same as XmI18List_gc */ /* not really used in this case */ XmI18List_entry_background_fill_gc(ilist) = XtGetGC(w, mask, &values); } if (XmI18List_entry_background_use(ilist)) { Pixel cache_background = values.background; values.background = XmI18List_entry_background_pixel(ilist); XmI18List_entry_background_gc(ilist) = XtGetGC(w, mask, &values); values.background = cache_background; } else { /* same as XmI18List_gc */ XmI18List_entry_background_gc(ilist) = XtGetGC(w, mask, &values); } #ifdef FIX_1381 /*added for gray insensitive foreground (instead stipple)*/ temp = values.foreground; values.foreground=_XmAssignInsensitiveColor(w); #endif XmI18List_stippled_gc(ilist) = XtGetGC(w, smask, &values); if (XmI18List_entry_background_use(ilist)) { Pixel cache_background = values.background; values.background = XmI18List_entry_background_pixel(ilist); XmI18List_entry_background_stippled_gc(ilist) = XtGetGC(w, smask, &values); values.background = cache_background; } else { /* same as XmI18List_stippled_gc */ XmI18List_entry_background_stippled_gc(ilist) = XtGetGC(w, smask, &values); } #ifndef FIX_1381 temp = values.foreground; #endif values.foreground = values.background; values.background = temp; XmI18List_rev_gc(ilist) = XtGetGC(w, mask, &values); if (XmI18List_entry_background_use(ilist)) { Pixel cache_foreground = values.foreground; values.foreground = XmI18List_entry_background_pixel(ilist); XmI18List_entry_background_rev_gc(ilist) = XtGetGC(w, mask, &values); values.foreground = cache_foreground; } else { /* same as XmI18List_rev_gc */ XmI18List_entry_background_rev_gc(ilist) = XtGetGC(w, mask, &values); } XmI18List_stippled_rev_gc(ilist) = XtGetGC(w, smask, &values); if (XmI18List_entry_background_use(ilist)) { Pixel cache_background = values.background; values.background = XmI18List_entry_background_pixel(ilist); XmI18List_entry_background_stippled_rev_gc(ilist) = XtGetGC(w, smask, &values); values.background = cache_background; } else { /* same as XmI18List_stippled_rev_gc */ XmI18List_entry_background_stippled_rev_gc(ilist) = XtGetGC(w, smask, &values); } values.foreground ^= values.background; values.function = GXxor; mask = GCForeground | GCFunction; XmI18List_inv_gc(ilist) = XtGetGC(w, mask, &values); if (XmI18List_entry_background_use(ilist)) { /* last one; we can skip caching */ /* Pixel cache_foreground = values.foreground; */ /* Pixel cache_background = values.background; */ values.foreground = XmI18List_entry_background_pixel(ilist); values.foreground ^= values.background; XmI18List_entry_background_inv_gc(ilist) = XtGetGC(w, mask, &values); /* values.background = cache_background; */ /* values.foreground = cache_foreground; */ } else { /* same as XmI18List_inv_gc */ XmI18List_entry_background_inv_gc(ilist) = XtGetGC(w, mask, &values); } XFreePixmap(XtDisplay(w), stipple); } /* Function Name: DestroyGCs * Description: Destroys all GC's needed by the list. * Arguments: w - the ilist widget. * Returns: none. */ static void DestroyGCs(Widget w) { XmI18ListWidget ilist = (XmI18ListWidget) w; XtReleaseGC(w, XmI18List_gc(ilist)); XtReleaseGC(w, XmI18List_rev_gc(ilist)); XtReleaseGC(w, XmI18List_stippled_gc(ilist)); XtReleaseGC(w, XmI18List_stippled_rev_gc(ilist)); XtReleaseGC(w, XmI18List_inv_gc(ilist)); XtReleaseGC(w, XmI18List_entry_background_gc(ilist)); XtReleaseGC(w, XmI18List_entry_background_fill_gc(ilist)); XtReleaseGC(w, XmI18List_entry_background_stippled_gc(ilist)); XtReleaseGC(w, XmI18List_entry_background_stippled_rev_gc(ilist)); XtReleaseGC(w, XmI18List_entry_background_inv_gc(ilist)); XtReleaseGC(w, XmI18List_entry_background_rev_gc(ilist)); } /* Function Name: GetPixmapInfo * Description: Gets the information about each pixmap. * Arguments: w - the ilist widget. * Returns: none */ static void GetPixmapInfo(Widget w) { XmI18ListWidget ilist = (XmI18ListWidget) w; register int i, num_rows = XmI18List_num_rows(ilist); for (i = 0; i < num_rows; i++) { int x, y; unsigned int width, height, bw, depth; Window root; width = height = depth = 0; if (IsValidPixmap(XmI18List_row_data(ilist)[i].pixmap)) { XGetGeometry(XtDisplay(w), XmI18List_row_data(ilist)[i].pixmap, &root, &x, &y, &width, &height, &bw, &depth); } XmI18List_row_data(ilist)[i].pix_width = width; XmI18List_row_data(ilist)[i].pix_height = height; XmI18List_row_data(ilist)[i].pix_depth = depth; } } /* Function Name: SetVisibleSize * Description: Calculates and sets list height (& optionally width) * Arguments: w - the ilist widget. * set_width - if true, set width * Returns: none */ static void SetVisibleSize(Widget w, Boolean set_width) { XmI18ListWidget ilist = (XmI18ListWidget) w; Dimension title_height; int height; CalcColumnInfo(w, True); title_height = 2 * VERTICAL_SPACE + XmI18List_title_row_height(ilist); if(XmI18List_new_visual_style(ilist)) title_height += ilist->primitive.shadow_thickness; else title_height += LINE_HEIGHT; /* If we have no rows, guess at row size with font struct info... */ if (XmI18List_num_rows(ilist) == 0) { #if USE_XFT XmRenderTableGetDefaultFontExtents(XmI18List_font_list(ilist), &height, NULL, NULL); if (height == 0) height = VERTICAL_SPACE * XmI18List_visible_rows(ilist); #else XFontStruct *font = (XFontStruct *) NULL; XmeRenderTableGetDefaultFont(XmI18List_font_list(ilist), &font); if (font) height = (font->ascent + font->descent + VERTICAL_SPACE) * XmI18List_visible_rows(ilist); else height = VERTICAL_SPACE * XmI18List_visible_rows(ilist); #endif } else { height = (XmI18List_row_height(ilist) + VERTICAL_SPACE) * XmI18List_visible_rows(ilist); } /* Go ahead and set the widget's height resource... */ ilist->core.height = title_height + height + VERTICAL_SPACE; if (set_width) ilist->core.width = GetListWidth(w); } /* Function Name: CalcColumnInfo * Description: Calculates the layout info for the columns. * Arguments: w - the ilist widget. * Returns: none */ static void CalcColumnInfo(Widget w, Boolean force) { XmI18ListWidget ilist = (XmI18ListWidget) w; register int i, j; int max_width = 0, max_title_height = 0, max_height = 0; Dimension width, height; XmString ptr; register int num_cols = XmI18List_num_columns(ilist); register int num_rows = XmI18List_num_rows(ilist); if (XmI18List_first_col_pixmaps(ilist)) GetPixmapInfo(w); if (((XmI18List_column_widths(ilist) == NULL) || force) && (num_cols != 0)) { if (force) XtFree((XtPointer) XmI18List_column_widths(ilist)); XmI18List_column_widths(ilist) = (short *) XtMalloc(sizeof(short) * num_cols); } for (i = 0 ; i < num_cols; i++) { if (XmI18List_column_titles(ilist) != NULL) { ptr = XmI18List_column_titles(ilist)[i]; XmStringExtent(XmI18List_font_list(ilist), ptr, &width, &height); /* the max height for the title row */ if ((int) height > max_title_height) max_title_height = height; /* find the max width for just this column */ max_width = width; } if (XmI18List_first_col_pixmaps(ilist) && (i == 0)) { for (j = 0 ; j < num_rows; j++) { if( (int)(height =XmI18List_row_data(ilist)[j].pix_height) > (int)max_height ) max_height = height; if ( (int)(width = XmI18List_row_data(ilist)[j].pix_width) > (int)max_width ) max_width = width; } } else { for (j = 0 ; j < num_rows; j++) { ptr = XmI18List_row_data(ilist)[j].values[i]; XmStringExtent(XmI18List_font_list(ilist), ptr, &width, &height); if ((int)width > (int)max_width) max_width = width; if ((int)height > (int)max_height) max_height = height; } } XmI18List_column_widths(ilist)[i] = max_width; } XmI18List_row_height(ilist) = max_height; if (XmI18List_num_columns(ilist) && XmI18List_column_titles(ilist)) /* CR03506 */ XmI18List_title_row_height(ilist) = max_title_height; else XmI18List_title_row_height(ilist) = 0; /* CR03506 */ } /* Function Name: ResizeSliders * Description: Resizes the thumbs of the v and h scrollbars. * Arguments: w - the ilist widget. * Returns: none * * Modified: 03/17/92 beth - converted to pixels */ static void ResizeSliders(Widget w) { XmI18ListWidget ilist = (XmI18ListWidget) w; Arg args[5]; Cardinal num_args=0; register int i, height, max_width, rows_per_screen; register int slide_pos, slide_size, col_width=0, min=0; /* * Get maximum width of data to display */ max_width = HORIZONTAL_SPACE; for (i=0; i < XmI18List_num_columns(ilist); i++) { if (XmI18List_column_widths(ilist)[i] > col_width) col_width = XmI18List_column_widths(ilist)[i]; max_width += XmI18List_column_widths(ilist)[i] + HORIZONTAL_SPACE; } if (((col_width + HORIZONTAL_SPACE) != 0) && (XmI18List_h_bar(ilist) != NULL)) { /* * Adjust the slider size and page increment values * The size and position (returned and set) are relative to * the number of columns of data that we have - BUT, we * have to convert this information to pixels for correct * processing. */ slide_size = ilist->core.width; if (slide_size < 1) slide_size = 1; if (slide_size > max_width) slide_size = max_width; /* * Adjust slider position according to new size * and location of first pixel of display data */ if (XmI18List_left_loc(ilist) >= 0) slide_pos = 1; else { i = (0 - XmI18List_left_loc(ilist)) + ilist->core.width; if (i >= max_width) slide_pos = max_width - slide_size; else if (i < max_width) slide_pos = i - slide_size; } if (slide_pos < 1) slide_pos = 1; if (slide_pos > (max_width - slide_size)) slide_pos = max_width - slide_size; XtSetArg(args[num_args], XmNvalue, slide_pos); num_args++; XtSetArg(args[num_args], XmNmaximum, max_width); num_args++; XtSetArg(args[num_args], XmNsliderSize, slide_size); num_args++; XtSetArg(args[num_args], XmNpageIncrement, slide_size); num_args++; XtSetValues(XmI18List_h_bar(ilist), args, num_args); } height = ilist->core.height - (2 * VERTICAL_SPACE + XmI18List_title_row_height(ilist)); if(XmI18List_new_visual_style(ilist)) height -= ilist->primitive.shadow_thickness; else height -= LINE_HEIGHT; if ((height > 0) && (XmI18List_v_bar(ilist) != NULL)) { int max_first; rows_per_screen = height / (XmI18List_row_height(ilist) + VERTICAL_SPACE); max_first = XmI18List_num_rows(ilist) - rows_per_screen; if (max_first < XmI18List_first_row(ilist)) { if (max_first > 0) XmI18List_first_row(ilist) = max_first; else XmI18List_first_row(ilist) = 0; } /* * Set up the scroll bars resources * MUST BE very thorough, otherwise warnings are issued. */ slide_size = rows_per_screen; max_width = XmI18List_num_rows(ilist); slide_pos = XmI18List_first_row(ilist); if (max_width <= 1) max_width = 1; if (slide_size > max_width) slide_size = max_width; if (slide_pos > (max_width - slide_size)) slide_pos = (max_width - slide_size); if (slide_pos < min) slide_pos = min; num_args = 0; XtSetArg(args[num_args], XmNminimum, min); num_args++; XtSetArg(args[num_args], XmNvalue, slide_pos); num_args++; XtSetArg(args[num_args], XmNmaximum, max_width); num_args++; XtSetArg(args[num_args], XmNsliderSize, slide_size); num_args++; XtSetArg(args[num_args], XmNpageIncrement, slide_size); num_args++; XtSetValues(XmI18List_v_bar(ilist), args, num_args); } } /* Function Name: VScroll * Description: Scrolls the window a given number of * rows up or down (up is negative) * Arguments: w - the ICS list widget. * amount - the number of rows to scroll, negative * values scroll backward. * Returns: none */ static void VScroll(Widget w, short amount) { XmI18ListWidget ilist = (XmI18ListWidget) w; int y_start; short num_rows; XmI18List_first_row(ilist) += amount; if (XmI18List_first_row(ilist) < 0) XmI18List_first_row(ilist) = 0; y_start = XmI18List_sep_y(ilist); if(XmI18List_new_visual_style(ilist)) y_start += ilist->primitive.shadow_thickness; else y_start += LINE_HEIGHT; XClearArea(XtDisplay(w), XtWindow(w), 0, y_start, (unsigned int) 0, (unsigned int) 0, FALSE); num_rows = XmI18List_num_rows(ilist) - XmI18List_first_row(ilist); DisplayList(w, XmI18List_first_row(ilist), num_rows, TRUE); } /* Function Name: CvtColNumToPixelVal * Description: determines which is the first visible pixel * in the passed column number * Arguments: w - the ilist widget data to retrieve info from * col - the column number to search in * Returns: the pixel value * * Added: 03/17/92 beth */ static short CvtColNumToPixelVal(Widget w, short col) { XmI18ListWidget ilist = (XmI18ListWidget) w; register int i; short value=0; /* * Sum up the widest pixel values in each column * until we reach the passed in column */ for (i = 0; i < col && i < XmI18List_num_columns(ilist); i++) value += XmI18List_column_widths(ilist)[i] + HORIZONTAL_SPACE; return(value); } /* Function Name: CvtPixelValToColNum * Description: determines which is the visible column * corresponding to the passed pixel value * Arguments: w - the ilist widget data to retrieve info from * x - the x pixel value to look for * Returns: the column number * * Added: 03/17/92 beth */ static short CvtPixelValToColNum(Widget w, short x) { XmI18ListWidget ilist = (XmI18ListWidget) w; register int i=0; short cur_col; /* * Sum up the widest pixel values in each column * and see where the passed in x pixel value falls */ if (LayoutIsRtoLP(w)) cur_col = XtWidth(w) - XmI18List_left_loc(ilist); else cur_col = XmI18List_left_loc(ilist); for (; i < XmI18List_num_columns(ilist); i++) { if (LayoutIsRtoLP(w)) { cur_col -= XmI18List_column_widths(ilist)[i] + HORIZONTAL_SPACE; if (cur_col < x) break; } else { cur_col += XmI18List_column_widths(ilist)[i] + HORIZONTAL_SPACE; if (cur_col > x) break; } } return((short) i); } /* Function Name: HScroll * Description: Scrolls the window a given number of pixels/ * columns left or right (left is negative) * Arguments: w - the ICS list widget. * amount - the pixel amount to scroll. * Returns: none * * Modified: 03/17/92 beth - converted to pixels */ static void HScroll(Widget w, short amount) { XmI18ListWidget ilist = (XmI18ListWidget) w; int y_start; unsigned int title_height; short num_rows; if ((0 - amount) >= 0) XmI18List_left_loc(ilist) = amount; else XmI18List_left_loc(ilist) = 0 - amount; title_height = XmI18List_sep_y(ilist); y_start = XmI18List_sep_y(ilist); if(XmI18List_new_visual_style(ilist)) y_start += ilist->primitive.shadow_thickness; else y_start += LINE_HEIGHT; XClearArea(XtDisplay(w), XtWindow(w), 0, 0, (unsigned int) 0, title_height, FALSE); XClearArea(XtDisplay(w), XtWindow(w), 0, y_start, (unsigned int) 0, (unsigned int) 0, FALSE); num_rows = XmI18List_num_rows(ilist) - XmI18List_first_row(ilist); DisplayList(w, XmI18List_first_row(ilist), num_rows, TRUE); } /* Function Name: CvtPositionToRowColumn * Description: Converts an X location to a row and column. * Arguments: w - the ilist widget. * x, y - the location in the window in pixel space. * RETURNED row, column - the location of this point in list space. * Returns: none. * * NOTE: This functions can return cells the are off the end of * the current space. It is up to the caller to check * to be sure he does not run off then end of an array. * * Modified: 03/17/92 beth - converted to pixels */ static void CvtPositionToRowColumn(Widget w, short x, short y, short * row, short * column) { XmI18ListWidget ilist = (XmI18ListWidget) w; int title_extra; if(XmI18List_new_visual_style(ilist)) title_extra = ilist->primitive.shadow_thickness; else title_extra = LINE_HEIGHT; /* * See if the y pixel value passed is located in the header * or a row visible within the clip window or not visible at all */ if (y < 0) { *row = IN_COLUMN_HEADER + y/(XmI18List_row_height(ilist) + VERTICAL_SPACE); } else if (y < (XmI18List_sep_y(ilist) + title_extra)) { *row = IN_COLUMN_HEADER; } else { y -= XmI18List_sep_y(ilist) + title_extra + VERTICAL_SPACE/2; *row = XmI18List_first_row(ilist) + y/(XmI18List_row_height(ilist) + VERTICAL_SPACE); } *column = CvtPixelValToColNum((Widget) w, x); } /* Function Name: CvtRowColumnToPosition * Description: Converts a row and column to an X Window Position. * the coord's are of the upper left corner of the cell. * Arguments: w - the ilist widget. * row, column - the location of this point in list space. * RETURNED x, y - the location in the window in pixel space. * Returns: none. * * Modified: 03/17/92 beth - converted to pixels */ static void CvtRowColumnToPosition(Widget w, short row, short column, short * x, short * y) { XmI18ListWidget ilist = (XmI18ListWidget) w; int title_extra; if(XmI18List_new_visual_style(ilist)) title_extra = ilist->primitive.shadow_thickness; else title_extra = LINE_HEIGHT; if (row == IN_COLUMN_HEADER) *y = VERTICAL_SPACE/2; else { *y = (XmI18List_sep_y(ilist) + title_extra + (row - XmI18List_first_row(ilist)) * (XmI18List_row_height(ilist) + VERTICAL_SPACE) + VERTICAL_SPACE/2); } *x = CvtColNumToPixelVal((Widget) ilist, column); } /* Function Name: ToggleRow * Description: Toggles the state of the given row. * Arguments: w - the ilist widget. * row - the row to select. * Returns: none */ static void ToggleRow(Widget w, short row) { XmI18ListWidget ilist = (XmI18ListWidget) w; XmI18List_row_data(ilist)[row].selected = !XmI18List_row_data(ilist)[row].selected; if (IsRowVisible(w, row) >= 0) InvertArea(w, row, ENTIRE_ROW); } /* Function Name: UnselectRows * Description: Unselects some rows (see below) and returns the * row that was left selected. * Arguments: w - the ilist widget. * row - row to leave selected. * Returns: none. */ static void UnselectRows(Widget w, short sel_row) { XmI18ListWidget ilist = (XmI18ListWidget) w; register short row; XmMultiListRowInfo *ptr = XmI18List_row_data(ilist); XmI18List_end(ilist) = XmI18List_anchor(ilist) = sel_row; for (row = 0; row < XmI18List_num_rows(ilist); row++, ptr++) { /* * if the row is correct and it is unselected * or if the row incorrect and it is selected then toggle the row. */ if (ptr->selected != (row == sel_row)) ToggleRow(w, row); } } /* Function Name: SelectHeader * Description: Sets the header corrosponding to the column passed in. * Arguments: w - the ilist widget. * column - the column header to select. * Returns: none */ static void SelectHeader(Widget w, short column) { XmI18ListWidget ilist = (XmI18ListWidget) w; if ((XmI18List_selected_header(ilist) == column) || (XmI18List_sort_functions(ilist) == NULL)) { return; } XmI18List_selected_header(ilist) = column; SortList(w, True); /* Causes a rediplay. */ } /* Function Name: SortList * Description: Sorts the elements in the list. * Arguments: w - the ilist widget. * redisplay - redraw the ilist widget. * Returns: none. */ static void SortList(Widget w, Boolean redisplay) { XmI18ListWidget ilist = (XmI18ListWidget) w; if (XmI18List_sort_functions(ilist) != NULL) { global_current_widget = w; qsort(XmI18List_row_data(ilist), XmI18List_num_rows(ilist), sizeof(XmMultiListRowInfo), QSortTest); if (redisplay) RedrawList(w); } /* this is kind of unnecessary, instead should just update headers */ else RedrawList(w); } /* Function Name: QSortTest * Description: Takes the internal data, and the calls the * appropriate sort routine supplied by the client. * Arguments: str1, str2 - the two values to compare. * Returns: */ static int QSortTest(const void * row1, const void * row2) { XmI18ListWidget ilist = (XmI18ListWidget) global_current_widget; short col = XmI18List_selected_header(ilist); Xm18SortFunction sort_f = XmI18List_sort_functions(ilist)[(int)col]; return ((*sort_f) (col, (XmMultiListRowInfo*)row1, (XmMultiListRowInfo*)row2)); } /* Function Name: InvertArea * Description: Inverts the the area specified. * Arguments: w - the ilist widget. * row, column - row/column to invert. * Returns: none. * * NOTE: The value IN_COLUMN_HEADER for the row means the area * to be inverted is in the column header. * * The value ENTIRE_ROW for the column causes the entire row to * be inverted. * * Modified: 03/17/92 beth - converted to pixels */ static void InvertArea(Widget w, short row, short column) { XmI18ListWidget ilist = (XmI18ListWidget) w; unsigned int width, height; short x, y, pix_y_offset; GC gc_to_use; if (!XtIsRealized(w)) return; if ((row == NO_SELECTION) || (column == NO_SELECTION)) return; if (column == ENTIRE_ROW) { CvtRowColumnToPosition(w, row, 0, &x, &y); width = GetListWidth((Widget) ilist); if (LayoutIsRtoLP(w)) x = -width + XtWidth(w) - XmI18List_left_loc(ilist) + HORIZONTAL_SPACE/2; else x = XmI18List_left_loc(ilist) - HORIZONTAL_SPACE/2; } else { CvtRowColumnToPosition(w, row, column, &x, &y); width = HORIZONTAL_SPACE + XmI18List_column_widths(ilist)[column]; } if (row == IN_COLUMN_HEADER) { height = XmI18List_title_row_height(ilist) + VERTICAL_SPACE; gc_to_use = XmI18List_inv_gc(ilist); } else { height = XmI18List_row_height(ilist) + VERTICAL_SPACE; gc_to_use = XmI18List_entry_background_inv_gc(ilist); } XFillRectangle(XtDisplay(w), XtWindow(w), gc_to_use, (int) x, (int) y, width, height); if ( (XmI18List_first_col_pixmaps(ilist)) && (XmI18List_row_data(ilist)[row].pix_depth != 1 ) && IsValidPixmap(XmI18List_row_data(ilist)[row].pixmap) ) { pix_y_offset = (height - XmI18List_row_data(ilist)[row].pix_height)/2; XCopyArea(XtDisplay(w), XmI18List_row_data(ilist)[row].pixmap, XtWindow(w), XmI18List_entry_background_gc(ilist), 0, 0, XmI18List_row_data(ilist)[row].pix_width, XmI18List_row_data(ilist)[row].pix_height, LayoutIsRtoLP(w) ? XtWidth(ilist) - XmI18List_left_loc(ilist) - XmI18List_row_data(ilist)[row].pix_height : XmI18List_left_loc(ilist), y+pix_y_offset ); } } /* Function Name: RedrawList * Description: Redraws the current list contents. * Arguments: w - the ilist widget. * Returns: none. * * Modified: 03/17/92 beth - converted to pixels */ static void RedrawList(Widget w) { XmI18ListWidget ilist = (XmI18ListWidget) w; short num_rows; if (XtIsRealized(w)) { XClearWindow(XtDisplay(w), XtWindow(w)); num_rows = XmI18List_num_rows(ilist) - XmI18List_first_row(ilist); DisplayList(w, XmI18List_first_row(ilist), num_rows, TRUE); DrawSeparator(w); } } /* Function Name: IsRowVisible * Description: returns 0 if the row is visable. Otherwise returns * the number of rows down we have to scroll (- values for up) * to make the row visible. * Arguments: w - the ilist widget. * row - the row to check. * Returns: none. */ static int IsRowVisible(Widget w, short row) { XmI18ListWidget ilist = (XmI18ListWidget) w; short r_row, r_col; if (row < XmI18List_first_row(ilist)) return(row - XmI18List_first_row(ilist)); CvtPositionToRowColumn((Widget) w, 0, (short) (ilist->core.height + 1), &r_row, &r_col); if (row >= r_row) return(row - r_row + 1); return(0); } /* Function Name: AdjustVisiblePosition * Description: makes the string found by find, visible * Arguments: w - the ilist widget. * position - the new position for lef_loc * check - whether we should check the new position * to see if it's valid * value - the amount to check the position against * Returns: none * * Added: 03/17/92 beth - for conversion to pixels */ static void AdjustVisiblePosition(Widget w, short position, Boolean check, short value) { XmI18ListWidget ilist = (XmI18ListWidget) w; /* * Check to make sure that we can move the amount requested */ if (check && position > value) position = 0 - value; else position = 0 - position; XmI18List_left_loc(ilist) += position; HScroll(w, XmI18List_left_loc(ilist)); AdjustFirstCol(w); ResizeSliders(w); } static void AdjustFirstRowAndCol( XmI18ListWidget ilist ) { Dimension total_width, height; int rows_per_screen, new_left_loc; register int j; int title_extra; if(XmI18List_new_visual_style(ilist)) title_extra = ilist->primitive.shadow_thickness; else title_extra = LINE_HEIGHT; new_left_loc = 0; for (j=0; j < XmI18List_first_col(ilist); j++){ new_left_loc -= (XmI18List_column_widths(ilist)[j] + HORIZONTAL_SPACE); } total_width = GetListWidth((Widget)ilist); if (ilist->core.width > total_width ){ XmI18List_left_loc(ilist) = 0; } else if (new_left_loc < (int)((int)ilist->core.width- (int)total_width)){ XmI18List_left_loc(ilist) = (int)((int)ilist->core.width- (int)total_width); } else XmI18List_left_loc(ilist) = new_left_loc; height = ilist->core.height - (2 * VERTICAL_SPACE + XmI18List_title_row_height(ilist) + title_extra); rows_per_screen = (int)height/(int)(XmI18List_row_height(ilist)+ VERTICAL_SPACE); if (XmI18List_num_rows(ilist) < rows_per_screen) { XmI18List_first_row(ilist) = 0; } else if (XmI18List_first_row(ilist) > (XmI18List_num_rows(ilist) - rows_per_screen)) { XmI18List_first_row(ilist) = (XmI18List_num_rows(ilist) - rows_per_screen); } } /* Function Name: MakePositionVisible * Description: makes sure that the string found by the find * procedure, is as visible (length) as possible * Arguments: w - the ilist widget. * row - the row to make visible. * start - the start pixel of the string * last - the last pixel of the string * width - the width of the display data * Returns: status (True if search and move worked). * * Modified: 03/17/92 beth - converted to pixels */ static Boolean MakePositionVisible(Widget w, short row, short start, short last, int width) { XmI18ListWidget ilist = (XmI18ListWidget) w; short amount, before = 0; if ((amount = IsRowVisible(w, row)) != 0) VScroll(w, amount); /* * Adjust the start and last values for better viewing */ if (start >= HORIZONTAL_SPACE) start -= HORIZONTAL_SPACE; last += HORIZONTAL_SPACE; /* * Convert the start pixel we want to see to visible pixels. * This involves comparing the start pixel location within * the visible window and seeing if it's possible to move * the visible window to contain the pixels we wish to see. */ if (XmI18List_left_loc(ilist) < 0) before -= XmI18List_left_loc(ilist); if (XmI18List_left_loc(ilist) < 0 && before >= start) { /* * The start pixel is to the left of the visible window * pass a negative value - it will be converted to positive later */ AdjustVisiblePosition((Widget) ilist, (0 - (before - start)), False, 0); return(TRUE); } else if (start >= before && start <= width) { short move, begin, end; if ((int)start <= (int)(before + ilist->core.width)) { /* * The start pixel is inside the visible window */ begin = (before + ilist->core.width) - start; end = last - start; if (begin < end) move = end - begin; else move = 0; } else { /* * The start pixel is to the right of the visible window */ move = last - (before + ilist->core.width); } if (move != 0) AdjustVisiblePosition((Widget) ilist, move, True, (width - (before + ilist->core.width))); return(TRUE); } return(FALSE); } /************************************************************ * * Exported Functions. * ************************************************************/ /* -kat 1/18/91 * Function Name: XmI18ListGetSelectedRows * Description: Takes an IList and returns a NULL terminated array * of pointers to selected rows * Arguments: w - the ilist widget * Returns: A NULL terminated array of the row info structures. * NULL is returned if nothing is selected. */ XmMultiListRowInfo ** XmI18ListGetSelectedRows(Widget w) { register int i, j; register XmMultiListRowInfo *row_data, **ptr; XmMultiListRowInfo **ret_rows = NULL; XmI18ListWidget ilist = (XmI18ListWidget) w; row_data = XmI18List_row_data(ilist); for (i = j = 0; j < XmI18List_num_rows(ilist); j++, row_data++) { if (row_data->selected) i++; } if (i != 0) { ptr = ret_rows = (XmMultiListRowInfo **) XtMalloc( sizeof(XmMultiListRowInfo *) * (i + 1)); ret_rows[i] = NULL; row_data = XmI18List_row_data(ilist); for (j = 0; j < XmI18List_num_rows(ilist); j++, row_data++) { if (row_data->selected) *ptr++ = row_data; } } return(ret_rows); } /* Function Name: XmI18ListDoSearch. * Description: Performs a search for the specified string. * Arguments: w - the ilist widget. * str - the string to search for. * reset - indicates if we are searching for * something new * Returns: status (True if search worked). * * Rewritten: 11/17/93 dave - works for I18List now */ Boolean XmI18ListDoSearch(Widget w, String str, Boolean reset) { XmI18ListWidget ilist = (XmI18ListWidget) w; Boolean foundit; XmString xms = XmStringCreateLocalized(str); int found_row, found_column, search_column; int first_selected_row = FirstSelectedRow(w); if ( reset ) XmI18List_search_column(ilist) = -1; /* * If we've searched last, be sure to start at NEXT column. * Otherwise start at first (0th) column */ search_column = XmI18List_search_column(ilist) + 1; if ( first_selected_row == -1 ) first_selected_row = 0; foundit = Search(ilist, xms, first_selected_row, search_column, &found_row, &found_column); if ( foundit ) { XmI18List_search_column(ilist) = found_column; UnselectRows(w, found_row); MakeCellVisible(w, found_row, found_column); } else { XmI18List_search_column(ilist) = -1; } return (foundit); } /* Function Name: XmI18ListFindRow * Description: Performs a search for the specified string. * Arguments: w - the ilist widget. * str - the string to search for. * reset - indicates if we are searching for * something new * do_visual - whether or not to toggle selected rows... * Returns: XmMultiListRowInfo of matching row (or NULL if no match found) * */ XmMultiListRowInfo *XmI18ListFindRow(Widget w, String str, int *found_column, Boolean reset, Boolean do_visual) { XmI18ListWidget ilist = (XmI18ListWidget) w; XmMultiListRowInfo *ptr = XmI18List_row_data(ilist); Boolean foundit; XmString xms = XmStringCreateLocalized(str); int found_row, search_column; int first_selected_row = FirstSelectedRow(w); if (reset) XmI18List_search_column(ilist) = -1; /* * If we've searched last, be sure to start at NEXT column. * Otherwise start at first (0th) column */ search_column = XmI18List_search_column(ilist) + 1; if (first_selected_row == -1) first_selected_row = 0; foundit = Search(ilist, xms, first_selected_row, search_column, &found_row, found_column); if (do_visual) { if (foundit) { XmI18List_search_column(ilist) = *found_column; UnselectRows(w, found_row); MakeCellVisible(w, found_row, *found_column); } else XmI18List_search_column(ilist) = -1; } return (XmMultiListRowInfo *)(foundit ? &ptr[found_row] : NULL); } static int FirstSelectedRow(Widget w) { XmI18ListWidget ilist = (XmI18ListWidget) w; XmMultiListRowInfo *ptr = XmI18List_row_data(ilist); int i; for (i=0;i= XmI18List_num_columns(ilist)) end = width; else end = XmI18List_column_widths(ilist)[col] + start; (void) MakePositionVisible(w, row, start, end, width); ResizeSliders(w); } /* * * Public Convenience Routines * */ /* Function Name: Xm18IListUnselectAllItems * Description: Unselects all rows * Arguments: w - the ilist widget. * Returns: none */ void Xm18IListUnselectAllItems( Widget w ) { register int row; XmI18ListWidget ilist = (XmI18ListWidget) w; XmMultiListRowInfo *ptr = XmI18List_row_data(ilist); _XmWidgetToAppContext(w); _XmAppLock(app); for (row = 0; row < XmI18List_num_rows(ilist); row++, ptr++) { if (ptr->selected) ToggleRow(w, row); } _XmAppUnlock(app); } /* Function Name: Xm18IListUnselectItem * Description: Unselects the row passed in * Arguments: w - the ilist widget. * row_info - ptr to the row passed in * Returns: none */ void Xm18IListUnselectItem( Widget w, XmMultiListRowInfo *row_info ) { register int row=0; XmI18ListWidget ilist = (XmI18ListWidget) w; XmMultiListRowInfo *ptr = XmI18List_row_data(ilist); Boolean done=False; while (row < XmI18List_num_rows(ilist) && !done){ if (ptr == row_info){ if (ptr->selected) ToggleRow( w, row); done = True; } else { ptr++; row++; } } } /* Function Name: XmI18ListToggleRow * Description: Toggles the selection state of a specified row * Arguments: w - the ilist widget. * Returns: none */ void XmI18ListToggleRow(Widget w, short row) { ToggleRow(w, row); } /* * Function: * CopyColumnTitles(ilist) * Description: * This function copies the XmStringTable that is the column titles * into local (widget controled) memory. * Input: * ilist : XmI18ListWidget - the widget to copy titles * Output: * None. */ static void CopyColumnTitles(XmI18ListWidget ilist) { int i; XmStringTable copy; if( XmI18List_num_columns(ilist) == 0 || XmI18List_column_titles(ilist) == NULL ) { copy = (XmStringTable) NULL; } else { copy = (XmStringTable) XtMalloc(sizeof(XmString) * XmI18List_num_columns(ilist)); for( i = 0; i < XmI18List_num_columns(ilist); ++i ) { copy[i] = XmStringCopy(XmI18List_column_titles(ilist)[i]); } } XmI18List_column_titles(ilist) = copy; } /* * Function: * FreeColumnTitles(ilist) * Description: * This function frees the memory associated with the column titles * for the list. * Input: * ilist : XmI18ListWidget - the widget to copy titles * Output: * None. */ static void FreeColumnTitles(XmI18ListWidget ilist) { int i; if( XmI18List_num_columns(ilist) == 0 || XmI18List_column_titles(ilist) == NULL ) { return; } for( i = 0; i < XmI18List_num_columns(ilist); ++i ) { XmStringFree(XmI18List_column_titles(ilist)[i]); } XtFree((XtPointer) XmI18List_column_titles(ilist)); XmI18List_column_titles(ilist) = (XmStringTable) NULL; } /* Function Name: GetSelectedRows * Description: Creates an array of integers which are selected row #'s * Arguments: i18list - the extended list widget * rows - pointer to the array of selected row #'s * num_rows - pointer to the number of selected rows * Returns: rows */ static int * GetSelectedRows(XmI18ListWidget i18list, int *num_rows) { XmMultiListRowInfo *row_info = XmI18List_row_data(i18list); int *rows, i; rows = NULL; for (*num_rows = 0, i = 0; i < XmI18List_num_rows(i18list); i++) if (row_info[i].selected) (*num_rows)++; if (*num_rows > 0) { int j; rows = (int *) XtMalloc(*num_rows * sizeof(int)); for (i = 0, j = 0; i < XmI18List_num_rows(i18list); i++) if (row_info[i].selected) rows[j++] = i; } return rows; } /* Function Name: SelectRow * Description: Set selection state of row * Arguments: i18list - the extended list widget * row - the row to select/unselect * select - True/False * notify - if True, call XmNsingleSelectionCallback * Returns: none */ static void SelectRow(XmI18ListWidget i18list, int row, Boolean select, Boolean notify) { XmMultiListRowInfo *rows = XmI18List_row_data(i18list); if ((row >= 0) && (rows[row].selected != select)) { ToggleRow((Widget) i18list, row); } /* Call the appropriate notification callbacks... */ if (notify) Notify((Widget) i18list, False); } /* Function Name: SelectItems * Description: Set selection state by matching column entries to XmString * Arguments: i18list - the extended list widget * item - XmString to use as selection key (NULL matches all) * column - column number (0 - N) to match (or XmANY_COLUMN) * select - True/False whether or not to select matching rows * notify - if True, call XmNsingleSelectionCallback * Returns: none */ static void SelectItems(XmI18ListWidget i18list, XmString item, int column, Boolean select, Boolean notify) { XmMultiListRowInfo *rows = XmI18List_row_data(i18list); int i, j; int rowcount, colcount, colstart; _XmWidgetToAppContext((Widget)i18list); _XmAppLock(app); colstart = (XmI18List_first_col_pixmaps(i18list) ? 1 : 0); rowcount = XmI18List_num_rows(i18list); colcount = XmI18List_num_columns(i18list); for (i = 0; i < rowcount; i++) for (j = colstart; j < colcount; j++) /* Check indiviual column entries against XmString, item... * If XmString item matches column etnry (or item is NULL), then * set the selection state of the row */ if ((((column == XmANY_COLUMN) || (column == j)) && XmStringCompare(item, rows[i].values[j])) || !item) { if (rows[i].selected != select) { ToggleRow((Widget) i18list, i); } /* Call the appropriate notification callbacks... */ if (notify) Notify((Widget) i18list, False); break; } _XmAppUnlock(app); } /* * XmRCallProc routine for checking font_list before setting it to NULL * If "check_set_render_table" is True, then function has * been called twice on same widget, thus resource needs to be set NULL, * otherwise leave it alone. */ /*ARGSUSED*/ static void CheckSetRenderTable(Widget wid, int offset, XrmValue *value) { XmI18ListWidget il = (XmI18ListWidget)wid; /* Check if been here before */ if (il->ilist.check_set_render_table) value->addr = NULL; else { il->ilist.check_set_render_table = True; value->addr = (char*)&(il->ilist.font_list); } } /*************************************************************************** * * * ListConvert - Convert routine for dragNDrop. * * * ***************************************************************************/ /*ARGSUSED*/ static void ListConvert(Widget w, XtPointer client_data, XmConvertCallbackStruct *cs) { enum { XmA_MOTIF_COMPOUND_STRING, XmACOMPOUND_TEXT, XmATEXT, XmATARGETS, XmA_MOTIF_DROP, XmA_MOTIF_LOSE_SELECTION, XmA_MOTIF_EXPORT_TARGETS, XmA_MOTIF_CLIPBOARD_TARGETS, XmAUTF8_STRING, NUM_ATOMS }; static char *atom_names[] = { XmS_MOTIF_COMPOUND_STRING, XmSCOMPOUND_TEXT, XmSTEXT, XmSTARGETS, XmS_MOTIF_DROP, XmS_MOTIF_LOSE_SELECTION, XmS_MOTIF_EXPORT_TARGETS, XmS_MOTIF_CLIPBOARD_TARGETS, XmSUTF8_STRING }; Atom atoms[XtNumber(atom_names)]; Atom C_ENCODING = XmeGetEncodingAtom(w); int target_count = 0; int i; Atom type = None; XtPointer value = NULL; unsigned long size = 0; int format = 8; XmI18ListWidget lw = (XmI18ListWidget) w; XmI18ListDragConvertStruct *ListDragConv = lw->ilist.drag_conv; assert(XtNumber(atom_names) == NUM_ATOMS); XInternAtoms(XtDisplay(w), atom_names, XtNumber(atom_names), False, atoms); if (cs->target == atoms[XmATARGETS]) { Atom *targs = XmeStandardTargets(w, 5, &target_count); value = (XtPointer) targs; targs[target_count++] = atoms[XmA_MOTIF_COMPOUND_STRING]; targs[target_count++] = atoms[XmACOMPOUND_TEXT]; targs[target_count++] = atoms[XmATEXT]; targs[target_count++] = atoms[XmAUTF8_STRING]; targs[target_count++] = C_ENCODING; if (XA_STRING != C_ENCODING) targs[target_count++] = XA_STRING; if (ListDragConv->pixmap != None) targs[target_count++] = XA_PIXMAP; type = XA_ATOM; size = target_count; format = 32; } else if ((cs->target == atoms[XmA_MOTIF_EXPORT_TARGETS]) || (cs->target == atoms[XmA_MOTIF_CLIPBOARD_TARGETS])) { Atom *targs = (Atom *) XtMalloc(sizeof(Atom) * 5); int n = 0; value = (XtPointer) targs; targs[n++] = atoms[XmA_MOTIF_COMPOUND_STRING]; targs[n++] = atoms[XmACOMPOUND_TEXT]; targs[n++] = atoms[XmATEXT]; targs[n++] = C_ENCODING; if (XA_STRING != C_ENCODING) targs[n++] = XA_STRING; if (ListDragConv->pixmap != None) targs[n++] = XA_PIXMAP; format = 32; size = n; type = XA_ATOM; cs->status = XmCONVERT_DONE; } else if (cs->target == atoms[XmACOMPOUND_TEXT] || cs->target == atoms[XmA_MOTIF_COMPOUND_STRING] || cs->target == XA_STRING || cs->target == C_ENCODING || cs->target == atoms[XmATEXT] || cs->target == atoms[XmAUTF8_STRING]) { XmString concat; XmString sep = XmStringSeparatorCreate(); format = 8; if (cs->selection == atoms[XmA_MOTIF_DROP]) { int itemcount = ListDragConv->num_items; XmString *items = ListDragConv->strings; concat = (itemcount ? XmStringCopy(items[0]) : NULL); for (i = 1; i < itemcount; i++) { concat = XmStringConcatAndFree(concat, XmStringCopy(sep)); concat = XmStringConcatAndFree(concat, XmStringCopy(items[i])); } } else { Cardinal row; int rowcount; int * rows = GetSelectedRows(lw, &rowcount); concat = NULL; for (row = 0; row < rowcount; row++) { if (concat) { concat = XmStringConcatAndFree(concat, XmStringCopy(GetConcatenatedRow(w, rows[row]))); } else { concat = GetConcatenatedRow(w, rows[row]); } if (row < rowcount-1) { concat = XmStringConcatAndFree(concat, XmStringCopy(sep)); } } XtFree((XtPointer)rows); } if (cs->target == atoms[XmACOMPOUND_TEXT] || cs->target == C_ENCODING || cs->target == XA_STRING || cs->target == atoms[XmATEXT]) { if (concat != NULL) value = XmCvtXmStringToCT(concat); else value = NULL; type = atoms[XmACOMPOUND_TEXT]; if (value != NULL) size = strlen((char*) value); else size = 0; if (cs->target == XA_STRING) { XTextProperty tmp_prop; int ret_status; /* convert value to 8859.1 */ ret_status = XmbTextListToTextProperty(XtDisplay(w), (char**) &value, 1, (XICCEncodingStyle) XStringStyle, &tmp_prop); XtFree((char*) value); if (ret_status == Success || ret_status > 0) { value = (XtPointer) tmp_prop.value; type = XA_STRING; size = tmp_prop.nitems; } else { value = NULL; size = 0; } /* If the target was TEXT then try and convert it. If * fully converted then we'll pass it back in locale * text. For locale text requests, always pass * back the converted text */ } else if ((cs->target == atoms[XmATEXT] || cs->target == C_ENCODING) && (value != NULL)) { char *cvt; Boolean success; cvt = _XmTextToLocaleText(w, value, type, format, size, &success); if ((cvt != NULL && success) || cs->target == C_ENCODING) { if (! success && cvt != NULL) cs->flags |= XmCONVERTING_PARTIAL; XtFree((char*) value); value = cvt; type = C_ENCODING; } } } #ifdef UTF8_SUPPORTED else if (cs->target == atoms[XmAUTF8_STRING]) { type = atoms[XmAUTF8_STRING]; value = XmCvtXmStringToUTF8String(concat); if (value != NULL) size = strlen((char*) value); else size = 0; } #endif else { size = XmCvtXmStringToByteStream(concat, (unsigned char**) &value); type = atoms[XmA_MOTIF_COMPOUND_STRING]; } XmStringFree(concat); XmStringFree(sep); } else if (cs->target == atoms[XmA_MOTIF_LOSE_SELECTION]) { /* Deselect everything in the list since we lost the primary selection. */ Xm18IListUnselectAllItems(w); } else if (cs->target == XA_PIXMAP) { /* Get row's pixmap */ Pixmap *pix; pix = (Pixmap *) XtMalloc(sizeof(Pixmap)); *pix = ListDragConv->pixmap; /* value, type, size, and format must be set */ value = (XtPointer) pix; type = XA_DRAWABLE; size = 1; format = 32; } _XmConvertComplete(w, value, size, format, type, cs); } /*ARGSUSED*/ static void ListPreDestProc(Widget w, XtPointer ignore, /* unused */ XmDestinationCallbackStruct *cs) { XmDropProcCallbackStruct *ds; Atom XA_MOTIF_DROP = XInternAtom(XtDisplay(w), XmS_MOTIF_DROP, False); int index; short row, col; if (cs->selection != XA_MOTIF_DROP) return; /* If this is the result of a drop, we can fill in location_data with * the apparent site */ ds = (XmDropProcCallbackStruct *) cs->destination_data; CvtPositionToRowColumn(w, ds->x, ds->y, &row, &col); cs->location_data = (XtPointer) (long) row; } /* * Function: * GetConcatenatedRow(ilist) * Description: * Helper fucntion for UTM operations. Returns joined collumns of a row, * with tabs between column values. * Input: * w : Widget - the widget to copy titles * row : XmMultiListRowInfo - the row to concatenate * Output: * XmString - the concatenated string. */ static XmString GetConcatenatedRow(Widget w, int row) { XmString result = NULL; XmString temp_string; XmString tab = XmStringComponentCreate(XmSTRING_COMPONENT_TAB, 0, NULL); XmI18ListWidget lw = (XmI18ListWidget)w; short i; for (i = 0; i < lw->ilist.num_columns; i++) { if (lw->ilist.row_data[row].values[i]) { if (result) { temp_string = XmStringConcat(tab, lw->ilist.row_data[row].values[i]); result = XmStringConcatAndFree(result, temp_string); } else { result = XmStringCopy(lw->ilist.row_data[row].values[i]); } } } XmStringFree(tab); return result; } /*************************************************************************** * * * ProcessDrag - drag the selected items * * * ***************************************************************************/ /*ARGSUSED*/ static void ProcessDrag(Widget wid, XEvent *event, String *params, /* unused */ Cardinal *num_params) /* unused */ { XmI18ListWidget lw = (XmI18ListWidget) wid; register int i; short row, col; Widget drag_icon, dc; Arg args[10]; int n, location_data; XmI18ListDragConvertStruct *ListDragConv; XmString temp_string = NULL; XmString temp_string2 = NULL; XmString tab; /* Don't allow multi-button drags. */ if (event->xbutton.state & ~((Button1Mask >> 1) << event->xbutton.button) & (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask)) return; CvtPositionToRowColumn(wid, event->xbutton.x, event->xbutton.y, &row, &col); if (col < 0 || row >= lw->ilist.num_rows || col >= lw->ilist.num_columns) return; location_data = row; lw->ilist.drag_conv = ListDragConv = (XmI18ListDragConvertStruct *) XtMalloc(sizeof(XmI18ListDragConvertStruct)); ListDragConv->w = wid; ListDragConv->strings = NULL; ListDragConv->pixmap = None; ListDragConv->num_items = 0; if (col == 0 && lw->ilist.first_col_pixmaps && row >= 0) { ListDragConv->num_items = 1; ListDragConv->pixmap = lw->ilist.row_data[row].pixmap; } if (row >= 0) { if (lw->ilist.row_data[row].selected) { int rowcount; int * rows = GetSelectedRows(lw, &rowcount); ListDragConv->num_items = rowcount; ListDragConv->strings = (XmString *) XtMalloc(sizeof(XmString) * ListDragConv->num_items); for (i = 0; i < rowcount; i++) ListDragConv->strings[i] = GetConcatenatedRow(wid, rows[i]); XtFree((XtPointer)rows); } else { ListDragConv->strings = (XmString *) XtMalloc(sizeof(XmString)); ListDragConv->num_items = 1; ListDragConv->strings[0] = GetConcatenatedRow(wid, row); } } else if (row == -2 && lw->ilist.column_titles) { /* drag column header */ ListDragConv->strings = (XmString *) XtMalloc(sizeof(XmString)); ListDragConv->num_items = 1; ListDragConv->strings[0] = lw->ilist.column_titles[col]; } else { return; } /* OK, now start the drag... */ drag_icon = XmeGetTextualDragIcon(wid); n = 0; XtSetArg(args[n], XmNcursorForeground, lw->primitive.foreground), n++; XtSetArg(args[n], XmNcursorBackground, lw->core.background_pixel), n++; XtSetArg(args[n], XmNsourceCursorIcon, drag_icon), n++; XtSetArg(args[n], XmNdragOperations, XmDROP_COPY), n++; dc = XmeDragSource(wid, (XtPointer) (long) location_data, event, args, n); if (dc) XtAddCallback(dc, XmNdragDropFinishCallback, DragDropFinished, lw); else DragDropFinished(dc, lw, NULL); } /*************************************************************************** * * * CopyToClipboard - copy the current selected items to the clipboard. * * * * This is a *sloow* process... * * * ***************************************************************************/ /*ARGSUSED*/ static void CopyToClipboard(Widget w, XEvent *event, String *params, Cardinal *num_params) { XmI18ListWidget lw = (XmI18ListWidget) w; int rowcount; /* text to the clipboard */ (void)GetSelectedRows(lw, &rowcount); if (rowcount > 0) (void) XmeClipboardSource(w, XmCOPY, 0); } /*ARGSUSED*/ static void DragDropFinished(Widget w, /* unused */ XtPointer closure, XtPointer call_data) /* unused */ { int i; XmI18ListWidget lw = (XmI18ListWidget)closure; XmI18ListDragConvertStruct *ListDragConv = lw->ilist.drag_conv; for (i = 0; i < ListDragConv->num_items; i++) XmStringFree(ListDragConv->strings[i]); XtFree((char *) ListDragConv->strings); XtFree((char *) ListDragConv); } /* Function Name: XmI18ListSelectItems * Description: Set selection state by matching column entries to XmString * Arguments: i18list - the extended list widget * item - XmString to use as selection key * column - column number (0 - N) to match (or XmANY_COLUMN) * notify - if True, call XmNsingleSelectionCallback * Returns: none */ void XmI18ListSelectItems(XmI18ListWidget i18list, XmString item, int column, Boolean notify) { SelectItems(i18list, item, column, True, notify); } /* Function Name: XmI18ListDeselectItems * Description: Set selection state by matching column entries to XmString * Arguments: i18list - the extended list widget * item - XmString to use as selection key * column - column number (0 - N) to match (or XmANY_COLUMN) * Returns: none */ void XmI18ListDeselectItems(XmI18ListWidget i18list, XmString item, int column) { SelectItems(i18list, item, column, False, False); } /* Function Name: XmI18ListSelectAllItems * Description: Set selection state by matching column entries to XmString * Arguments: i18list - the extended list widget * item - XmString to use as selection key * column - column number (0 - N) to match (or XmANY_COLUMN) * notify - if True, call XmNsingleSelectionCallback * Returns: none */ void XmI18ListSelectAllItems(XmI18ListWidget i18list, Boolean notify) { SelectItems(i18list, NULL, XmANY_COLUMN, True, notify); } /* Function Name: XmI18SelectRow * Description: Set selection state of row * Arguments: i18list - the extended list widget * row - the row to select * notify - if True, call XmNsingleSelectionCallback * Returns: none */ void XmI18ListSelectRow(XmI18ListWidget i18list, int row, Boolean notify) { SelectRow(i18list, row, True, notify); } /* Function Name: XmI18DeselectRow * Description: Set selection state of row * Arguments: i18list - the extended list widget * row - the row to deselect * Returns: none */ void XmI18ListDeselectRow(XmI18ListWidget i18list, int row) { SelectRow(i18list, row, False, False); } /* Function Name: XmI18ListGetSelectedRowArray * Description: Creates an array of integers which are selected row #'s * Arguments: i18list - the extended list widget * rows - pointer to the array of selected row #'s * num_rows - pointer to the number of selected rows * Returns: selected rows array */ int * XmI18ListGetSelectedRowArray(XmI18ListWidget i18list, int *num_rows) { return GetSelectedRows(i18list, num_rows); } /* Function Name: XmI18ListMakeRowVisible * Description: Shifts the visible extended list rows as desired * Arguments: i18list - the extended list widget * row - the row number wished to be made visible * Returns: none */ void XmI18ListMakeRowVisible(XmI18ListWidget i18list, int row) { /* Use column zero as a rule when making a row visible... */ MakeCellVisible((Widget) i18list, row, 0); }