2 #include <WINGs/WINGsP.h>
3 #include <X11/cursorfont.h>
6 #include "wtableview.h"
8 const char *WMTableViewSelectionDidChangeNotification
= "WMTableViewSelectionDidChangeNotification";
10 struct W_TableColumn
{
20 WMTableColumnDelegate
*delegate
;
26 static void handleResize(W_ViewDelegate
* self
, WMView
* view
);
28 static void rearrangeHeader(WMTableView
* table
);
30 static WMRange
rowsInRect(WMTableView
* table
, WMRect rect
);
32 WMTableColumn
*WMCreateTableColumn(char *title
)
34 WMTableColumn
*col
= wmalloc(sizeof(WMTableColumn
));
44 col
->title
= wstrdup(title
);
54 void WMSetTableColumnId(WMTableColumn
* column
, void *id
)
59 void *WMGetTableColumnId(WMTableColumn
* column
)
64 void WMSetTableColumnWidth(WMTableColumn
* column
, unsigned width
)
66 if (column
->maxWidth
== 0)
67 column
->width
= WMAX(column
->minWidth
, width
);
69 column
->width
= WMAX(column
->minWidth
, WMIN(column
->maxWidth
, width
));
72 rearrangeHeader(column
->table
);
76 void WMSetTableColumnDelegate(WMTableColumn
* column
, WMTableColumnDelegate
* delegate
)
78 column
->delegate
= delegate
;
81 void WMSetTableColumnConstraints(WMTableColumn
* column
, unsigned minWidth
, unsigned maxWidth
)
83 wassertr(maxWidth
== 0 || minWidth
<= maxWidth
);
85 column
->minWidth
= minWidth
;
86 column
->maxWidth
= maxWidth
;
88 if (column
->width
< column
->minWidth
)
89 WMSetTableColumnWidth(column
, column
->minWidth
);
90 else if (column
->width
> column
->maxWidth
&& column
->maxWidth
!= 0)
91 WMSetTableColumnWidth(column
, column
->maxWidth
);
94 void WMSetTableColumnEditable(WMTableColumn
* column
, Bool flag
)
96 column
->editable
= ((flag
== 0) ? 0 : 1);
99 WMTableView
*WMGetTableColumnTableView(WMTableColumn
* column
)
101 return column
->table
;
116 WMPixmap
*viewBuffer
;
121 WMArray
*selectedRows
;
132 Cursor splitterCursor
;
136 WMTableViewDelegate
*delegate
;
146 unsigned headerHeight
;
151 unsigned drawsGrid
:1;
152 unsigned canSelectRow
:1;
153 unsigned canSelectMultiRows
:1;
154 unsigned canDeselectRow
:1;
156 unsigned int hasVScroller
:1;
157 unsigned int hasHScroller
:1;
160 static W_Class tableClass
= 0;
162 static W_ViewDelegate viewDelegate
= {
170 static void reorganizeInterior(WMTableView
* table
);
172 static void handleEvents(XEvent
* event
, void *data
);
173 static void handleTableEvents(XEvent
* event
, void *data
);
174 static void repaintTable(WMTableView
* table
);
176 static WMSize
getTotalSize(WMTableView
* table
)
181 /* get width from columns */
183 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
184 WMTableColumn
*column
;
186 column
= WMGetFromArray(table
->columns
, i
);
188 size
.width
+= column
->width
;
191 /* get height from rows */
192 size
.height
= table
->rows
* table
->rowHeight
;
197 static WMRect
getVisibleRect(WMTableView
* table
)
199 WMSize size
= getTotalSize(table
);
202 if (table
->vscroll
) {
203 rect
.size
.height
= size
.height
* WMGetScrollerKnobProportion(table
->vscroll
);
204 rect
.pos
.y
= (size
.height
- rect
.size
.height
) * WMGetScrollerValue(table
->vscroll
);
206 rect
.size
.height
= size
.height
;
210 if (table
->hscroll
) {
211 rect
.size
.width
= size
.width
* WMGetScrollerKnobProportion(table
->hscroll
);
212 rect
.pos
.x
= (size
.width
- rect
.size
.width
) * WMGetScrollerValue(table
->hscroll
);
214 rect
.size
.width
= size
.width
;
221 static void scrollToPoint(WMTableView
* table
, int x
, int y
)
223 WMSize size
= getTotalSize(table
);
227 if (table
->hscroll
) {
228 if (size
.width
> W_VIEW_WIDTH(table
->tableView
)) {
229 prop
= (float)W_VIEW_WIDTH(table
->tableView
) / (float)size
.width
;
230 value
= (float)x
/ (float)(size
.width
- W_VIEW_WIDTH(table
->tableView
));
235 WMSetScrollerParameters(table
->hscroll
, value
, prop
);
238 if (table
->vscroll
) {
239 if (size
.height
> W_VIEW_HEIGHT(table
->tableView
)) {
240 prop
= (float)W_VIEW_HEIGHT(table
->tableView
) / (float)size
.height
;
241 value
= (float)y
/ (float)(size
.height
- W_VIEW_HEIGHT(table
->tableView
));
247 WMSetScrollerParameters(table
->vscroll
, value
, prop
);
250 if (table
->editingRow
>= 0) {
251 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
252 WMTableColumn
*column
;
254 column
= WMGetFromArray(table
->columns
, i
);
256 if (column
->delegate
&& column
->delegate
->beginCellEdit
)
257 (*column
->delegate
->beginCellEdit
) (column
->delegate
, column
, table
->editingRow
);
264 static void adjustScrollers(WMTableView
* table
)
266 WMSize size
= getTotalSize(table
);
267 WMSize vsize
= WMGetViewSize(table
->tableView
);
271 if (table
->hscroll
) {
272 if (size
.width
<= vsize
.width
) {
276 oprop
= WMGetScrollerKnobProportion(table
->hscroll
);
279 ovalue
= WMGetScrollerValue(table
->hscroll
);
281 prop
= (float)vsize
.width
/ (float)size
.width
;
282 value
= prop
* ovalue
/ oprop
;
284 WMSetScrollerParameters(table
->hscroll
, value
, prop
);
287 if (table
->vscroll
) {
288 if (size
.height
<= vsize
.height
) {
292 oprop
= WMGetScrollerKnobProportion(table
->vscroll
);
295 ovalue
= WMGetScrollerValue(table
->vscroll
);
297 prop
= (float)vsize
.height
/ (float)size
.height
;
298 value
= prop
* ovalue
/ oprop
;
300 WMSetScrollerParameters(table
->vscroll
, value
, prop
);
304 static void doScroll(WMWidget
* self
, void *data
)
306 WMTableView
*table
= (WMTableView
*) data
;
310 WMSize ts
= getTotalSize(table
);
312 value
= WMGetScrollerValue(self
);
314 if (table
->hscroll
== (WMScroller
*) self
) {
315 vpsize
= W_VIEW_WIDTH(table
->tableView
);
318 vpsize
= W_VIEW_HEIGHT(table
->tableView
);
322 switch (WMGetScrollerHitPart(self
)) {
323 case WSDecrementWheel
:
324 case WSDecrementLine
:
325 value
-= (float)table
->rowHeight
/ size
;
328 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
332 case WSIncrementWheel
:
333 case WSIncrementLine
:
334 value
+= (float)table
->rowHeight
/ size
;
337 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
345 case WSDecrementPage
:
346 value
-= vpsize
/ size
;
349 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
353 case WSIncrementPage
:
354 value
+= vpsize
/ size
;
357 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
366 if (table
->editingRow
>= 0) {
368 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
369 WMTableColumn
*column
;
371 column
= WMGetFromArray(table
->columns
, i
);
373 if (column
->delegate
&& column
->delegate
->beginCellEdit
)
374 (*column
->delegate
->beginCellEdit
) (column
->delegate
, column
, table
->editingRow
);
378 if (table
->hscroll
== self
) {
381 WMRect rect
= getVisibleRect(table
);
383 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
384 WMTableColumn
*column
;
387 column
= WMGetFromArray(table
->columns
, i
);
389 WMMoveWidget(column
->titleW
, x
- rect
.pos
.x
, 0);
391 x
+= W_VIEW_WIDTH(WMWidgetView(column
->titleW
)) + 1;
393 splitter
= WMGetFromArray(table
->splitters
, i
);
394 W_MoveView(splitter
, x
- rect
.pos
.x
- 1, 0);
399 static void splitterHandler(XEvent
* event
, void *data
)
401 WMTableColumn
*column
= (WMTableColumn
*) data
;
402 WMTableView
*table
= column
->table
;
406 WMScreen
*scr
= WMWidgetScreen(table
);
408 Display
*dpy
= WMScreenDisplay(scr
);
409 int h
= WMWidgetHeight(table
) - 22;
410 Window w
= WMViewXID(table
->view
);
412 pos
= WMGetViewPosition(WMWidgetView(column
->titleW
));
414 offsX
= pos
.x
+ column
->width
;
418 XDrawLine(dpy
, w
, gc
, cx
+ 20, 0, cx
+ 20, h
);
423 WMMaskEvent(dpy
, ButtonMotionMask
| ButtonReleaseMask
, &ev
);
429 if (column
->width
+ ev
.xmotion
.x
< column
->minWidth
)
430 cx
= pos
.x
+ column
->minWidth
;
431 else if (column
->maxWidth
> 0 && column
->width
+ ev
.xmotion
.x
> column
->maxWidth
)
432 cx
= pos
.x
+ column
->maxWidth
;
434 cx
= offsX
+ ev
.xmotion
.x
;
436 XDrawLine(dpy
, w
, gc
, ox
+ 20, 0, ox
+ 20, h
);
437 XDrawLine(dpy
, w
, gc
, cx
+ 20, 0, cx
+ 20, h
);
441 column
->width
= cx
- pos
.x
;
447 XDrawLine(dpy
, w
, gc
, cx
+ 20, 0, cx
+ 20, h
);
448 rearrangeHeader(table
);
452 static void realizeTable(void *data
, WMNotification
* notif
)
457 WMTableView
*WMCreateTableView(WMWidget
* parent
)
459 WMTableView
*table
= wmalloc(sizeof(WMTableView
));
460 WMScreen
*scr
= WMWidgetScreen(parent
);
462 memset(table
, 0, sizeof(WMTableView
));
465 tableClass
= W_RegisterUserWidget();
467 table
->widgetClass
= tableClass
;
469 table
->view
= W_CreateView(W_VIEW(parent
));
472 table
->view
->self
= table
;
474 table
->view
->delegate
= &viewDelegate
;
476 table
->headerHeight
= 20;
478 table
->hscroll
= WMCreateScroller(table
);
479 WMSetScrollerAction(table
->hscroll
, doScroll
, table
);
480 WMMoveWidget(table
->hscroll
, 1, 2 + table
->headerHeight
);
481 WMMapWidget(table
->hscroll
);
483 table
->hasHScroller
= 1;
485 table
->vscroll
= WMCreateScroller(table
);
486 WMSetScrollerArrowsPosition(table
->vscroll
, WSAMaxEnd
);
487 WMSetScrollerAction(table
->vscroll
, doScroll
, table
);
488 WMMoveWidget(table
->vscroll
, 1, 2 + table
->headerHeight
);
489 WMMapWidget(table
->vscroll
);
491 table
->hasVScroller
= 1;
493 table
->header
= WMCreateFrame(table
);
494 WMMoveWidget(table
->header
, 22, 2);
495 WMMapWidget(table
->header
);
496 WMSetFrameRelief(table
->header
, WRFlat
);
498 table
->corner
= WMCreateLabel(table
);
499 WMResizeWidget(table
->corner
, 20, table
->headerHeight
);
500 WMMoveWidget(table
->corner
, 2, 2);
501 WMMapWidget(table
->corner
);
502 WMSetLabelRelief(table
->corner
, WRRaised
);
503 WMSetWidgetBackgroundColor(table
->corner
, scr
->darkGray
);
505 table
->tableView
= W_CreateView(table
->view
);
506 if (!table
->tableView
)
508 table
->tableView
->self
= table
;
509 W_MapView(table
->tableView
);
511 WMAddNotificationObserver(realizeTable
, table
, WMViewRealizedNotification
, table
->tableView
);
513 table
->tableView
->flags
.dontCompressExpose
= 1;
515 table
->gridColor
= WMCreateNamedColor(scr
, "#cccccc", False
);
516 /* table->gridColor = WMGrayColor(scr); */
521 table
->backColor
= WMWhiteColor(scr
);
523 gcv
.foreground
= WMColorPixel(table
->gridColor
);
525 gcv
.line_style
= LineOnOffDash
;
526 table
->gridGC
= XCreateGC(WMScreenDisplay(scr
), W_DRAWABLE(scr
), GCForeground
, &gcv
);
529 table
->editingRow
= -1;
530 table
->clickedRow
= -1;
532 table
->drawsGrid
= 1;
533 table
->rowHeight
= 16;
535 table
->tableWidth
= 1;
537 table
->columns
= WMCreateArray(4);
538 table
->splitters
= WMCreateArray(4);
540 table
->selectedRows
= WMCreateArray(16);
542 table
->splitterCursor
= XCreateFontCursor(WMScreenDisplay(scr
), XC_sb_h_double_arrow
);
544 table
->canSelectRow
= 1;
546 WMCreateEventHandler(table
->view
, ExposureMask
| StructureNotifyMask
, handleEvents
, table
);
548 WMCreateEventHandler(table
->tableView
, ExposureMask
| ButtonPressMask
|
549 ButtonReleaseMask
| ButtonMotionMask
, handleTableEvents
, table
);
551 WMResizeWidget(table
, 50, 50);
556 if (table
->tableView
)
557 W_DestroyView(table
->tableView
);
559 W_DestroyView(table
->view
);
564 void WMAddTableViewColumn(WMTableView
* table
, WMTableColumn
* column
)
566 WMScreen
*scr
= WMWidgetScreen(table
);
568 column
->table
= table
;
570 WMAddToArray(table
->columns
, column
);
572 if (!column
->titleW
) {
573 column
->titleW
= WMCreateLabel(table
);
574 WMSetLabelRelief(column
->titleW
, WRRaised
);
575 WMSetLabelFont(column
->titleW
, scr
->boldFont
);
576 WMSetLabelTextColor(column
->titleW
, scr
->white
);
577 WMSetWidgetBackgroundColor(column
->titleW
, scr
->darkGray
);
578 WMSetLabelText(column
->titleW
, column
->title
);
579 W_ReparentView(WMWidgetView(column
->titleW
), WMWidgetView(table
->header
), 0, 0);
580 if (W_VIEW_REALIZED(table
->view
))
581 WMRealizeWidget(column
->titleW
);
582 WMMapWidget(column
->titleW
);
586 WMView
*splitter
= W_CreateView(WMWidgetView(table
->header
));
588 W_SetViewBackgroundColor(splitter
, WMWhiteColor(scr
));
590 if (W_VIEW_REALIZED(table
->view
))
591 W_RealizeView(splitter
);
593 W_ResizeView(splitter
, 2, table
->headerHeight
);
596 W_SetViewCursor(splitter
, table
->splitterCursor
);
597 WMCreateEventHandler(splitter
, ButtonPressMask
| ButtonReleaseMask
, splitterHandler
, column
);
599 WMAddToArray(table
->splitters
, splitter
);
602 rearrangeHeader(table
);
605 void WMSetTableViewHeaderHeight(WMTableView
* table
, unsigned height
)
607 table
->headerHeight
= height
;
609 handleResize(NULL
, table
->view
);
612 void WMSetTableViewDelegate(WMTableView
* table
, WMTableViewDelegate
* delegate
)
614 table
->delegate
= delegate
;
617 void WMSetTableViewAction(WMTableView
* table
, WMAction
* action
, void *clientData
)
619 table
->action
= action
;
621 table
->clientData
= clientData
;
624 void *WMGetTableViewClickedColumn(WMTableView
* table
)
626 return table
->clickedColumn
;
629 int WMGetTableViewClickedRow(WMTableView
* table
)
631 return table
->clickedRow
;
634 WMArray
*WMGetTableViewSelectedRows(WMTableView
* table
)
636 return table
->selectedRows
;
639 WMView
*WMGetTableViewDocumentView(WMTableView
* table
)
641 return table
->tableView
;
644 void *WMTableViewDataForCell(WMTableView
* table
, WMTableColumn
* column
, int row
)
646 return (*table
->delegate
->valueForCell
) (table
->delegate
, column
, row
);
649 void WMSetTableViewDataForCell(WMTableView
* table
, WMTableColumn
* column
, int row
, void *data
)
651 (*table
->delegate
->setValueForCell
) (table
->delegate
, column
, row
, data
);
654 WMRect
WMTableViewRectForCell(WMTableView
* table
, WMTableColumn
* column
, int row
)
660 rect
.pos
.y
= row
* table
->rowHeight
;
661 rect
.size
.height
= table
->rowHeight
;
663 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
665 col
= WMGetFromArray(table
->columns
, i
);
668 rect
.size
.width
= col
->width
;
672 rect
.pos
.x
+= col
->width
;
676 WMRect r
= getVisibleRect(table
);
678 rect
.pos
.y
-= r
.pos
.y
;
679 rect
.pos
.x
-= r
.pos
.x
;
685 void WMSetTableViewDataSource(WMTableView
* table
, void *source
)
687 table
->dataSource
= source
;
690 void *WMGetTableViewDataSource(WMTableView
* table
)
692 return table
->dataSource
;
695 void WMSetTableViewHasHorizontalScroller(WMTableView
* tPtr
, Bool flag
)
698 if (tPtr
->hasHScroller
)
700 tPtr
->hasHScroller
= 1;
702 tPtr
->hscroll
= WMCreateScroller(tPtr
);
703 WMSetScrollerAction(tPtr
->hscroll
, doScroll
, tPtr
);
704 WMSetScrollerArrowsPosition(tPtr
->hscroll
, WSAMaxEnd
);
705 /* make it a horiz. scroller */
706 WMResizeWidget(tPtr
->hscroll
, 1, 2);
708 if (W_VIEW_REALIZED(tPtr
->view
)) {
709 WMRealizeWidget(tPtr
->hscroll
);
712 reorganizeInterior(tPtr
);
714 WMMapWidget(tPtr
->hscroll
);
716 if (!tPtr
->hasHScroller
)
718 tPtr
->hasHScroller
= 0;
720 WMUnmapWidget(tPtr
->hscroll
);
721 WMDestroyWidget(tPtr
->hscroll
);
722 tPtr
->hscroll
= NULL
;
724 reorganizeInterior(tPtr
);
729 /* not supported by now */
730 void WMSetTableViewHasVerticalScroller(WMTableView
* tPtr
, Bool flag
)
733 if (tPtr
->hasVScroller
)
735 tPtr
->hasVScroller
= 1;
737 tPtr
->vscroll
= WMCreateScroller(tPtr
);
738 WMSetScrollerAction(tPtr
->vscroll
, doScroll
, tPtr
);
739 WMSetScrollerArrowsPosition(tPtr
->vscroll
, WSAMaxEnd
);
740 /* make it a vert. scroller */
741 WMResizeWidget(tPtr
->vscroll
, 1, 2);
743 if (W_VIEW_REALIZED(tPtr
->view
)) {
744 WMRealizeWidget(tPtr
->vscroll
);
747 reorganizeInterior(tPtr
);
749 WMMapWidget(tPtr
->vscroll
);
751 if (!tPtr
->hasVScroller
)
753 tPtr
->hasVScroller
= 0;
755 WMUnmapWidget(tPtr
->vscroll
);
756 WMDestroyWidget(tPtr
->vscroll
);
757 tPtr
->vscroll
= NULL
;
759 reorganizeInterior(tPtr
);
764 void WMSetTableViewBackgroundColor(WMTableView
* table
, WMColor
* color
)
766 W_SetViewBackgroundColor(table
->tableView
, color
);
768 if (table
->backColor
)
769 WMReleaseColor(table
->backColor
);
771 table
->backColor
= WMRetainColor(color
);
776 void WMSetTableViewGridColor(WMTableView
* table
, WMColor
* color
)
778 WMReleaseColor(table
->gridColor
);
779 table
->gridColor
= WMRetainColor(color
);
780 XSetForeground(WMScreenDisplay(WMWidgetScreen(table
)), table
->gridGC
, WMColorPixel(color
));
784 void WMSetTableViewRowHeight(WMTableView
* table
, int height
)
786 table
->rowHeight
= height
;
791 void WMScrollTableViewRowToVisible(WMTableView
* table
, int row
)
793 WMScroller
*scroller
;
798 rect
= getVisibleRect(table
);
799 range
= rowsInRect(table
, rect
);
801 scroller
= table
->vscroll
;
803 if (row
< range
.position
) {
804 newY
= row
* table
->rowHeight
- rect
.size
.height
/ 2;
805 } else if (row
>= range
.position
+ range
.count
) {
806 newY
= row
* table
->rowHeight
- rect
.size
.height
/ 2;
810 tmp
= table
->rows
* table
->rowHeight
- rect
.size
.height
;
811 newY
= WMAX(0, WMIN(newY
, tmp
));
813 scrollToPoint(table
, rect
.pos
.x
, newY
);
816 static void drawGrid(WMTableView
* table
, WMRect rect
)
818 WMScreen
*scr
= WMWidgetScreen(table
);
819 Display
*dpy
= WMScreenDisplay(scr
);
824 Drawable d
= WMGetPixmapXID(table
->viewBuffer
);
825 GC gc
= table
->gridGC
;
828 char dashl
[1] = { 1 };
830 XSetDashes(dpy
, gc
, 0, dashl
, 1);
832 y1
= (rect
.pos
.y
/ table
->rowHeight
- 1) * table
->rowHeight
;
833 y2
= y1
+ (rect
.size
.height
/ table
->rowHeight
+ 2) * table
->rowHeight
;
836 y2
= W_VIEW_HEIGHT(table
->tableView
);
839 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
840 WMTableColumn
*column
;
842 XDrawLine(dpy
, d
, gc
, xx
, y1
, xx
, y2
);
844 column
= WMGetFromArray(table
->columns
, i
);
847 XDrawLine(dpy
, d
, gc
, xx
, y1
, xx
, y2
);
850 x2
= rect
.size
.width
;
855 XSetDashes(dpy
, gc
, (rect
.pos
.x
& 1), dashl
, 1);
858 y1
= -rect
.pos
.y
% table
->rowHeight
;
859 y2
= y1
+ rect
.size
.height
+ table
->rowHeight
;
861 for (i
= y1
; i
<= y2
; i
+= table
->rowHeight
) {
862 XDrawLine(dpy
, d
, gc
, x1
, i
, x2
, i
);
866 static WMRange
columnsInRect(WMTableView
* table
, WMRect rect
)
868 WMTableColumn
*column
;
871 int totalColumns
= WMGetArrayItemCount(table
->columns
);
876 for (i
= 0; i
< totalColumns
; i
++) {
877 column
= WMGetFromArray(table
->columns
, i
);
879 if (rect
.pos
.x
>= pos
&& rect
.pos
.x
< pos
+ column
->width
) {
885 if (pos
> rect
.pos
.x
+ rect
.size
.width
) {
890 pos
+= column
->width
;
892 range
.count
= WMAX(1, WMIN(range
.count
, totalColumns
- range
.position
));
896 static WMRange
rowsInRect(WMTableView
* table
, WMRect rect
)
899 int rh
= table
->rowHeight
;
902 dif
= rect
.pos
.y
% rh
;
904 range
.position
= WMAX(0, (rect
.pos
.y
- dif
) / rh
);
905 range
.count
= WMAX(1, WMIN((rect
.size
.height
+ dif
) / rh
, table
->rows
));
910 static void drawRow(WMTableView
* table
, int row
, WMRect clipRect
)
913 WMRange cols
= columnsInRect(table
, clipRect
);
914 WMTableColumn
*column
;
915 Drawable d
= WMGetPixmapXID(table
->viewBuffer
);
917 for (i
= cols
.position
; i
< cols
.position
+ cols
.count
; i
++) {
918 column
= WMGetFromArray(table
->columns
, i
);
920 if (!column
->delegate
|| !column
->delegate
->drawCell
)
923 if (WMFindInArray(table
->selectedRows
, NULL
, (void *)(uintptr_t) row
) != WANotFound
)
924 (*column
->delegate
->drawSelectedCell
) (column
->delegate
, column
, row
, d
);
926 (*column
->delegate
->drawCell
) (column
->delegate
, column
, row
, d
);
931 static void drawFullRow(WMTableView
* table
, int row
)
934 WMTableColumn
*column
;
935 Drawable d
= WMGetPixmapXID(table
->viewBuffer
);
937 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
938 column
= WMGetFromArray(table
->columns
, i
);
940 if (!column
->delegate
|| !column
->delegate
->drawCell
)
943 if (WMFindInArray(table
->selectedRows
, NULL
, (void *)row
) != WANotFound
)
944 (*column
->delegate
->drawSelectedCell
) (column
->delegate
, column
, row
, d
);
946 (*column
->delegate
->drawCell
) (column
->delegate
, column
, row
, d
);
951 static void setRowSelected(WMTableView
* table
, unsigned row
, Bool flag
)
955 if (WMFindInArray(table
->selectedRows
, NULL
, (void *)(uintptr_t) row
) != WANotFound
) {
957 WMRemoveFromArray(table
->selectedRows
, (void *)(uintptr_t) row
);
962 WMAddToArray(table
->selectedRows
, (void *)(uintptr_t) row
);
966 if (repaint
&& row
< table
->rows
) {
967 /*drawFullRow(table, row); */
972 static void repaintTable(WMTableView
* table
)
976 WMScreen
*scr
= WMWidgetScreen(table
);
979 if (!table
->delegate
|| !W_VIEW_REALIZED(table
->view
))
982 wassertr(table
->delegate
->numberOfRows
);
984 if (!table
->viewBuffer
) {
985 table
->viewBuffer
= WMCreatePixmap(scr
,
986 W_VIEW_WIDTH(table
->tableView
),
987 W_VIEW_HEIGHT(table
->tableView
), WMScreenDepth(scr
), 0);
990 XFillRectangle(scr
->display
,
991 WMGetPixmapXID(table
->viewBuffer
),
992 WMColorGC(table
->backColor
), 0, 0,
993 W_VIEW_WIDTH(table
->tableView
), W_VIEW_HEIGHT(table
->tableView
));
995 rect
= getVisibleRect(table
);
997 if (table
->drawsGrid
) {
998 drawGrid(table
, rect
);
1001 rows
= rowsInRect(table
, rect
);
1002 for (i
= rows
.position
; i
< WMIN(rows
.position
+ rows
.count
+ 1, table
->rows
); i
++) {
1003 drawRow(table
, i
, rect
);
1006 XSetWindowBackgroundPixmap(scr
->display
, table
->tableView
->window
, WMGetPixmapXID(table
->viewBuffer
));
1007 XClearWindow(scr
->display
, table
->tableView
->window
);
1010 static void stopRowEdit(WMTableView
* table
, int row
)
1013 WMTableColumn
*column
;
1015 table
->editingRow
= -1;
1016 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
1017 column
= WMGetFromArray(table
->columns
, i
);
1019 if (column
->delegate
&& column
->delegate
->endCellEdit
)
1020 (*column
->delegate
->endCellEdit
) (column
->delegate
, column
, row
);
1024 void WMEditTableViewRow(WMTableView
* table
, int row
)
1027 WMTableColumn
*column
;
1029 if (table
->editingRow
>= 0) {
1030 stopRowEdit(table
, table
->editingRow
);
1033 table
->editingRow
= row
;
1038 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
1039 column
= WMGetFromArray(table
->columns
, i
);
1041 if (column
->delegate
&& column
->delegate
->beginCellEdit
)
1042 (*column
->delegate
->beginCellEdit
) (column
->delegate
, column
, row
);
1046 void WMSelectTableViewRow(WMTableView
* table
, int row
)
1048 if (table
->clickedRow
>= 0)
1049 setRowSelected(table
, table
->clickedRow
, False
);
1051 if (row
>= table
->rows
) {
1055 setRowSelected(table
, row
, True
);
1056 table
->clickedRow
= row
;
1059 (*table
->action
) (table
, table
->clientData
);
1060 WMPostNotificationName(WMTableViewSelectionDidChangeNotification
, table
, NULL
);
1063 void WMReloadTableView(WMTableView
* table
)
1065 if (table
->editingRow
>= 0)
1066 stopRowEdit(table
, table
->editingRow
);
1068 /* when this is called, nothing in the table can be assumed to be
1069 * like the last time we accessed it (ie, rows might have disappeared) */
1071 WMEmptyArray(table
->selectedRows
);
1073 if (table
->clickedRow
>= 0) {
1075 (*table
->action
) (table
, table
->clientData
);
1076 WMPostNotificationName(WMTableViewSelectionDidChangeNotification
, table
, NULL
);
1077 table
->clickedRow
= -1;
1080 if (table
->delegate
&& table
->delegate
->numberOfRows
) {
1083 rows
= (*table
->delegate
->numberOfRows
) (table
->delegate
, table
);
1085 if (rows
!= table
->rows
) {
1087 handleResize(table
->view
->delegate
, table
->view
);
1089 repaintTable(table
);
1094 void WMNoteTableViewNumberOfRowsChanged(WMTableView
* table
)
1096 WMReloadTableView(table
);
1099 static void handleTableEvents(XEvent
* event
, void *data
)
1101 WMTableView
*table
= (WMTableView
*) data
;
1104 switch (event
->type
) {
1106 if (event
->xbutton
.button
== Button1
) {
1107 WMRect rect
= getVisibleRect(table
);
1109 row
= (event
->xbutton
.y
+ rect
.pos
.y
) / table
->rowHeight
;
1110 if (row
!= table
->clickedRow
) {
1111 setRowSelected(table
, table
->clickedRow
, False
);
1112 setRowSelected(table
, row
, True
);
1113 table
->clickedRow
= row
;
1114 table
->dragging
= 1;
1116 table
->dragging
= 1;
1122 if (table
->dragging
&& event
->xmotion
.y
>= 0) {
1123 WMRect rect
= getVisibleRect(table
);
1125 row
= (event
->xmotion
.y
+ rect
.pos
.y
) / table
->rowHeight
;
1126 if (table
->clickedRow
!= row
&& row
>= 0 && row
< table
->rows
) {
1127 setRowSelected(table
, table
->clickedRow
, False
);
1128 setRowSelected(table
, row
, True
);
1129 table
->clickedRow
= row
;
1135 if (event
->xbutton
.button
== Button1
) {
1137 (*table
->action
) (table
, table
->clientData
);
1138 WMPostNotificationName(WMTableViewSelectionDidChangeNotification
, table
, NULL
);
1139 table
->dragging
= 0;
1145 static void handleEvents(XEvent
* event
, void *data
)
1147 WMTableView
*table
= (WMTableView
*) data
;
1148 WMScreen
*scr
= WMWidgetScreen(table
);
1150 switch (event
->type
) {
1152 W_DrawRelief(scr
, W_VIEW_DRAWABLE(table
->view
), 0, 0,
1153 W_VIEW_WIDTH(table
->view
), W_VIEW_HEIGHT(table
->view
), WRSunken
);
1158 static void handleResize(W_ViewDelegate
* self
, WMView
* view
)
1160 reorganizeInterior(view
->self
);
1163 static void reorganizeInterior(WMTableView
* table
)
1167 WMSize size
= getTotalSize(table
);
1168 WMView
*view
= table
->view
;
1170 int hsThickness
, vsThickness
;
1173 vsThickness
= WMWidgetWidth(table
->vscroll
);
1175 hsThickness
= WMWidgetHeight(table
->hscroll
);
1177 width
= W_VIEW_WIDTH(view
) - 2;
1178 height
= W_VIEW_HEIGHT(view
) - 3;
1180 height
-= table
->headerHeight
; /* table header */
1183 WMResizeWidget(table
->corner
, 20, table
->headerHeight
);
1185 WMMoveWidget(table
->vscroll
, 1, table
->headerHeight
+ 1);
1186 WMResizeWidget(table
->vscroll
, 20, height
+ 1);
1188 if (table
->hscroll
) {
1189 WMMoveWidget(table
->hscroll
, vsThickness
, W_VIEW_HEIGHT(view
) - hsThickness
- 1);
1190 WMResizeWidget(table
->hscroll
, width
- (vsThickness
+ 1), hsThickness
);
1194 WMResizeWidget(table
->header
, width
- (vsThickness
+ 1), table
->headerHeight
);
1196 if (table
->viewBuffer
) {
1197 WMReleasePixmap(table
->viewBuffer
);
1198 table
->viewBuffer
= NULL
;
1201 width
-= vsThickness
;
1202 height
-= hsThickness
;
1204 vw
= WMIN(size
.width
, width
);
1205 vh
= WMIN(size
.height
, height
);
1207 W_MoveView(table
->tableView
, vsThickness
+ 1, 1 + table
->headerHeight
+ 1);
1208 W_ResizeView(table
->tableView
, WMAX(vw
, 1), WMAX(vh
, 1) + 1);
1210 adjustScrollers(table
);
1212 repaintTable(table
);
1215 static void rearrangeHeader(WMTableView
* table
)
1220 /*WMRect rect = WMGetScrollViewVisibleRect(table->scrollView); */
1224 count
= WMGetArrayItemCount(table
->columns
);
1225 for (i
= 0; i
< count
; i
++) {
1226 WMTableColumn
*column
= WMGetFromArray(table
->columns
, i
);
1227 WMView
*splitter
= WMGetFromArray(table
->splitters
, i
);
1229 WMMoveWidget(column
->titleW
, width
, 0);
1230 WMResizeWidget(column
->titleW
, column
->width
- 1, table
->headerHeight
);
1232 width
+= column
->width
;
1233 W_MoveView(splitter
, width
- 1, 0);
1236 wassertr(table
->delegate
&& table
->delegate
->numberOfRows
);
1238 table
->rows
= table
->delegate
->numberOfRows(table
->delegate
, table
);
1240 table
->tableWidth
= width
+ 1;
1242 handleResize(table
->view
->delegate
, table
->view
);