fixed some Bool flags passed to WINgs functions to always set 1 or 0 values internally
[wmaker-crm.git] / WINGs / Extras / wtableview.c
blob3c173ff3bbe6b38f02c7b1ac072ee47bcfd05c99
3 #include <WINGs/WINGsP.h>
4 #include <X11/cursorfont.h>
6 #include "wtableview.h"
9 const char *WMTableViewSelectionDidChangeNotification = "WMTableViewSelectionDidChangeNotification";
12 struct W_TableColumn {
13 WMTableView *table;
14 WMWidget *titleW;
15 char *title;
16 int width;
17 int minWidth;
18 int maxWidth;
20 void *id;
22 WMTableColumnDelegate *delegate;
24 unsigned resizable:1;
25 unsigned editable:1;
30 static void handleResize(W_ViewDelegate *self, WMView *view);
32 static void rearrangeHeader(WMTableView *table);
34 static WMRange rowsInRect(WMTableView *table, WMRect rect);
37 WMTableColumn *WMCreateTableColumn(char *title)
39 WMTableColumn *col = wmalloc(sizeof(WMTableColumn));
41 col->table = NULL;
42 col->titleW = NULL;
43 col->width = 50;
44 col->minWidth = 5;
45 col->maxWidth = 0;
47 col->id = NULL;
49 col->title = wstrdup(title);
51 col->delegate = NULL;
53 col->resizable = 1;
54 col->editable = 0;
56 return col;
60 void WMSetTableColumnId(WMTableColumn *column, void *id)
62 column->id = id;
66 void *WMGetTableColumnId(WMTableColumn *column)
68 return column->id;
72 void WMSetTableColumnWidth(WMTableColumn *column, unsigned width)
74 if (column->maxWidth == 0)
75 column->width = WMAX(column->minWidth, width);
76 else
77 column->width = WMAX(column->minWidth, WMIN(column->maxWidth, width));
79 if (column->table) {
80 rearrangeHeader(column->table);
85 void WMSetTableColumnDelegate(WMTableColumn *column,
86 WMTableColumnDelegate *delegate)
88 column->delegate = delegate;
92 void WMSetTableColumnConstraints(WMTableColumn *column,
93 unsigned minWidth, unsigned maxWidth)
95 wassertr(maxWidth == 0 || minWidth <= maxWidth);
97 column->minWidth = minWidth;
98 column->maxWidth = maxWidth;
100 if (column->width < column->minWidth)
101 WMSetTableColumnWidth(column, column->minWidth);
102 else if (column->width > column->maxWidth && column->maxWidth != 0)
103 WMSetTableColumnWidth(column, column->maxWidth);
107 void WMSetTableColumnEditable(WMTableColumn *column, Bool flag)
109 column->editable = ((flag==0) ? 0 : 1);
113 WMTableView *WMGetTableColumnTableView(WMTableColumn *column)
115 return column->table;
120 struct W_TableView {
121 W_Class widgetClass;
122 WMView *view;
124 WMFrame *header;
126 WMLabel *corner;
128 WMScroller *hscroll;
129 WMScroller *vscroll;
130 WMView *tableView;
132 WMPixmap *viewBuffer;
134 WMArray *columns;
135 WMArray *splitters;
137 WMArray *selectedRows;
139 int tableWidth;
141 int rows;
143 WMColor *backColor;
145 GC gridGC;
146 WMColor *gridColor;
148 Cursor splitterCursor;
150 void *dataSource;
152 WMTableViewDelegate *delegate;
154 WMAction *action;
155 void *clientData;
157 void *clickedColumn;
158 int clickedRow;
160 int editingRow;
162 unsigned headerHeight;
164 unsigned rowHeight;
166 unsigned dragging:1;
167 unsigned drawsGrid:1;
168 unsigned canSelectRow:1;
169 unsigned canSelectMultiRows:1;
170 unsigned canDeselectRow:1;
173 static W_Class tableClass = 0;
176 static W_ViewDelegate viewDelegate = {
177 NULL,
178 NULL,
179 handleResize,
180 NULL,
181 NULL
188 static void handleEvents(XEvent *event, void *data);
189 static void handleTableEvents(XEvent *event, void *data);
190 static void repaintTable(WMTableView *table);
192 static WMSize getTotalSize(WMTableView *table)
194 WMSize size;
195 int i;
197 /* get width from columns */
198 size.width = 0;
199 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
200 WMTableColumn *column;
202 column = WMGetFromArray(table->columns, i);
204 size.width += column->width;
207 /* get height from rows */
208 size.height = table->rows * table->rowHeight;
210 return size;
214 static WMRect getVisibleRect(WMTableView *table)
216 WMSize size = getTotalSize(table);
217 WMRect rect;
219 rect.size.height = size.height * WMGetScrollerKnobProportion(table->vscroll);
220 rect.size.width = size.width * WMGetScrollerKnobProportion(table->hscroll);
222 rect.pos.x = (size.width - rect.size.width) * WMGetScrollerValue(table->hscroll);
223 rect.pos.y = (size.height - rect.size.height) * WMGetScrollerValue(table->vscroll);
225 return rect;
229 static void scrollToPoint(WMTableView *table, int x, int y)
231 WMSize size = getTotalSize(table);
232 int i;
233 float value, prop;
235 if (size.width > W_VIEW_WIDTH(table->tableView)) {
236 prop = (float)W_VIEW_WIDTH(table->tableView) / (float)size.width;
237 value = (float)x / (float)(size.width - W_VIEW_WIDTH(table->tableView));
238 } else {
239 prop = 1.0;
240 value = 0.0;
242 WMSetScrollerParameters(table->hscroll, value, prop);
245 if (size.height > W_VIEW_HEIGHT(table->tableView)) {
246 prop = (float)W_VIEW_HEIGHT(table->tableView) / (float)size.height;
247 value = (float)y / (float)(size.height - W_VIEW_HEIGHT(table->tableView));
248 } else {
249 prop = 1.0;
250 value = 0.0;
253 WMSetScrollerParameters(table->vscroll, value, prop);
257 if (table->editingRow >= 0) {
258 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
259 WMTableColumn *column;
261 column = WMGetFromArray(table->columns, i);
263 if (column->delegate && column->delegate->beginCellEdit)
264 (*column->delegate->beginCellEdit)(column->delegate, column,
265 table->editingRow);
269 repaintTable(table);
273 static void adjustScrollers(WMTableView *table)
275 WMSize size = getTotalSize(table);
276 WMSize vsize = WMGetViewSize(table->tableView);
277 float prop, value;
278 float oprop, ovalue;
280 if (size.width <= vsize.width) {
281 value = 0.0;
282 prop = 1.0;
283 } else {
284 oprop = WMGetScrollerKnobProportion(table->hscroll);
285 if (oprop == 0.0)
286 oprop = 1.0;
287 ovalue = WMGetScrollerValue(table->hscroll);
289 prop = (float)vsize.width/(float)size.width;
290 value = prop*ovalue / oprop;
292 WMSetScrollerParameters(table->hscroll, value, prop);
294 if (size.height <= vsize.height) {
295 value = 0.0;
296 prop = 1.0;
297 } else {
298 oprop = WMGetScrollerKnobProportion(table->vscroll);
299 oprop = WMGetScrollerKnobProportion(table->hscroll);
300 if (oprop == 0.0)
301 oprop = 1.0;
302 ovalue = WMGetScrollerValue(table->vscroll);
304 prop = (float)vsize.height/(float)size.height;
305 value = prop*ovalue / oprop;
307 WMSetScrollerParameters(table->vscroll, value, prop);
311 static void doScroll(WMWidget *self, void *data)
313 WMTableView *table = (WMTableView*)data;
314 float value;
315 float vpsize;
316 float size;
317 WMSize ts = getTotalSize(table);
319 value = WMGetScrollerValue(self);
321 if (table->hscroll == (WMScroller *)self) {
322 vpsize = W_VIEW_WIDTH(table->tableView);
323 size = ts.width;
324 } else {
325 vpsize = W_VIEW_HEIGHT(table->tableView);
326 size = ts.height;
329 switch (WMGetScrollerHitPart(self)) {
330 case WSDecrementWheel:
331 case WSDecrementLine:
332 value -= (float)table->rowHeight / size;
333 if (value < 0)
334 value = 0.0;
335 WMSetScrollerParameters(self, value,
336 WMGetScrollerKnobProportion(self));
337 repaintTable(table);
338 break;
340 case WSIncrementWheel:
341 case WSIncrementLine:
342 value += (float)table->rowHeight / size;
343 if (value > 1.0)
344 value = 1.0;
345 WMSetScrollerParameters(self, value,
346 WMGetScrollerKnobProportion(self));
347 repaintTable(table);
348 break;
350 case WSKnob:
351 repaintTable(table);
352 break;
354 case WSDecrementPage:
355 value -= vpsize / size;
356 if (value < 0.0)
357 value = 0.0;
358 WMSetScrollerParameters(self, value,
359 WMGetScrollerKnobProportion(self));
360 repaintTable(table);
361 break;
363 case WSIncrementPage:
364 value += vpsize / size;
365 if (value > 1.0)
366 value = 1.0;
367 WMSetScrollerParameters(self, value,
368 WMGetScrollerKnobProportion(self));
369 repaintTable(table);
370 break;
373 case WSNoPart:
374 case WSKnobSlot:
375 break;
378 if (table->editingRow >= 0) {
379 int i;
380 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
381 WMTableColumn *column;
383 column = WMGetFromArray(table->columns, i);
385 if (column->delegate && column->delegate->beginCellEdit)
386 (*column->delegate->beginCellEdit)(column->delegate, column,
387 table->editingRow);
392 if (table->hscroll == self) {
393 int x = 0;
394 int i;
395 WMRect rect = getVisibleRect(table);
397 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
398 WMTableColumn *column;
399 WMView *splitter;
401 column = WMGetFromArray(table->columns, i);
403 WMMoveWidget(column->titleW, x - rect.pos.x, 0);
405 x += W_VIEW_WIDTH(WMWidgetView(column->titleW)) + 1;
407 splitter = WMGetFromArray(table->splitters, i);
408 W_MoveView(splitter, x - rect.pos.x - 1, 0);
414 static void
415 splitterHandler(XEvent *event, void *data)
417 WMTableColumn *column = (WMTableColumn*)data;
418 WMTableView *table = column->table;
419 int done = 0;
420 int cx, ox, offsX;
421 WMPoint pos;
422 WMScreen *scr = WMWidgetScreen(table);
423 GC gc = scr->ixorGC;
424 Display *dpy = WMScreenDisplay(scr);
425 int h = WMWidgetHeight(table) - 22;
426 Window w = WMViewXID(table->view);
428 pos = WMGetViewPosition(WMWidgetView(column->titleW));
430 offsX = pos.x + column->width;
432 ox = cx = offsX;
434 XDrawLine(dpy, w, gc, cx+20, 0, cx+20, h);
436 while (!done) {
437 XEvent ev;
439 WMMaskEvent(dpy, ButtonMotionMask|ButtonReleaseMask, &ev);
441 switch (ev.type) {
442 case MotionNotify:
443 ox = cx;
445 if (column->width + ev.xmotion.x < column->minWidth)
446 cx = pos.x + column->minWidth;
447 else if (column->maxWidth > 0
448 && column->width + ev.xmotion.x > column->maxWidth)
449 cx = pos.x + column->maxWidth;
450 else
451 cx = offsX + ev.xmotion.x;
453 XDrawLine(dpy, w, gc, ox+20, 0, ox+20, h);
454 XDrawLine(dpy, w, gc, cx+20, 0, cx+20, h);
455 break;
457 case ButtonRelease:
458 column->width = cx - pos.x;
459 done = 1;
460 break;
464 XDrawLine(dpy, w, gc, cx+20, 0, cx+20, h);
465 rearrangeHeader(table);
466 repaintTable(table);
470 static void realizeTable(void *data, WMNotification *notif)
472 repaintTable(data);
476 WMTableView *WMCreateTableView(WMWidget *parent)
478 WMTableView *table = wmalloc(sizeof(WMTableView));
479 WMScreen *scr = WMWidgetScreen(parent);
481 memset(table, 0, sizeof(WMTableView));
483 if (!tableClass) {
484 tableClass = W_RegisterUserWidget();
486 table->widgetClass = tableClass;
488 table->view = W_CreateView(W_VIEW(parent));
489 if (!table->view)
490 goto error;
491 table->view->self = table;
493 table->view->delegate = &viewDelegate;
495 table->headerHeight = 20;
497 table->hscroll = WMCreateScroller(table);
498 WMSetScrollerAction(table->hscroll, doScroll, table);
499 WMMoveWidget(table->hscroll, 1, 2+table->headerHeight);
500 WMMapWidget(table->hscroll);
502 table->vscroll = WMCreateScroller(table);
503 WMSetScrollerArrowsPosition(table->vscroll, WSAMaxEnd);
504 WMSetScrollerAction(table->vscroll, doScroll, table);
505 WMMoveWidget(table->vscroll, 1, 2+table->headerHeight);
506 WMMapWidget(table->vscroll);
509 table->header = WMCreateFrame(table);
510 WMMoveWidget(table->header, 22, 2);
511 WMMapWidget(table->header);
512 WMSetFrameRelief(table->header, WRFlat);
514 table->corner = WMCreateLabel(table);
515 WMResizeWidget(table->corner, 20, table->headerHeight);
516 WMMoveWidget(table->corner, 2, 2);
517 WMMapWidget(table->corner);
518 WMSetLabelRelief(table->corner, WRRaised);
519 WMSetWidgetBackgroundColor(table->corner, scr->darkGray);
522 table->tableView = W_CreateView(table->view);
523 if (!table->tableView)
524 goto error;
525 table->tableView->self = table;
526 W_MapView(table->tableView);
528 WMAddNotificationObserver(realizeTable, table, WMViewRealizedNotification,
529 table->tableView);
531 table->tableView->flags.dontCompressExpose = 1;
533 table->gridColor = WMCreateNamedColor(scr, "#cccccc", False);
534 /* table->gridColor = WMGrayColor(scr);*/
537 XGCValues gcv;
539 table->backColor = WMWhiteColor(scr);
541 gcv.foreground = WMColorPixel(table->gridColor);
542 gcv.dashes = 1;
543 gcv.line_style = LineOnOffDash;
544 table->gridGC = XCreateGC(WMScreenDisplay(scr), W_DRAWABLE(scr),
545 GCForeground, &gcv);
548 table->editingRow = -1;
549 table->clickedRow = -1;
551 table->drawsGrid = 1;
552 table->rowHeight = 16;
554 table->tableWidth = 1;
556 table->columns = WMCreateArray(4);
557 table->splitters = WMCreateArray(4);
559 table->selectedRows = WMCreateArray(16);
561 table->splitterCursor = XCreateFontCursor(WMScreenDisplay(scr),
562 XC_sb_h_double_arrow);
564 table->canSelectRow = 1;
566 WMCreateEventHandler(table->view, ExposureMask|StructureNotifyMask,
567 handleEvents, table);
569 WMCreateEventHandler(table->tableView, ExposureMask|ButtonPressMask|
570 ButtonReleaseMask|ButtonMotionMask,
571 handleTableEvents, table);
573 WMResizeWidget(table, 50, 50);
575 return table;
577 error:
578 if (table->tableView)
579 W_DestroyView(table->tableView);
580 if (table->view)
581 W_DestroyView(table->view);
582 wfree(table);
583 return NULL;
587 void WMAddTableViewColumn(WMTableView *table, WMTableColumn *column)
589 WMScreen *scr = WMWidgetScreen(table);
591 column->table = table;
593 WMAddToArray(table->columns, column);
595 if (!column->titleW) {
596 column->titleW = WMCreateLabel(table);
597 WMSetLabelRelief(column->titleW, WRRaised);
598 WMSetLabelFont(column->titleW, scr->boldFont);
599 WMSetLabelTextColor(column->titleW, scr->white);
600 WMSetWidgetBackgroundColor(column->titleW, scr->darkGray);
601 WMSetLabelText(column->titleW, column->title);
602 W_ReparentView(WMWidgetView(column->titleW),
603 WMWidgetView(table->header), 0, 0);
604 if (W_VIEW_REALIZED(table->view))
605 WMRealizeWidget(column->titleW);
606 WMMapWidget(column->titleW);
610 WMView *splitter = W_CreateView(WMWidgetView(table->header));
612 W_SetViewBackgroundColor(splitter, WMWhiteColor(scr));
614 if (W_VIEW_REALIZED(table->view))
615 W_RealizeView(splitter);
617 W_ResizeView(splitter, 2, table->headerHeight);
618 W_MapView(splitter);
620 W_SetViewCursor(splitter, table->splitterCursor);
621 WMCreateEventHandler(splitter, ButtonPressMask|ButtonReleaseMask,
622 splitterHandler, column);
624 WMAddToArray(table->splitters, splitter);
627 rearrangeHeader(table);
631 void WMSetTableViewHeaderHeight(WMTableView *table, unsigned height)
633 table->headerHeight = height;
635 handleResize(NULL, table->view);
639 void WMSetTableViewDelegate(WMTableView *table, WMTableViewDelegate *delegate)
641 table->delegate = delegate;
645 void WMSetTableViewAction(WMTableView *table, WMAction *action, void *clientData)
647 table->action = action;
649 table->clientData = clientData;
653 void *WMGetTableViewClickedColumn(WMTableView *table)
655 return table->clickedColumn;
659 int WMGetTableViewClickedRow(WMTableView *table)
661 return table->clickedRow;
665 WMArray *WMGetTableViewSelectedRows(WMTableView *table)
667 return table->selectedRows;
671 WMView *WMGetTableViewDocumentView(WMTableView *table)
673 return table->tableView;
677 void *WMTableViewDataForCell(WMTableView *table, WMTableColumn *column,
678 int row)
680 return (*table->delegate->valueForCell)(table->delegate, column, row);
684 void WMSetTableViewDataForCell(WMTableView *table, WMTableColumn *column,
685 int row, void *data)
687 (*table->delegate->setValueForCell)(table->delegate, column, row, data);
691 WMRect WMTableViewRectForCell(WMTableView *table, WMTableColumn *column,
692 int row)
694 WMRect rect;
695 int i;
697 rect.pos.x = 0;
698 rect.pos.y = row * table->rowHeight;
699 rect.size.height = table->rowHeight;
701 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
702 WMTableColumn *col;
703 col = WMGetFromArray(table->columns, i);
705 if (col == column) {
706 rect.size.width = col->width;
707 break;
710 rect.pos.x += col->width;
714 WMRect r = getVisibleRect(table);
716 rect.pos.y -= r.pos.y;
717 rect.pos.x -= r.pos.x;
720 return rect;
724 void WMSetTableViewDataSource(WMTableView *table, void *source)
726 table->dataSource = source;
730 void *WMGetTableViewDataSource(WMTableView *table)
732 return table->dataSource;
736 void WMSetTableViewBackgroundColor(WMTableView *table, WMColor *color)
738 W_SetViewBackgroundColor(table->tableView, color);
740 if (table->backColor)
741 WMReleaseColor(table->backColor);
743 table->backColor = WMRetainColor(color);
745 repaintTable(table);
749 void WMSetTableViewGridColor(WMTableView *table, WMColor *color)
751 WMReleaseColor(table->gridColor);
752 table->gridColor = WMRetainColor(color);
753 XSetForeground(WMScreenDisplay(WMWidgetScreen(table)), table->gridGC,
754 WMColorPixel(color));
755 repaintTable(table);
760 void WMSetTableViewRowHeight(WMTableView *table, int height)
762 table->rowHeight = height;
764 repaintTable(table);
768 void WMScrollTableViewRowToVisible(WMTableView *table, int row)
770 WMScroller *scroller;
771 WMRange range;
772 WMRect rect;
773 int newY, tmp;
775 rect = getVisibleRect(table);
776 range = rowsInRect(table, rect);
778 scroller = table->vscroll;
780 if (row < range.position) {
781 newY = row * table->rowHeight - rect.size.height / 2;
782 } else if (row >= range.position + range.count) {
783 newY = row * table->rowHeight - rect.size.height / 2;
784 } else {
785 return;
787 tmp = table->rows*table->rowHeight - rect.size.height;
788 newY = WMAX(0, WMIN(newY, tmp));
790 scrollToPoint(table, rect.pos.x, newY);
795 static void drawGrid(WMTableView *table, WMRect rect)
797 WMScreen *scr = WMWidgetScreen(table);
798 Display *dpy = WMScreenDisplay(scr);
799 int i;
800 int y1, y2;
801 int x1, x2;
802 int xx;
803 Drawable d = WMGetPixmapXID(table->viewBuffer);
804 GC gc = table->gridGC;
806 #if 0
807 char dashl[1] = {1};
809 XSetDashes(dpy, gc, 0, dashl, 1);
811 y1 = (rect.pos.y/table->rowHeight - 1)*table->rowHeight;
812 y2 = y1 + (rect.size.height/table->rowHeight+2)*table->rowHeight;
813 #endif
814 y1 = 0;
815 y2 = W_VIEW_HEIGHT(table->tableView);
817 xx = -rect.pos.x;
818 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
819 WMTableColumn *column;
821 XDrawLine(dpy, d, gc, xx, y1, xx, y2);
823 column = WMGetFromArray(table->columns, i);
824 xx += column->width;
826 XDrawLine(dpy, d, gc, xx, y1, xx, y2);
828 x1 = 0;
829 x2 = rect.size.width;
831 if (x2 <= x1)
832 return;
833 #if 0
834 XSetDashes(dpy, gc, (rect.pos.x&1), dashl, 1);
835 #endif
837 y1 = -rect.pos.y%table->rowHeight;
838 y2 = y1 + rect.size.height + table->rowHeight;
840 for (i = y1; i <= y2; i += table->rowHeight) {
841 XDrawLine(dpy, d, gc, x1, i, x2, i);
846 static WMRange columnsInRect(WMTableView *table, WMRect rect)
848 WMTableColumn *column;
849 int width;
850 int i , j;
851 int totalColumns = WMGetArrayItemCount(table->columns);
852 WMRange range;
854 j = 0;
855 width = 0;
856 for (i = 0; i < totalColumns; i++) {
857 column = WMGetFromArray(table->columns, i);
858 if (j == 0) {
859 if (width <= rect.pos.x && width + column->width > rect.pos.x) {
860 range.position = i;
861 j = 1;
863 } else {
864 range.count++;
865 if (width > rect.pos.x + rect.size.width) {
866 break;
869 width += column->width;
871 range.count = WMAX(1, WMIN(range.count, totalColumns - range.position));
872 return range;
876 static WMRange rowsInRect(WMTableView *table, WMRect rect)
878 WMRange range;
879 int rh = table->rowHeight;
880 int dif;
882 dif = rect.pos.y % rh;
884 range.position = WMAX(0, (rect.pos.y - dif) / rh);
885 range.count = WMAX(1, WMIN((rect.size.height + dif) / rh, table->rows));
887 return range;
891 static void drawRow(WMTableView *table, int row, WMRect clipRect)
893 int i;
894 WMRange cols = columnsInRect(table, clipRect);
895 WMTableColumn *column;
896 Drawable d = WMGetPixmapXID(table->viewBuffer);
898 for (i = cols.position; i < cols.position+cols.count; i++) {
899 column = WMGetFromArray(table->columns, i);
901 if (!column->delegate || !column->delegate->drawCell)
902 continue;
904 if (WMFindInArray(table->selectedRows, NULL, (void*)row) != WANotFound)
905 (*column->delegate->drawSelectedCell)(column->delegate, column, row, d);
906 else
907 (*column->delegate->drawCell)(column->delegate, column, row, d);
912 #if 0
913 static void drawFullRow(WMTableView *table, int row)
915 int i;
916 WMTableColumn *column;
917 Drawable d = WMGetPixmapXID(table->viewBuffer);
919 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
920 column = WMGetFromArray(table->columns, i);
922 if (!column->delegate || !column->delegate->drawCell)
923 continue;
925 if (WMFindInArray(table->selectedRows, NULL, (void*)row) != WANotFound)
926 (*column->delegate->drawSelectedCell)(column->delegate, column, row, d);
927 else
928 (*column->delegate->drawCell)(column->delegate, column, row, d);
931 #endif
934 static void setRowSelected(WMTableView *table, unsigned row, Bool flag)
936 int repaint = 0;
938 if (WMFindInArray(table->selectedRows, NULL, (void*)row) != WANotFound) {
939 if (!flag) {
940 WMRemoveFromArray(table->selectedRows, (void*)row);
941 repaint = 1;
943 } else {
944 if (flag) {
945 WMAddToArray(table->selectedRows, (void*)row);
946 repaint = 1;
949 if (repaint && row < table->rows) {
950 /*drawFullRow(table, row);*/
951 repaintTable(table);
956 static void repaintTable(WMTableView *table)
958 WMRect rect;
959 WMRange rows;
960 WMScreen *scr = WMWidgetScreen(table);
961 int i;
963 if (!table->delegate || !W_VIEW_REALIZED(table->view))
964 return;
966 wassertr(table->delegate->numberOfRows);
968 if (!table->viewBuffer) {
969 table->viewBuffer = WMCreatePixmap(scr,
970 W_VIEW_WIDTH(table->tableView),
971 W_VIEW_HEIGHT(table->tableView),
972 WMScreenDepth(scr), 0);
975 XFillRectangle(scr->display,
976 WMGetPixmapXID(table->viewBuffer),
977 WMColorGC(table->backColor), 0, 0,
978 W_VIEW_WIDTH(table->tableView),
979 W_VIEW_HEIGHT(table->tableView));
981 rect = getVisibleRect(table);
983 if (table->drawsGrid) {
984 drawGrid(table, rect);
987 rows = rowsInRect(table, rect);
988 for (i = rows.position;
989 i < WMIN(rows.position+rows.count + 1, table->rows);
990 i++) {
991 drawRow(table, i, rect);
994 XSetWindowBackgroundPixmap(scr->display, table->tableView->window,
995 WMGetPixmapXID(table->viewBuffer));
996 XClearWindow(scr->display, table->tableView->window);
1000 static void stopRowEdit(WMTableView *table, int row)
1002 int i;
1003 WMTableColumn *column;
1005 table->editingRow = -1;
1006 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
1007 column = WMGetFromArray(table->columns, i);
1009 if (column->delegate && column->delegate->endCellEdit)
1010 (*column->delegate->endCellEdit)(column->delegate, column, row);
1016 void WMEditTableViewRow(WMTableView *table, int row)
1018 int i;
1019 WMTableColumn *column;
1021 if (table->editingRow >= 0) {
1022 stopRowEdit(table, table->editingRow);
1025 table->editingRow = row;
1027 if (row < 0)
1028 return;
1030 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
1031 column = WMGetFromArray(table->columns, i);
1033 if (column->delegate && column->delegate->beginCellEdit)
1034 (*column->delegate->beginCellEdit)(column->delegate, column, row);
1039 void WMSelectTableViewRow(WMTableView *table, int row)
1041 if (table->clickedRow >= 0)
1042 setRowSelected(table, table->clickedRow, False);
1044 if (row >= table->rows) {
1045 return;
1048 setRowSelected(table, row, True);
1049 table->clickedRow = row;
1051 if (table->action)
1052 (*table->action)(table, table->clientData);
1053 WMPostNotificationName(WMTableViewSelectionDidChangeNotification,
1054 table, NULL);
1058 void WMReloadTableView(WMTableView *table)
1060 if (table->editingRow >= 0)
1061 stopRowEdit(table, table->editingRow);
1063 /* when this is called, nothing in the table can be assumed to be
1064 * like the last time we accessed it (ie, rows might have disappeared) */
1066 WMEmptyArray(table->selectedRows);
1068 if (table->clickedRow >= 0) {
1069 table->clickedRow = -1;
1071 if (table->action)
1072 (*table->action)(table, table->clientData);
1073 WMPostNotificationName(WMTableViewSelectionDidChangeNotification,
1074 table, NULL);
1077 if (table->delegate && table->delegate->numberOfRows) {
1078 int rows;
1080 rows = (*table->delegate->numberOfRows)(table->delegate, table);
1082 if (rows != table->rows) {
1083 table->rows = rows;
1084 handleResize(table->view->delegate, table->view);
1085 } else {
1086 repaintTable(table);
1092 void WMNoteTableViewNumberOfRowsChanged(WMTableView *table)
1094 WMReloadTableView(table);
1098 static void handleTableEvents(XEvent *event, void *data)
1100 WMTableView *table = (WMTableView*)data;
1101 int row;
1103 switch (event->type) {
1104 case ButtonPress:
1105 if (event->xbutton.button == Button1) {
1106 WMRect rect = getVisibleRect(table);
1108 row = (event->xbutton.y + rect.pos.y)/table->rowHeight;
1109 if (row != table->clickedRow) {
1110 setRowSelected(table, table->clickedRow, False);
1111 setRowSelected(table, row, True);
1112 table->clickedRow = row;
1113 table->dragging = 1;
1114 } else {
1115 table->dragging = 1;
1118 break;
1120 case MotionNotify:
1121 if (table->dragging && event->xmotion.y >= 0) {
1122 WMRect rect = getVisibleRect(table);
1124 row = (event->xmotion.y + rect.pos.y)/table->rowHeight;
1125 if (table->clickedRow != row && row >= 0 && row < table->rows) {
1126 setRowSelected(table, table->clickedRow, False);
1127 setRowSelected(table, row, True);
1128 table->clickedRow = row;
1131 break;
1133 case ButtonRelease:
1134 if (event->xbutton.button == Button1) {
1135 if (table->action)
1136 (*table->action)(table, table->clientData);
1137 WMPostNotificationName(WMTableViewSelectionDidChangeNotification,
1138 table, NULL);
1139 table->dragging = 0;
1141 break;
1146 static void handleEvents(XEvent *event, void *data)
1148 WMTableView *table = (WMTableView*)data;
1149 WMScreen *scr = WMWidgetScreen(table);
1151 switch (event->type) {
1152 case Expose:
1153 W_DrawRelief(scr, W_VIEW_DRAWABLE(table->view), 0, 0,
1154 W_VIEW_WIDTH(table->view), W_VIEW_HEIGHT(table->view),
1155 WRSunken);
1156 break;
1161 static void handleResize(W_ViewDelegate *self, WMView *view)
1163 int width;
1164 int height;
1165 WMTableView *table = view->self;
1166 WMSize size = getTotalSize(table);
1167 int vw, vh;
1169 width = W_VIEW_WIDTH(view) - 2;
1170 height = W_VIEW_HEIGHT(view) - 3;
1172 height -= table->headerHeight; /* table header */
1174 if (table->corner)
1175 WMResizeWidget(table->corner, 20, table->headerHeight);
1177 WMMoveWidget(table->vscroll, 1, table->headerHeight + 1);
1178 WMResizeWidget(table->vscroll, 20, height + 1);
1180 WMMoveWidget(table->hscroll, 20, W_VIEW_HEIGHT(view) - 20 - 1);
1181 WMResizeWidget(table->hscroll, width-20+1, 20);
1183 if (table->header)
1184 WMResizeWidget(table->header, width - 21, table->headerHeight);
1186 if (table->viewBuffer) {
1187 WMReleasePixmap(table->viewBuffer);
1188 table->viewBuffer = NULL;
1191 width -= 20;
1192 height -= 20;
1194 vw = WMIN(size.width, width);
1195 vh = WMIN(size.height, height);
1197 W_MoveView(table->tableView, 21, 1+table->headerHeight+1);
1198 W_ResizeView(table->tableView, WMAX(vw, 1), WMAX(vh, 1)+1);
1200 adjustScrollers(table);
1202 repaintTable(table);
1206 static void rearrangeHeader(WMTableView *table)
1208 int width;
1209 int count;
1210 int i;
1211 /*WMRect rect = WMGetScrollViewVisibleRect(table->scrollView);*/
1213 width = 0;
1215 count = WMGetArrayItemCount(table->columns);
1216 for (i = 0; i < count; i++) {
1217 WMTableColumn *column = WMGetFromArray(table->columns, i);
1218 WMView *splitter = WMGetFromArray(table->splitters, i);
1220 WMMoveWidget(column->titleW, width, 0);
1221 WMResizeWidget(column->titleW, column->width-1, table->headerHeight);
1223 width += column->width;
1224 W_MoveView(splitter, width-1, 0);
1227 wassertr(table->delegate && table->delegate->numberOfRows);
1229 table->rows = table->delegate->numberOfRows(table->delegate, table);
1231 table->tableWidth = width + 1;
1233 handleResize(table->view->delegate, table->view);