home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / Microline3.0 / XmL / Tree.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  37.2 KB  |  1,322 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20.  * The following source code is part of the Microline Widget Library.
  21.  * The Microline widget library is made available to Mozilla developers
  22.  * under the Netscape Public License (NPL) by Neuron Data.  To learn
  23.  * more about Neuron Data, please visit the Neuron Data Home Page at
  24.  * http://www.neurondata.com.
  25.  */
  26.  
  27. #include "TreeP.h"
  28.  
  29. #include <stdio.h>
  30.  
  31. static void Initialize(Widget req, Widget newW, ArgList args, Cardinal *nargs);
  32. static void Destroy(Widget w);
  33. static Boolean SetValues(Widget curW, Widget, Widget newW, 
  34.     ArgList args, Cardinal *nargs);
  35. static int _PreLayout(XmLGridWidget g, int isVert);
  36. static int _CellAction(XmLGridCell cell, Widget w,
  37.     XmLGridCallbackStruct *cbs);
  38. static void DrawIconCell(XmLGridCell cell, Widget w,
  39.     int row, XRectangle *clipRect, XmLGridDrawStruct *ds);
  40. static void DrawConnectingLine(Display *dpy, Window win, GC gc,
  41.     XRectangle *clipRect, int offFlag, int x1, int y1, int x2, int y2);
  42. static void BtnPress(Widget w, XtPointer closure, XEvent *event,
  43.     Boolean *ctd);
  44. static void Activate(Widget w, XtPointer clientData, XtPointer callData);
  45. static void SwitchRowState(XmLTreeWidget t, int row, XEvent *event);
  46. static XmLGridRow _RowNew(Widget tree);
  47. static void _GetRowValueMask(XmLGridWidget g, char *s, long *mask);
  48. static void _GetRowValue(XmLGridWidget g, XmLGridRow r,
  49.     XtArgVal value, long mask);
  50. static int _SetRowValues(XmLGridWidget g, XmLGridRow r, long mask);
  51. static int _SetCellValuesResize(XmLGridWidget g, XmLGridRow row,
  52.     XmLGridColumn col, XmLGridCell cell, long mask);
  53.  
  54. static void GetManagerForeground(Widget w, int, XrmValue *value);
  55. static void CreateDefaultPixmaps(XmLTreeWidget t);
  56. static XmLTreeWidget WidgetToTree(Widget w, char *funcname);
  57.  
  58. static XtResource resources[] =
  59.     {
  60.         {
  61.         XmNcollapseCallback, XmCCallback,
  62.         XmRCallback, sizeof(XtCallbackList),
  63.         XtOffset(XmLTreeWidget, tree.collapseCallback),
  64.         XmRImmediate, (XtPointer)0,
  65.         },
  66.         {
  67.         XmNconnectingLineColor, XmCConnectingLineColor,
  68.         XmRPixel, sizeof(Pixel),
  69.         XtOffset(XmLTreeWidget, tree.lineColor),
  70.         XmRCallProc, (XtPointer)GetManagerForeground,
  71.         },
  72.         {
  73.         XmNexpandCallback, XmCCallback,
  74.         XmRCallback, sizeof(XtCallbackList),
  75.         XtOffset(XmLTreeWidget, tree.expandCallback),
  76.         XmRImmediate, (XtPointer)0,
  77.         },
  78.         {
  79.         XmNlevelSpacing, XmCLevelSpacing,
  80.         XmRDimension, sizeof(Dimension),
  81.         XtOffset(XmLTreeWidget, tree.levelSpacing),
  82.         XmRImmediate, (XtPointer)11,
  83.         },
  84.         {
  85.         XmNplusMinusColor, XmCPlusMinusColor,
  86.         XmRPixel, sizeof(Pixel),
  87.         XtOffset(XmLTreeWidget, tree.pmColor),
  88.         XmRCallProc, (XtPointer)GetManagerForeground,
  89.         },
  90.         /* Row Resources */
  91.         {
  92.         XmNrowExpands, XmCRowExpands,
  93.         XmRBoolean, sizeof(Boolean),
  94.         XtOffset(XmLTreeWidget, tree.rowExpands),
  95.         XmRImmediate, (XtPointer)False,
  96.         },
  97.         {
  98.         XmNrowIsExpanded, XmCRowIsExpanded,
  99.         XmRBoolean, sizeof(Boolean),
  100.         XtOffset(XmLTreeWidget, tree.rowIsExpanded),
  101.         XmRImmediate, (XtPointer)True,
  102.         },
  103.         {
  104.         XmNrowLevel, XmCRowLevel,
  105.         XmRInt, sizeof(int),
  106.         XtOffset(XmLTreeWidget, tree.rowLevel),
  107.         XmRImmediate, (XtPointer)0,
  108.         },
  109.  
  110.         /* XmNignorePixmaps.  Causes the tree to NOT render any pixmaps */
  111.         {
  112.         XmNignorePixmaps, XmCIgnorePixmaps,
  113.         XmRBoolean, sizeof(Boolean),
  114.         XtOffset(XmLTreeWidget, tree.ignorePixmaps),
  115.         XmRImmediate, (XtPointer) False,
  116.         },
  117.     };
  118.  
  119. XmLTreeClassRec xmlTreeClassRec =
  120.     {
  121.         { /* core_class */
  122.         (WidgetClass)&xmlGridClassRec,            /* superclass         */
  123.         "XmLTree",                                /* class_name         */
  124.         sizeof(XmLTreeRec),                       /* widget_size        */
  125.         (XtProc)NULL,                             /* class_init         */
  126.         0,                                        /* class_part_init    */
  127.         FALSE,                                    /* class_inited       */
  128.         (XtInitProc)Initialize,                   /* initialize         */
  129.         0,                                        /* initialize_hook    */
  130.         XtInheritRealize,                         /* realize            */
  131.         NULL,                                     /* actions            */
  132.         0,                                        /* num_actions        */
  133.         resources,                                /* resources          */
  134.         XtNumber(resources),                      /* num_resources      */
  135.         NULLQUARK,                                /* xrm_class          */
  136.         TRUE,                                     /* compress_motion    */
  137.         XtExposeCompressMaximal,                  /* compress_exposure  */
  138.         TRUE,                                     /* compress_enterleav */
  139.         TRUE,                                     /* visible_interest   */
  140.         (XtWidgetProc)Destroy,                    /* destroy            */
  141.         XtInheritResize,                          /* resize             */
  142.         XtInheritExpose,                          /* expose             */
  143.         (XtSetValuesFunc)SetValues,               /* set_values         */
  144.         0,                                        /* set_values_hook    */
  145.         XtInheritSetValuesAlmost,                 /* set_values_almost  */
  146.         0,                                        /* get_values_hook    */
  147.         0,                                        /* accept_focus       */
  148.         XtVersion,                                /* version            */
  149.         0,                                        /* callback_private   */
  150.         XtInheritTranslations,                    /* tm_table           */
  151.         0,                                        /* query_geometry     */
  152.         0,                                        /* display_accelerato */
  153.         0,                                        /* extension          */
  154.         },
  155.         { /* composite_class */
  156.         XtInheritGeometryManager,                 /* geometry_manager   */
  157.         XtInheritChangeManaged,                   /* change_managed     */
  158.         XtInheritInsertChild,                     /* insert_child       */
  159.         XtInheritDeleteChild,                     /* delete_child       */
  160.         0,                                        /* extension          */
  161.         },
  162.         { /* constraint_class */
  163.         0,                                          /* subresources       */
  164.         0,                                        /* subresource_count  */
  165.         sizeof(XmLTreeConstraintRec),             /* constraint_size    */
  166.         0,                                        /* initialize         */
  167.         0,                                        /* destroy            */
  168.         0,                                        /* set_values         */
  169.         0,                                        /* extension          */
  170.         },
  171.         { /* manager_class */
  172.         XtInheritTranslations,                    /* translations       */
  173.         0,                                        /* syn resources      */
  174.         0,                                        /* num syn_resources  */
  175.         0,                                        /* get_cont_resources */
  176.         0,                                        /* num_get_cont_resou */
  177.         XmInheritParentProcess,                   /* parent_process     */
  178.         0,                                        /* extension          */
  179.         },
  180.         { /* grid_class */
  181.         0,                                        /* initial rows       */
  182.         1,                                        /* initial cols       */
  183.         _PreLayout,                               /* post layout        */
  184.         sizeof(struct _XmLTreeRowRec),            /* row rec size       */
  185.         _RowNew,                                  /* row new            */
  186.         XmInheritGridRowFree,                     /* row free           */
  187.         _GetRowValueMask,                         /* get row value mask */
  188.         _GetRowValue,                             /* get row value      */
  189.         _SetRowValues,                            /* set row values     */
  190.         sizeof(struct _XmLGridColumnRec),         /* column rec size    */
  191.         XmInheritGridColumnNew,                   /* column new         */
  192.         XmInheritGridColumnFree,                  /* column free        */
  193.         XmInheritGridGetColumnValueMask,          /* get col value mask */
  194.         XmInheritGridGetColumnValue,              /* get column value   */
  195.         XmInheritGridSetColumnValues,             /* set column values  */
  196.         _SetCellValuesResize,                     /* set cell vl resize */
  197.         _CellAction,                              /* cell action        */
  198.         },
  199.         { /* tree_class */
  200.         0,                                        /* unused             */
  201.         }
  202.     };
  203.  
  204. WidgetClass xmlTreeWidgetClass = (WidgetClass)&xmlTreeClassRec;
  205.  
  206. static void
  207. Initialize(Widget reqW,
  208.        Widget newW,
  209.        ArgList args,
  210.        Cardinal *narg)
  211.     {
  212.     XmLTreeWidget t;
  213.  
  214.     t = (XmLTreeWidget)newW;
  215.     if (t->core.width <= 0) 
  216.         t->core.width = 100;
  217.     if (t->core.height <= 0) 
  218.         t->core.height = 100;
  219.     t->tree.defaultPixmapsCreated = 0;
  220.     t->tree.linesData = 0;
  221.     t->tree.linesSize = 0;
  222.     t->tree.recalcTreeWidth = 0;
  223.     if (t->grid.rowCount)
  224.         {
  225.         XmLWarning(newW, "Initialize() - can't set XmNrows");
  226.         XmLGridDeleteAllRows(newW, XmCONTENT);
  227.         }
  228.     XtAddCallback(newW, XmNactivateCallback, Activate, NULL);
  229.     XtAddEventHandler(newW, ButtonPressMask,
  230.         True, (XtEventHandler)BtnPress, (XtPointer)0);
  231.  
  232.     XtVaSetValues(newW,
  233.         XmNcellDefaults, True,
  234.         XmNcolumn, 0,
  235.         XmNcellType, XmICON_CELL,
  236.         NULL);
  237.     }
  238.  
  239. static void
  240. Destroy(Widget w)
  241.     {
  242.     XmLTreeWidget t;
  243.     Display *dpy;
  244.     XWindowAttributes attr;
  245.  
  246.     t = (XmLTreeWidget)w;
  247.     dpy = XtDisplay(t);
  248.     if (t->tree.linesData)
  249.         free((char *)t->tree.linesData);
  250.     if (t->tree.defaultPixmapsCreated)
  251.         {
  252.         XGetWindowAttributes(dpy, XtWindow(w), &attr);
  253.         XFreePixmap(dpy, t->tree.filePixmask);
  254.         XFreePixmap(dpy, t->tree.folderPixmask);
  255.         XFreePixmap(dpy, t->tree.folderOpenPixmask);
  256.         XFreePixmap(dpy, t->tree.filePixmask);
  257.         XFreePixmap(dpy, t->tree.folderPixmask);
  258.         XFreePixmap(dpy, t->tree.folderOpenPixmask);
  259.         XFreeColors(dpy, attr.colormap, t->tree.pixColors, 4, 0L);
  260.         }
  261.     }
  262.  
  263. static Boolean
  264. SetValues(Widget curW,
  265.       Widget reqW,
  266.       Widget newW,
  267.       ArgList args,
  268.       Cardinal *nargs)
  269. {
  270.     XmLTreeWidget t, cur;
  271.     XmLGridColumn col;
  272.     Boolean needsResize, needsRedraw;
  273.  
  274.     t = (XmLTreeWidget)newW;
  275.     cur = (XmLTreeWidget)curW;
  276.     needsResize = False;
  277.     needsRedraw = False;
  278.  
  279. #define NE(value) (t->value != cur->value)
  280.     if (NE(grid.rowCount))
  281.         XmLWarning(newW, "SetValues() - can't set XmNrows");
  282.     if (NE(tree.pmColor) || NE(tree.lineColor))
  283.         needsRedraw = True;
  284.     if (NE(tree.levelSpacing) ||
  285.         t->tree.recalcTreeWidth)
  286.         {
  287.         col = XmLGridGetColumn(newW, XmCONTENT, 0);
  288.         if (col)
  289.             col->grid.widthInPixelsValid = 0;
  290.         t->tree.recalcTreeWidth = 0;
  291.         needsResize = True;
  292.         needsRedraw = True;
  293.         }
  294. #undef NE
  295.     if (needsResize)
  296.         _XmLGridLayout((XmLGridWidget)t);
  297.     if (needsRedraw)
  298.         XmLGridRedrawAll((Widget)t);
  299.     return False;
  300. }
  301.  
  302. static int
  303. _PreLayout(XmLGridWidget g,
  304.            int isVert)
  305.     {
  306.     XmLTreeWidget t;
  307.     XmLTreeRow row;
  308.     Widget w;
  309.     int i, j, size, maxLevel, hideLevel, lineWidth;
  310.     char *thisLine, *prevLine;
  311.  
  312.     t = (XmLTreeWidget)g;
  313.     w = (Widget)g;
  314.     if (!t->grid.vertVisChangedHint)
  315.         return 0; /* ?? */
  316.     t->grid.vertVisChangedHint = 0;
  317.  
  318.     /* top down calculation of hidden states and maxLevel */
  319.     hideLevel = -1;
  320.     maxLevel = 0;
  321.     t->grid.layoutFrozen = True;
  322.     for (i = 0; i < t->grid.rowCount; i++)
  323.         {
  324.         row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, i);
  325.         if (row->tree.level > maxLevel)
  326.             maxLevel = row->tree.level;
  327.  
  328.         if (hideLevel != -1 && row->tree.level > hideLevel)
  329.             {
  330.             if (row->grid.height)
  331.                 XtVaSetValues(w,
  332.                     XmNrow, i,
  333.                     XmNrowHeight, 0,
  334.                     NULL);
  335.             }
  336.         else
  337.             {
  338.             if (row->tree.expands == True && row->tree.isExpanded == False)
  339.                 hideLevel = row->tree.level;
  340.             else
  341.                 hideLevel = -1;
  342.             if (!row->grid.height)
  343.                 XtVaSetValues(w,
  344.                     XmNrow, i,
  345.                     XmNrowHeight, 1,
  346.                     NULL);
  347.             }
  348.         }
  349.     t->grid.layoutFrozen = False;
  350.     t->tree.linesMaxLevel = maxLevel;
  351.     if (!t->grid.rowCount)
  352.         return 0;
  353.  
  354.     /* bottom up calculation of connecting lines */
  355.     lineWidth = maxLevel + 1;
  356.     size = lineWidth * t->grid.rowCount;
  357.     if (t->tree.linesSize < size)
  358.         {
  359.         if (t->tree.linesData)
  360.             free((char *)t->tree.linesData);
  361.         t->tree.linesSize = size;
  362.         t->tree.linesData = (char *)malloc(size);
  363.         }
  364.     prevLine = 0;
  365.     thisLine = &t->tree.linesData[size - lineWidth];
  366.     for (i = t->grid.rowCount - 1; i >= 0; i--)
  367.         {
  368.         row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, i);
  369.         if (!row->grid.height)
  370.             {
  371.             thisLine -= lineWidth;
  372.             continue;
  373.             }
  374.         for (j = 0; j < row->tree.level - 1; j++)
  375.             {
  376.             if (prevLine && (prevLine[j] == 'L' || prevLine[j] == 'I' ||
  377.                 prevLine[j] == 'E'))
  378.                 thisLine[j] = 'I';
  379.             else
  380.                 thisLine[j] = ' ';
  381.             }    
  382.         if (row->tree.level)
  383.             {
  384.             if (prevLine && (prevLine[j] == 'L' || prevLine[j] == 'I' ||
  385.                 prevLine[j] == 'E'))
  386.                 thisLine[j++] = 'E';
  387.             else
  388.                 thisLine[j++] = 'L';
  389.             }
  390.         thisLine[j++] = 'O';
  391.         for (; j < lineWidth; j++)
  392.             thisLine[j] = ' ';
  393.         prevLine = thisLine;
  394.         thisLine -= lineWidth;
  395.         }
  396.     if (prevLine)
  397.         {
  398.         for (i = 0; i < lineWidth; i++)
  399.             {
  400.             if (prevLine[i] == 'L')
  401.                 prevLine[i] = '-';
  402.             else if (prevLine[i] == 'E')
  403.                 prevLine[i] = 'P';
  404.             }
  405.         }
  406.  
  407.     /* if we are in VertLayout(), the horizontal size may need */
  408.     /* recomputing because of the row hides. */
  409.     if (isVert)
  410.         return 1;
  411.  
  412.     /* if we are in HorizLayout(), the vertical recomputation */
  413.     /* will be happening regardless, since row changes (vertical) */
  414.     /* are why we are here */
  415.     return 0;
  416.     }
  417.  
  418. static int
  419. _CellAction(XmLGridCell cell,
  420.             Widget w,
  421.             XmLGridCallbackStruct *cbs)
  422.     {
  423.     XmLTreeWidget t;
  424.     XmLTreeRow row;
  425.     XmLGridColumn col;
  426.     XmLGridWidgetClass sc;
  427.     XmLGridCellActionProc cellActionProc;
  428.     XmLGridCellRefValues *cellValues;
  429.     XmLGridCellIcon *icon;
  430.     /*    XRectangle *rect, cRect;*/
  431.     int ret, h, isTreeCell;
  432.  
  433.  
  434.     Dimension default_icon_width = 16;
  435.     Dimension default_icon_height = 16;
  436.  
  437.     t = (XmLTreeWidget)w;
  438.     if (cbs->rowType == XmCONTENT &&
  439.         cbs->columnType == XmCONTENT &&
  440.         cbs->column == 0)
  441.         isTreeCell = 1;
  442.     else
  443.         isTreeCell = 0;
  444.     sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
  445.     cellActionProc = sc->grid_class.cellActionProc;
  446.     ret = 0;
  447.  
  448.     /* Check for ignore pixmaps */
  449.     if (t->tree.ignorePixmaps)
  450.     {
  451.         default_icon_width = 0;
  452.         default_icon_height = 0;
  453.     }
  454.  
  455.     switch (cbs->reason)
  456.         {
  457.         case XmCR_CELL_DRAW:
  458.             if (isTreeCell)
  459.                 DrawIconCell(cell, w, cbs->row, cbs->clipRect, cbs->drawInfo);
  460.             else
  461.                 ret = cellActionProc(cell, w, cbs);
  462.             break;
  463.         case XmCR_PREF_HEIGHT:
  464.             ret = cellActionProc(cell, w, cbs);
  465.             if (isTreeCell)
  466.                 {
  467.                 cellValues = cell->cell.refValues;
  468.                 if (cellValues->type != XmICON_CELL)
  469.                     return 0;
  470.                 icon = (XmLGridCellIcon *)cell->cell.value;
  471.  
  472.                 h = 4 + default_icon_height + cellValues->topMargin + cellValues->bottomMargin;
  473.  
  474.                 if (icon && icon->pix.pixmap == XmUNSPECIFIED_PIXMAP &&
  475.                     ret < h)
  476.                     ret = h;
  477.                 }
  478.             break;
  479.         case XmCR_PREF_WIDTH:
  480.             if (isTreeCell)
  481.                 {
  482.                 cellValues = cell->cell.refValues;
  483.                 if (cellValues->type != XmICON_CELL)
  484.                     return 0;
  485.                 icon = (XmLGridCellIcon *)cell->cell.value;
  486.                 col = (XmLGridColumn)cbs->object;
  487.                 row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, cbs->row);
  488.                 if (row->tree.stringWidthValid == False)
  489.                     {
  490.                     if (icon && icon->string)
  491.                         row->tree.stringWidth =
  492.                             XmStringWidth(cellValues->fontList, icon->string);
  493.                     else
  494.                         row->tree.stringWidth = 0;
  495.                     row->tree.stringWidthValid = True;
  496.                     }
  497.                 ret = 4 + cellValues->leftMargin + t->tree.levelSpacing * 2 *
  498.                     row->tree.level + t->grid.iconSpacing + row->tree.stringWidth +
  499.                     cellValues->rightMargin;
  500.                 if (!icon)
  501.                      ret += default_icon_width;
  502.                 else if (icon->pix.pixmap == XmUNSPECIFIED_PIXMAP)
  503.                      ret += default_icon_width;
  504.                 else
  505.                     ret += icon->pix.width;
  506.                 if (!row->grid.height)
  507.                     ret = 0;
  508.                 }
  509.             else
  510.                 ret = cellActionProc(cell, w, cbs);
  511.             break;
  512.         default:
  513.             ret = cellActionProc(cell, w, cbs);
  514.             break;
  515.         }
  516.     return ret;
  517.     }
  518.  
  519. static void
  520. DrawIconCell(XmLGridCell cell,
  521.              Widget w,
  522.              int row,
  523.              XRectangle *clipRect,
  524.              XmLGridDrawStruct *ds)
  525.     {
  526.     XmLTreeWidget t;
  527.     XmLTreeRow rowp;
  528.     XmLGridCellRefValues *cellValues;
  529.     XmLGridCellIcon *icon;
  530.     XRectangle *cellRect, rect;
  531.     Display *dpy;
  532.     Window win;
  533.     char *thisLine;
  534.     int i, clipSet, pixWidth, pixHeight;
  535.     int xoff, xoff2, midy, oddFlag, x1, y1, x2, y2;
  536.     Pixmap pixmap, pixmask;
  537.  
  538.     t = (XmLTreeWidget)w;
  539.     rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
  540.     dpy = XtDisplay(w);
  541.     win = XtWindow(w);
  542.     cellValues = cell->cell.refValues;
  543.     if (cellValues->type != XmICON_CELL)
  544.         return;
  545.     icon = (XmLGridCellIcon *)cell->cell.value;
  546.     if (!icon)
  547.         return;
  548.     cellRect = ds->cellRect;
  549.     if (!t->tree.linesData)
  550.         {
  551.         XmLWarning(w, "DrawIconCell() - no lines data calculated");
  552.         return;
  553.         }
  554.  
  555.     /* draw background */
  556.     XSetForeground(dpy, ds->gc, cell->cell.refValues->background);
  557.     XFillRectangle(dpy, win, ds->gc, clipRect->x, clipRect->y,
  558.         clipRect->width, clipRect->height);
  559.  
  560.     if (t->grid.singleColScrollMode)
  561.         oddFlag = t->grid.singleColScrollPos & 1;
  562.     else
  563.         oddFlag = 0;
  564.  
  565.     pixWidth = 0;
  566.     xoff = t->tree.levelSpacing;
  567.     xoff2 = xoff * 2;
  568.     y1 = cellRect->y;
  569.     y2 = cellRect->y + cellRect->height - 1;
  570.     midy = cellRect->y + cellRect->height / 2;
  571.     if (midy & 1)
  572.         midy += 1;
  573.  
  574.     /* draw connecting lines and pixmap */
  575.     XSetForeground(dpy, ds->gc, t->tree.lineColor);
  576.     thisLine = &t->tree.linesData[row * (t->tree.linesMaxLevel + 1)];
  577.     for (i = 0; i <= t->tree.linesMaxLevel; i++)
  578.         {
  579.         x1 = cellRect->x + (xoff2 * i);
  580.         if (x1 >= clipRect->x + (int)clipRect->width)
  581.             continue;
  582.         switch (thisLine[i])
  583.             {
  584.             case 'O':
  585.               if (!t->tree.ignorePixmaps)
  586.               {
  587.                 rect.x = x1;
  588.                 rect.y = cellRect->y;
  589.                 rect.width = cellRect->width;
  590.                 rect.height = cellRect->height;
  591.                 if (icon->pix.pixmap != XmUNSPECIFIED_PIXMAP)
  592.                     {
  593.                     pixmap = icon->pix.pixmap;
  594.                     pixmask = icon->pix.pixmask;
  595.                     pixWidth = icon->pix.width;
  596.                     pixHeight = icon->pix.height;
  597.                     }
  598.                 else
  599.                     {
  600.                     if (!t->tree.defaultPixmapsCreated)
  601.                         CreateDefaultPixmaps(t);
  602.                     if (rowp->tree.expands && rowp->tree.isExpanded)
  603.                         {
  604.                         pixmap = t->tree.folderOpenPixmap;
  605.                         pixmask = t->tree.folderOpenPixmask;
  606.                         }
  607.                     else if (rowp->tree.expands)
  608.                         {
  609.                         pixmap = t->tree.folderPixmap;
  610.                         pixmask = t->tree.folderPixmask;
  611.                         }
  612.                     else
  613.                         {
  614.                         pixmap = t->tree.filePixmap;
  615.                         pixmask = t->tree.filePixmask;
  616.                         }
  617.                     pixWidth = 16;
  618.                     pixHeight = 16;
  619.                     }
  620.                 
  621.                 XmLPixmapDraw(w, pixmap, pixmask, pixWidth, pixHeight,
  622.                               XmALIGNMENT_BOTTOM_LEFT, ds->gc, &rect, clipRect);
  623.               } /* !t->tree.ignorePixmaps */
  624.                 break;
  625.             case 'I':
  626.                 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
  627.                     x1 + xoff, y1, x1 + xoff, y2);
  628.                 break;
  629.             case 'E':
  630.                 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
  631.                     x1 + xoff, y1, x1 + xoff, y2);
  632.                 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
  633.                     x1 + xoff, midy, x1 + xoff2, midy);
  634.                 break;
  635.             case 'L':
  636.                 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
  637.                     x1 + xoff, y1, x1 + xoff, midy);
  638.                 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
  639.                     x1 + xoff, midy, x1 + xoff2, midy);
  640.                 break;
  641.             case 'P':
  642.                 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
  643.                     x1 + xoff, midy, x1 + xoff, y2);
  644.                 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
  645.                     x1 + xoff, midy, x1 + xoff2, midy);
  646.                 break;
  647.             case '-':
  648.                 DrawConnectingLine(dpy, win, ds->gc, clipRect, oddFlag,
  649.                     x1 + xoff, midy, x1 + xoff2, midy);
  650.                 break;
  651.             }
  652.         }
  653.  
  654.     clipSet = 0;
  655.  
  656.     /* draw expand/collapse graphic */
  657.     rect.x = cellRect->x + (rowp->tree.level - 1) * xoff2 + xoff - 5;
  658.     rect.y = midy - 5;
  659.     rect.width = 11;
  660.     rect.height = 11;
  661.     i = XmLRectIntersect(&rect, clipRect);
  662.     if (rowp->tree.expands && rowp->tree.level && i != XmLRectOutside)
  663.         {
  664.         if (i == XmLRectPartial)
  665.             {
  666.             clipSet = 1;
  667.             XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted);
  668.             }
  669.         x1 = rect.x;
  670.         x2 = rect.x + rect.width - 1;
  671.         y1 = rect.y;
  672.         y2 = rect.y + rect.height - 1;
  673.         XSetForeground(dpy, ds->gc, cellValues->background);
  674.         XFillRectangle(dpy, win, ds->gc, x1, y1, 11, 11);
  675.         XSetForeground(dpy, ds->gc, t->tree.lineColor);
  676.         XDrawLine(dpy, win, ds->gc, x1 + 2, y1 + 1, x2 - 2, y1 + 1);
  677.         XDrawLine(dpy, win, ds->gc, x2 - 1, y1 + 2, x2 - 1, y2 - 2);
  678.         XDrawLine(dpy, win, ds->gc, x1 + 2, y2 - 1, x2 - 2, y2 - 1);
  679.         XDrawLine(dpy, win, ds->gc, x1 + 1, y1 + 2, x1 + 1, y2 - 2);
  680.         XSetForeground(dpy, ds->gc, t->tree.pmColor);
  681.         if (!rowp->tree.isExpanded)
  682.             XDrawLine(dpy, win, ds->gc, x1 + 5, y1 + 3, x1 + 5, y1 + 7);
  683.         XDrawLine(dpy, win, ds->gc, x1 + 3, y1 + 5, x1 + 7, y1 + 5);
  684.         }
  685.  
  686.     /* draw select background and highlight */
  687.     i = rowp->tree.level * xoff2 + pixWidth + t->grid.iconSpacing;
  688.     rect.x = cellRect->x + i;
  689.     rect.y = cellRect->y;
  690.     rect.height = cellRect->height;
  691.     rect.width = 0;
  692.     if (t->grid.colCount == 1 && rowp->tree.stringWidthValid)
  693.         rect.width = rowp->tree.stringWidth + 4;
  694.     else if ((int)cellRect->width > i)
  695.         rect.width = cellRect->width - i;
  696.     i = XmLRectIntersect(&rect, clipRect);
  697.     if (i != XmLRectOutside && ds->drawSelected)
  698.         {
  699.         if (i == XmLRectPartial && !clipSet)
  700.             {
  701.             clipSet = 1;
  702.             XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted);
  703.             }
  704.         XSetForeground(dpy, ds->gc, ds->selectBackground);
  705.         XFillRectangle(dpy, win, ds->gc, rect.x, rect.y,
  706.             rect.width, rect.height);
  707.         }
  708.     if (ds->drawFocusType != XmDRAW_FOCUS_NONE &&
  709.         t->grid.highlightThickness >= 2)
  710.         {
  711.         if (i == XmLRectPartial && !clipSet)
  712.             {
  713.             clipSet = 1;
  714.             XSetClipRectangles(dpy, ds->gc, 0, 0, clipRect, 1, Unsorted);
  715.             }
  716.         XSetForeground(dpy, ds->gc, t->manager.highlight_color);
  717.         x1 = rect.x;
  718.         x2 = rect.x + rect.width - 1;
  719.         y1 = rect.y;
  720.         y2 = rect.y + rect.height - 1;
  721.         XDrawLine(dpy, win, ds->gc, x1, y1, x2, y1);
  722.         if (ds->drawFocusType == XmDRAW_FOCUS_CELL ||
  723.             ds->drawFocusType == XmDRAW_FOCUS_RIGHT)
  724.             XDrawLine(dpy, win, ds->gc, x2, y1, x2, y2);
  725.         XDrawLine(dpy, win, ds->gc, x1, y2, x2, y2);
  726.         XDrawLine(dpy, win, ds->gc, x1, y1, x1, y2);
  727.         y1 += 1;
  728.         y2 -= 1;
  729.         XDrawLine(dpy, win, ds->gc, x1, y2, x2, y2);
  730.         XDrawLine(dpy, win, ds->gc, x1, y1, x2, y1);
  731.         x1 += 1;
  732.         x2 -= 1;
  733.         XDrawLine(dpy, win, ds->gc, x1, y1, x1, y2);
  734.         if (ds->drawFocusType == XmDRAW_FOCUS_CELL ||
  735.             ds->drawFocusType == XmDRAW_FOCUS_RIGHT)
  736.             XDrawLine(dpy, win, ds->gc, x2, y1, x2, y2);
  737.         }
  738.  
  739.     /* draw string */
  740.     if (icon->string)
  741.         {
  742.         if (ds->drawSelected == True)
  743.             XSetForeground(dpy, ds->gc, ds->selectForeground);
  744.         else
  745.             XSetForeground(dpy, ds->gc, cellValues->foreground);
  746.         XmLStringDraw(w, icon->string, ds->stringDirection,
  747.             cellValues->fontList, XmALIGNMENT_LEFT,
  748.             ds->gc, &rect, clipRect);
  749.         }
  750.  
  751.     if (clipSet)
  752.         XSetClipMask(dpy, ds->gc, None);
  753.     }
  754.  
  755. static void
  756. DrawConnectingLine(Display *dpy,
  757.                     Window win,
  758.                     GC gc,
  759.                     XRectangle *clipRect,
  760.                     int oddFlag,
  761.                     int x1,
  762.                     int y1,
  763.                     int x2,
  764.                     int y2)
  765.     {
  766.     int i, x, y;
  767.     XPoint points[100];
  768.  
  769.     i = 0;
  770.     for (x = x1; x <= x2; x++)
  771.         for (y = y1; y <= y2; y++)
  772.             {
  773.             if ((((x + oddFlag) & 1) == (y & 1)) ||
  774.                 x < clipRect->x ||
  775.                 x >= (clipRect->x + (int)clipRect->width) ||
  776.                 y < clipRect->y ||
  777.                 y >= (clipRect->y + (int)clipRect->height))
  778.                 continue;
  779.             points[i].x = x;
  780.             points[i].y = y;
  781.             if (++i < 100)
  782.                 continue;
  783.             XDrawPoints(dpy, win, gc, points, i, CoordModeOrigin);
  784.             i = 0;
  785.             }
  786.     if (i)
  787.         XDrawPoints(dpy, win, gc, points, i, CoordModeOrigin);
  788.     }
  789.  
  790. static void
  791. BtnPress(Widget w,
  792.          XtPointer closure,
  793.          XEvent *event,
  794.          Boolean *ctd)
  795.     {
  796.     XmLTreeWidget t;
  797.     XmLTreeRow rowp;
  798.     unsigned char rowType, colType;
  799.     int row, col, x1, y1, x2, y2, xoff;
  800.     XRectangle rect;
  801.     XButtonEvent *be;
  802.     static int lastRow = -1;
  803.     static Time lastSelectTime = 0;
  804.  
  805.     t = (XmLTreeWidget)w;
  806.     if (event->type != ButtonPress)
  807.         return;
  808.     be = (XButtonEvent *)event;
  809.     if (be->button != Button1 || be->state & ControlMask ||
  810.         be->state & ShiftMask)
  811.         return;
  812.     if (XmLGridXYToRowColumn(w, be->x, be->y, &rowType, &row,
  813.         &colType, &col) == -1)
  814.         return;
  815.     rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
  816.     if (rowType != XmCONTENT || colType != XmCONTENT || col != 0)
  817.         return;
  818.     if (XmLGridRowColumnToXY(w, rowType, row, colType, col,
  819.         False, &rect) == -1)
  820.         return;
  821.     if ((be->time - lastSelectTime) < XtGetMultiClickTime(XtDisplay(w)) &&
  822.         lastRow == row)
  823.         {
  824.         /* activate callback will be handling expand/collapse */
  825.         lastSelectTime = be->time;
  826.         return;
  827.         }
  828.     lastSelectTime = be->time;
  829.     lastRow = row;
  830.     xoff = t->tree.levelSpacing;
  831.     x1 = rect.x + (rowp->tree.level - 1) * xoff * 2 + xoff - 6;
  832.     x2 = x1 + 13;
  833.     y1 = rect.y + rect.height / 2 - 6;
  834.     y2 = y1 + 13;
  835.     if (be->x > x2 || be->x < x1 || be->y > y2 || be->y < y1)
  836.         return;
  837.     SwitchRowState(t, row, event);
  838.     }
  839.  
  840. static void
  841. Activate(Widget w,
  842.          XtPointer clientData,
  843.          XtPointer callData)
  844.     {
  845.     XmLTreeWidget t;
  846.     XmLGridCallbackStruct *cbs;
  847.  
  848.     t = (XmLTreeWidget)w;
  849.     cbs = (XmLGridCallbackStruct *)callData;
  850.     if (cbs->rowType != XmCONTENT)
  851.     if (t->grid.selectionPolicy == XmSELECT_CELL &&
  852.         (cbs->columnType != XmCONTENT || cbs->column != 0))
  853.         return;
  854.     SwitchRowState(t, cbs->row, cbs->event);
  855.     }
  856.  
  857. static void
  858. SwitchRowState(XmLTreeWidget t,
  859.                int row,
  860.                XEvent *event)
  861.     {
  862.     Widget w;
  863.     XmLTreeRow rowp;
  864.     XmLGridCallbackStruct cbs;
  865.  
  866.     w = (Widget)t;
  867.     rowp = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, row);
  868.     if (rowp->tree.expands == False) 
  869.         return;
  870.     cbs.event = event;
  871.     cbs.columnType = XmCONTENT;
  872.     cbs.column = 0;
  873.     cbs.rowType = XmCONTENT;
  874.     cbs.row = row;
  875.     if (rowp->tree.isExpanded == True)
  876.         {
  877.         XtVaSetValues(w,
  878.             XmNrow, row,
  879.             XmNrowIsExpanded, False,
  880.             NULL);
  881.         cbs.reason = XmCR_COLLAPSE_ROW;
  882.         XtCallCallbackList(w, t->tree.collapseCallback, (XtPointer)&cbs);
  883.         }
  884.     else
  885.         {
  886.         XtVaSetValues(w,
  887.             XmNrow, row,
  888.             XmNrowIsExpanded, True,
  889.             NULL);
  890.         cbs.reason = XmCR_EXPAND_ROW;
  891.         XtCallCallbackList(w, t->tree.expandCallback, (XtPointer)&cbs);
  892.         }
  893.     }
  894.  
  895. /* Only to be called through Grid class */
  896. static XmLGridRow
  897. _RowNew(Widget tree)
  898.     {
  899.     XmLGridWidgetClass sc;
  900.     XmLTreeRow row;
  901.  
  902.     sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
  903.     row = (XmLTreeRow)sc->grid_class.rowNewProc(tree);
  904.     row->tree.level = 0;
  905.     row->tree.expands = False;
  906.     row->tree.isExpanded = True;
  907.     row->tree.hasSiblings = False;
  908.     row->tree.stringWidth = 0;
  909.     row->tree.stringWidthValid = False;
  910.     return (XmLGridRow)row;
  911.     }
  912.  
  913. /* Only to be called through Grid class */
  914. static void
  915. _GetRowValueMask(XmLGridWidget g,
  916.                  char *s,
  917.                  long *mask)
  918.         {
  919.     XmLGridWidgetClass sc;
  920.     static XrmQuark qLevel, qExpands, qIsExpanded;
  921.     static int quarksValid = 0;
  922.     XrmQuark q;
  923.  
  924.     sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
  925.     sc->grid_class.getRowValueMaskProc(g, s, mask);
  926.     if (!quarksValid)
  927.         {
  928.         qLevel = XrmStringToQuark(XmNrowLevel);
  929.         qExpands = XrmStringToQuark(XmNrowExpands);
  930.         qIsExpanded = XrmStringToQuark(XmNrowIsExpanded);
  931.         quarksValid = 1;
  932.         }
  933.     q = XrmStringToQuark(s);
  934.     if (q == qLevel)
  935.         *mask |= XmLTreeRowLevel;
  936.     else if (q == qExpands)
  937.         *mask |= XmLTreeRowExpands;
  938.     else if (q == qIsExpanded)
  939.         *mask |= XmLTreeRowIsExpanded;
  940.     }
  941.  
  942. /* Only to be called through Grid class */
  943. static void
  944. _GetRowValue(XmLGridWidget g,
  945.              XmLGridRow r,
  946.              XtArgVal value,
  947.              long mask)
  948.     {
  949.     XmLGridWidgetClass sc;
  950.     XmLTreeRow row;
  951.  
  952.     sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
  953.     sc->grid_class.getRowValueProc(g, r, value, mask);
  954.     row = (XmLTreeRow)r;
  955.     switch (mask)
  956.         {
  957.         case XmLTreeRowLevel:
  958.             *((int *)value) = row->tree.level;
  959.             break;
  960.         case XmLTreeRowExpands:
  961.             *((Boolean *)value) = row->tree.expands;
  962.             break;
  963.         case XmLTreeRowIsExpanded:
  964.             *((Boolean *)value) = row->tree.isExpanded;
  965.             break;
  966.         }
  967.     }
  968.  
  969. /* Only to be called through Grid class */
  970. static int
  971. _SetRowValues(XmLGridWidget g,
  972.               XmLGridRow r,
  973.               long mask)
  974.     {
  975.     XmLGridWidgetClass sc;
  976.     int needsResize;
  977.     XmLTreeRow row;
  978.     XmLTreeWidget t;
  979.  
  980.     sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
  981.     needsResize = sc->grid_class.setRowValuesProc(g, r, mask);
  982.     t = (XmLTreeWidget)g;
  983.     row = (XmLTreeRow)r;
  984.     if ((mask & XmLGridRowHeight) && needsResize)
  985.         t->tree.recalcTreeWidth = 1;
  986.     if (mask & XmLTreeRowLevel)
  987.         {
  988.         row->tree.level = t->tree.rowLevel;
  989.         t->tree.recalcTreeWidth = 1;
  990.         t->grid.vertVisChangedHint = 1;
  991.         needsResize = 1;
  992.         }
  993.     if (mask & XmLTreeRowExpands)
  994.         {
  995.         row->tree.expands = t->tree.rowExpands;
  996.         t->grid.vertVisChangedHint = 1;
  997.         needsResize = 1;
  998.         }
  999.     if (mask & XmLTreeRowIsExpanded)
  1000.         {
  1001.         row->tree.isExpanded = t->tree.rowIsExpanded;
  1002.         t->grid.vertVisChangedHint = 1;
  1003.         needsResize = 1;
  1004.         }
  1005.     return needsResize;
  1006.     }
  1007.  
  1008. /* Only to be called through Grid class */
  1009. static int
  1010. _SetCellValuesResize(XmLGridWidget g,
  1011.               XmLGridRow row,
  1012.               XmLGridColumn col,
  1013.               XmLGridCell cell,
  1014.                 long mask)
  1015.     {
  1016.     XmLGridWidgetClass sc;
  1017.     int needsResize;
  1018.  
  1019.     sc = (XmLGridWidgetClass)xmlTreeWidgetClass->core_class.superclass;
  1020.     needsResize = 0;
  1021.     if (col->grid.pos == g->grid.headingColCount &&
  1022.         row->grid.pos >= g->grid.headingRowCount &&
  1023.         row->grid.pos < g->grid.headingRowCount + g->grid.rowCount)
  1024.         {
  1025.         if (mask & XmLGridCellFontList)
  1026.             {
  1027.             row->grid.heightInPixelsValid = 0;
  1028.             ((XmLTreeRow)row)->tree.stringWidthValid = False;
  1029.             col->grid.widthInPixelsValid = 0;
  1030.             needsResize = 1;
  1031.             }
  1032.         if (mask & XmLGridCellString)
  1033.             {
  1034.             ((XmLTreeRow)row)->tree.stringWidthValid = False;
  1035.             col->grid.widthInPixelsValid = 0;
  1036.             needsResize = 1;
  1037.             }
  1038.         }
  1039.     if (sc->grid_class.setCellValuesResizeProc(g, row, col, cell, mask))
  1040.         needsResize = 1;
  1041.     return needsResize;
  1042.     }
  1043.  
  1044. /*
  1045.   Utility
  1046. */
  1047.  
  1048. static void
  1049. GetManagerForeground(Widget w,
  1050.                       int offset,
  1051.                       XrmValue *value)
  1052.     {
  1053.     XmLTreeWidget t;
  1054.  
  1055.     t = (XmLTreeWidget)w;
  1056.     value->addr = (caddr_t)&t->manager.foreground;
  1057.     }
  1058.  
  1059. static void
  1060. CreateDefaultPixmaps(XmLTreeWidget t)
  1061.     {
  1062.     Display *dpy;
  1063.     Window win;
  1064.     XWindowAttributes attr;
  1065.     XColor color;
  1066.     Pixmap pixmap;
  1067.     Pixel pixel;
  1068.     XImage *image;
  1069.     int i, x, y;
  1070.     enum { white = 0, black = 1, yellow = 2, gray = 3 };
  1071.     static unsigned short colors[4][3] =
  1072.         {
  1073.             { 65535, 65535, 65535 },
  1074.             { 0,         0,     0 },
  1075.             { 57344, 57344,     0 },
  1076.             { 32768, 32768, 32768 },
  1077.         };
  1078.     static unsigned char fileMask_bits[] =
  1079.         {
  1080.         0xf8, 0x0f, 0xfc, 0x1f, 0xfc, 0x3f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f,
  1081.         0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f,
  1082.         0xfc, 0x7f, 0xfc, 0x7f, 0xfc, 0x7f, 0xf8, 0x7f
  1083.         };
  1084.     static unsigned char folderMask_bits[] =
  1085.         {
  1086.         0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf0, 0x0f, 0xfc, 0x3f, 0xfe, 0x7f,
  1087.         0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff,
  1088.         0xfe, 0xff, 0xfe, 0xff, 0xfc, 0xff, 0xf8, 0x7f
  1089.         };
  1090.     static unsigned char folderOpenMask_bits[] =
  1091.         {
  1092.         0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0xf0, 0x0f, 0xfc, 0x3f, 0xfe, 0x7f,
  1093.         0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff,
  1094.         0xfc, 0xff, 0xfc, 0xff, 0xf8, 0xff, 0xf0, 0x7f
  1095.         };
  1096.     static char icons[3][16][16] =
  1097.         {
  1098.             {
  1099.             "   GGGGGGGGG    ",
  1100.             "  GWWWWWWWWKK   ",
  1101.             "  GWWWWWWWWKWK  ",
  1102.             "  GWWWWWWWWKKKK ",
  1103.             "  GWWWWWWWWWWGK ",
  1104.             "  GWGGGGGGGWWGK ",
  1105.             "  GWWKKKKKKKWGK ",
  1106.             "  GWWWWWWWWWWGK ",
  1107.             "  GWGGGGGGGWWGK ",
  1108.             "  GWWKKKKKKKWGK ",
  1109.             "  GWWWWWWWWWWGK ",
  1110.             "  GWGGGGGGGWWGK ",
  1111.             "  GWWKKKKKKKWGK ",
  1112.             "  GWWWWWWWWWWGK ",
  1113.             "  GGGGGGGGGGGGK ",
  1114.             "   KKKKKKKKKKKK ",
  1115.             },
  1116.             {
  1117.             "                ",
  1118.             "                ",
  1119.             "     GGGGGG     ",
  1120.             "    GYYYYYYG    ",
  1121.             "  GGYYYYYYYYGG  ",
  1122.             " GWWWWWWWWWWWYG ",
  1123.             " GWYYYYYYYYYYYGK",
  1124.             " GWYYYYYYYYYYYGK",
  1125.             " GWYYYYYYYYYYYGK",
  1126.             " GWYYYYYYYYYYYGK",
  1127.             " GWYYYYYYYYYYYGK",
  1128.             " GWYYYYYYYYYYYGK",
  1129.             " GWYYYYYYYYYYYGK",
  1130.             " GYYYYYYYYYYYYGK",
  1131.             "  GGGGGGGGGGGGKK",
  1132.             "   KKKKKKKKKKKK ",
  1133.             },
  1134.             {
  1135.             "                ",
  1136.             "                ",
  1137.             "     GGGGGG     ",
  1138.             "    GYYYYYYG    ",
  1139.             "  GGYYYYYYYYGG  ",
  1140.             " GYYYYYYYYYYYYG ",
  1141.             " GYYYYYYYYYYYYGK",
  1142.             "GGGGGGGGGGGYYYGK",
  1143.             "GWWWWWWWWWYKYYGK",
  1144.             "GWYYYYYYYYYKYYGK",
  1145.             " GYYYYYYYYYYKYGK",
  1146.             " GYYYYYYYYYYKYGK",
  1147.             "  GYYYYYYYYYYKGK",
  1148.             "  GYYYYYYYYYYKGK",
  1149.             "   GGGGGGGGGGGKK",
  1150.             "    KKKKKKKKKKK ",
  1151.             },
  1152.         };
  1153.  
  1154.     dpy = XtDisplay(t);
  1155.     win = XtWindow(t);
  1156.     XGetWindowAttributes(dpy, win, &attr);
  1157.     t->tree.filePixmask = XCreatePixmapFromBitmapData(dpy, win,
  1158.         (char *)fileMask_bits, 16, 16, 1L, 0L, 1);
  1159.     t->tree.folderPixmask = XCreatePixmapFromBitmapData(dpy, win,
  1160.         (char *)folderMask_bits, 16, 16, 1L, 0L, 1);
  1161.     t->tree.folderOpenPixmask = XCreatePixmapFromBitmapData(dpy, win,
  1162.         (char *)folderOpenMask_bits, 16, 16, 1L, 0L, 1);
  1163.     for (i = 0; i < 4; i++)
  1164.         {
  1165.         color.red = colors[i][0];
  1166.         color.green = colors[i][1];
  1167.         color.blue = colors[i][2];
  1168.         color.flags = DoRed | DoGreen | DoBlue;
  1169.         if (XAllocColor(dpy, attr.colormap, &color))
  1170.             t->tree.pixColors[i] = color.pixel;
  1171.         else
  1172.             {
  1173.             color.flags = 0;
  1174.             XAllocColor(dpy, attr.colormap, &color);
  1175.             t->tree.pixColors[i] = color.pixel;
  1176.             }
  1177.         }
  1178.     image = XCreateImage(dpy, attr.visual, attr.depth, ZPixmap, 0,
  1179.         NULL, 16, 16, XBitmapPad(dpy), 0);
  1180.     if (!image)
  1181.         XmLWarning((Widget)t,
  1182.             "CreateDefaultPixmaps() - can't allocate image");
  1183.     else
  1184.         image->data = (char *)malloc(image->bytes_per_line * 16);
  1185.     for (i = 0; i < 3; i++)
  1186.         {
  1187.         pixmap = XCreatePixmap(dpy, win, 16, 16, attr.depth);
  1188.         for (x = 0; x < 16; x++)
  1189.             for (y = 0; y < 16; y++)
  1190.                 {
  1191.                 switch (icons[i][y][x])
  1192.                     {
  1193.                     case ' ':
  1194.                         pixel = t->core.background_pixel;
  1195.                         break;
  1196.                     case 'W':
  1197.                         pixel = t->tree.pixColors[white];
  1198.                         break;
  1199.                     case 'K':
  1200.                         pixel = t->tree.pixColors[black];
  1201.                         break;
  1202.                     case 'Y':
  1203.                         pixel = t->tree.pixColors[yellow];
  1204.                         break;
  1205.                     case 'G':
  1206.                         pixel = t->tree.pixColors[gray];
  1207.                         break;
  1208.                     }
  1209.                 XPutPixel(image, x, y, pixel);
  1210.                 }
  1211.         if (image)
  1212.             XPutImage(dpy, pixmap, t->grid.gc, image, 0, 0, 0, 0, 16, 16);
  1213.         if (i == 0)
  1214.             t->tree.filePixmap = pixmap;
  1215.         else if (i == 1)
  1216.             t->tree.folderPixmap = pixmap;
  1217.         else
  1218.             t->tree.folderOpenPixmap = pixmap;
  1219.         }
  1220.     if (image)
  1221.         XDestroyImage(image);
  1222.     t->tree.defaultPixmapsCreated = 1;
  1223.     }
  1224.  
  1225. static XmLTreeWidget
  1226. WidgetToTree(Widget w,
  1227.              char *funcname)
  1228.     {
  1229.     char buf[256];
  1230.  
  1231.     if (!XmLIsTree(w))
  1232.         {
  1233.         sprintf(buf, "%s - widget not an XmLTree", funcname);
  1234.         XmLWarning(w, buf);
  1235.         return 0;
  1236.         }
  1237.     return (XmLTreeWidget)w;
  1238.     }
  1239.  
  1240. /*
  1241.    Public Functions
  1242. */
  1243.  
  1244. Widget
  1245. XmLCreateTree(Widget parent,
  1246.               char *name,
  1247.               ArgList arglist,
  1248.               Cardinal argcount)
  1249.     {
  1250.     return XtCreateWidget(name, xmlTreeWidgetClass, parent,
  1251.         arglist, argcount);
  1252.     }
  1253.  
  1254. void
  1255. XmLTreeAddRow(Widget w,
  1256.               int level,
  1257.               Boolean expands,
  1258.               Boolean isExpanded,
  1259.               int position,
  1260.               Pixmap pixmap,
  1261.               Pixmap pixmask,
  1262.               XmString string)
  1263.     {
  1264.     XmLTreeRowDefinition row;
  1265.  
  1266.     row.level = level;
  1267.     row.expands = expands;
  1268.     row.isExpanded = isExpanded;
  1269.     row.pixmap = pixmap;
  1270.     row.pixmask = pixmask;
  1271.     row.string = string;
  1272.     XmLTreeAddRows(w, &row, 1, position);
  1273.     }
  1274.  
  1275. void 
  1276. XmLTreeAddRows(Widget w,
  1277.                 XmLTreeRowDefinition *rows,
  1278.                 int count,
  1279.                 int position)
  1280.     {
  1281.     XmLTreeWidget t;
  1282.     XmLTreeRow row;
  1283.     int i, level;
  1284.     unsigned char layoutFrozen;
  1285.  
  1286.     t = WidgetToTree(w, "XmLTreeAddRows()");
  1287.     if (!t || count <= 0)
  1288.         return;
  1289.     if (position < 0 || position > t->grid.rowCount)
  1290.         position = t->grid.rowCount;
  1291.     layoutFrozen = t->grid.layoutFrozen;
  1292.     if (layoutFrozen == False)
  1293.         XtVaSetValues(w,
  1294.             XmNlayoutFrozen, True,
  1295.             NULL);
  1296.     XmLGridAddRows(w, XmCONTENT, position, count);
  1297.     for (i = 0; i < count; i++)
  1298.         {
  1299.         row = (XmLTreeRow)XmLGridGetRow(w, XmCONTENT, position + i);
  1300.         if (!row)
  1301.             continue;
  1302.         level = rows[i].level;
  1303.         if (level < 0)
  1304.             level = 0;
  1305.         row->tree.level = level;
  1306.         row->tree.expands = rows[i].expands;
  1307.         row->tree.isExpanded = rows[i].isExpanded;
  1308.  
  1309.         XtVaSetValues(w,
  1310.             XmNrow, position + i,
  1311.             XmNcolumn, 0,
  1312.             XmNcellString, rows[i].string,
  1313.             XmNcellPixmap, rows[i].pixmap,
  1314.             XmNcellPixmapMask, rows[i].pixmask,
  1315.             NULL);
  1316.         }
  1317.     if (layoutFrozen == False)
  1318.         XtVaSetValues(w,
  1319.             XmNlayoutFrozen, False,
  1320.             NULL);
  1321.     }
  1322.