Fixed compilation warning caused by wrong parameter passed to function.
[wmaker-crm.git] / WINGs / Extras / wtableview.c
blobbd467569699e3501ddaff89fcb9055fd96a2baff
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;
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)size.width / (float)W_VIEW_WIDTH(table->tableView);
237 value = 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)size.height / (float)W_VIEW_HEIGHT(table->tableView);
247 value = y * (float)(size.height - W_VIEW_HEIGHT(table->tableView));
248 } else {
249 prop = 1.0;
250 value = 0.0;
252 WMSetScrollerParameters(table->vscroll, value, prop);
256 if (table->editingRow >= 0) {
257 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
258 WMTableColumn *column;
260 column = WMGetFromArray(table->columns, i);
262 if (column->delegate && column->delegate->beginCellEdit)
263 (*column->delegate->beginCellEdit)(column->delegate, column,
264 table->editingRow);
268 repaintTable(table);
272 static void adjustScrollers(WMTableView *table)
274 WMSize size = getTotalSize(table);
275 WMSize vsize = WMGetViewSize(table->tableView);
276 float prop, value;
277 float oprop, ovalue;
279 if (size.width <= vsize.width) {
280 value = 0.0;
281 prop = 1.0;
282 } else {
283 oprop = WMGetScrollerKnobProportion(table->hscroll);
284 if (oprop == 0.0)
285 oprop = 1.0;
286 ovalue = WMGetScrollerValue(table->hscroll);
288 prop = (float)vsize.width/(float)size.width;
289 value = prop*ovalue / oprop;
291 WMSetScrollerParameters(table->hscroll, value, prop);
293 if (size.height <= vsize.height) {
294 value = 0.0;
295 prop = 1.0;
296 } else {
297 oprop = WMGetScrollerKnobProportion(table->vscroll);
298 oprop = WMGetScrollerKnobProportion(table->hscroll);
299 if (oprop == 0.0)
300 oprop = 1.0;
301 ovalue = WMGetScrollerValue(table->vscroll);
303 prop = (float)vsize.height/(float)size.height;
304 value = prop*ovalue / oprop;
306 WMSetScrollerParameters(table->vscroll, value, prop);
310 static void doScroll(WMWidget *self, void *data)
312 WMTableView *table = (WMTableView*)data;
313 float value;
314 float vpsize;
315 float size;
316 WMSize ts = getTotalSize(table);
318 value = WMGetScrollerValue(self);
320 if (table->hscroll == (WMScroller *)self) {
321 vpsize = W_VIEW_WIDTH(table->tableView);
322 size = ts.width;
323 } else {
324 vpsize = W_VIEW_HEIGHT(table->tableView);
325 size = ts.height;
328 switch (WMGetScrollerHitPart(self)) {
329 case WSDecrementWheel:
330 case WSDecrementLine:
331 value -= (float)table->rowHeight / size;
332 if (value < 0)
333 value = 0.0;
334 WMSetScrollerParameters(self, value,
335 WMGetScrollerKnobProportion(self));
336 repaintTable(table);
337 break;
339 case WSIncrementWheel:
340 case WSIncrementLine:
341 value += (float)table->rowHeight / size;
342 if (value > 1.0)
343 value = 1.0;
344 WMSetScrollerParameters(self, value,
345 WMGetScrollerKnobProportion(self));
346 repaintTable(table);
347 break;
349 case WSKnob:
350 repaintTable(table);
351 break;
353 case WSDecrementPage:
354 value -= vpsize / size;
355 if (value < 0.0)
356 value = 0.0;
357 WMSetScrollerParameters(self, value,
358 WMGetScrollerKnobProportion(self));
359 repaintTable(table);
360 break;
362 case WSIncrementPage:
363 value += vpsize / size;
364 if (value > 1.0)
365 value = 1.0;
366 WMSetScrollerParameters(self, value,
367 WMGetScrollerKnobProportion(self));
368 repaintTable(table);
369 break;
372 case WSNoPart:
373 case WSKnobSlot:
374 break;
377 if (table->editingRow >= 0) {
378 int i;
379 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
380 WMTableColumn *column;
382 column = WMGetFromArray(table->columns, i);
384 if (column->delegate && column->delegate->beginCellEdit)
385 (*column->delegate->beginCellEdit)(column->delegate, column,
386 table->editingRow);
391 if (table->hscroll == self) {
392 int x = 0;
393 int i;
394 WMRect rect = getVisibleRect(table);
396 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
397 WMTableColumn *column;
398 WMView *splitter;
400 column = WMGetFromArray(table->columns, i);
402 WMMoveWidget(column->titleW, x - rect.pos.x, 0);
404 x += W_VIEW_WIDTH(WMWidgetView(column->titleW)) + 1;
406 splitter = WMGetFromArray(table->splitters, i);
407 W_MoveView(splitter, x - rect.pos.x - 1, 0);
413 static void splitterHandler(XEvent *event, void *data)
415 WMTableColumn *column = (WMTableColumn*)data;
416 WMTableView *table = column->table;
417 int done = 0;
418 int cx, ox, offsX;
419 WMPoint pos;
420 WMScreen *scr = WMWidgetScreen(table);
421 GC gc = scr->ixorGC;
422 Display *dpy = WMScreenDisplay(scr);
423 int h = WMWidgetHeight(table) - 22;
424 Window w = WMViewXID(table->view);
426 pos = WMGetViewPosition(WMWidgetView(column->titleW));
428 offsX = pos.x + column->width;
430 ox = cx = offsX;
432 XDrawLine(dpy, w, gc, cx+20, 0, cx+20, h);
434 while (!done) {
435 XEvent ev;
437 WMMaskEvent(dpy, ButtonMotionMask|ButtonReleaseMask, &ev);
439 switch (ev.type) {
440 case MotionNotify:
441 ox = cx;
443 if (column->width + ev.xmotion.x < column->minWidth)
444 cx = pos.x + column->minWidth;
445 else if (column->maxWidth > 0
446 && column->width + ev.xmotion.x > column->maxWidth)
447 cx = pos.x + column->maxWidth;
448 else
449 cx = offsX + ev.xmotion.x;
451 XDrawLine(dpy, w, gc, ox+20, 0, ox+20, h);
452 XDrawLine(dpy, w, gc, cx+20, 0, cx+20, h);
453 break;
455 case ButtonRelease:
456 column->width = cx - pos.x;
457 done = 1;
458 break;
462 XDrawLine(dpy, w, gc, cx+20, 0, cx+20, h);
463 rearrangeHeader(table);
464 repaintTable(table);
468 static void realizeTable(void *data, WMNotification *notif)
470 repaintTable(data);
474 WMTableView *WMCreateTableView(WMWidget *parent)
476 WMTableView *table = wmalloc(sizeof(WMTableView));
477 WMScreen *scr = WMWidgetScreen(parent);
479 memset(table, 0, sizeof(WMTableView));
481 if (!tableClass) {
482 tableClass = W_RegisterUserWidget();
484 table->widgetClass = tableClass;
486 table->view = W_CreateView(W_VIEW(parent));
487 if (!table->view)
488 goto error;
489 table->view->self = table;
491 table->view->delegate = &viewDelegate;
493 table->headerHeight = 20;
495 table->hscroll = WMCreateScroller(table);
496 WMSetScrollerAction(table->hscroll, doScroll, table);
497 WMMoveWidget(table->hscroll, 1, 2+table->headerHeight);
498 WMMapWidget(table->hscroll);
500 table->vscroll = WMCreateScroller(table);
501 WMSetScrollerArrowsPosition(table->vscroll, WSAMaxEnd);
502 WMSetScrollerAction(table->vscroll, doScroll, table);
503 WMMoveWidget(table->vscroll, 1, 2+table->headerHeight);
504 WMMapWidget(table->vscroll);
507 table->header = WMCreateFrame(table);
508 WMMoveWidget(table->header, 22, 2);
509 WMMapWidget(table->header);
510 WMSetFrameRelief(table->header, WRFlat);
512 table->corner = WMCreateLabel(table);
513 WMResizeWidget(table->corner, 20, table->headerHeight);
514 WMMoveWidget(table->corner, 2, 2);
515 WMMapWidget(table->corner);
516 WMSetLabelRelief(table->corner, WRRaised);
517 WMSetWidgetBackgroundColor(table->corner, scr->darkGray);
520 table->tableView = W_CreateView(table->view);
521 if (!table->tableView)
522 goto error;
523 table->tableView->self = table;
524 W_MapView(table->tableView);
526 WMAddNotificationObserver(realizeTable, table, WMViewRealizedNotification,
527 table->tableView);
529 table->tableView->flags.dontCompressExpose = 1;
531 table->gridColor = WMCreateNamedColor(scr, "#cccccc", False);
532 /* table->gridColor = WMGrayColor(scr);*/
535 XGCValues gcv;
537 table->backColor = WMWhiteColor(scr);
539 gcv.foreground = WMColorPixel(table->gridColor);
540 gcv.dashes = 1;
541 gcv.line_style = LineOnOffDash;
542 table->gridGC = XCreateGC(WMScreenDisplay(scr), W_DRAWABLE(scr),
543 GCForeground, &gcv);
546 table->editingRow = -1;
547 table->clickedRow = -1;
549 table->drawsGrid = 1;
550 table->rowHeight = 16;
552 table->tableWidth = 1;
554 table->columns = WMCreateArray(4);
555 table->splitters = WMCreateArray(4);
557 table->selectedRows = WMCreateArray(16);
559 table->splitterCursor = XCreateFontCursor(WMScreenDisplay(scr),
560 XC_sb_h_double_arrow);
562 table->canSelectRow = 1;
564 WMCreateEventHandler(table->view, ExposureMask|StructureNotifyMask,
565 handleEvents, table);
567 WMCreateEventHandler(table->tableView, ExposureMask|ButtonPressMask|
568 ButtonReleaseMask|ButtonMotionMask,
569 handleTableEvents, table);
571 WMResizeWidget(table, 50, 50);
573 return table;
575 error:
576 if (table->tableView)
577 W_DestroyView(table->tableView);
578 if (table->view)
579 W_DestroyView(table->view);
580 wfree(table);
581 return NULL;
585 void WMAddTableViewColumn(WMTableView *table, WMTableColumn *column)
587 WMScreen *scr = WMWidgetScreen(table);
589 column->table = table;
591 WMAddToArray(table->columns, column);
593 if (!column->titleW) {
594 column->titleW = WMCreateLabel(table);
595 WMSetLabelRelief(column->titleW, WRRaised);
596 WMSetLabelFont(column->titleW, scr->boldFont);
597 WMSetLabelTextColor(column->titleW, scr->white);
598 WMSetWidgetBackgroundColor(column->titleW, scr->darkGray);
599 WMSetLabelText(column->titleW, column->title);
600 W_ReparentView(WMWidgetView(column->titleW),
601 WMWidgetView(table->header), 0, 0);
602 if (W_VIEW_REALIZED(table->view))
603 WMRealizeWidget(column->titleW);
604 WMMapWidget(column->titleW);
608 WMView *splitter = W_CreateView(WMWidgetView(table->header));
610 W_SetViewBackgroundColor(splitter, WMWhiteColor(scr));
612 if (W_VIEW_REALIZED(table->view))
613 W_RealizeView(splitter);
615 W_ResizeView(splitter, 2, table->headerHeight);
616 W_MapView(splitter);
618 W_SetViewCursor(splitter, table->splitterCursor);
619 WMCreateEventHandler(splitter, ButtonPressMask|ButtonReleaseMask,
620 splitterHandler, column);
622 WMAddToArray(table->splitters, splitter);
625 rearrangeHeader(table);
629 void WMSetTableViewHeaderHeight(WMTableView *table, unsigned height)
631 table->headerHeight = height;
633 handleResize(NULL, table->view);
637 void WMSetTableViewDelegate(WMTableView *table, WMTableViewDelegate *delegate)
639 table->delegate = delegate;
643 void WMSetTableViewAction(WMTableView *table, WMAction *action, void *clientData)
645 table->action = action;
647 table->clientData = clientData;
651 void *WMGetTableViewClickedColumn(WMTableView *table)
653 return table->clickedColumn;
657 int WMGetTableViewClickedRow(WMTableView *table)
659 return table->clickedRow;
663 WMArray *WMGetTableViewSelectedRows(WMTableView *table)
665 return table->selectedRows;
669 WMView *WMGetTableViewDocumentView(WMTableView *table)
671 return table->tableView;
675 void *WMTableViewDataForCell(WMTableView *table, WMTableColumn *column,
676 int row)
678 return (*table->delegate->valueForCell)(table->delegate, column, row);
682 void WMSetTableViewDataForCell(WMTableView *table, WMTableColumn *column,
683 int row, void *data)
685 (*table->delegate->setValueForCell)(table->delegate, column, row, data);
689 WMRect WMTableViewRectForCell(WMTableView *table, WMTableColumn *column,
690 int row)
692 WMRect rect;
693 int i;
695 rect.pos.x = 0;
696 rect.pos.y = row * table->rowHeight;
697 rect.size.height = table->rowHeight;
699 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
700 WMTableColumn *col;
701 col = WMGetFromArray(table->columns, i);
703 if (col == column) {
704 rect.size.width = col->width;
705 break;
708 rect.pos.x += col->width;
712 WMRect r = getVisibleRect(table);
714 rect.pos.y -= r.pos.y;
715 rect.pos.x -= r.pos.x;
718 return rect;
722 void WMSetTableViewDataSource(WMTableView *table, void *source)
724 table->dataSource = source;
728 void *WMGetTableViewDataSource(WMTableView *table)
730 return table->dataSource;
734 void WMSetTableViewBackgroundColor(WMTableView *table, WMColor *color)
736 W_SetViewBackgroundColor(table->tableView, color);
738 if (table->backColor)
739 WMReleaseColor(table->backColor);
741 table->backColor = WMRetainColor(color);
743 repaintTable(table);
747 void WMSetTableViewGridColor(WMTableView *table, WMColor *color)
749 WMReleaseColor(table->gridColor);
750 table->gridColor = WMRetainColor(color);
751 XSetForeground(WMScreenDisplay(WMWidgetScreen(table)), table->gridGC,
752 WMColorPixel(color));
753 repaintTable(table);
758 void WMSetTableViewRowHeight(WMTableView *table, int height)
760 table->rowHeight = height;
762 repaintTable(table);
766 void WMScrollTableViewRowToVisible(WMTableView *table, int row)
768 WMScroller *scroller;
769 WMRange range;
770 WMRect rect;
771 int newY, tmp;
773 rect = getVisibleRect(table);
774 range = rowsInRect(table, rect);
776 scroller = table->vscroll;
778 if (row < range.position) {
779 newY = row * table->rowHeight - rect.size.height / 2;
780 } else if (row >= range.position + range.count) {
781 newY = row * table->rowHeight - rect.size.height / 2;
782 } else {
783 return;
785 tmp = table->rows*table->rowHeight - rect.size.height;
786 newY = WMAX(0, WMIN(newY, tmp));
788 scrollToPoint(table, rect.pos.x, newY);
793 static void drawGrid(WMTableView *table, WMRect rect)
795 WMScreen *scr = WMWidgetScreen(table);
796 Display *dpy = WMScreenDisplay(scr);
797 int i;
798 int y1, y2;
799 int x1, x2;
800 int xx;
801 Drawable d = WMGetPixmapXID(table->viewBuffer);
802 GC gc = table->gridGC;
804 #if 0
805 char dashl[1] = {1};
807 XSetDashes(dpy, gc, 0, dashl, 1);
809 y1 = (rect.pos.y/table->rowHeight - 1)*table->rowHeight;
810 y2 = y1 + (rect.size.height/table->rowHeight+2)*table->rowHeight;
811 #endif
812 y1 = 0;
813 y2 = W_VIEW_HEIGHT(table->tableView);
815 xx = -rect.pos.x;
816 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
817 WMTableColumn *column;
819 XDrawLine(dpy, d, gc, xx, y1, xx, y2);
821 column = WMGetFromArray(table->columns, i);
822 xx += column->width;
824 XDrawLine(dpy, d, gc, xx, y1, xx, y2);
826 x1 = 0;
827 x2 = rect.size.width;
829 if (x2 <= x1)
830 return;
831 #if 0
832 XSetDashes(dpy, gc, (rect.pos.x&1), dashl, 1);
833 #endif
835 y1 = -rect.pos.y%table->rowHeight;
836 y2 = y1 + rect.size.height + table->rowHeight;
838 for (i = y1; i <= y2; i += table->rowHeight) {
839 XDrawLine(dpy, d, gc, x1, i, x2, i);
844 static WMRange columnsInRect(WMTableView *table, WMRect rect)
846 WMTableColumn *column;
847 int width;
848 int i , j;
849 int totalColumns = WMGetArrayItemCount(table->columns);
850 WMRange range;
852 j = 0;
853 width = 0;
854 for (i = 0; i < totalColumns; i++) {
855 column = WMGetFromArray(table->columns, i);
856 if (j == 0) {
857 if (width <= rect.pos.x && width + column->width > rect.pos.x) {
858 range.position = i;
859 j = 1;
861 } else {
862 range.count++;
863 if (width > rect.pos.x + rect.size.width) {
864 break;
867 width += column->width;
869 range.count = WMAX(1, WMIN(range.count, totalColumns - range.position));
870 return range;
874 static WMRange rowsInRect(WMTableView *table, WMRect rect)
876 WMRange range;
877 int rh = table->rowHeight;
878 int dif;
880 dif = rect.pos.y % rh;
882 range.position = WMAX(0, (rect.pos.y - dif) / rh);
883 range.count = WMAX(1, WMIN((rect.size.height + dif) / rh, table->rows));
885 return range;
889 static void drawRow(WMTableView *table, int row, WMRect clipRect)
891 int i;
892 WMRange cols = columnsInRect(table, clipRect);
893 WMTableColumn *column;
894 Drawable d = WMGetPixmapXID(table->viewBuffer);
896 for (i = cols.position; i < cols.position+cols.count; i++) {
897 column = WMGetFromArray(table->columns, i);
899 if (!column->delegate || !column->delegate->drawCell)
900 continue;
902 if (WMFindInArray(table->selectedRows, NULL, (void*)row) != WANotFound)
903 (*column->delegate->drawSelectedCell)(column->delegate, column, row, d);
904 else
905 (*column->delegate->drawCell)(column->delegate, column, row, d);
910 static void drawFullRow(WMTableView *table, int row)
912 int i;
913 WMTableColumn *column;
914 Drawable d = WMGetPixmapXID(table->viewBuffer);
916 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
917 column = WMGetFromArray(table->columns, i);
919 if (!column->delegate || !column->delegate->drawCell)
920 continue;
922 if (WMFindInArray(table->selectedRows, NULL, (void*)row) != WANotFound)
923 (*column->delegate->drawSelectedCell)(column->delegate, column, row, d);
924 else
925 (*column->delegate->drawCell)(column->delegate, column, row, d);
930 static void setRowSelected(WMTableView *table, unsigned row, Bool flag)
932 int repaint = 0;
934 if (WMFindInArray(table->selectedRows, NULL, (void*)row) != WANotFound) {
935 if (!flag) {
936 WMRemoveFromArray(table->selectedRows, (void*)row);
937 repaint = 1;
939 } else {
940 if (flag) {
941 WMAddToArray(table->selectedRows, (void*)row);
942 repaint = 1;
945 if (repaint && row < table->rows) {
946 //drawFullRow(table, row);
947 repaintTable(table);
952 static void repaintTable(WMTableView *table)
954 WMRect rect;
955 WMRange rows;
956 WMScreen *scr = WMWidgetScreen(table);
957 int i;
959 if (!table->delegate || !W_VIEW_REALIZED(table->view))
960 return;
962 wassertr(table->delegate->numberOfRows);
964 if (!table->viewBuffer) {
965 table->viewBuffer = WMCreatePixmap(scr,
966 W_VIEW_WIDTH(table->tableView),
967 W_VIEW_HEIGHT(table->tableView),
968 WMScreenDepth(scr), 0);
971 XFillRectangle(scr->display,
972 WMGetPixmapXID(table->viewBuffer),
973 WMColorGC(table->backColor), 0, 0,
974 W_VIEW_WIDTH(table->tableView),
975 W_VIEW_HEIGHT(table->tableView));
977 rect = getVisibleRect(table);
979 if (table->drawsGrid) {
980 drawGrid(table, rect);
983 rows = rowsInRect(table, rect);
984 for (i = rows.position;
985 i < WMIN(rows.position+rows.count + 1, table->rows);
986 i++) {
987 drawRow(table, i, rect);
990 XSetWindowBackgroundPixmap(scr->display, table->tableView->window,
991 WMGetPixmapXID(table->viewBuffer));
992 XClearWindow(scr->display, table->tableView->window);
996 static void stopRowEdit(WMTableView *table, int row)
998 int i;
999 WMTableColumn *column;
1001 table->editingRow = -1;
1002 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
1003 column = WMGetFromArray(table->columns, i);
1005 if (column->delegate && column->delegate->endCellEdit)
1006 (*column->delegate->endCellEdit)(column->delegate, column, row);
1012 void WMEditTableViewRow(WMTableView *table, int row)
1014 int i;
1015 WMTableColumn *column;
1017 if (table->editingRow >= 0) {
1018 stopRowEdit(table, table->editingRow);
1021 table->editingRow = row;
1023 if (row < 0)
1024 return;
1026 for (i = 0; i < WMGetArrayItemCount(table->columns); i++) {
1027 column = WMGetFromArray(table->columns, i);
1029 if (column->delegate && column->delegate->beginCellEdit)
1030 (*column->delegate->beginCellEdit)(column->delegate, column, row);
1035 void WMSelectTableViewRow(WMTableView *table, int row)
1037 if (table->clickedRow >= 0)
1038 setRowSelected(table, table->clickedRow, False);
1040 if (row >= table->rows) {
1041 return;
1044 setRowSelected(table, row, True);
1045 table->clickedRow = row;
1047 if (table->action)
1048 (*table->action)(table, table->clientData);
1049 WMPostNotificationName(WMTableViewSelectionDidChangeNotification,
1050 table, NULL);
1054 void WMReloadTableView(WMTableView *table)
1056 WMRect rect = getVisibleRect(table);
1058 if (table->editingRow >= 0)
1059 stopRowEdit(table, table->editingRow);
1061 /* when this is called, nothing in the table can be assumed to be
1062 * like the last time we accessed it (ie, rows might have disappeared) */
1064 WMEmptyArray(table->selectedRows);
1066 if (table->clickedRow >= 0) {
1067 table->clickedRow = -1;
1069 if (table->action)
1070 (*table->action)(table, table->clientData);
1071 WMPostNotificationName(WMTableViewSelectionDidChangeNotification,
1072 table, NULL);
1075 if (table->delegate && table->delegate->numberOfRows) {
1076 int rows;
1078 rows = (*table->delegate->numberOfRows)(table->delegate, table);
1080 if (rows != table->rows) {
1081 table->rows = rows;
1082 handleResize(table->view->delegate, table->view);
1083 } else {
1084 repaintTable(table);
1090 void WMNoteTableViewNumberOfRowsChanged(WMTableView *table)
1092 WMReloadTableView(table);
1096 static void handleTableEvents(XEvent *event, void *data)
1098 WMTableView *table = (WMTableView*)data;
1099 int row;
1101 switch (event->type) {
1102 case ButtonPress:
1103 if (event->xbutton.button == Button1) {
1104 WMRect rect = getVisibleRect(table);
1106 row = (event->xbutton.y + rect.pos.y)/table->rowHeight;
1107 if (row != table->clickedRow) {
1108 setRowSelected(table, table->clickedRow, False);
1109 setRowSelected(table, row, True);
1110 table->clickedRow = row;
1111 table->dragging = 1;
1112 } else {
1113 table->dragging = 1;
1116 break;
1118 case MotionNotify:
1119 if (table->dragging && event->xmotion.y >= 0) {
1120 WMRect rect = getVisibleRect(table);
1122 row = (event->xmotion.y + rect.pos.y)/table->rowHeight;
1123 if (table->clickedRow != row && row >= 0 && row < table->rows) {
1124 setRowSelected(table, table->clickedRow, False);
1125 setRowSelected(table, row, True);
1126 table->clickedRow = row;
1129 break;
1131 case ButtonRelease:
1132 if (event->xbutton.button == Button1) {
1133 if (table->action)
1134 (*table->action)(table, table->clientData);
1135 WMPostNotificationName(WMTableViewSelectionDidChangeNotification,
1136 table, NULL);
1137 table->dragging = 0;
1139 break;
1144 static void handleEvents(XEvent *event, void *data)
1146 WMTableView *table = (WMTableView*)data;
1147 WMScreen *scr = WMWidgetScreen(table);
1149 switch (event->type) {
1150 case Expose:
1151 W_DrawRelief(scr, W_VIEW_DRAWABLE(table->view), 0, 0,
1152 W_VIEW_WIDTH(table->view), W_VIEW_HEIGHT(table->view),
1153 WRSunken);
1154 break;
1159 static void handleResize(W_ViewDelegate *self, WMView *view)
1161 int width;
1162 int height;
1163 WMTableView *table = view->self;
1164 WMSize size = getTotalSize(table);
1165 WMScreen *scr = WMWidgetScreen(table);
1166 int vw, vh;
1168 width = W_VIEW_WIDTH(view) - 2;
1169 height = W_VIEW_HEIGHT(view) - 3;
1171 height -= table->headerHeight; /* table header */
1173 if (table->corner)
1174 WMResizeWidget(table->corner, 20, table->headerHeight);
1176 WMMoveWidget(table->vscroll, 1, table->headerHeight + 1);
1177 WMResizeWidget(table->vscroll, 20, height + 1);
1179 WMMoveWidget(table->hscroll, 20, W_VIEW_HEIGHT(view) - 20 - 1);
1180 WMResizeWidget(table->hscroll, width-20+1, 20);
1182 if (table->header)
1183 WMResizeWidget(table->header, width - 21, table->headerHeight);
1185 if (table->viewBuffer) {
1186 WMReleasePixmap(table->viewBuffer);
1187 table->viewBuffer = NULL;
1190 width -= 20;
1191 height -= 20;
1193 vw = WMIN(size.width, width);
1194 vh = WMIN(size.height, height);
1196 W_MoveView(table->tableView, 21, 1+table->headerHeight+1);
1197 W_ResizeView(table->tableView, WMAX(vw, 1), WMAX(vh, 1));
1199 adjustScrollers(table);
1201 repaintTable(table);
1205 static void rearrangeHeader(WMTableView *table)
1207 int width;
1208 int count;
1209 int i;
1210 /*WMRect rect = WMGetScrollViewVisibleRect(table->scrollView);*/
1212 width = 0;
1214 count = WMGetArrayItemCount(table->columns);
1215 for (i = 0; i < count; i++) {
1216 WMTableColumn *column = WMGetFromArray(table->columns, i);
1217 WMView *splitter = WMGetFromArray(table->splitters, i);
1219 WMMoveWidget(column->titleW, width, 0);
1220 WMResizeWidget(column->titleW, column->width-1, table->headerHeight);
1222 width += column->width;
1223 W_MoveView(splitter, width-1, 0);
1226 wassertr(table->delegate && table->delegate->numberOfRows);
1228 table->rows = table->delegate->numberOfRows(table->delegate, table);
1230 table->tableWidth = width + 1;
1232 handleResize(table->view->delegate, table->view);