/* * Copyright(c) 1992 Bell Communications Research, Inc. (Bellcore) * Copyright(c) 1995-99 Andrew Lister * All rights reserved * Permission to use, copy, modify and distribute this material for * any purpose and without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies, and that the name of Bellcore not be used in advertising * or publicity pertaining to this material without the specific, * prior written permission of an authorized representative of * Bellcore. * * BELLCORE MAKES NO REPRESENTATIONS AND EXTENDS NO WARRANTIES, EX- * PRESS OR IMPLIED, WITH RESPECT TO THE SOFTWARE, INCLUDING, BUT * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR ANY PARTICULAR PURPOSE, AND THE WARRANTY AGAINST IN- * FRINGEMENT OF PATENTS OR OTHER INTELLECTUAL PROPERTY RIGHTS. THE * SOFTWARE IS PROVIDED "AS IS", AND IN NO EVENT SHALL BELLCORE OR * ANY OF ITS AFFILIATES BE LIABLE FOR ANY DAMAGES, INCLUDING ANY * LOST PROFITS OR OTHER INCIDENTAL OR CONSEQUENTIAL DAMAGES RELAT- * ING TO THE SOFTWARE. * * MatrixWidget Author: Andrew Wason, Bellcore, aw@bae.bellcore.com * * $Id: Matrix.c,v 1.1.2.2 2004/07/02 21:53:02 fnevgeny Exp $ */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #if XmVersion > 1001 #include #include #include #endif #include #include #include #include #include #include #include #include #include #ifndef XlibSpecificationRelease #define XrmPermStringToQuark XrmStringToQuark #endif /* * Translations for Matrix (these will also be used by the Clip child). */ static char defaultTranslations[] = " : DefaultAction()\n\ : DefaultAction() EditCell(Pointer)\n\ Shift : ResizeColumns()\n\ : ProcessDrag()\n\ : HandleMotion()"; /* * Default translations for XmNtextTranslations resource */ static char default_text_translations[] = "#override\n\ Shift ~Ctrl ~Meta ~Alt Tab : EditCell(Left)\n\ ~Ctrl ~Meta ~Alt Tab : EditCell(Right)\n\ osfUp : EditCell(Up)\n\ osfDown : EditCell(Down)\n\ osfActivate : CommitEdit(False)\n\ ~Shift ~Meta ~Alt Return : CommitEdit(False)\n\ Ctrl osfCancel : CancelEdit(False)\n\ Shift Ctrl ~Meta ~Alt Tab : TraversePrev()\n\ Ctrl ~Meta ~Alt Tab : TraverseNext()\n\ osfPageDown : PageDown()\n\ osfPageUp : PageUp()"; #define offset(field) XtOffsetOf(XbaeMatrixRec, field) static XtResource resources[] = { #ifdef ALLOW_COLUMN_RESIZE {XmNallowColumnResize, XmCColumnResize, XmRBoolean, sizeof(Boolean), offset(matrix.allow_column_resize), XmRImmediate, (XtPointer) True}, #else {XmNallowColumnResize, XmCColumnResize, XmRBoolean, sizeof(Boolean), offset(matrix.allow_column_resize), XmRImmediate, (XtPointer) False}, #endif {XmNaltRowCount, XmCAltRowCount, XmRInt, sizeof(int), offset(matrix.alt_row_count), XmRImmediate, (XtPointer) 1}, {XmNboldLabels, XmCBoldLabels, XmRBoolean, sizeof(Boolean), offset(matrix.bold_labels), XmRImmediate, (XtPointer) False}, {XmNbuttonLabels, XmCButtonLabels, XmRBoolean, sizeof(Boolean), offset(matrix.button_labels), XmRImmediate, (XtPointer) False}, {XmNbuttonLabelBackground, XmCColor, XmRPixel, sizeof(Pixel), offset(matrix.button_label_background), XmRCallProc, (XtPointer)xbaeCopyBackground}, {XmNcalcCursorPosition, XmCCalcCursorPosition, XmRBoolean, sizeof(Boolean), offset(matrix.calc_cursor_position), XmRImmediate, (XtPointer) False}, {XmNcellBackgrounds, XmCColors, XmRPixelTable, sizeof(Pixel **), offset(matrix.cell_background), XmRImmediate, (XtPointer) NULL}, {XmNcellHighlightThickness, XmCHighlightThickness, XmRHorizontalDimension, sizeof(Dimension), offset(matrix.cell_highlight_thickness), XmRImmediate, (XtPointer) 2}, {XmNcellMarginHeight, XmCMarginHeight, XmRVerticalDimension, sizeof(Dimension), offset(matrix.cell_margin_height), XmRImmediate, (XtPointer) 3}, {XmNcellMarginWidth, XmCMarginWidth, XmRHorizontalDimension, sizeof(Dimension), offset(matrix.cell_margin_width), XmRImmediate, (XtPointer) 3}, {XmNcellShadowThickness, XmCShadowThickness, XmRDimension, sizeof(Dimension), offset(matrix.cell_shadow_thickness), XmRImmediate, (XtPointer) 1}, {XmNcellShadowType, XmCShadowType, XmRShadowType, sizeof(unsigned char), offset(matrix.cell_shadow_type), XmRImmediate, (XtPointer) XmSHADOW_OUT}, {XmNcellShadowTypes, XmCCellShadowTypes, XmRShadowTypeTable, sizeof(unsigned char**), offset(matrix.cell_shadow_types), XmRImmediate, (XtPointer) NULL}, {XmNcellUserData, XmCCellUserData, XmRUserDataTable, sizeof(XtPointer**), offset(matrix.cell_user_data), XmRImmediate, (XtPointer) NULL}, #if CELL_WIDGETS {XmNcellWidgets, XmCCellWidgets, XmRWidgetTable, sizeof(Widget **), offset(matrix.cell_widgets), XmRImmediate, (XtPointer) NULL}, #endif {XmNcells, XmCCells, XmRCellTable, sizeof(String **), offset(matrix.cells), XmRImmediate, NULL}, {XmNclipWindow, XmCClipWindow, XmRWidget, sizeof(Widget), offset(matrix.clip_window), XmRImmediate, NULL}, {XmNcolors, XmCColors, XmRPixelTable, sizeof(Pixel **), offset(matrix.colors), XmRImmediate, (XtPointer) NULL}, {XmNcolumnAlignments, XmCAlignments, XmRAlignmentArray, sizeof(unsigned char *), offset(matrix.column_alignments), XmRImmediate, (XtPointer) NULL}, {XmNcolumnButtonLabels, XmCButtonLabels, XmRBooleanArray, sizeof(Boolean*), offset(matrix.column_button_labels), XmRImmediate, (XtPointer) NULL}, {XmNcolumnLabelAlignments, XmCAlignments, XmRAlignmentArray, sizeof(unsigned char *), offset(matrix.column_label_alignments), XmRImmediate, (XtPointer) NULL}, {XmNcolumnLabelColor, XmCColor, XmRPixel, sizeof(Pixel), offset(matrix.column_label_color), XmRCallProc, (XtPointer)xbaeCopyForeground}, {XmNcolumnLabels, XmCLabels, XmRStringArray, sizeof(String *), offset(matrix.column_labels), XmRImmediate, NULL}, {XmNcolumnMaxLengths, XmCColumnMaxLengths, XmRMaxLengthArray, sizeof(int *), offset(matrix.column_max_lengths), XmRImmediate, NULL}, {XmNcolumnShadowTypes, XmCShadowTypes, XmRShadowTypeArray, sizeof(unsigned char*), offset(matrix.column_shadow_types), XmRImmediate, (XtPointer) NULL}, {XmNcolumnUserData, XmCUserDatas, XmRUserDataArray, sizeof(XtPointer*), offset(matrix.column_user_data), XmRImmediate, (XtPointer) NULL}, {XmNcolumnWidths, XmCColumnWidths, XmRWidthArray, sizeof(short *), offset(matrix.column_widths), XmRImmediate, NULL}, {XmNcolumns, XmCColumns, XmRInt, sizeof(int), offset(matrix.columns), XmRImmediate, (XtPointer) 1}, {XmNdefaultActionCallback,XmCCallback,XmRCallback,sizeof(XtCallbackList), offset(matrix.default_action_callback),XmRCallback,NULL }, {XmNdoubleClickInterval, XmCDoubleClickInterval, XmRInt, sizeof(int), offset(matrix.double_click_interval), XmRCallProc, (XtPointer)xbaeCopyDoubleClick }, {XmNdrawCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), offset(matrix.draw_cell_callback), XmRCallback, NULL}, {XmNenterCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), offset(matrix.enter_cell_callback), XmRCallback, NULL}, {XmNevenRowBackground, XmCBackground, XmRPixel, sizeof(Pixel), offset(matrix.even_row_background), XmRCallProc, (XtPointer)xbaeCopyBackground}, {XmNfill, XmCFill, XmRBoolean, sizeof(Boolean), offset(matrix.fill), XmRImmediate, (XtPointer) False}, {XmNfixedColumns, XmCFixedColumns, XmRDimension, sizeof(Dimension), offset(matrix.fixed_columns), XmRImmediate, (XtPointer) 0}, {XmNfixedRows, XmCFixedRows, XmRDimension, sizeof(Dimension), offset(matrix.fixed_rows), XmRImmediate, (XtPointer) 0}, {XmNfontList, XmCFontList, XmRFontList, sizeof(XmFontList), offset(matrix.font_list), XmRString, (XtPointer) "fixed"}, {XmNgridLineColor, XmCColor, XmRPixel, sizeof(Pixel), offset(matrix.grid_line_color), XmRCallProc, (XtPointer)xbaeCopyForeground}, {XmNgridType, XmCGridType, XmRGridType, sizeof(unsigned char), offset(matrix.grid_type), XmRImmediate, (XtPointer)XmGRID_CELL_LINE}, #if XmVersion >= 1002 {XmNhighlightedCells, XmCHighlightedCells, XmRHighlightTable, sizeof(unsigned char **), offset(matrix.highlighted_cells), XmRImmediate, (XtPointer) NULL}, #endif {XmNhorizontalScrollBar, XmCHorizontalScrollBar, XmRWidget, sizeof(Widget), offset(matrix.horizontal_sb), XmRImmediate, NULL}, {XmNhorizontalScrollBarDisplayPolicy, XmCMatrixScrollBarDisplayPolicy, XmRMatrixScrollBarDisplayPolicy, sizeof(unsigned char), offset(matrix.hsb_display_policy), XmRImmediate, (XtPointer) XmDISPLAY_AS_NEEDED}, {XmNlabelActivateCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), offset(matrix.label_activate_callback), XmRCallback, NULL}, {XmNlabelFont, XmCFontList, XmRFontList, sizeof(XmFontList), offset(matrix.label_font_list), XmRString, (XtPointer)NULL }, {XmNleaveCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), offset(matrix.leave_cell_callback), XmRCallback, NULL}, {XmNleftColumn, XmCLeftColumn, XmRInt, sizeof(int), offset(matrix.left_column), XmRImmediate, (XtPointer) 0 }, {XmNmodifyVerifyCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), offset(matrix.modify_verify_callback), XmRCallback, NULL}, {XmNoddRowBackground, XmCBackground, XmRPixel, sizeof(Pixel), offset(matrix.odd_row_background), XmRCallProc, (XtPointer)xbaeCopyBackground}, #if XmVersion > 1001 {XmNprocessDragCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), offset(matrix.process_drag_callback), XmRCallback, NULL}, #endif /* Resize callback resource. Added by mjs */ {XmNresizeCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), offset(matrix.resize_callback), XmRCallback, NULL}, {XmNresizeColumnCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), offset(matrix.resize_column_callback), XmRCallback, NULL}, {XmNreverseSelect, XmCReverseSelect, XmRBoolean, sizeof(Boolean), offset(matrix.reverse_select), XmRImmediate, (XtPointer) False}, {XmNrowButtonLabels, XmCButtonLabels, XmRBooleanArray, sizeof(Boolean*), offset(matrix.row_button_labels), XmRImmediate, (XtPointer) NULL}, {XmNrowLabelAlignment, XmCAlignment, XmRAlignment, sizeof(unsigned char), offset(matrix.row_label_alignment), XmRImmediate, (XtPointer) XmALIGNMENT_END}, {XmNrowLabelColor, XmCColor, XmRPixel, sizeof(Pixel), offset(matrix.row_label_color), XmRCallProc, (XtPointer)xbaeCopyForeground }, {XmNrowLabelWidth, XmCRowLabelWidth, XmRShort, sizeof(short), offset(matrix.row_label_width), XmRImmediate, (XtPointer) 0}, {XmNrowLabels, XmCLabels, XmRStringArray, sizeof(String *), offset(matrix.row_labels), XmRImmediate, NULL}, {XmNrowShadowTypes, XmCShadowTypes, XmRShadowTypeArray, sizeof(unsigned char*), offset(matrix.row_shadow_types), XmRImmediate, (XtPointer) NULL}, {XmNrowUserData, XmCUserDatas, XmRUserDataArray, sizeof(XtPointer*), offset(matrix.row_user_data), XmRImmediate, (XtPointer) NULL}, {XmNrows, XmCRows, XmRInt, sizeof(int), offset(matrix.rows), XmRImmediate, (XtPointer) 1}, {XmNscrollBarPlacement, XmCScrollBarPlacement, XmRScrollBarPlacement, sizeof(unsigned char), offset(matrix.scrollbar_placement), XmRImmediate, (XtPointer) XmBOTTOM_RIGHT }, {XmNselectCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), offset(matrix.select_cell_callback), XmRCallback, NULL}, {XmNselectScrollVisible, XmCSelectScrollVisible, XmRBoolean, sizeof(Boolean), offset(matrix.scroll_select), XmRImmediate, (XtPointer) True}, {XmNselectedBackground, XmCColor, XmRPixel, sizeof(Pixel), offset(matrix.selected_background), XmRCallProc, (XtPointer)xbaeCopyForeground}, {XmNselectedCells, XmCSelectedCells, XmRBooleanTable, sizeof(Boolean **), offset(matrix.selected_cells), XmRImmediate, (XtPointer) NULL}, {XmNselectedForeground, XmCColor, XmRPixel, sizeof(Pixel), offset(matrix.selected_foreground), XmRCallProc, (XtPointer)xbaeCopyBackground}, {XmNselectionPolicy, XmCSelectionPolicy, XmRSelectionPolicy, sizeof(unsigned char), offset(matrix.selection_policy), XmRImmediate, XmSINGLE_SELECT}, /* Override Manager default */ {XmNshadowThickness, XmCShadowThickness, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmManagerRec, manager.shadow_thickness), XmRImmediate, (XtPointer) 2}, {XmNshadowType, XmCShadowType, XmRShadowType, sizeof(unsigned char), offset(matrix.shadow_type), XmRImmediate, (XtPointer) XmSHADOW_IN}, {XmNshowArrows, XmCShowArrows, XmRBoolean, sizeof(Boolean), offset(matrix.show_arrows), XmRImmediate, (XtPointer) False}, {XmNspace, XmCSpace, XmRHorizontalDimension, sizeof(Dimension), offset(matrix.space), XmRImmediate, (XtPointer) 4}, {XmNtextBackground, XmCTextBackground, XmRPixel, sizeof(Pixel), offset(matrix.text_background), XmRCallProc, (XtPointer)xbaeCopyBackground}, {XmNtextField, XmCTextField, XmRWidget, sizeof(Widget), offset(matrix.text_field), XmRImmediate, NULL}, {XmNtextShadowThickness, XmCTextShadowThickness, XmRDimension, sizeof(Dimension), offset(matrix.text_shadow_thickness), XmRImmediate, (XtPointer) 0}, {XmNtextTranslations, XmCTranslations, XmRTranslationTable, sizeof(XtTranslations), offset(matrix.text_translations), XmRString, (XtPointer) default_text_translations}, {XmNtopRow, XmCTopRow, XmRInt, sizeof(int), offset(matrix.top_row), XmRImmediate, (XtPointer) 0}, {XmNtrailingAttachedBottom, XmCTrailingAttachedBottom, XmRBoolean, sizeof(Boolean), offset(matrix.trailing_attached_bottom), XmRImmediate, (XtPointer) False}, {XmNtrailingAttachedRight, XmCTrailingAttachedRight, XmRBoolean, sizeof(Boolean), offset(matrix.trailing_attached_right), XmRImmediate, (XtPointer) False}, {XmNtrailingFixedColumns, XmCTrailingFixedColumns, XmRDimension, sizeof(Dimension), offset(matrix.trailing_fixed_columns), XmRImmediate, (XtPointer) 0}, {XmNtrailingFixedRows, XmCTrailingFixedRows, XmRDimension, sizeof(Dimension), offset(matrix.trailing_fixed_rows), XmRImmediate, (XtPointer) 0}, {XmNtraverseCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), offset(matrix.traverse_cell_callback), XmRCallback, NULL}, {XmNtraverseFixedCells, XmCTraverseFixedCells, XmRBoolean, sizeof(Boolean), offset(matrix.traverse_fixed), XmRImmediate, (XtPointer) False}, {XmNverticalScrollBar, XmCVerticalScrollBar, XmRWidget, sizeof(Widget), offset(matrix.vertical_sb), XmRImmediate, NULL}, {XmNverticalScrollBar, XmCVerticalScrollBar, XmRWidget, sizeof(Widget), offset(matrix.vertical_sb), XmRImmediate, NULL}, {XmNverticalScrollBarDisplayPolicy, XmCMatrixScrollBarDisplayPolicy, XmRMatrixScrollBarDisplayPolicy, sizeof(unsigned char), offset(matrix.vsb_display_policy), XmRImmediate, (XtPointer) XmDISPLAY_AS_NEEDED}, {XmNvisibleColumns, XmCVisibleColumns, XmRDimension, sizeof(Dimension), offset(matrix.visible_columns), XmRImmediate, (XtPointer) 0}, {XmNvisibleRows, XmCVisibleRows, XmRDimension, sizeof(Dimension), offset(matrix.visible_rows), XmRImmediate, (XtPointer) 0}, {XmNwriteCellCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), offset(matrix.write_cell_callback), XmRCallback, NULL}, }; static XmSyntheticResource syn_resources[] = { {XmNcellHighlightThickness, sizeof(Dimension), offset(matrix.cell_highlight_thickness), _XmFromHorizontalPixels, _XmToHorizontalPixels}, {XmNcellMarginHeight, sizeof(Dimension), offset(matrix.cell_margin_height), _XmFromVerticalPixels, _XmToVerticalPixels}, {XmNcellMarginWidth, sizeof(Dimension), offset(matrix.cell_margin_width), _XmFromHorizontalPixels, _XmToHorizontalPixels}, {XmNcellShadowThickness, sizeof(Dimension), offset(matrix.cell_shadow_thickness), _XmFromHorizontalPixels, _XmToHorizontalPixels}, {XmNspace, sizeof(Dimension), offset(matrix.space), _XmFromHorizontalPixels, _XmToHorizontalPixels}, }; #if XmVersion >= 1002 static XtIntervalId TraverseID = 0; #endif /* * Declaration of methods */ static void ClassInitialize P((void)); static void xbaeRegisterConverters P((void)); static void ClassPartInitialize P((XbaeMatrixWidgetClass)); static void Initialize P((XbaeMatrixWidget, XbaeMatrixWidget, ArgList, Cardinal *)); static void Realize P((XbaeMatrixWidget, XtValueMask *, XSetWindowAttributes *)); static void InsertChild P((Widget)); static void Redisplay P((Widget, XEvent *, Region)); static Boolean SetValues P((XbaeMatrixWidget, XbaeMatrixWidget, XbaeMatrixWidget, ArgList, Cardinal *)); static void SetValuesAlmost P((XbaeMatrixWidget, XbaeMatrixWidget, XtWidgetGeometry *, XtWidgetGeometry *)); static void Destroy P((XbaeMatrixWidget)); static XtGeometryResult GeometryManager P((Widget, XtWidgetGeometry *, XtWidgetGeometry *)); static XtGeometryResult QueryGeometry P((XbaeMatrixWidget, XtWidgetGeometry *, XtWidgetGeometry *)); /* * Redraw function for clip widget */ static void ClipRedisplay P((Widget, XEvent *, Region)); /* * Private functions unique to Matrix */ static void ResizeCells P((XbaeMatrixWidget, XbaeMatrixWidget)); static void ResizeSelectedCells P((XbaeMatrixWidget, XbaeMatrixWidget)); #if XmVersion >= 1002 static void ResizeHighlightedCells P((XbaeMatrixWidget, XbaeMatrixWidget)); #endif static void ResizeColors P((XbaeMatrixWidget, XbaeMatrixWidget, Boolean)); static void TraverseIn P((XbaeMatrixWidget)); #if XmVersion >= 1002 static void TraverseInTimeOut P((XtPointer, XtIntervalId *)); #endif /* XmVersion >= 1002 */ /* * Clip widget focusCallback */ static void TraverseInCB P((Widget, XbaeMatrixWidget, XtPointer)); /* * Matrix actions */ static XtActionsRec actions[] = { {"EditCell", xbaeEditCellACT}, {"CancelEdit", xbaeCancelEditACT}, {"DefaultAction", xbaeDefaultActionACT}, {"CommitEdit", xbaeCommitEditACT}, {"ResizeColumns", xbaeResizeColumnsACT}, {"SelectCell", xbaeSelectCellACT}, {"TraverseNext", xbaeTraverseNextACT}, {"TraversePrev", xbaeTraversePrevACT}, {"ProcessDrag", xbaeProcessDragACT}, {"HandleMotion", xbaeHandleMotionACT}, {"PageDown", xbaePageDownACT}, {"PageUp", xbaePageUpACT} }; static XmBaseClassExtRec BaseClassExtRec = { NULL, /* next_extension */ NULLQUARK, /* record_type */ XmBaseClassExtVersion, /* version */ sizeof(XmBaseClassExtRec), /* record_size */ NULL, /* InitializePrehook */ NULL, /* SetValuesPrehook */ NULL, /* InitializePosthook */ NULL, /* SetValuesPosthook */ NULL, /* secondaryObjectClass */ NULL, /* secondaryCreate */ NULL, /* getSecRes data */ { 0 }, /* fastSubclass flags */ NULL, /* get_values_prehook */ NULL, /* get_values_posthook */ NULL, /* classPartInitPrehook */ NULL, /* classPartInitPosthook*/ NULL, /* ext_resources */ NULL, /* compiled_ext_resources*/ 0, /* num_ext_resources */ FALSE, /* use_sub_resources */ XmInheritWidgetNavigable, /* widgetNavigable */ XmInheritFocusChange, /* focusChange */ }; externaldef(xbaematrixclassrec) XbaeMatrixClassRec xbaeMatrixClassRec = { { /* core_class fields */ (WidgetClass) & xmManagerClassRec, /* superclass */ "XbaeMatrix", /* class_name */ sizeof(XbaeMatrixRec), /* widget_size */ ClassInitialize, /* class_initialize */ (XtWidgetClassProc)ClassPartInitialize, /* class_part_initialize*/ False, /* class_inited */ (XtInitProc)Initialize, /* initialize */ NULL, /* initialize_hook */ (XtRealizeProc)Realize, /* realize */ actions, /* actions */ XtNumber(actions), /* num_actions */ resources, /* resources */ XtNumber(resources), /* num_resources */ NULLQUARK, /* xrm_class */ True, /* compress_motion */ XtExposeCompressMultiple | /* compress_exposure */ XtExposeGraphicsExpose | XtExposeNoExpose, True, /* compress_enterleave */ False, /* visible_interest */ (XtWidgetProc)Destroy, /* destroy */ (XtWidgetProc)xbaeResize, /* resize */ (XtExposeProc)Redisplay, /* expose */ (XtSetValuesFunc)SetValues, /* set_values */ NULL, /* set_values_hook */ (XtAlmostProc)SetValuesAlmost, /* set_values_almost */ NULL, /* get_values_hook */ NULL, /* accept_focus */ XtVersionDontCheck, /* version */ NULL, /* callback_private */ defaultTranslations, /* tm_table */ (XtGeometryHandler)QueryGeometry, /* query_geometry */ NULL, /* display_accelerator */ (XtPointer) &BaseClassExtRec /* extension */ }, { /* composite_class fields */ GeometryManager, /* geometry_manager */ NULL, /* change_managed */ InsertChild, /* insert_child */ XtInheritDeleteChild, /* delete_child */ NULL, /* extension */ }, { /* constraint_class fields */ NULL, /* resources */ 0, /* num_resources */ 0, /* constraint_size */ NULL, /* initialize */ NULL, /* destroy */ NULL, /* set_values */ NULL /* extension */ }, { /* manager_class fields */ XtInheritTranslations, /* translations */ syn_resources, /* syn_resources */ XtNumber(syn_resources), /* num_syn_resources */ NULL, /* syn_constraint_resources */ 0, /* num_syn_constraint_resources */ XmInheritParentProcess, /* parent_process */ NULL /* extension */ }, { /* matrix_class fields */ xbaeSetCell, /* set_cell */ xbaeGetCell, /* get_cell */ xbaeEditCell, /* edit_cell */ xbaeSelectCell, /* select_cell */ xbaeSelectRow, /* select_row */ xbaeSelectColumn, /* select_column */ xbaeDeselectAll, /* deselect_all */ xbaeSelectAll, /* select_all */ xbaeDeselectCell, /* deselect_cell */ xbaeDeselectRow, /* deselect_row */ xbaeDeselectColumn, /* deselect_column */ xbaeCommitEdit, /* commit_edit */ xbaeCancelEdit, /* cancel_edit */ xbaeAddRows, /* add_rows */ xbaeDeleteRows, /* delete_rows */ xbaeAddColumns, /* add_columns */ xbaeDeleteColumns, /* delete_columns */ xbaeSetRowColors, /* set_row_colors */ xbaeSetColumnColors, /* set_column_colors */ xbaeSetCellColor, /* set_cell_color */ NULL, /* extension */ } }; externaldef(xbaematrixwidgetclass) WidgetClass xbaeMatrixWidgetClass = (WidgetClass) & xbaeMatrixClassRec; static XtConvertArgRec convertArg[] = { {XtWidgetBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.screen), sizeof(Screen *)}, {XtWidgetBaseOffset, (XtPointer) XtOffsetOf(WidgetRec, core.colormap), sizeof(Colormap)} }; static void xbaeRegisterConverters() { /* * String to StringArray is used for XmNrowLabels and XmNcolumnLabels * We make a private copy of this table */ XtSetTypeConverter(XmRString, XmRStringArray, CvtStringToStringArray, NULL, 0, XtCacheAll | XtCacheRefCount, StringArrayDestructor); /* * String to String2DArray is used for XmNcells resource * We make a private copy of this table */ XtSetTypeConverter(XmRString, XmRCellTable, CvtStringToCellTable, NULL, 0, XtCacheNone, StringCellDestructor); /* * String to ShortArray is used for XmNcolumnWidths resource. * We make a private copy of this table */ XtSetTypeConverter(XmRString, XmRWidthArray, CvtStringToWidthArray, NULL, 0, XtCacheAll | XtCacheRefCount, WidthArrayDestructor); /* * String to IntArray is used for XmNcolumnMaxLengths resource. * We make a private copy of this table */ XtSetTypeConverter(XmRString, XmRMaxLengthArray, CvtStringToMaxLengthArray, NULL, 0, XtCacheAll | XtCacheRefCount, MaxLengthArrayDestructor); /* * String to PixelTable is used for XmNcolors * and XmNcellBackgrounds resources. */ XtSetTypeConverter(XmRString, XmRPixelTable, CvtStringToPixelTable,convertArg, XtNumber(convertArg), XtCacheNone, PixelTableDestructor); /* * String to BooleanArray is used for XmNcolumnButtonLabels and * XmNrowButtonLabels resources. */ XtSetTypeConverter(XmRString, XmRBooleanArray, CvtStringToBooleanArray, NULL, 0, XtCacheAll | XtCacheRefCount, BooleanArrayDestructor); /* * String to AlignmentArray is used for XmNcolumnAlignments * and XmNcolumnLabelAlignments resources. */ XtSetTypeConverter(XmRString, XmRAlignmentArray, CvtStringToAlignmentArray, NULL, 0, XtCacheAll | XtCacheRefCount, AlignmentArrayDestructor); /* * String to grid type is used for XmNgridType */ XtSetTypeConverter(XmRString, XmRGridType, CvtStringToGridType, NULL, 0, XtCacheAll, NULL); /* * String to matrix display policy is used for * XmN{vertical,horizontal}ScrollBarDisplayPolicy */ XtSetTypeConverter(XmRString, XmRMatrixScrollBarDisplayPolicy, #ifdef __VMS CvtStringToMatrixScrollBarDisp, #else CvtStringToMatrixScrollBarDisplayPolicy, #endif NULL, 0, XtCacheAll, NULL); } static void ClassInitialize() { xbaeRegisterConverters(); } static void ClassPartInitialize(mwc) XbaeMatrixWidgetClass mwc; { register XbaeMatrixWidgetClass super = (XbaeMatrixWidgetClass) mwc->core_class.superclass; /* * Allow subclasses to inherit new Matrix methods */ if (mwc->matrix_class.set_cell == XbaeInheritSetCell) mwc->matrix_class.set_cell = super->matrix_class.set_cell; if (mwc->matrix_class.get_cell == XbaeInheritGetCell) mwc->matrix_class.get_cell = super->matrix_class.get_cell; if (mwc->matrix_class.edit_cell == XbaeInheritEditCell) mwc->matrix_class.edit_cell = super->matrix_class.edit_cell; if (mwc->matrix_class.select_cell == XbaeInheritSelectCell) mwc->matrix_class.select_cell = super->matrix_class.select_cell; if (mwc->matrix_class.select_row == XbaeInheritSelectRow) mwc->matrix_class.select_row = super->matrix_class.select_row; if (mwc->matrix_class.select_column == XbaeInheritSelectColumn) mwc->matrix_class.select_column = super->matrix_class.select_column; if (mwc->matrix_class.deselect_all == XbaeInheritDeselectAll) mwc->matrix_class.deselect_all = super->matrix_class.deselect_all; if (mwc->matrix_class.select_all == XbaeInheritSelectAll) mwc->matrix_class.select_all = super->matrix_class.select_all; if (mwc->matrix_class.deselect_cell == XbaeInheritDeselectCell) mwc->matrix_class.deselect_cell = super->matrix_class.deselect_cell; if (mwc->matrix_class.deselect_row == XbaeInheritDeselectRow) mwc->matrix_class.deselect_row = super->matrix_class.deselect_row; if (mwc->matrix_class.deselect_column == XbaeInheritDeselectColumn) mwc->matrix_class.deselect_column = super->matrix_class.deselect_column; if (mwc->matrix_class.commit_edit == XbaeInheritCommitEdit) mwc->matrix_class.commit_edit = super->matrix_class.commit_edit; if (mwc->matrix_class.cancel_edit == XbaeInheritCancelEdit) mwc->matrix_class.cancel_edit = super->matrix_class.cancel_edit; if (mwc->matrix_class.add_rows == XbaeInheritAddRows) mwc->matrix_class.add_rows = super->matrix_class.add_rows; if (mwc->matrix_class.delete_rows == XbaeInheritDeleteRows) mwc->matrix_class.delete_rows = super->matrix_class.delete_rows; if (mwc->matrix_class.add_columns == XbaeInheritAddColumns) mwc->matrix_class.add_columns = super->matrix_class.add_columns; if (mwc->matrix_class.delete_columns == XbaeInheritDeleteColumns) mwc->matrix_class.delete_columns = super->matrix_class.delete_columns; if (mwc->matrix_class.set_row_colors == XbaeInheritSetRowColors) mwc->matrix_class.set_row_colors = super->matrix_class.set_row_colors; if (mwc->matrix_class.set_column_colors == XbaeInheritSetColumnColors) mwc->matrix_class.set_column_colors = super->matrix_class.set_column_colors; if (mwc->matrix_class.set_cell_color == XbaeInheritSetCellColor) mwc->matrix_class.set_cell_color = super->matrix_class.set_cell_color; } #ifdef NEED_24BIT_VISUAL static Widget get_shell_ancestor(w) Widget w; { Widget sh; for (sh=w ; !XtIsShell(sh) ; sh=XtParent(sh)) ; } #endif /* * Callbacks for our scrollbars. */ static XtCallbackRec VSCallback[] = { {(XtCallbackProc) xbaeScrollVertCB, (XtPointer) NULL}, {(XtCallbackProc) NULL, NULL} }; static XtCallbackRec HSCallback[] = { {(XtCallbackProc) xbaeScrollHorizCB, (XtPointer) NULL}, {(XtCallbackProc) NULL, NULL} }; /* ARGSUSED */ static void Initialize(request, new, args, num_args) XbaeMatrixWidget request, new; ArgList args; Cardinal *num_args; { Dimension marginHeight; /* * Initialize redisplay counters */ new->matrix.disable_redisplay = 0; new->matrix.first_row_offset = 0; #if XmVersion >= 1002 /* * Initialize highlight location */ new->matrix.highlight_location = HighlightNone; #endif /* * Check rows/cols set by resources for consistency/validity */ if (new->matrix.rows < 0 || new->matrix.columns < 0) { XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "initialize", "badSize", "XbaeMatrix", "XbaeMatrix: Number of rows or columns is less than zero", (String *) NULL, (Cardinal *) NULL); if (new->matrix.rows < 0) new->matrix.rows = 0; if (new->matrix.columns < 0) new->matrix.columns = 0; } /* * Make sure column_widths were specified. If not, use a default value. * This should keep the XDesigner users happy.... */ if (new->matrix.columns && (new->matrix.column_widths == NULL)) { int i; new->matrix.column_widths = (short*)XtMalloc(new->matrix.columns * sizeof(short)); for (i = 0; i < new->matrix.columns; i++) new->matrix.column_widths[i] = 5; } /* If no label font is specified, copy the default fontList, but if we do then override the bold_labels resource */ if (!new->matrix.label_font_list) new->matrix.label_font_list = XmFontListCopy(new->matrix.font_list); else new->matrix.bold_labels = False; /* * We must have at least one non-fixed row/column. Only complain if there * are some to complain about, though. We may have none at all (yet). */ if ((int)(new->matrix.fixed_rows + new->matrix.trailing_fixed_rows) > 0 && (int)(new->matrix.fixed_rows + new->matrix.trailing_fixed_rows) >= new->matrix.rows) { XtAppWarningMsg(XtWidgetToApplicationContext((Widget) new), "initialize", "tooManyFixed", "XbaeMatrix", "XbaeMatrix: At least one row must not be fixed", NULL, 0); new->matrix.fixed_rows = 0; new->matrix.trailing_fixed_rows = 0; } if ((int)(new->matrix.fixed_columns + new->matrix.trailing_fixed_columns) > 0 && (int)(new->matrix.fixed_columns + new->matrix.trailing_fixed_columns) >= new->matrix.columns) { XtAppWarningMsg(XtWidgetToApplicationContext((Widget) new), "initialize", "tooManyFixed", "XbaeMatrix", "XbaeMatrix: At least one column must not be fixed", NULL, 0); new->matrix.fixed_columns = 0; new->matrix.trailing_fixed_columns = 0; } /* * We can't have too many visible columns */ if (new->matrix.columns && ((int)new->matrix.visible_columns > (new->matrix.columns - (int)new->matrix.fixed_columns - (int)new->matrix.trailing_fixed_columns))) { XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "initialize", "tooManyVisibleColumns", "XbaeMatrix", "XbaeMatrix: visibleColumns must not be greater than\n (columns - fixedColumns - trailingFixedColumns)", (String *) NULL, (Cardinal *) NULL); new->matrix.visible_columns = 0; } if (new->matrix.grid_type >= XmGRID_LINE) /* Deprecated types. To be removed in next version. */ XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "cvtStringToGridType", "deprecatedType", "XbaeMatrix", "Value for GridType is deprecated and will be removed in next release", NULL, NULL); /* * Copy the pointed to resources. * If cells is NULL, we create an array of "" strings. */ if (new->matrix.cells) xbaeCopyCells(new); if (new->matrix.row_labels) xbaeCopyRowLabels(new); if (new->matrix.column_labels) xbaeCopyColumnLabels(new); else { new->matrix.column_label_lines = NULL; new->matrix.column_label_maxlines = 0; } xbaeCopyColumnWidths(new); if (new->matrix.cell_shadow_types) xbaeCopyCellShadowTypes(new); if (new->matrix.row_shadow_types) xbaeCopyRowShadowTypes(new); if (new->matrix.column_shadow_types) xbaeCopyColumnShadowTypes(new); if (new->matrix.cell_user_data) xbaeCopyCellUserData(new); if (new->matrix.row_user_data) xbaeCopyRowUserData(new); if (new->matrix.column_user_data) xbaeCopyColumnUserData(new); #if CELL_WIDGETS if (new->matrix.cell_widgets) xbaeCopyCellWidgets(new); #endif if (new->matrix.column_max_lengths) xbaeCopyColumnMaxLengths(new); if (new->matrix.column_alignments) xbaeCopyColumnAlignments(new); if (new->matrix.column_button_labels) xbaeCopyColumnButtonLabels(new); if (new->matrix.column_label_alignments) xbaeCopyColumnLabelAlignments(new); if (new->matrix.colors) xbaeCopyColors(new); if (new->matrix.cell_background) xbaeCopyBackgrounds(new); if (new->matrix.selected_cells) xbaeCopySelectedCells(new); #if XmVersion >= 1002 if (new->matrix.highlighted_cells) xbaeCopyHighlightedCells(new); #endif if (new->matrix.row_button_labels) xbaeCopyRowButtonLabels(new); /* * If user didn't specify a rowLabelWidth, then calculate one based on * the widest label */ if (new->matrix.row_label_width == 0 && new->matrix.row_labels) new->matrix.row_label_width = xbaeMaxRowLabel(new); /* * Copy the fontList. Get fontStruct from fontList. */ xbaeNewFont(new); xbaeNewLabelFont(new); /* * Create our 4 children (SBs and textField are unmanaged for now) * they must be created in this order so our macros work * (horiz scroll, vert scroll and then clip and textField). * We scroll horizontally by pixels, vertically by rows. */ new->matrix.horizontal_sb = XtVaCreateWidget( "horizScroll", xmScrollBarWidgetClass, (Widget) new, XmNorientation, XmHORIZONTAL, XmNdragCallback, HSCallback, XmNvalueChangedCallback, HSCallback, XmNincrement, FONT_WIDTH(new), XmNsliderSize, 1, XmNminimum, 0, XmNmaximum, 1, XmNbackground, new->core.background_pixel, XmNforeground, new->manager.foreground, XmNbottomShadowColor, new->manager.bottom_shadow_color, XmNbottomShadowPixmap, new->manager.bottom_shadow_pixmap, XmNhighlightColor, new->manager.highlight_color, XmNhighlightPixmap, new->manager.highlight_pixmap, XmNtopShadowColor, new->manager.top_shadow_color, XmNtopShadowPixmap, new->manager.top_shadow_pixmap, NULL); HORIZ_ORIGIN(new) = 0; new->matrix.vertical_sb = XtVaCreateWidget( "vertScroll", xmScrollBarWidgetClass, (Widget) new, XmNorientation, XmVERTICAL, XmNdragCallback, VSCallback, XmNvalueChangedCallback, VSCallback, XmNincrement, 1, XmNminimum, 0, XmNmaximum, new->matrix.rows ? (new->matrix.rows - (int) new->matrix.fixed_rows - (int) new->matrix.trailing_fixed_rows) : 1, XmNsliderSize, 1, XmNbackground, new->core.background_pixel, XmNforeground, new->manager.foreground, XmNbottomShadowColor, new->manager.bottom_shadow_color, XmNbottomShadowPixmap, new->manager.bottom_shadow_pixmap, XmNhighlightColor, new->manager.highlight_color, XmNhighlightPixmap, new->manager.highlight_pixmap, XmNtopShadowColor, new->manager.top_shadow_color, XmNtopShadowPixmap, new->manager.top_shadow_pixmap, NULL); /* * Create the Clip widget managed so we can use it for traversal */ new->matrix.clip_window = XtVaCreateManagedWidget( "clip", xbaeClipWidgetClass, (Widget) new, XmNexposeProc, ClipRedisplay, XmNtraversalOn, new->manager.traversal_on, XmNbackground, new->core.background_pixel, NULL); /* * Add a callback to the Clip widget so we know when it gets the focus * and can use it in traversal. */ XtAddCallback(ClipChild(new), XmNfocusCallback, (XtCallbackProc)TraverseInCB, (XtPointer) new); /* * Calculate an imaginary cellMarginHeight based on the largest of * the label and cell font. If the font for the labels is bigger, * the cellMarginHeight needs to be increased to allow the cell font * to still appear centrally placed */ if (LABEL_HEIGHT(new) > FONT_HEIGHT(new)) marginHeight = (int)(LABEL_HEIGHT(new) + (new->matrix.cell_margin_height * 2) - FONT_HEIGHT(new)) / 2; else marginHeight = new->matrix.cell_margin_height; /* * Create text field (unmanaged for now) - its window will be reparented * in Realize to be a subwindow of Clip * * Set the shadow thickness to 0 to prevent a shadow drawn inside the * highlight region. The shadow thickness is used to draw the shadows * *around* the highlight */ new->matrix.text_field = XtVaCreateWidget( "textField", xmTextFieldWidgetClass, (Widget) new, XmNmarginWidth, new->matrix.cell_margin_width, XmNmarginHeight, marginHeight, XmNtranslations, new->matrix.text_translations, XmNfontList, new->matrix.font_list, XmNshadowThickness, new->matrix.text_shadow_thickness, XmNbackground, new->matrix.text_background, XmNforeground, new->manager.foreground, XmNbottomShadowColor, new->manager.bottom_shadow_color, XmNbottomShadowPixmap, new->manager.bottom_shadow_pixmap, XmNhighlightThickness, new->matrix.cell_highlight_thickness, XmNhighlightColor, new->manager.highlight_color, XmNhighlightPixmap, new->manager.highlight_pixmap, XmNeditMode, XmSINGLE_LINE_EDIT, NULL); XtAddCallback(TextChild(new), XmNmodifyVerifyCallback, xbaeModifyVerifyCB, (XtPointer) new); /* Add a handler on top of the text field to handle clicks on it */ XtAddEventHandler(TextChild(new), ButtonPressMask | ButtonReleaseMask, True, (XtEventHandler)xbaeHandleClick, (XtPointer)new); XtAddEventHandler((Widget)new, ButtonPressMask | ButtonReleaseMask, True, (XtEventHandler)xbaeHandleClick, (XtPointer)new); /* * Compute cell text baseline based on TextField widget */ new->matrix.text_baseline = XmTextGetBaseline(TextChild(new)) + new->matrix.cell_shadow_thickness; /* * Adjust the label_baseline according to the larger of the two fonts */ if (LABEL_HEIGHT(new) == FONT_HEIGHT(new)) new->matrix.label_baseline = new->matrix.text_baseline; else { if (LABEL_HEIGHT(new) < FONT_HEIGHT(new)) marginHeight = (int)(FONT_HEIGHT(new) + new->matrix.text_shadow_thickness * 2 + new->matrix.cell_margin_height * 2 - LABEL_HEIGHT(new)) / 2; else marginHeight = new->matrix.cell_margin_height + new->matrix.text_shadow_thickness; new->matrix.label_baseline = marginHeight + new->matrix.cell_shadow_thickness - new->matrix.label_font_y; } /* * Calculate total pixel width of cell area */ xbaeGetCellTotalWidth(new); /* * Make the clips for the fixed cells which are scrollable (i.e. the * fixed rows that can scroll horizontally, and the fixed columns which * can scroll vertically. This makes 4 scrollable fixed-cell areas. */ new->matrix.left_clip = XtVaCreateWidget( "leftclip", xbaeClipWidgetClass, (Widget) new, XmNexposeProc, Redisplay, XmNtraversalOn, new->manager.traversal_on, XmNbackground, new->core.background_pixel, NULL); new->matrix.right_clip = XtVaCreateWidget( "rightclip", xbaeClipWidgetClass, (Widget) new, XmNexposeProc, Redisplay, XmNtraversalOn, new->manager.traversal_on, XmNbackground, new->core.background_pixel, NULL); new->matrix.top_clip = XtVaCreateWidget( "topclip", xbaeClipWidgetClass, (Widget) new, XmNexposeProc, Redisplay, XmNtraversalOn, new->manager.traversal_on, XmNbackground, new->core.background_pixel, NULL); new->matrix.bottom_clip = XtVaCreateWidget( "bottomclip", xbaeClipWidgetClass, (Widget) new, XmNexposeProc, Redisplay, XmNtraversalOn, new->manager.traversal_on, XmNbackground, new->core.background_pixel, NULL); /* * Cache the pixel position of each column */ new->matrix.column_positions = CreateColumnPositions(new); xbaeGetColumnPositions(new); /* * Now we can set the VSB maximum (relies on data from * GetCellTotalWidth above) */ XtVaSetValues(HorizScrollChild(new), XmNmaximum, NON_FIXED_TOTAL_WIDTH(new) ? NON_FIXED_TOTAL_WIDTH(new) : 1, NULL); /* * Current position starts at the top left editable cell. */ new->matrix.current_row = new->matrix.fixed_rows; new->matrix.current_column = new->matrix.fixed_columns; new->matrix.current_clip = CLIP_NONE; /* * We aren't trying to traverse out */ new->matrix.traversing = NOT_TRAVERSING; #ifndef NEED_24BIT_VISUAL /* * Get/create our GCs */ xbaeCreateDrawGC(new); xbaeCreatePixmapGC(new); xbaeCreateLabelGC(new); xbaeCreateLabelClipGC(new); xbaeCreateGridLineGC(new); xbaeCreateTopShadowClipGC(new); xbaeCreateBottomShadowClipGC(new); #endif /* * Now we have created our GCs, check if the widget is sensitive */ if (!new->core.sensitive) { XGCValues values; unsigned long valuemask = GCFillStyle; Display *dpy = XtDisplay(new); if (!new->core.sensitive) { int i; values.fill_style = FillStippled; /* * Change our drawing GC's to the stipple effect to indicate * the widget is insensitive and redraw */ XChangeGC(dpy, new->matrix.draw_gc, valuemask, &values); XChangeGC(dpy, new->matrix.label_gc, valuemask, &values); XChangeGC(dpy, new->matrix.label_clip_gc, valuemask, &values); XChangeGC(dpy, new->matrix.pixmap_gc, valuemask, &values); /* * Propogate the insensitive feel to our children */ for (i = 0; i < XbaeNumChildren; i++) XtSetSensitive(new->composite.children[i], False); } } /* * Create ScrollMgrs to manage scrolling events */ new->matrix.matrix_scroll_mgr = xbaeSmCreateScrollMgr(); new->matrix.clip_scroll_mgr = xbaeSmCreateScrollMgr(); /* * Set the last row and column to an impossible value */ new->matrix.last_row = -1; new->matrix.last_column = -1; new->matrix.last_click_time = (Time)0; /* * Compute our size. If either dimension was explicitly set to 0, * then that dimension is computed. * Use request because superclasses modify width/height. */ if (request->core.width == 0 || request->core.height == 0) xbaeComputeSize(new, request->core.width == 0, request->core.height == 0); /* * Make sure top_row is sensible before we call Resize */ if (VERT_ORIGIN(new) < 0) VERT_ORIGIN(new) = 0; else if (VERT_ORIGIN(new) > new->matrix.rows) VERT_ORIGIN(new) = new->matrix.rows; /* * Tweak top_row to make sure it is valid before calling Resize */ if (VERT_ORIGIN(new)) xbaeAdjustTopRow(new); if (new->matrix.left_column) xbaeAdjustLeftColumn(new); /* * Layout the scrollbars and clip widget based on our size */ xbaeResize(new); } static void Realize(mw, valueMask, attributes) XbaeMatrixWidget mw; XtValueMask *valueMask; XSetWindowAttributes *attributes; { *valueMask |= CWDontPropagate; attributes->do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | PointerMotionMask; /* * Don't call our superclasses realize method, because Manager sets * bit_gravity */ XtCreateWindow((Widget) mw, InputOutput, CopyFromParent, *valueMask, attributes); #ifdef NEED_24BIT_VISUAL /* * Now that we have a window... * Get/create our GCs */ xbaeCreateDrawGC(mw); xbaeCreatePixmapGC(mw); xbaeCreateLabelGC(mw); xbaeCreateLabelClipGC(mw); xbaeCreateTopShadowClipGC(mw); xbaeCreateBottomShadowClipGC(mw); #endif /* * Reparent the textFields window to be a subwindow of Clip widget * (we need to realize them first) */ XtRealizeWidget(TextChild(mw)); XtRealizeWidget(ClipChild(mw)); XtRealizeWidget(LeftClip(mw)); XtRealizeWidget(RightClip(mw)); XtRealizeWidget(TopClip(mw)); XtRealizeWidget(BottomClip(mw)); XReparentWindow(XtDisplay(mw), XtWindow(TextChild(mw)), XtWindow(ClipChild(mw)), TextChild(mw)->core.x, TextChild(mw)->core.y); mw->matrix.current_parent = ClipChild(mw); /* * Set the clip_mask in our clipping GCs. */ xbaeSetClipMask(mw, CLIP_NONE); } static void InsertChild(w) Widget w; { #if 0 if (((CompositeWidget) XtParent(w))->composite.num_children > 7) { #if XmVersion > 1001 /* Hah! Cannot use XmIsDragIconObjectClass because it is defined * using XtIsSubclass() (at least in the 1.2 and 2.0 headers I have * available to me). Nothing like a little QA, huh. * * Anyways, since the drag icon & context are created as widget * children of the matrix, we need to allow just those extra types * to be created as our kids. */ if ((!XmIsDragContext(w)) && (!XtIsSubclass(w, xmDragIconObjectClass))) { #endif String params[1]; Cardinal num_params = 1; params[0] = XtClass(XtParent(w))->core_class.class_name; XtAppWarningMsg( XtWidgetToApplicationContext(w), "insertChild", "badChild", "XbaeMatrix", "XbaeMatrix: Applications cannot add children to %s widgets", params, &num_params); #if XmVersion > 1001 } #endif return; } #endif #if XmVersion > 1001 (*((XmManagerWidgetClass) (xbaeMatrixWidgetClass->core_class.superclass))->composite_class.insert_child) (w); #endif } /* * This is the expose method for the Matrix widget. * It redraws the row and column labels, the cells in fixed rows and columns * and the clip window shadow. */ /* ARGSUSED */ static void Redisplay(w, event, region) Widget w; XEvent *event; Region region; { Rectangle expose; XbaeMatrixWidget mw; if (XtIsSubclass(w, xbaeMatrixWidgetClass)) mw = (XbaeMatrixWidget) w; else /* must be one of the clips */ { int *x = NULL, *y = NULL; mw = (XbaeMatrixWidget) XtParent(w); /* point at the correct x,y pair */ switch (event->type) { case Expose: x = &event->xexpose.x; y = &event->xexpose.y; break; case GraphicsExpose: x = &event->xgraphicsexpose.x; y = &event->xgraphicsexpose.y; break; case NoExpose: break; default: return; } /* NoExpose event can't be translated so make sure x is set */ if (x) { /* * Translate expose event coords into matrix coords if it occured * on a clip. xbaeRedrawLabelsAndFixed needs to check intersections * in matrix coords, even though the xbaeDraw* routines will * correctly retranslate these onto the correct windows for drawing. */ if (w == LeftClip(mw)) { *x += ROW_LABEL_WIDTH(mw) + mw->manager.shadow_thickness; *y += FIXED_ROW_LABEL_OFFSET(mw); } else if (w == RightClip(mw)) { *x += TRAILING_FIXED_COLUMN_LABEL_OFFSET(mw); *y += FIXED_ROW_LABEL_OFFSET(mw); } else if (w == TopClip(mw)) { *x += FIXED_COLUMN_LABEL_OFFSET(mw); *y += (COLUMN_LABEL_HEIGHT(mw) + mw->manager.shadow_thickness); } else if (w == BottomClip(mw)) { *x += FIXED_COLUMN_LABEL_OFFSET(mw); *y += TRAILING_FIXED_ROW_LABEL_OFFSET(mw); } else return; /* eek! Run away quickly */ } } if (mw->matrix.disable_redisplay) return; /* * Send our events to the mw ScrollMgr to be adjusted. */ switch (event->type) { case Expose: /* * The Expose event will be translated into our scrolled * coordinate system. Then it is put in a Rectangle. */ xbaeSmScrollEvent(mw->matrix.matrix_scroll_mgr, event); SETRECT(expose, event->xexpose.x, event->xexpose.y, event->xexpose.x + event->xexpose.width, event->xexpose.y + event->xexpose.height); break; case GraphicsExpose: /* * The GraphicsExpose event will cause a scroll to be removed * from the managers queue, then the event will be translated * into our scrolled coordinate system. Then it is put in a Rectangle. */ xbaeSmScrollEvent(mw->matrix.matrix_scroll_mgr, event); SETRECT(expose, event->xgraphicsexpose.x, event->xgraphicsexpose.y, event->xgraphicsexpose.x + event->xgraphicsexpose.width, event->xgraphicsexpose.y + event->xgraphicsexpose.height); break; case NoExpose: /* * The NoExpose event means we won't be getting any GraphicsExpose * events, so the scroll will be removed from the queue and * we are done. */ xbaeSmScrollEvent(mw->matrix.matrix_scroll_mgr, event); return; default: /* maybe handled above already */ return; } /* * Redraw the row/column labels and fixed rows/columns which are * overlapped by the expose Rectangle. */ if ((! mw->matrix.trailing_fixed_columns) && IN_GRID_ROW_MODE(mw) && NEED_HORIZ_FILL(mw)) { Rectangle nonfixed; /* * We need to ensure that the last column of cells gets * redrawn so that the fill is properly redrawn. */ SETRECT(nonfixed, COLUMN_POSITION(mw, mw->matrix.columns-1), 0, COLUMN_POSITION(mw, mw->matrix.columns-1)+1, ClipChild(mw)->core.height-1); xbaeRedrawCells(mw, &nonfixed); } else if ((! mw->matrix.trailing_fixed_rows) && IN_GRID_COLUMN_MODE(mw) && NEED_VERT_FILL(mw)) { Rectangle nonfixed; /* * We need to ensure that the last row of cells gets * redrawn so that the fill is properly redrawn. */ SETRECT(nonfixed, 0, ROW_HEIGHT(mw) * (mw->matrix.rows - 1), ClipChild(mw)->core.width-1, ROW_HEIGHT(mw) * mw->matrix.rows); xbaeRedrawCells(mw, &nonfixed); } xbaeRedrawLabelsAndFixed(mw, &expose); } /* * This is the exposeProc function for the Clip widget. * It handles expose events for the Clip widget by redrawing those * non-fixed cells which were damaged. * It receives Expose, GraphicsExpose and NoExpose events. */ /* ARGSUSED */ static void ClipRedisplay(w, event, region) Widget w; XEvent *event; Region region; { XbaeMatrixWidget mw = (XbaeMatrixWidget) XtParent(w); Rectangle expose, clip, intersect; if (mw->matrix.disable_redisplay) return; /* * Send our events to the clip ScrollMgr to be adjusted. */ switch (event->type) { case Expose: /* * The Expose event will be translated into our scrolled * coordinate system. Then it is put in a Rectangle. */ xbaeSmScrollEvent(mw->matrix.clip_scroll_mgr, event); SETRECT(expose, event->xexpose.x, event->xexpose.y, event->xexpose.x + event->xexpose.width - 1, event->xexpose.y + event->xexpose.height - 1); break; case GraphicsExpose: /* * The GraphicsExpose event will cause a scroll to be removed * from the managers queue, then the event will be translated * into our scrolled coordinate system. Then it is put in a Rectangle. */ xbaeSmScrollEvent(mw->matrix.clip_scroll_mgr, event); SETRECT(expose, event->xgraphicsexpose.x, event->xgraphicsexpose.y, event->xgraphicsexpose.x + event->xgraphicsexpose.width - 1, event->xgraphicsexpose.y + event->xgraphicsexpose.height - 1); break; case NoExpose: /* * The NoExpose event means we won't be getting any GraphicsExpose * events, so the scroll well be removed from the queue and * we are done. */ xbaeSmScrollEvent(mw->matrix.clip_scroll_mgr, event); return; default: return; } /* * We may get an expose event larger than the size of the Clip widget. * This is because in set_values we may clear the Clip widget * before it gets resized smaller (maybe in set_values_almost). * So here we intersect the expose event with the clip widget * to ensure the expose Rectangle is not larger than the Clip widget. */ SETRECT(clip, 0, 0, w->core.width - 1, w->core.height - 1); INTERSECT(clip, expose, intersect); /* * Redraw those cells which overlap the intersect Rectangle. */ xbaeRedrawCells(mw, &intersect); } /* ARGSUSED */ static Boolean SetValues(current, request, new, args, num_args) XbaeMatrixWidget current, request, new; ArgList args; Cardinal *num_args; { Boolean redisplay = False; /* need to redraw */ Boolean relayout = False; /* need to layout, but same size */ Boolean new_column_widths = False; /* column widths changed */ Boolean new_cells = False; /* cells changed */ Boolean do_top_row = False; /* reset top_row */ Boolean do_left_column = False; /* reset left_column */ int n; Arg wargs[9]; #define NE(field) (current->field != new->field) #define EQ(field) (current->field == new->field) /* * We cannot re-set either of the scrollbars, the textField or * clip window. */ if (NE(matrix.vertical_sb) || NE(matrix.horizontal_sb) || NE(matrix.clip_window) || NE(matrix.text_field)) { XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "setValues", "set matrix children", "XbaeMatrix", "XbaeMatrix: Cannot set matrix widget children", NULL, 0); new->matrix.vertical_sb = current->matrix.vertical_sb; new->matrix.horizontal_sb = current->matrix.horizontal_sb; new->matrix.clip_window = current->matrix.clip_window; new->matrix.text_field = current->matrix.text_field; } /* * If rows changed, then: * row_labels must change or be NULL * row_button_labels must change or be NULL */ if ((NE(matrix.rows) && (new->matrix.row_labels && EQ(matrix.row_labels))) || (new->matrix.row_button_labels && EQ(matrix.row_button_labels))) { XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "setValues", "rows", "XbaeMatrix", "XbaeMatrix: Number of rows changed but dependent resources did not", NULL, 0); new->matrix.rows = current->matrix.rows; new->matrix.row_labels = current->matrix.row_labels; new->matrix.row_button_labels = current->matrix.row_button_labels; } /* * If columns changed, then: * column_widths must change * column_max_lengths must change or be NULL * column_labels must change or be NULL * column_alignments must change or be NULL * column_button_labels must change or be NULL * column_label_alignments must change or be NULL */ if (NE(matrix.columns) && ((new->matrix.column_labels && EQ(matrix.column_labels)) || (new->matrix.column_max_lengths && EQ(matrix.column_max_lengths)) || (new->matrix.column_alignments && EQ(matrix.column_alignments)) || (new->matrix.column_button_labels && EQ(matrix.column_button_labels)) || (new->matrix.column_label_alignments && EQ(matrix.column_label_alignments)) || EQ(matrix.column_widths))) { XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "setValues", "columns", "XbaeMatrix", "XbaeMatrix: Number of columns changed but dependent resources did not", NULL, 0); new->matrix.columns = current->matrix.columns; new->matrix.column_widths = current->matrix.column_widths; new->matrix.column_max_lengths = current->matrix.column_max_lengths; new->matrix.column_labels = current->matrix.column_labels; new->matrix.column_alignments = current->matrix.column_alignments; new->matrix.column_button_labels = current->matrix.column_button_labels; new->matrix.column_label_alignments = current->matrix.column_label_alignments; } /* * Make sure we have at least one row/column. */ if (new->matrix.columns < 0 || new->matrix.rows < 0) { XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "setValues", "size", "XbaeMatrix", "XbaeMatrix: Must have at least one row and column", NULL, 0); if (new->matrix.columns < 0) new->matrix.columns = current->matrix.columns; if (new->matrix.rows < 0) new->matrix.rows = current->matrix.rows; } /* * We must have at least one non-fixed row/column. * This could be caused by (trailing) fixed_rows/columns or * rows/columns changing. */ if ((int)(new->matrix.fixed_rows + new->matrix.trailing_fixed_rows) > 0 && (int)(new->matrix.fixed_rows + new->matrix.trailing_fixed_rows) >= new->matrix.rows) { XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "setValues", "tooManyFixed", "XbaeMatrix", "XbaeMatrix: At least one row must not be fixed", NULL, 0); if (NE(matrix.fixed_rows)) new->matrix.fixed_rows = current->matrix.fixed_rows; if (NE(matrix.trailing_fixed_rows)) new->matrix.trailing_fixed_rows = current->matrix.trailing_fixed_rows; if (NE(matrix.rows)) new->matrix.rows = current->matrix.rows; } if ((int)(new->matrix.fixed_columns + new->matrix.trailing_fixed_columns) > 0 && (int)(new->matrix.fixed_columns + new->matrix.trailing_fixed_columns) >= new->matrix.columns) { XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "setValues", "tooManyFixed", "XbaeMatrix", "XbaeMatrix: At least one column must not be fixed", NULL, 0); if (NE(matrix.fixed_columns)) new->matrix.fixed_columns = current->matrix.fixed_columns; if (NE(matrix.trailing_fixed_columns)) new->matrix.trailing_fixed_columns = current->matrix.trailing_fixed_columns; if (NE(matrix.columns)) new->matrix.columns = current->matrix.columns; } /* * We can't have too many visible columns. * This could be caused by visible_columns or columns or fixed_columns * changing. */ if (new->matrix.columns && ((int)new->matrix.visible_columns > (new->matrix.columns - (int)new->matrix.fixed_columns - (int)new->matrix.trailing_fixed_columns))) { XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "setValues", "tooManyVisibleColumns", "XbaeMatrix", "XbaeMatrix: visibleColumns must not be greater than\n (columns - fixedColumns - trailingFixedColumns)", (String *) NULL, (Cardinal *) NULL); if (NE(matrix.visible_columns)) new->matrix.visible_columns = current->matrix.visible_columns; if (NE(matrix.columns)) new->matrix.columns = current->matrix.columns; if (NE(matrix.fixed_columns)) new->matrix.fixed_columns = current->matrix.fixed_columns; if (NE(matrix.trailing_fixed_columns)) new->matrix.trailing_fixed_columns = current->matrix.trailing_fixed_columns; } /* * Make sure we have column_widths */ if (new->matrix.columns && (new->matrix.column_widths == NULL)) { XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "setValues", "columnWidths", "XbaeMatrix", "XbaeMatrix: Must specify columnWidths", NULL, 0); new->matrix.column_widths = current->matrix.column_widths; } /* * If rows or columns or fixed rows/columns changed, * then we need to relayout. */ if (NE(matrix.rows) || NE(matrix.fixed_rows) || NE(matrix.trailing_fixed_rows)) { /* * Reset VSB maximum. sliderSize will be reset later in Resize. */ XtVaSetValues(VertScrollChild(new), XmNmaximum, (new->matrix.rows - (int) new->matrix.fixed_rows - (int) new->matrix.trailing_fixed_rows), XmNsliderSize, 1, NULL); do_top_row = True; relayout = True; } if (NE(matrix.columns) || NE(matrix.fixed_columns) || NE(matrix.trailing_fixed_columns)) relayout = True; /* * Copy any pointed to resources if they changed */ #if CELL_WIDGETS if (NE(matrix.cell_widgets)) { xbaeFreeCellWidgets(current); xbaeCopyCellWidgets(current); redisplay = True; } #endif if (NE(matrix.cells)) { xbaeFreeCells(current); xbaeCopyCells(new); redisplay = True; new_cells = True; } else if (NE(matrix.rows) || NE(matrix.columns)) ResizeCells(current, new); if (NE(matrix.cell_user_data)) { xbaeFreeCellUserData(current); if (new->matrix.cell_user_data) xbaeCopyCellUserData(new); } if (NE(matrix.row_user_data)) { xbaeFreeRowUserData(current); if (new->matrix.row_user_data) xbaeCopyRowUserData(new); } if (NE(matrix.column_user_data)) { xbaeFreeColumnUserData(current); if (new->matrix.column_user_data) xbaeCopyColumnUserData(new); } if (NE(matrix.cell_shadow_types)) { xbaeFreeCellShadowTypes(current); if (new->matrix.cell_shadow_types) xbaeCopyCellShadowTypes(new); } if (NE(matrix.row_shadow_types)) { xbaeFreeRowShadowTypes(current); if (new->matrix.row_shadow_types) xbaeCopyRowShadowTypes(new); } if (NE(matrix.column_shadow_types)) { xbaeFreeColumnShadowTypes(current); if (new->matrix.column_shadow_types) xbaeCopyColumnShadowTypes(new); } if (NE(matrix.row_labels)) { /* * If we added or deleted row_labels, we need to layout. */ if (!current->matrix.row_labels || !new->matrix.row_labels) relayout = True; else redisplay = True; xbaeFreeRowLabels(current); if (new->matrix.row_labels) xbaeCopyRowLabels(new); } if (NE(matrix.column_labels)) { xbaeFreeColumnLabels(current); if (new->matrix.column_labels) xbaeCopyColumnLabels(new); else { new->matrix.column_label_lines = NULL; new->matrix.column_label_maxlines = 0; } /* * If the number of lines in column labels changed, we need to relayout */ if (current->matrix.column_label_maxlines != new->matrix.column_label_maxlines) relayout = True; else redisplay = True; } if (NE(matrix.column_max_lengths)) { xbaeFreeColumnMaxLengths(current); if (new->matrix.column_max_lengths) xbaeCopyColumnMaxLengths(new); redisplay = True; } if (NE(matrix.column_alignments)) { xbaeFreeColumnAlignments(current); if (new->matrix.column_alignments) xbaeCopyColumnAlignments(new); redisplay = True; } if (NE(matrix.column_button_labels)) { xbaeFreeColumnButtonLabels(current); if (new->matrix.column_button_labels) xbaeCopyColumnButtonLabels(new); redisplay = True; } if (NE(matrix.row_button_labels)) { xbaeFreeRowButtonLabels(current); if (new->matrix.row_button_labels) xbaeCopyRowButtonLabels(new); redisplay = True; } if (NE(matrix.column_label_alignments)) { xbaeFreeColumnLabelAlignments(current); if (new->matrix.column_label_alignments) xbaeCopyColumnLabelAlignments(new); redisplay = True; } if (NE(matrix.row_label_alignment)) redisplay = True; if (NE(matrix.row_label_color) || NE(matrix.column_label_color) || NE(matrix.button_label_background)) redisplay = True; if (NE(matrix.colors)) { xbaeFreeColors(current); if (new->matrix.colors) xbaeCopyColors(new); redisplay = True; } if (NE(matrix.cell_background)) { xbaeFreeBackgrounds(current); if (new->matrix.cell_background) xbaeCopyBackgrounds(new); redisplay = True; } if (NE(matrix.grid_line_color)) { XtReleaseGC((Widget)new, new->matrix.grid_line_gc); XFreeGC(XtDisplay(new), new->matrix.cell_grid_line_gc); xbaeCreateGridLineGC(new); if ((new->matrix.grid_type == XmGRID_CELL_LINE) || (new->matrix.grid_type == XmGRID_ROW_LINE) || (new->matrix.grid_type == XmGRID_COLUMN_LINE)) redisplay = True; } if (NE(matrix.alt_row_count) && (new->matrix.even_row_background != current->core.background_pixel || new->matrix.odd_row_background != current->core.background_pixel)) redisplay = True; if (NE(matrix.even_row_background) || NE(matrix.odd_row_background) || NE(matrix.grid_type) || NE(matrix.selected_foreground) || NE(matrix.selected_background)) redisplay = True; if (NE(matrix.grid_type) && (new->matrix.grid_type >= XmGRID_LINE)) /* Deprecated types. To be removed in next version. */ XtAppWarningMsg( XtWidgetToApplicationContext((Widget) new), "cvtStringToGridType", "deprecatedType", "XbaeMatrix", "Value for GridType is deprecated and will be removed in next release", NULL, NULL); if (new->matrix.colors && EQ(matrix.colors) && (NE(matrix.rows) || NE(matrix.columns))) { ResizeColors(current, new, False); redisplay = True; } if (new->matrix.cell_background && EQ(matrix.cell_background) && (NE(matrix.rows) || NE(matrix.columns))) { ResizeColors(current, new, True); redisplay = True; } if (NE(matrix.cell_shadow_type) || NE(matrix.shadow_type) || NE(matrix.reverse_select)) redisplay = True; if (NE(matrix.column_widths)) { xbaeFreeColumnWidths(current); xbaeCopyColumnWidths(new); relayout = True; new_column_widths = True; } if (NE(matrix.selected_cells)) { xbaeFreeSelectedCells(current); xbaeCopySelectedCells(new); redisplay = True; } else if (NE(matrix.rows) || NE(matrix.columns)) ResizeSelectedCells(current, new); #if XmVersion >= 1002 if (NE(matrix.highlighted_cells)) { xbaeFreeHighlightedCells(current); xbaeCopyHighlightedCells(new); redisplay = True; } else if (NE(matrix.rows) || NE(matrix.columns)) ResizeHighlightedCells(current, new); #endif /* * If traversal changes, pass through to Clip and textField children. */ if (NE(manager.traversal_on)) { XtVaSetValues(ClipChild(new), XmNtraversalOn, new->manager.traversal_on, NULL); } if (NE(matrix.even_row_background) || NE(matrix.odd_row_background)) redisplay = True; /* * Pass through primitive/manager resources to our children */ n = 0; if (NE(core.background_pixel)) { /* * Set all clip widgets to the new background (thanks Daiji) */ XtVaSetValues(ClipChild(new), XmNbackground, new->core.background_pixel, NULL); XtVaSetValues(LeftClip(new), XmNbackground, new->core.background_pixel, NULL); XtVaSetValues(RightClip(new), XmNbackground, new->core.background_pixel, NULL); XtVaSetValues(TopClip(new), XmNbackground, new->core.background_pixel, NULL); XtVaSetValues(BottomClip(new), XmNbackground, new->core.background_pixel, NULL); XtSetArg(wargs[n], XmNbackground, new->core.background_pixel); n++; } if (NE(manager.foreground)) { XtSetArg(wargs[n], XmNforeground, new->manager.foreground); n++; } if (NE(manager.bottom_shadow_color)) { XtSetArg(wargs[n], XmNbottomShadowColor, new->manager.bottom_shadow_color); n++; } if (NE(manager.bottom_shadow_pixmap)) { XtSetArg(wargs[n], XmNbottomShadowPixmap, new->manager.bottom_shadow_pixmap); n++; } if (NE(manager.highlight_color)) { XtSetArg(wargs[n], XmNhighlightColor, new->manager.highlight_color); n++; } if (NE(manager.highlight_pixmap)) { XtSetArg(wargs[n], XmNhighlightPixmap, new->manager.highlight_pixmap); n++; } if (NE(manager.top_shadow_color)) { XtSetArg(wargs[n], XmNtopShadowColor, new->manager.top_shadow_color); n++; } if (NE(manager.top_shadow_pixmap)) { XtSetArg(wargs[n], XmNtopShadowPixmap, new->manager.top_shadow_pixmap); n++; } if (n) { XtSetValues(VertScrollChild(new), wargs, n); XtSetValues(HorizScrollChild(new), wargs, n); XtSetValues(TextChild(new), wargs, n); } /* * Would really like to do this in the above, * but we need to override background_pixel. */ if (EQ(matrix.text_background) && (current->matrix.text_background == current->core.background_pixel)) new->matrix.text_background = new->core.background_pixel; if (NE(matrix.text_background) || NE(core.background_pixel)) { XtVaSetValues(TextChild(new), XmNbackground, new->matrix.text_background, NULL); if (XtIsManaged(TextChild(new))) redisplay = True; } /* * Get a new XFontStruct and copy the fontList if it changed * and pass it to the textField. * Reset the HSB increment. * redisplay and relayout will be set below. */ if (NE(matrix.font_list)) { XmFontListFree(current->matrix.font_list); xbaeNewFont(new); XtVaSetValues(TextChild(new), XmNfontList, new->matrix.font_list, NULL); XtVaSetValues(HorizScrollChild(new), XmNincrement, FONT_WIDTH(new), NULL); } if (NE(matrix.label_font_list)) { XmFontListFree(current->matrix.label_font_list); xbaeNewLabelFont(new); XtVaSetValues(HorizScrollChild(new), XmNincrement, FONT_WIDTH(new), NULL); } /* * Pass the cell resources on to the textField. * Both redisplay and relayout will be set below. * * If anything changed to affect cell total width or column positions, * recalc them */ if (new_cells || NE(matrix.fid) || NE(matrix.label_fid) || NE(matrix.cell_margin_width) || NE(matrix.cell_margin_height) || NE(matrix.cell_shadow_thickness) || NE(matrix.fixed_columns) || NE(matrix.trailing_fixed_columns) || NE(matrix.cell_highlight_thickness) || new_column_widths || NE(matrix.text_shadow_thickness)) { /* * Recalculate the margin height, based on the larger of the * label and general fonts. */ int marginHeight = new->matrix.cell_margin_height; /* by default */ if (LABEL_HEIGHT(new) > FONT_HEIGHT(new)) marginHeight = (int)(LABEL_HEIGHT(new) + (new->matrix.cell_margin_height * 2) - FONT_HEIGHT(new)) / 2; /* * Cancel the edit -> If I think of a better way of doing this * I'll do it, AL. */ (*((XbaeMatrixWidgetClass) XtClass(new))->matrix_class.cancel_edit) (new, True); XtVaSetValues( TextChild(new), XmNmarginWidth, new->matrix.cell_margin_width, XmNhighlightThickness, new->matrix.cell_highlight_thickness, XmNshadowThickness, new->matrix.text_shadow_thickness, XmNmarginHeight, marginHeight, NULL); xbaeGetCellTotalWidth(new); /* * Reset the HSB maximum. sliderSize will be reset later in Resize. */ XtVaSetValues(HorizScrollChild(new), XmNmaximum, NON_FIXED_TOTAL_WIDTH(new) ? NON_FIXED_TOTAL_WIDTH(new) : 1, XmNsliderSize, 1, NULL); /* * If the number of columns changed, we need to allocate a new array. */ if (NE(matrix.columns)) { xbaeFreeColumnPositions(current); new->matrix.column_positions = CreateColumnPositions(new); } /* * If anything but (trailing_)fixed_columns or the highlight color * changed, we need to recalc column positions. */ if (new_cells || NE(matrix.fid) || NE(matrix.label_fid) || NE(matrix.cell_margin_width) || NE(matrix.cell_margin_height) || NE(matrix.cell_shadow_thickness) || NE(matrix.cell_highlight_thickness) || new_column_widths || NE(matrix.text_shadow_thickness)) xbaeGetColumnPositions(new); /* * Recalculate the baselines */ new->matrix.text_baseline = XmTextGetBaseline(TextChild(new)) + new->matrix.cell_shadow_thickness /*+ new->matrix.text_shadow_thickness*/; /* * Adjust the label_baseline according to the larger of the two fonts */ if (LABEL_HEIGHT(new) == FONT_HEIGHT(new)) new->matrix.label_baseline = new->matrix.text_baseline; else { if (LABEL_HEIGHT(new) < FONT_HEIGHT(new)) marginHeight = (FONT_HEIGHT(new) + new->matrix.text_shadow_thickness * 2 + new->matrix.cell_margin_height * 2 - (int)LABEL_HEIGHT(new)) / 2; else marginHeight = new->matrix.cell_margin_height + new->matrix.text_shadow_thickness; new->matrix.label_baseline = marginHeight + new->matrix.cell_shadow_thickness - new->matrix.label_font_y; } /* JDS: The comment above this section says both redisplay and * relayout get set, but only relayout was being set. I noticed * this because the resizeColumns action was setting the * columnWidths, but the clip widget wasn't properly redrawing * its cells when they were resized. This was in conjunction with * calling clipRedisplay only when the matrix redisplayed instead * of also when it relayedout :) (see the comment below). * * However, I'm not sure what else this might impact. But, I'm in * favor of the change I made to only redisplay when the matrix * redisplays since that's more efficient, I think, and it eliminated * some ugly redraws that I at least encountered. So there :). */ redisplay = relayout = True; } /* * Install text_translations on textField */ if (NE(matrix.text_translations)) XtVaSetValues(TextChild(new), XmNtranslations, new->matrix.text_translations, NULL); /* * If row_label_width was set to 0, calculate it. * Otherwise if it was changed, set flags. */ if (new->matrix.row_label_width == 0 && new->matrix.row_labels) { new->matrix.row_label_width = xbaeMaxRowLabel(new); relayout = True; } else if (NE(matrix.row_label_width)) relayout = True; /* * Check whether the widget is sensitive has changed and set our GC's * appropriately */ if (XtIsSensitive((Widget)current) != XtIsSensitive((Widget)new)) { XGCValues values; int i; unsigned long valuemask = GCFillStyle; Display *dpy = XtDisplay(new); if (!XtIsSensitive((Widget)new)) { values.fill_style = FillStippled; /* * Change our drawing GC's to the stipple effect to indicate * the widget is insensitive and redraw */ XChangeGC(dpy, new->matrix.draw_gc, valuemask, &values); XChangeGC(dpy, new->matrix.label_gc, valuemask, &values); XChangeGC(dpy, new->matrix.label_clip_gc, valuemask, &values); XChangeGC(dpy, new->matrix.pixmap_gc, valuemask, &values); /* * Propogate the insensitive feel to our children */ for (i = 0; i < XbaeNumChildren; i++) XtSetSensitive(new->composite.children[i], False); } else { values.fill_style = FillSolid; XChangeGC(dpy, new->matrix.draw_gc, valuemask, &values); XChangeGC(dpy, new->matrix.label_gc, valuemask, &values); XChangeGC(dpy, new->matrix.label_clip_gc, valuemask, &values); XChangeGC(dpy, new->matrix.pixmap_gc, valuemask, &values); for (i = 0; i < XbaeNumChildren; i++) XtSetSensitive(new->composite.children[i], True); } redisplay = True; } /* * If our fill policy changed or our bottom attachment, * we must redisplay and relayout. */ if (NE(matrix.fill) || NE(matrix.trailing_attached_bottom)) { redisplay = True; relayout = True; } /* * If either of the scrollbar display policies changed, * we need to redisplay and relayout. */ if (NE(matrix.vsb_display_policy) || NE(matrix.hsb_display_policy)) relayout = True; /* * If the place of the scrollbars changes, we must redisplay */ if (NE(matrix.scrollbar_placement)) relayout = True; /* * Change created GCs if needed */ if (NE(manager.foreground)) { /* * We don't need to put the new foreground in draw_gc or * draw_clip_gc because they get a new foreground when they are used. */ XSetForeground(XtDisplay(new), new->matrix.cell_top_shadow_clip_gc, new->manager.foreground); XSetBackground(XtDisplay(new), new->matrix.cell_bottom_shadow_clip_gc, new->manager.foreground); redisplay = True; } if (NE(manager.top_shadow_color)) { XSetForeground(XtDisplay(new), new->matrix.cell_top_shadow_clip_gc, new->manager.top_shadow_color); XSetForeground(XtDisplay(new), new->matrix.resize_top_shadow_gc, new->manager.top_shadow_color); redisplay = True; } if (NE(manager.top_shadow_pixmap)) { XSetTile(XtDisplay(new), new->matrix.cell_top_shadow_clip_gc, new->manager.top_shadow_pixmap); XSetTile(XtDisplay(new), new->matrix.resize_top_shadow_gc, new->manager.top_shadow_pixmap); redisplay = True; } if (NE(manager.bottom_shadow_color)) { XSetForeground(XtDisplay(new), new->matrix.cell_bottom_shadow_clip_gc, new->manager.bottom_shadow_color); XSetForeground(XtDisplay(new), new->matrix.resize_bottom_shadow_gc, new->manager.bottom_shadow_color); redisplay = True; } if (NE(manager.bottom_shadow_pixmap)) { XSetTile(XtDisplay(new), new->matrix.cell_bottom_shadow_clip_gc, new->manager.bottom_shadow_pixmap); XSetTile(XtDisplay(new), new->matrix.resize_bottom_shadow_gc, new->manager.bottom_shadow_pixmap); redisplay = True; } if (NE(matrix.fid)) { XSetFont(XtDisplay(new), new->matrix.draw_gc, new->matrix.fid); redisplay = True; } if (NE(matrix.label_fid)) { XSetFont(XtDisplay(new), new->matrix.label_gc, new->matrix.label_fid); XSetFont(XtDisplay(new), new->matrix.label_clip_gc, new->matrix.label_fid); redisplay = True; } /* * See if any other resources changed which will require a relayout */ if (NE(matrix.space) || NE(matrix.cell_shadow_thickness) || NE(manager.shadow_thickness)) relayout = True; /* * If bold_labels or button labels changed, and we have labels, * we must redisplay */ if ((NE(matrix.bold_labels) || NE(matrix.button_labels)) && (new->matrix.row_labels || new->matrix.column_labels)) redisplay = True; /* * If showArrows is changed, redisplay to get rid of existing arrows */ if (NE(matrix.show_arrows)) redisplay = True; /* * Compute a new size if: * visible_rows or visible_columns changed. * user set our width or height to zero. */ if (NE(matrix.visible_rows) || NE(matrix.visible_columns) || request->core.height == 0 || request->core.width == 0) xbaeComputeSize(new, request->core.width == 0, request->core.height == 0); /* * If our size didn't change, but we need to layout, call Resize. * If our size did change, then Xt will call our Resize method for us. * If our size did change, but the new size is later refused, * then SetValuesAlmost will call Resize to layout. */ if (EQ(core.width) && EQ(core.height) && relayout) xbaeResize(new); /* * The user forced a new top_row or something changed to force * us to recheck the current top_row. */ if (NE(matrix.top_row) || do_top_row) { XmScrollBarCallbackStruct call_data; xbaeAdjustTopRow(new); call_data.value = VERT_ORIGIN(new); /* * Trick xbaeScrollVertCB() into believing it needs to scroll */ VERT_ORIGIN(new) = VERT_ORIGIN(current); xbaeScrollVertCB((Widget)VertScrollChild(new), NULL, &call_data); VERT_ORIGIN(new) = call_data.value; /* and reset VERT_ORIGIN */ XtVaSetValues(VertScrollChild(new), XmNvalue, VERT_ORIGIN(new), NULL); } if (NE(matrix.left_column) || do_left_column) { XmScrollBarCallbackStruct call_data; xbaeAdjustLeftColumn(new); call_data.value = HORIZ_ORIGIN(new); HORIZ_ORIGIN(new) = HORIZ_ORIGIN(current); xbaeScrollHorizCB((Widget)HorizScrollChild(new), NULL, &call_data); HORIZ_ORIGIN(new) = call_data.value; XtVaSetValues(HorizScrollChild(new), XmNvalue, HORIZ_ORIGIN(new), NULL); } /* * Force the Clip widget to redisplay. Note: this may generate an * expose event for the current size of the Clip widget, and the Clip * widget may be sized smaller in set_values_almost. The ClipRedisplay * function can handle this case. * * JDS: Don't need to force a redisplay on a relayout, since the Clip * widget's resize method (now non-NULL) will be called and Xt will * automatically do an expose after that occurs. Seems to work, anyways :). */ if (redisplay) XbaeMatrixRefresh((Widget)new); /* * We want to return True when we need to redisplay or relayout. */ return redisplay || relayout; #undef NE #undef EQ } /* ARGSUSED */ static void SetValuesAlmost(old, new, request, reply) XbaeMatrixWidget old; XbaeMatrixWidget new; XtWidgetGeometry *request; XtWidgetGeometry *reply; { /* * If XtGeometryAlmost, accept compromize - Resize will take care of it */ if (reply->request_mode) { *request = *reply; #if XtSpecificationRelease > 4 /* * In R5, XtSetValues changed so that when a widgets parent * returns XtGeometryAlmost, Xt will only call the widgets resize * method if the widgets size actually changed. It turns out that * some manager widgets (old Wcl XmpTable and 1.1.x XmForm) return * XtGeometryAlmost with a compromise size which is the widgets * original size (not much of a compromise)! This means as of R5, * Matrix's resize method won't get called in that case. * * So, for R5 we explicitly call our resize method here for the * case of XtGeometryAlmost where our size did not change. */ if ((reply->request_mode & CWWidth || reply->request_mode & CWHeight) && (old->core.width == new->core.width && old->core.height == new->core.height)) xbaeResize(new); #endif } /* * If XtGeometryNo, call Resize to relayout if it was a size change * that was denied. * Accept the original geometry. * (we need to call Resize even though the size * didn't change to force a relayout - set_values relies on this) */ else { if ((request->request_mode & CWWidth || request->request_mode & CWHeight)) xbaeResize(new); request->request_mode = 0; } } static void Destroy(mw) XbaeMatrixWidget mw; { #if XmVersion >= 1002 if (TraverseID) XtRemoveTimeOut(TraverseID); #endif XtReleaseGC((Widget) mw, mw->matrix.grid_line_gc); XFreeGC(XtDisplay(mw), mw->matrix.cell_grid_line_gc); XFreeGC(XtDisplay(mw), mw->matrix.label_gc); XFreeGC(XtDisplay(mw), mw->matrix.label_clip_gc); XFreeGC(XtDisplay(mw), mw->matrix.draw_gc); XFreeGC(XtDisplay(mw), mw->matrix.pixmap_gc); XFreeGC(XtDisplay(mw), mw->matrix.cell_top_shadow_clip_gc); XFreeGC(XtDisplay(mw), mw->matrix.cell_bottom_shadow_clip_gc); XtReleaseGC((Widget) mw, mw->matrix.resize_top_shadow_gc); XtReleaseGC((Widget) mw, mw->matrix.resize_bottom_shadow_gc); xbaeFreeCells(mw); #if CELL_WIDGETS xbaeFreeCellWidgets(mw); #endif xbaeFreeRowLabels(mw); xbaeFreeColumnLabels(mw); xbaeFreeColumnWidths(mw); xbaeFreeColumnMaxLengths(mw); xbaeFreeColumnPositions(mw); xbaeFreeColumnAlignments(mw); xbaeFreeColumnButtonLabels(mw); xbaeFreeRowButtonLabels(mw); xbaeFreeColumnLabelAlignments(mw); xbaeFreeCellUserData(mw); xbaeFreeRowUserData(mw); xbaeFreeColumnUserData(mw); xbaeFreeCellShadowTypes(mw); xbaeFreeRowShadowTypes(mw); xbaeFreeColumnShadowTypes(mw); xbaeFreeColors(mw); xbaeFreeBackgrounds(mw); xbaeFreeSelectedCells(mw); #if XmVersion >= 1002 xbaeFreeHighlightedCells(mw); #endif XmFontListFree(mw->matrix.font_list); XmFontListFree(mw->matrix.label_font_list); xbaeSmDestroyScrollMgr(mw->matrix.matrix_scroll_mgr); xbaeSmDestroyScrollMgr(mw->matrix.clip_scroll_mgr); } /* * Since we totally control our childrens geometry, allow anything. */ /* ARGSUSED */ static XtGeometryResult GeometryManager(w, desired, allowed) Widget w; XtWidgetGeometry *desired, *allowed; { #define Wants(flag) (desired->request_mode & flag) if (Wants(XtCWQueryOnly)) return (XtGeometryYes); if (Wants(CWWidth)) w->core.width = desired->width; if (Wants(CWHeight)) w->core.height = desired->height; if (Wants(CWX)) w->core.x = desired->x; if (Wants(CWY)) w->core.y = desired->y; if (Wants(CWBorderWidth)) w->core.border_width = desired->border_width; return (XtGeometryYes); #undef Wants } /* * We would prefer to be the size calculated in ComputeSize and saved in * desired_width/height */ static XtGeometryResult QueryGeometry(mw, proposed, desired) XbaeMatrixWidget mw; XtWidgetGeometry *proposed, *desired; { #define Set(bit) (proposed->request_mode & bit) desired->width = mw->matrix.desired_width; desired->height = mw->matrix.desired_height; desired->request_mode = CWWidth | CWHeight; if (Set(CWWidth) && proposed->width == desired->width && Set(CWHeight) && proposed->height == desired->height) return (XtGeometryYes); if (desired->width == mw->core.width && desired->height == mw->core.height) return (XtGeometryNo); return (XtGeometryAlmost); #undef Set } /* * This function is called from either the Clip focus CB or a timeout proc. * It is called as a result of the Clip getting the focus. We want to give * the focus to the textField if a cell is being edited. If no cells are * being edited, force an edit on the top left most visible cell. */ static void TraverseIn(mw) XbaeMatrixWidget mw; { /* * If the traversing flag is set, then Clip got the focus because * textField was trying to traverse out of mw. We'll help it along. * Sickening. */ if (mw->matrix.traversing != NOT_TRAVERSING) { XmProcessTraversal(ClipChild(mw), mw->matrix.traversing); return; } /* * If the textField is managed and not visible, scroll it onto the screen * and traverse to it. */ if (XtIsManaged(TextChild(mw))) { if (mw->matrix.scroll_select) xbaeMakeCellVisible(mw, mw->matrix.current_row, mw->matrix.current_column); XmProcessTraversal(TextChild(mw), XmTRAVERSE_CURRENT); } /* * Otherwise, no cell is being edited. Force an edit on the top-left * most visible cell. */ else { int column = xbaeXtoCol(mw, FIXED_COLUMN_WIDTH(mw) + HORIZ_ORIGIN(mw)); int row = VERT_ORIGIN(mw) + mw->matrix.fixed_rows; /* * Call the traverseCellCallback to allow the application to * perform custom traversal. */ if (mw->matrix.traverse_cell_callback) { XbaeMatrixTraverseCellCallbackStruct call_data; call_data.reason = XbaeTraverseCellReason; call_data.event = (XEvent *)NULL; call_data.row = 0; call_data.column = 0; call_data.next_row = row; call_data.next_column = column; call_data.fixed_rows = mw->matrix.fixed_rows; call_data.fixed_columns = mw->matrix.fixed_columns; call_data.trailing_fixed_rows = mw->matrix.trailing_fixed_rows; call_data.trailing_fixed_columns = mw->matrix.trailing_fixed_columns; call_data.num_rows = mw->matrix.rows; call_data.num_columns = mw->matrix.columns; call_data.param = NULL; call_data.qparam = NULLQUARK; XtCallCallbackList((Widget) mw, mw->matrix.traverse_cell_callback, (XtPointer) & call_data); row = call_data.next_row; column = call_data.next_column; } (*((XbaeMatrixWidgetClass) XtClass(mw))->matrix_class.edit_cell) (mw, NULL, row, column, NULL, 0); XmProcessTraversal(TextChild(mw), XmTRAVERSE_CURRENT); } } #if XmVersion >= 1002 /* * Under Motif 1.2, TraverseInCB can't call TraverseIn directly, so it * adds a zero length timeout and we call it from here. */ /* ARGSUSED */ static void TraverseInTimeOut(mw, timer) XtPointer mw; XtIntervalId *timer; { TraverseIn((XbaeMatrixWidget)mw); } #endif /* XmVersion >= 1002 */ /* * This is the Clip widgets focusCallback. We want to give the focus to * the textField if a cell is being edited. If no cells are being edited, * force an edit on the top left most visible cell. */ /* ARGSUSED */ static void TraverseInCB(w, mw, call_data) Widget w; XbaeMatrixWidget mw; XtPointer call_data; { #if XmVersion < 1002 TraverseIn(mw); #else /* * Under Motif 1.2, we can't call TraverseIn directly because it * calls XmProcessTraversal and recursive calls to XmProcessTraversal * are disallowed in 1.2 (we may be in this CB as a result of someone * calling XmProcessTraversal). So we add a zero length timeout * and call TraverseIn from there. */ TraverseID = XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) w), 0L, TraverseInTimeOut, (XtPointer) mw); #endif } /* * Add rows/columns of cells when set_values changes our rows/columns */ static void ResizeCells(current, new) XbaeMatrixWidget current; XbaeMatrixWidget new; { int i, j; int safe_rows = 0; /* * If there is a draw cell callback, we don't need to allocate any * memory for the cells so get outta here. If there is a draw cell * callback, no memory should have been allocated when this point is * reached. */ if (!new->matrix.cells) return; if (new->matrix.rows == current->matrix.rows) safe_rows = new->matrix.rows; /* * Adding rows */ if (new->matrix.rows > current->matrix.rows) { /* * Realloc a larger array of row pointers */ new->matrix.cells = (String **) XtRealloc((char *) new->matrix.cells, new->matrix.rows * sizeof(String *)); /* * Malloc a new row array for each row. Initialize it with * NULL Strings. Use the new column size. */ for (i = current->matrix.rows; i < new->matrix.rows; i++) { new->matrix.cells[i] = (String *) XtMalloc(new->matrix.columns * sizeof(String)); for (j = 0; j < new->matrix.columns; j++) new->matrix.cells[i][j] = XtNewString(""); } safe_rows = current->matrix.rows; } /* * Deleting rows */ if (new->matrix.rows < current->matrix.rows) { /* * Free the cells in the rows being deleted and the rows themselves */ for (i = new->matrix.rows; i < current->matrix.rows; i++) { for (j = 0; j < current->matrix.columns; j++) XtFree((XtPointer) new->matrix.cells[i][j]); XtFree((XtPointer) new->matrix.cells[i]); } safe_rows = new->matrix.rows; } /* * Adding columns */ if (new->matrix.columns > current->matrix.columns) { /* * Realloc each row array. Do not touch any rows added/deleted above * (use safe_rows) */ for (i = 0; i < safe_rows; i++) { new->matrix.cells[i] = (String *) XtRealloc((char *) new->matrix.cells[i], new->matrix.columns * sizeof(String)); for (j = current->matrix.columns; j < new->matrix.columns; j++) new->matrix.cells[i][j] = XtNewString(""); } } /* * Deleting columns */ if (new->matrix.columns < current->matrix.columns) { /* * Free all the cells in the deleted columns. Do not touch any * rows added/deleted above (use safe_rows). * We don't bother to realloc each row, just leave some wasted space. * XXX is this a problem? */ for (i = 0; i < safe_rows; i++) for (j = new->matrix.columns; j < current->matrix.columns; j++) XtFree((XtPointer) new->matrix.cells[i][j]); } } /* * Add rows/columns of selected flags when set_values changes our rows/columns */ static void ResizeSelectedCells(current, new) XbaeMatrixWidget current; XbaeMatrixWidget new; { int i; int safe_rows = 0; /* * selectedCells is allocated when the first cell is selected. If it * is still NULL, no cells have been selected up to this point. */ if (!new->matrix.selected_cells) return; if (new->matrix.rows == current->matrix.rows) safe_rows = new->matrix.rows; /* * Adding rows */ if (new->matrix.rows > current->matrix.rows) { /* * Realloc a larger array of row pointers */ new->matrix.selected_cells = (Boolean **) XtRealloc((char *) new->matrix.selected_cells, new->matrix.rows * sizeof(Boolean *)); /* * Calloc a new row array for each row. Use the new column size. */ for (i = current->matrix.rows; i < new->matrix.rows; i++) new->matrix.selected_cells[i] = (Boolean *) XtCalloc(new->matrix.columns, sizeof(Boolean)); safe_rows = current->matrix.rows; } /* * Deleting rows */ if (new->matrix.rows < current->matrix.rows) { for (i = new->matrix.rows; i < current->matrix.rows; i++) XtFree((XtPointer) new->matrix.selected_cells[i]); safe_rows = new->matrix.rows; } /* * Adding columns */ if (new->matrix.columns > current->matrix.columns) { /* * Realloc each row array. Do not touch any rows added/deleted above * (use safe_rows) */ for (i = 0; i < safe_rows; i++) { int j; new->matrix.selected_cells[i] = (Boolean *) XtRealloc((char *) new->matrix.selected_cells[i], new->matrix.columns * sizeof(Boolean)); for (j = current->matrix.columns; j < new->matrix.columns; j++) new->matrix.selected_cells[i][j] = False; } } /* * Deleting columns * if (new->matrix.columns < current->matrix.columns) * We don't bother to realloc, just leave some wasted space. * XXX is this a problem? */ } #if XmVersion >= 1002 /* * Add rows/columns of highlighted flags when set_values changes our rows/columns */ static void ResizeHighlightedCells(current, new) XbaeMatrixWidget current; XbaeMatrixWidget new; { int i; int safe_rows = 0; if (!new->matrix.highlighted_cells) return; if (new->matrix.rows == current->matrix.rows) safe_rows = new->matrix.rows; /* * Adding rows */ if (new->matrix.rows > current->matrix.rows) { /* * Realloc a larger array of row pointers */ new->matrix.highlighted_cells = (unsigned char **) XtRealloc( (char *) new->matrix.highlighted_cells, new->matrix.rows * sizeof(unsigned char *)); /* * Calloc a new row array for each row. Use the new column size. */ for (i = current->matrix.rows; i < new->matrix.rows; i++) new->matrix.highlighted_cells[i] = (unsigned char *) XtCalloc(new->matrix.columns, sizeof(unsigned char)); safe_rows = current->matrix.rows; } /* * Deleting rows */ if (new->matrix.rows < current->matrix.rows) { for (i = new->matrix.rows; i < current->matrix.rows; i++) XtFree((XtPointer) new->matrix.highlighted_cells[i]); safe_rows = new->matrix.rows; } /* * Adding columns */ if (new->matrix.columns > current->matrix.columns) { /* * Realloc each row array. Do not touch any rows added/deleted above * (use safe_rows) */ for (i = 0; i < safe_rows; i++) { int j; new->matrix.highlighted_cells[i] = (unsigned char *) XtRealloc( (char *) new->matrix.highlighted_cells[i], new->matrix.columns * sizeof(unsigned char)); for (j = current->matrix.columns; j < new->matrix.columns; j++) new->matrix.highlighted_cells[i][j] = HighlightNone; } } /* * Deleting columns * if (new->matrix.columns < current->matrix.columns) * We don't bother to realloc, just leave some wasted space. * XXX is this a problem? */ } #endif /* * Add rows/columns of colors when set_values changes our rows/columns */ static void #if NeedFunctionPrototypes ResizeColors(XbaeMatrixWidget current, XbaeMatrixWidget new, Boolean bg) #else ResizeColors(current, new, bg) XbaeMatrixWidget current; XbaeMatrixWidget new; Boolean bg; #endif { int i, j; int safe_rows = 0; if (! new->matrix.rows) return; if (new->matrix.rows == current->matrix.rows) safe_rows = new->matrix.rows; /* * Adding rows */ if (new->matrix.rows > current->matrix.rows) { /* * Realloc a larger array of row pointers */ if (bg) { new->matrix.cell_background = (Pixel **) XtRealloc((char *) new->matrix.cell_background, new->matrix.rows * sizeof(Pixel *)); for (i = current->matrix.rows; i < new->matrix.rows; i++) { new->matrix.cell_background[i] = (Pixel *) XtMalloc(new->matrix.columns * sizeof(Pixel)); for (j = 0; j < new->matrix.columns; j++) new->matrix.cell_background[i][j] = new->core.background_pixel; } } else { new->matrix.colors = (Pixel **) XtRealloc((char *) new->matrix.colors, new->matrix.rows * sizeof(Pixel *)); for (i = current->matrix.rows; i < new->matrix.rows; i++) { new->matrix.colors[i] = (Pixel *) XtMalloc(new->matrix.columns * sizeof(Pixel)); for (j = 0; j < new->matrix.columns; j++) new->matrix.colors[i][j] = new->manager.foreground; } } /* * Malloc a new row array for each row. Initialize it with foreground. * Use the new column size. */ safe_rows = current->matrix.rows; } /* * Deleting rows */ if (new->matrix.rows < current->matrix.rows) { if (bg) for (i = new->matrix.rows; i < current->matrix.rows; i++) XtFree((XtPointer) new->matrix.cell_background[i]); else for (i = new->matrix.rows; i < current->matrix.rows; i++) XtFree((XtPointer) new->matrix.colors[i]); safe_rows = new->matrix.rows; } /* * Adding columns */ if (new->matrix.columns > current->matrix.columns) { /* * Realloc each row array. Do not touch any rows added/deleted above * (use safe_rows) */ if (bg) { for (i = 0; i < safe_rows; i++) { int k; new->matrix.cell_background[i] = (Pixel *) XtRealloc( (char *) new->matrix.cell_background[i], new->matrix.columns * sizeof(Pixel)); for (k = current->matrix.columns; k < new->matrix.columns; k++) new->matrix.cell_background[i][k] = new->core.background_pixel; } } else { for (i = 0; i < safe_rows; i++) { int k; new->matrix.colors[i] = (Pixel *) XtRealloc( (char *) new->matrix.colors[i], new->matrix.columns * sizeof(Pixel)); for (k = current->matrix.columns; k < new->matrix.columns; k++) new->matrix.colors[i][k] = new->manager.foreground; } } } /* * Deleting columns * if (new->matrix.columns < current->matrix.columns) * We don't bother to realloc, just leave some wasted space. * XXX is this a problem? AL: Probably! If you are deleting enough * columns, it would be nice to make the memory available again. * I'll get to it later. */ }