1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 #include <Xm/Xm.h>
51 #include <Xm/Text.h>
52 #include <XmL/Grid.h>
53
54
55
56 int dbTableNumRows =
14;
57 int dbTableNumColumns =
5;
58
59 typedef enum {
60 ID, Desc, Price, Qty, UnitPrice, Buyer
61 }
62 DbTableColumnID;
63
64 typedef struct
65 {
66 DbTableColumnID id;
67 char label[
15];
68 int width;
69 unsigned char cellAlignment;
70 Boolean cellEditable;
71 } DbTableColumn;
72
73 DbTableColumn dbTableColumns[] =
74 {
75 { Desc,
"Description",
16, XmALIGNMENT_LEFT, True },
76 { Price,
"Price",
9, XmALIGNMENT_LEFT, True },
77 { Qty,
"Qty",
5, XmALIGNMENT_LEFT, True },
78 { UnitPrice,
"Unit Prc",
9, XmALIGNMENT_LEFT, False },
79 { Buyer,
"Buyer",
15, XmALIGNMENT_LEFT, True },
80 };
81
82 typedef struct
83 {
84 char key[
10];
85 char desc[
20];
86 float price;
87 int qty;
88 char buyer[
20];
89 } DbTableRow;
90
91 DbTableRow dbTableRows[] =
92 {
93 {
"key01",
"Staples",
1.
32,
100,
"Tim Pick" },
94 {
"key02",
"Notebooks",
1.
11,
4,
"Mary Miner" },
95 {
"key03",
"3-Ring Binders",
2.
59,
2,
"Mary Miner" },
96 {
"key04",
"Pads",
1.
23,
3,
"Tim Pick" },
97 {
"key05",
"Scissors",
4.
41,
1,
"Mary Miner" },
98 {
"key06",
"Pens", .
29,
4,
"Mary Miner" },
99 {
"key07",
"Pencils", .
10,
5,
"Tim Pick" },
100 {
"key08",
"Markers", .
95,
3,
"Mary Miner" },
101 {
"key09",
"Fax Paper",
3.
89,
100,
"Bob Coal" },
102 {
"key10",
"3.5\" Disks",
15.
23,
30,
"Tim Pick" },
103 {
"key11",
"8mm Tape",
32.
22,
2,
"Bob Coal" },
104 {
"key12",
"Toner",
35.
69,
1,
"Tim Pick" },
105 {
"key13",
"Paper Cups",
4.
25,
3,
"Bob Coal" },
106 {
"key14",
"Paper Clips",
2.
09,
3,
"Tim Pick" },
107 };
108
109 DbTableRow *dbFindRow(rowKey)
110 char *rowKey;
111 {
112 int i;
113
114 for (i =
0; i < dbTableNumRows; i++)
115 if (!strcmp(rowKey, dbTableRows[i].key))
116 return &dbTableRows[i];
117 return 0;
118 }
119
120 int dbCompareRowKeys(userData, l, r)
121 void *userData;
122 void *l;
123 void *r;
124 {
125 DbTableRow *dbRow1, *dbRow2;
126 float u1, u2;
127
128 dbRow1 = dbFindRow(*(
char **)l);
129 dbRow2 = dbFindRow(*(
char **)r);
130 switch ((
int)userData)
131 {
132 case Desc:
133 return strcmp(dbRow1->desc, dbRow2->desc);
134 case Price:
135 u1 = dbRow1->price - dbRow2->price;
136 if (u1 <
0)
137 return -
1;
138 else if (u1 ==
0)
139 return 0;
140 return 1;
141 case Qty:
142 return dbRow1->qty - dbRow2->qty;
143 case UnitPrice:
144 u1 = dbRow1->price / (
float)dbRow1->qty;
145 u2 = dbRow2->price / (
float)dbRow2->qty;
146 if (u1 < u2)
147 return -
1;
148 else if (u1 == u2)
149 return 0;
150 else
151 return 1;
152 case Buyer:
153 return strcmp(dbRow1->buyer, dbRow2->buyer);
154 }
155 return (
int)(dbRow1 - dbRow2);
156 }
157
158 char **dbGetRowKeysSorted(sortColumnID)
159 int sortColumnID;
160 {
161 char **keys;
162 int i;
163
164 keys = (
char **)malloc(
sizeof(
char *) * dbTableNumRows);
165 for (i =
0; i < dbTableNumRows; i++)
166 keys[i] = dbTableRows[i].key;
167 XmLSort(keys, dbTableNumRows,
sizeof(
char *),
168 dbCompareRowKeys, (
void *)sortColumnID);
169 return keys;
170 }
171
172
173
174 void setRowKeysInGridSorted(grid, sortColumnID)
175 Widget grid;
176 int sortColumnID;
177 {
178 char **keys;
179 int i;
180
181 keys = dbGetRowKeysSorted(sortColumnID);
182
183 for (i =
0; i < dbTableNumRows; i++)
184 XtVaSetValues(grid,
185 XmNrow, i,
186 XmNrowUserData, (XtPointer)keys[i],
187 NULL);
188 free((
char *)keys);
189 }
190
191 void cellSelect(w, clientData, callData)
192 Widget w;
193 XtPointer clientData;
194 XtPointer callData;
195 {
196 XmLGridCallbackStruct *cbs;
197 XmLGridColumn column;
198 XtPointer columnUserData;
199
200 cbs = (XmLGridCallbackStruct *)callData;
201
202 if (cbs->rowType != XmHEADING)
203 return;
204
205
206 XmLGridEditCancel(w);
207
208 column = XmLGridGetColumn(w, cbs->columnType, cbs->column);
209 XtVaGetValues(w,
210 XmNcolumnPtr, column,
211 XmNcolumnUserData, &columnUserData,
212 NULL);
213 XtVaSetValues(w,
214 XmNcolumn, cbs->column,
215 XmNcolumnSortType, XmSORT_ASCENDING,
216 NULL);
217 setRowKeysInGridSorted(w, (DbTableColumnID)columnUserData);
218 XmLGridRedrawAll(w);
219 }
220
221 void cellDraw(w, clientData, callData)
222 Widget w;
223 XtPointer clientData;
224 XtPointer callData;
225 {
226 XmLGridCallbackStruct *cbs;
227 XmLGridDrawStruct *ds;
228 XmLGridRow row;
229 XmLGridColumn column;
230 XtPointer rowUserData, columnUserData;
231 DbTableRow *dbRow;
232 XRectangle cellRect;
233 int horizMargin, vertMargin;
234 XmString str;
235 char buf[
50];
236
237 cbs = (XmLGridCallbackStruct *)callData;
238 if (cbs->rowType != XmCONTENT)
239 return;
240
241 ds = cbs->drawInfo;
242
243
244 row = XmLGridGetRow(w, cbs->rowType, cbs->row);
245 XtVaGetValues(w,
246 XmNrowPtr, row,
247 XmNrowUserData, &rowUserData,
248 NULL);
249
250
251 column = XmLGridGetColumn(w, cbs->columnType, cbs->column);
252 XtVaGetValues(w,
253 XmNcolumnPtr, column,
254 XmNcolumnUserData, &columnUserData,
255 NULL);
256
257
258 dbRow = dbFindRow((
char *)rowUserData);
259 switch ((DbTableColumnID)columnUserData)
260 {
261 case Desc:
262 sprintf(buf,
"%s", dbRow->desc);
263 break;
264 case Price:
265 sprintf(buf,
"$%4.2f", dbRow->price);
266 break;
267 case Qty:
268 sprintf(buf,
"%d", dbRow->qty);
269 break;
270 case UnitPrice:
271 sprintf(buf,
"$%4.2f", dbRow->price / (
float)dbRow->qty);
272 break;
273 case Buyer:
274 sprintf(buf,
"%s", dbRow->buyer);
275 break;
276 }
277
278
279 cellRect = *ds->cellRect;
280 horizMargin = ds->leftMargin + ds->rightMargin;
281 vertMargin = ds->topMargin + ds->bottomMargin;
282 if (horizMargin >= (
int)cellRect.width ||
283 vertMargin >= (
int)cellRect.height)
284 return;
285 cellRect.x += ds->leftMargin;
286 cellRect.y += ds->topMargin;
287 cellRect.width -= horizMargin;
288 cellRect.height -= vertMargin;
289
290
291 str = XmStringCreateSimple(buf);
292 if (ds->drawSelected == True)
293 XSetForeground(XtDisplay(w), ds->gc, ds->selectForeground);
294 else
295 XSetForeground(XtDisplay(w), ds->gc, ds->foreground);
296 XmLStringDraw(w, str, ds->stringDirection, ds->fontList,
297 ds->alignment, ds->gc, &cellRect, cbs->clipRect);
298 XmStringFree(str);
299 }
300
301 void cellEdit(w, clientData, callData)
302 Widget w;
303 XtPointer clientData;
304 XtPointer callData;
305 {
306 XmLGridCallbackStruct *cbs;
307 XmLGridRow row;
308 XmLGridColumn column;
309 XtPointer rowUserData, columnUserData;
310 DbTableRow *dbRow;
311 Widget text;
312 float f;
313 int i;
314 char *value;
315 Boolean redrawRow;
316
317 cbs = (XmLGridCallbackStruct *)callData;
318
319
320
321
322
323
324
325 if (cbs->reason != XmCR_EDIT_COMPLETE)
326 return;
327
328
329 XtVaGetValues(w,
330 XmNtextWidget, &text,
331 NULL);
332 value = XmTextGetString(text);
333 if (!value)
334 return;
335
336
337 row = XmLGridGetRow(w, cbs->rowType, cbs->row);
338 XtVaGetValues(w,
339 XmNrowPtr, row,
340 XmNrowUserData, &rowUserData,
341 NULL);
342
343
344 column = XmLGridGetColumn(w, cbs->columnType, cbs->column);
345 XtVaGetValues(w,
346 XmNcolumnPtr, column,
347 XmNcolumnUserData, &columnUserData,
348 NULL);
349
350
351 redrawRow = False;
352 dbRow = dbFindRow((
char *)rowUserData);
353 switch ((DbTableColumnID)columnUserData)
354 {
355 case Desc:
356 if ((
int)strlen(value) <
20)
357 strcpy(dbRow->desc, value);
358 break;
359 case Price:
360 if (sscanf(value,
"%f", &f) ==
1)
361 {
362 dbRow->price = f;
363 redrawRow = True;
364 }
365 break;
366 case Qty:
367 if (sscanf(value,
"%d", &i) ==
1)
368 {
369 dbRow->qty = i;
370 redrawRow = True;
371 }
372 break;
373 case Buyer:
374 if ((
int)strlen(value) <
20)
375 strcpy(dbRow->buyer, value);
376 break;
377 }
378
379
380 if (redrawRow == True)
381 XmLGridRedrawRow(w, cbs->rowType, cbs->row);
382
383
384
385 XtVaSetValues(w,
386 XmNrow, cbs->row,
387 XmNcolumn, cbs->column,
388 XmNcellString,
NULL,
389 NULL);
390
391 XtFree(value);
392 }
393
394 main(argc, argv)
395 int argc;
396 char *argv[];
397 {
398 XtAppContext app;
399 Widget shell, grid;
400 XmString str;
401 int i;
402
403 shell = XtAppInitialize(&app,
"Grid6",
NULL,
0,
404 &argc, argv,
NULL,
NULL,
0);
405
406 grid = XtVaCreateManagedWidget(
"grid",
407 xmlGridWidgetClass, shell,
408 XmNhorizontalSizePolicy, XmVARIABLE,
409 XmNvisibleRows,
10,
410 XmNvsbDisplayPolicy, XmSTATIC,
411 XmNselectionPolicy, XmSELECT_NONE,
412 XmNshadowThickness,
0,
413 XtVaTypedArg, XmNbackground, XmRString,
"#C0C0C0",
8,
414 XtVaTypedArg, XmNforeground, XmRString,
"black",
6,
415 NULL);
416 XtAddCallback(grid, XmNcellDrawCallback, cellDraw,
NULL);
417 XtAddCallback(grid, XmNeditCallback, cellEdit,
NULL);
418 XtAddCallback(grid, XmNselectCallback, cellSelect,
NULL);
419
420 XtVaSetValues(grid,
421 XmNlayoutFrozen, True,
422 NULL);
423
424 XmLGridAddColumns(grid, XmCONTENT, -
1, dbTableNumColumns);
425
426
427
428 for (i =
0; i < dbTableNumColumns; i++)
429 {
430
431 XtVaSetValues(grid,
432 XmNcolumn, i,
433 XmNcolumnUserData, (XtPointer)dbTableColumns[i].id,
434 XmNcolumnWidth, dbTableColumns[i].width,
435 NULL);
436
437
438
439 XtVaSetValues(grid,
440 XmNcellDefaults, True,
441 XmNcolumn, i,
442 XmNcellAlignment, dbTableColumns[i].cellAlignment,
443 XmNcellEditable, dbTableColumns[i].cellEditable,
444 NULL);
445 }
446
447
448 XmLGridAddRows(grid, XmHEADING, -
1,
1);
449
450
451 for (i =
0; i < dbTableNumColumns; i++)
452 {
453
454 str = XmStringCreateSimple(dbTableColumns[i].label);
455 XtVaSetValues(grid,
456 XmNrowType, XmHEADING,
457 XmNrow,
0,
458 XmNcolumn, i,
459 XmNcellString, str,
460 NULL);
461 XmStringFree(str);
462 }
463
464
465 XtVaSetValues(grid,
466 XmNcellDefaults, True,
467 XtVaTypedArg, XmNcellBackground, XmRString,
"white",
6,
468 XmNcellLeftBorderType, XmBORDER_NONE,
469 XmNcellRightBorderType, XmBORDER_NONE,
470 XmNcellTopBorderType, XmBORDER_NONE,
471 XmNcellBottomBorderType, XmBORDER_NONE,
472 XmNcellMarginLeft,
1,
473 XmNcellMarginRight,
1,
474 NULL);
475
476 XmLGridAddRows(grid, XmCONTENT, -
1, dbTableNumRows);
477
478 XtVaSetValues(grid,
479 XmNlayoutFrozen, False,
480 NULL);
481
482
483 setRowKeysInGridSorted(grid, Desc);
484
485 XtRealizeWidget(shell);
486 XtAppMainLoop(app);
487 }
488