2 #include <WINGs/WINGsP.h>
3 #include <X11/cursorfont.h>
8 #include "wtableview.h"
10 const char *WMTableViewSelectionDidChangeNotification
= "WMTableViewSelectionDidChangeNotification";
12 struct W_TableColumn
{
22 WMTableColumnDelegate
*delegate
;
28 static void handleResize(W_ViewDelegate
* self
, WMView
* view
);
30 static void rearrangeHeader(WMTableView
* table
);
32 static WMRange
rowsInRect(WMTableView
* table
, WMRect rect
);
34 WMTableColumn
*WMCreateTableColumn(char *title
)
36 WMTableColumn
*col
= wmalloc(sizeof(WMTableColumn
));
46 col
->title
= wstrdup(title
);
56 void WMSetTableColumnId(WMTableColumn
* column
, void *id
)
61 void *WMGetTableColumnId(WMTableColumn
* column
)
66 void WMSetTableColumnWidth(WMTableColumn
* column
, unsigned width
)
68 if (column
->maxWidth
== 0)
69 column
->width
= WMAX(column
->minWidth
, width
);
71 column
->width
= WMAX(column
->minWidth
, WMIN(column
->maxWidth
, width
));
74 rearrangeHeader(column
->table
);
78 void WMSetTableColumnDelegate(WMTableColumn
* column
, WMTableColumnDelegate
* delegate
)
80 column
->delegate
= delegate
;
83 void WMSetTableColumnConstraints(WMTableColumn
* column
, unsigned minWidth
, unsigned maxWidth
)
85 wassertr(maxWidth
== 0 || minWidth
<= maxWidth
);
87 column
->minWidth
= minWidth
;
88 column
->maxWidth
= maxWidth
;
90 if (column
->width
< column
->minWidth
)
91 WMSetTableColumnWidth(column
, column
->minWidth
);
92 else if (column
->width
> column
->maxWidth
&& column
->maxWidth
!= 0)
93 WMSetTableColumnWidth(column
, column
->maxWidth
);
96 void WMSetTableColumnEditable(WMTableColumn
* column
, Bool flag
)
98 column
->editable
= ((flag
== 0) ? 0 : 1);
101 WMTableView
*WMGetTableColumnTableView(WMTableColumn
* column
)
103 return column
->table
;
118 WMPixmap
*viewBuffer
;
123 WMArray
*selectedRows
;
134 Cursor splitterCursor
;
138 WMTableViewDelegate
*delegate
;
148 unsigned headerHeight
;
153 unsigned drawsGrid
:1;
154 unsigned canSelectRow
:1;
155 unsigned canSelectMultiRows
:1;
156 unsigned canDeselectRow
:1;
158 unsigned int hasVScroller
:1;
159 unsigned int hasHScroller
:1;
162 static W_Class tableClass
= 0;
164 static W_ViewDelegate viewDelegate
= {
172 static void reorganizeInterior(WMTableView
* table
);
174 static void handleEvents(XEvent
* event
, void *data
);
175 static void handleTableEvents(XEvent
* event
, void *data
);
176 static void repaintTable(WMTableView
* table
);
178 static WMSize
getTotalSize(WMTableView
* table
)
183 /* get width from columns */
185 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
186 WMTableColumn
*column
;
188 column
= WMGetFromArray(table
->columns
, i
);
190 size
.width
+= column
->width
;
193 /* get height from rows */
194 size
.height
= table
->rows
* table
->rowHeight
;
199 static WMRect
getVisibleRect(WMTableView
* table
)
201 WMSize size
= getTotalSize(table
);
204 if (table
->vscroll
) {
205 rect
.size
.height
= size
.height
* WMGetScrollerKnobProportion(table
->vscroll
);
206 rect
.pos
.y
= (size
.height
- rect
.size
.height
) * WMGetScrollerValue(table
->vscroll
);
208 rect
.size
.height
= size
.height
;
212 if (table
->hscroll
) {
213 rect
.size
.width
= size
.width
* WMGetScrollerKnobProportion(table
->hscroll
);
214 rect
.pos
.x
= (size
.width
- rect
.size
.width
) * WMGetScrollerValue(table
->hscroll
);
216 rect
.size
.width
= size
.width
;
223 static void scrollToPoint(WMTableView
* table
, int x
, int y
)
225 WMSize size
= getTotalSize(table
);
229 if (table
->hscroll
) {
230 if (size
.width
> W_VIEW_WIDTH(table
->tableView
)) {
231 prop
= (float)W_VIEW_WIDTH(table
->tableView
) / (float)size
.width
;
232 value
= (float)x
/ (float)(size
.width
- W_VIEW_WIDTH(table
->tableView
));
237 WMSetScrollerParameters(table
->hscroll
, value
, prop
);
240 if (table
->vscroll
) {
241 if (size
.height
> W_VIEW_HEIGHT(table
->tableView
)) {
242 prop
= (float)W_VIEW_HEIGHT(table
->tableView
) / (float)size
.height
;
243 value
= (float)y
/ (float)(size
.height
- W_VIEW_HEIGHT(table
->tableView
));
249 WMSetScrollerParameters(table
->vscroll
, value
, prop
);
252 if (table
->editingRow
>= 0) {
253 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
254 WMTableColumn
*column
;
256 column
= WMGetFromArray(table
->columns
, i
);
258 if (column
->delegate
&& column
->delegate
->beginCellEdit
)
259 (*column
->delegate
->beginCellEdit
) (column
->delegate
, column
, table
->editingRow
);
266 static void adjustScrollers(WMTableView
* table
)
268 WMSize size
= getTotalSize(table
);
269 WMSize vsize
= WMGetViewSize(table
->tableView
);
273 if (table
->hscroll
) {
274 if (size
.width
<= vsize
.width
) {
278 oprop
= WMGetScrollerKnobProportion(table
->hscroll
);
279 if (fabs(oprop
) <= DBL_EPSILON
)
281 ovalue
= WMGetScrollerValue(table
->hscroll
);
283 prop
= (float)vsize
.width
/ (float)size
.width
;
284 value
= prop
* ovalue
/ oprop
;
286 WMSetScrollerParameters(table
->hscroll
, value
, prop
);
289 if (table
->vscroll
) {
290 if (size
.height
<= vsize
.height
) {
294 oprop
= WMGetScrollerKnobProportion(table
->vscroll
);
295 if (fabs(oprop
) <= DBL_EPSILON
)
297 ovalue
= WMGetScrollerValue(table
->vscroll
);
299 prop
= (float)vsize
.height
/ (float)size
.height
;
300 value
= prop
* ovalue
/ oprop
;
302 WMSetScrollerParameters(table
->vscroll
, value
, prop
);
306 static void doScroll(WMWidget
* self
, void *data
)
308 WMTableView
*table
= (WMTableView
*) data
;
312 WMSize ts
= getTotalSize(table
);
314 value
= WMGetScrollerValue(self
);
316 if (table
->hscroll
== (WMScroller
*) self
) {
317 vpsize
= W_VIEW_WIDTH(table
->tableView
);
320 vpsize
= W_VIEW_HEIGHT(table
->tableView
);
324 switch (WMGetScrollerHitPart(self
)) {
325 case WSDecrementWheel
:
326 case WSDecrementLine
:
327 value
-= (float)table
->rowHeight
/ size
;
330 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
334 case WSIncrementWheel
:
335 case WSIncrementLine
:
336 value
+= (float)table
->rowHeight
/ size
;
337 if (value
> (float)1.0)
339 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
347 case WSDecrementPage
:
348 value
-= vpsize
/ size
;
349 if (value
< (float)0.0)
351 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
355 case WSIncrementPage
:
356 value
+= vpsize
/ size
;
357 if (value
> (float)1.0)
359 WMSetScrollerParameters(self
, value
, WMGetScrollerKnobProportion(self
));
368 if (table
->editingRow
>= 0) {
370 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
371 WMTableColumn
*column
;
373 column
= WMGetFromArray(table
->columns
, i
);
375 if (column
->delegate
&& column
->delegate
->beginCellEdit
)
376 (*column
->delegate
->beginCellEdit
) (column
->delegate
, column
, table
->editingRow
);
380 if (table
->hscroll
== self
) {
383 WMRect rect
= getVisibleRect(table
);
385 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
386 WMTableColumn
*column
;
389 column
= WMGetFromArray(table
->columns
, i
);
391 WMMoveWidget(column
->titleW
, x
- rect
.pos
.x
, 0);
393 x
+= W_VIEW_WIDTH(WMWidgetView(column
->titleW
)) + 1;
395 splitter
= WMGetFromArray(table
->splitters
, i
);
396 W_MoveView(splitter
, x
- rect
.pos
.x
- 1, 0);
401 static void splitterHandler(XEvent
* event
, void *data
)
404 WMTableColumn
*column
= (WMTableColumn
*) data
;
405 WMTableView
*table
= column
->table
;
409 WMScreen
*scr
= WMWidgetScreen(table
);
411 Display
*dpy
= WMScreenDisplay(scr
);
412 int h
= WMWidgetHeight(table
) - 22;
413 Window w
= WMViewXID(table
->view
);
415 pos
= WMGetViewPosition(WMWidgetView(column
->titleW
));
417 offsX
= pos
.x
+ column
->width
;
421 XDrawLine(dpy
, w
, gc
, cx
+ 20, 0, cx
+ 20, h
);
426 WMMaskEvent(dpy
, ButtonMotionMask
| ButtonReleaseMask
, &ev
);
432 if (column
->width
+ ev
.xmotion
.x
< column
->minWidth
)
433 cx
= pos
.x
+ column
->minWidth
;
434 else if (column
->maxWidth
> 0 && column
->width
+ ev
.xmotion
.x
> column
->maxWidth
)
435 cx
= pos
.x
+ column
->maxWidth
;
437 cx
= offsX
+ ev
.xmotion
.x
;
439 XDrawLine(dpy
, w
, gc
, ox
+ 20, 0, ox
+ 20, h
);
440 XDrawLine(dpy
, w
, gc
, cx
+ 20, 0, cx
+ 20, h
);
444 column
->width
= cx
- pos
.x
;
450 XDrawLine(dpy
, w
, gc
, cx
+ 20, 0, cx
+ 20, h
);
451 rearrangeHeader(table
);
455 static void realizeTable(void *data
, WMNotification
* notif
)
462 WMTableView
*WMCreateTableView(WMWidget
* parent
)
464 WMTableView
*table
= wmalloc(sizeof(WMTableView
));
465 WMScreen
*scr
= WMWidgetScreen(parent
);
467 memset(table
, 0, sizeof(WMTableView
));
470 tableClass
= W_RegisterUserWidget();
472 table
->widgetClass
= tableClass
;
474 table
->view
= W_CreateView(W_VIEW(parent
));
477 table
->view
->self
= table
;
479 table
->view
->delegate
= &viewDelegate
;
481 table
->headerHeight
= 20;
483 table
->hscroll
= WMCreateScroller(table
);
484 WMSetScrollerAction(table
->hscroll
, doScroll
, table
);
485 WMMoveWidget(table
->hscroll
, 1, 2 + table
->headerHeight
);
486 WMMapWidget(table
->hscroll
);
488 table
->hasHScroller
= 1;
490 table
->vscroll
= WMCreateScroller(table
);
491 WMSetScrollerArrowsPosition(table
->vscroll
, WSAMaxEnd
);
492 WMSetScrollerAction(table
->vscroll
, doScroll
, table
);
493 WMMoveWidget(table
->vscroll
, 1, 2 + table
->headerHeight
);
494 WMMapWidget(table
->vscroll
);
496 table
->hasVScroller
= 1;
498 table
->header
= WMCreateFrame(table
);
499 WMMoveWidget(table
->header
, 22, 2);
500 WMMapWidget(table
->header
);
501 WMSetFrameRelief(table
->header
, WRFlat
);
503 table
->corner
= WMCreateLabel(table
);
504 WMResizeWidget(table
->corner
, 20, table
->headerHeight
);
505 WMMoveWidget(table
->corner
, 2, 2);
506 WMMapWidget(table
->corner
);
507 WMSetLabelRelief(table
->corner
, WRRaised
);
508 WMSetWidgetBackgroundColor(table
->corner
, scr
->darkGray
);
510 table
->tableView
= W_CreateView(table
->view
);
511 if (!table
->tableView
)
513 table
->tableView
->self
= table
;
514 W_MapView(table
->tableView
);
516 WMAddNotificationObserver(realizeTable
, table
, WMViewRealizedNotification
, table
->tableView
);
518 table
->tableView
->flags
.dontCompressExpose
= 1;
520 table
->gridColor
= WMCreateNamedColor(scr
, "#cccccc", False
);
521 /* table->gridColor = WMGrayColor(scr); */
526 table
->backColor
= WMWhiteColor(scr
);
528 gcv
.foreground
= WMColorPixel(table
->gridColor
);
530 gcv
.line_style
= LineOnOffDash
;
531 table
->gridGC
= XCreateGC(WMScreenDisplay(scr
), W_DRAWABLE(scr
), GCForeground
, &gcv
);
534 table
->editingRow
= -1;
535 table
->clickedRow
= -1;
537 table
->drawsGrid
= 1;
538 table
->rowHeight
= 16;
540 table
->tableWidth
= 1;
542 table
->columns
= WMCreateArray(4);
543 table
->splitters
= WMCreateArray(4);
545 table
->selectedRows
= WMCreateArray(16);
547 table
->splitterCursor
= XCreateFontCursor(WMScreenDisplay(scr
), XC_sb_h_double_arrow
);
549 table
->canSelectRow
= 1;
551 WMCreateEventHandler(table
->view
, ExposureMask
| StructureNotifyMask
, handleEvents
, table
);
553 WMCreateEventHandler(table
->tableView
, ExposureMask
| ButtonPressMask
|
554 ButtonReleaseMask
| ButtonMotionMask
, handleTableEvents
, table
);
556 WMResizeWidget(table
, 50, 50);
561 if (table
->tableView
)
562 W_DestroyView(table
->tableView
);
564 W_DestroyView(table
->view
);
569 void WMAddTableViewColumn(WMTableView
* table
, WMTableColumn
* column
)
571 WMScreen
*scr
= WMWidgetScreen(table
);
573 column
->table
= table
;
575 WMAddToArray(table
->columns
, column
);
577 if (!column
->titleW
) {
578 column
->titleW
= WMCreateLabel(table
);
579 WMSetLabelRelief(column
->titleW
, WRRaised
);
580 WMSetLabelFont(column
->titleW
, scr
->boldFont
);
581 WMSetLabelTextColor(column
->titleW
, scr
->white
);
582 WMSetWidgetBackgroundColor(column
->titleW
, scr
->darkGray
);
583 WMSetLabelText(column
->titleW
, column
->title
);
584 W_ReparentView(WMWidgetView(column
->titleW
), WMWidgetView(table
->header
), 0, 0);
585 if (W_VIEW_REALIZED(table
->view
))
586 WMRealizeWidget(column
->titleW
);
587 WMMapWidget(column
->titleW
);
591 WMView
*splitter
= W_CreateView(WMWidgetView(table
->header
));
593 W_SetViewBackgroundColor(splitter
, WMWhiteColor(scr
));
595 if (W_VIEW_REALIZED(table
->view
))
596 W_RealizeView(splitter
);
598 W_ResizeView(splitter
, 2, table
->headerHeight
);
601 W_SetViewCursor(splitter
, table
->splitterCursor
);
602 WMCreateEventHandler(splitter
, ButtonPressMask
| ButtonReleaseMask
, splitterHandler
, column
);
604 WMAddToArray(table
->splitters
, splitter
);
607 rearrangeHeader(table
);
610 void WMSetTableViewHeaderHeight(WMTableView
* table
, unsigned height
)
612 table
->headerHeight
= height
;
614 handleResize(NULL
, table
->view
);
617 void WMSetTableViewDelegate(WMTableView
* table
, WMTableViewDelegate
* delegate
)
619 table
->delegate
= delegate
;
622 void WMSetTableViewAction(WMTableView
* table
, WMAction
* action
, void *clientData
)
624 table
->action
= action
;
626 table
->clientData
= clientData
;
629 void *WMGetTableViewClickedColumn(WMTableView
* table
)
631 return table
->clickedColumn
;
634 int WMGetTableViewClickedRow(WMTableView
* table
)
636 return table
->clickedRow
;
639 WMArray
*WMGetTableViewSelectedRows(WMTableView
* table
)
641 return table
->selectedRows
;
644 WMView
*WMGetTableViewDocumentView(WMTableView
* table
)
646 return table
->tableView
;
649 void *WMTableViewDataForCell(WMTableView
* table
, WMTableColumn
* column
, int row
)
651 return (*table
->delegate
->valueForCell
) (table
->delegate
, column
, row
);
654 void WMSetTableViewDataForCell(WMTableView
* table
, WMTableColumn
* column
, int row
, void *data
)
656 (*table
->delegate
->setValueForCell
) (table
->delegate
, column
, row
, data
);
659 WMRect
WMTableViewRectForCell(WMTableView
* table
, WMTableColumn
* column
, int row
)
665 rect
.pos
.y
= row
* table
->rowHeight
;
666 rect
.size
.height
= table
->rowHeight
;
668 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
670 col
= WMGetFromArray(table
->columns
, i
);
673 rect
.size
.width
= col
->width
;
677 rect
.pos
.x
+= col
->width
;
681 WMRect r
= getVisibleRect(table
);
683 rect
.pos
.y
-= r
.pos
.y
;
684 rect
.pos
.x
-= r
.pos
.x
;
690 void WMSetTableViewDataSource(WMTableView
* table
, void *source
)
692 table
->dataSource
= source
;
695 void *WMGetTableViewDataSource(WMTableView
* table
)
697 return table
->dataSource
;
700 void WMSetTableViewHasHorizontalScroller(WMTableView
* tPtr
, Bool flag
)
703 if (tPtr
->hasHScroller
)
705 tPtr
->hasHScroller
= 1;
707 tPtr
->hscroll
= WMCreateScroller(tPtr
);
708 WMSetScrollerAction(tPtr
->hscroll
, doScroll
, tPtr
);
709 WMSetScrollerArrowsPosition(tPtr
->hscroll
, WSAMaxEnd
);
710 /* make it a horiz. scroller */
711 WMResizeWidget(tPtr
->hscroll
, 1, 2);
713 if (W_VIEW_REALIZED(tPtr
->view
)) {
714 WMRealizeWidget(tPtr
->hscroll
);
717 reorganizeInterior(tPtr
);
719 WMMapWidget(tPtr
->hscroll
);
721 if (!tPtr
->hasHScroller
)
723 tPtr
->hasHScroller
= 0;
725 WMUnmapWidget(tPtr
->hscroll
);
726 WMDestroyWidget(tPtr
->hscroll
);
727 tPtr
->hscroll
= NULL
;
729 reorganizeInterior(tPtr
);
734 /* not supported by now */
735 void WMSetTableViewHasVerticalScroller(WMTableView
* tPtr
, Bool flag
)
738 if (tPtr
->hasVScroller
)
740 tPtr
->hasVScroller
= 1;
742 tPtr
->vscroll
= WMCreateScroller(tPtr
);
743 WMSetScrollerAction(tPtr
->vscroll
, doScroll
, tPtr
);
744 WMSetScrollerArrowsPosition(tPtr
->vscroll
, WSAMaxEnd
);
745 /* make it a vert. scroller */
746 WMResizeWidget(tPtr
->vscroll
, 1, 2);
748 if (W_VIEW_REALIZED(tPtr
->view
)) {
749 WMRealizeWidget(tPtr
->vscroll
);
752 reorganizeInterior(tPtr
);
754 WMMapWidget(tPtr
->vscroll
);
756 if (!tPtr
->hasVScroller
)
758 tPtr
->hasVScroller
= 0;
760 WMUnmapWidget(tPtr
->vscroll
);
761 WMDestroyWidget(tPtr
->vscroll
);
762 tPtr
->vscroll
= NULL
;
764 reorganizeInterior(tPtr
);
769 void WMSetTableViewBackgroundColor(WMTableView
* table
, WMColor
* color
)
771 W_SetViewBackgroundColor(table
->tableView
, color
);
773 if (table
->backColor
)
774 WMReleaseColor(table
->backColor
);
776 table
->backColor
= WMRetainColor(color
);
781 void WMSetTableViewGridColor(WMTableView
* table
, WMColor
* color
)
783 WMReleaseColor(table
->gridColor
);
784 table
->gridColor
= WMRetainColor(color
);
785 XSetForeground(WMScreenDisplay(WMWidgetScreen(table
)), table
->gridGC
, WMColorPixel(color
));
789 void WMSetTableViewRowHeight(WMTableView
* table
, int height
)
791 table
->rowHeight
= height
;
796 void WMScrollTableViewRowToVisible(WMTableView
* table
, int row
)
802 rect
= getVisibleRect(table
);
803 range
= rowsInRect(table
, rect
);
806 if (row
< range
.position
) {
807 newY
= row
* table
->rowHeight
- rect
.size
.height
/ 2;
808 } else if (row
>= range
.position
+ range
.count
) {
809 newY
= row
* table
->rowHeight
- rect
.size
.height
/ 2;
813 tmp
= table
->rows
* table
->rowHeight
- rect
.size
.height
;
814 newY
= WMAX(0, WMIN(newY
, tmp
));
816 scrollToPoint(table
, rect
.pos
.x
, newY
);
819 static void drawGrid(WMTableView
* table
, WMRect rect
)
821 WMScreen
*scr
= WMWidgetScreen(table
);
822 Display
*dpy
= WMScreenDisplay(scr
);
827 Drawable d
= WMGetPixmapXID(table
->viewBuffer
);
828 GC gc
= table
->gridGC
;
831 char dashl
[1] = { 1 };
833 XSetDashes(dpy
, gc
, 0, dashl
, 1);
835 y1
= (rect
.pos
.y
/ table
->rowHeight
- 1) * table
->rowHeight
;
836 y2
= y1
+ (rect
.size
.height
/ table
->rowHeight
+ 2) * table
->rowHeight
;
839 y2
= W_VIEW_HEIGHT(table
->tableView
);
842 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
843 WMTableColumn
*column
;
845 XDrawLine(dpy
, d
, gc
, xx
, y1
, xx
, y2
);
847 column
= WMGetFromArray(table
->columns
, i
);
850 XDrawLine(dpy
, d
, gc
, xx
, y1
, xx
, y2
);
853 x2
= rect
.size
.width
;
858 XSetDashes(dpy
, gc
, (rect
.pos
.x
& 1), dashl
, 1);
861 y1
= -rect
.pos
.y
% table
->rowHeight
;
862 y2
= y1
+ rect
.size
.height
+ table
->rowHeight
;
864 for (i
= y1
; i
<= y2
; i
+= table
->rowHeight
) {
865 XDrawLine(dpy
, d
, gc
, x1
, i
, x2
, i
);
869 static WMRange
columnsInRect(WMTableView
* table
, WMRect rect
)
871 WMTableColumn
*column
;
874 int totalColumns
= WMGetArrayItemCount(table
->columns
);
879 for (i
= 0; i
< totalColumns
; i
++) {
880 column
= WMGetFromArray(table
->columns
, i
);
882 if (rect
.pos
.x
>= pos
&& rect
.pos
.x
< pos
+ column
->width
) {
888 if (pos
> rect
.pos
.x
+ rect
.size
.width
) {
893 pos
+= column
->width
;
895 range
.count
= WMAX(1, WMIN(range
.count
, totalColumns
- range
.position
));
899 static WMRange
rowsInRect(WMTableView
* table
, WMRect rect
)
902 int rh
= table
->rowHeight
;
905 dif
= rect
.pos
.y
% rh
;
907 range
.position
= WMAX(0, (rect
.pos
.y
- dif
) / rh
);
908 range
.count
= WMAX(1, WMIN((rect
.size
.height
+ dif
) / rh
, table
->rows
));
913 static void drawRow(WMTableView
* table
, int row
, WMRect clipRect
)
916 WMRange cols
= columnsInRect(table
, clipRect
);
917 WMTableColumn
*column
;
918 Drawable d
= WMGetPixmapXID(table
->viewBuffer
);
920 for (i
= cols
.position
; i
< cols
.position
+ cols
.count
; i
++) {
921 column
= WMGetFromArray(table
->columns
, i
);
923 if (!column
->delegate
|| !column
->delegate
->drawCell
)
926 if (WMFindInArray(table
->selectedRows
, NULL
, (void *)(uintptr_t) row
) != WANotFound
)
927 (*column
->delegate
->drawSelectedCell
) (column
->delegate
, column
, row
, d
);
929 (*column
->delegate
->drawCell
) (column
->delegate
, column
, row
, d
);
934 static void drawFullRow(WMTableView
* table
, int row
)
937 WMTableColumn
*column
;
938 Drawable d
= WMGetPixmapXID(table
->viewBuffer
);
940 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
941 column
= WMGetFromArray(table
->columns
, i
);
943 if (!column
->delegate
|| !column
->delegate
->drawCell
)
946 if (WMFindInArray(table
->selectedRows
, NULL
, (void *)row
) != WANotFound
)
947 (*column
->delegate
->drawSelectedCell
) (column
->delegate
, column
, row
, d
);
949 (*column
->delegate
->drawCell
) (column
->delegate
, column
, row
, d
);
954 static void setRowSelected(WMTableView
* table
, unsigned row
, Bool flag
)
958 if (WMFindInArray(table
->selectedRows
, NULL
, (void *)(uintptr_t) row
) != WANotFound
) {
960 WMRemoveFromArray(table
->selectedRows
, (void *)(uintptr_t) row
);
965 WMAddToArray(table
->selectedRows
, (void *)(uintptr_t) row
);
969 if (repaint
&& row
< table
->rows
) {
970 /*drawFullRow(table, row); */
975 static void repaintTable(WMTableView
* table
)
979 WMScreen
*scr
= WMWidgetScreen(table
);
982 if (!table
->delegate
|| !W_VIEW_REALIZED(table
->view
))
985 wassertr(table
->delegate
->numberOfRows
);
987 if (!table
->viewBuffer
) {
988 table
->viewBuffer
= WMCreatePixmap(scr
,
989 W_VIEW_WIDTH(table
->tableView
),
990 W_VIEW_HEIGHT(table
->tableView
), WMScreenDepth(scr
), 0);
993 XFillRectangle(scr
->display
,
994 WMGetPixmapXID(table
->viewBuffer
),
995 WMColorGC(table
->backColor
), 0, 0,
996 W_VIEW_WIDTH(table
->tableView
), W_VIEW_HEIGHT(table
->tableView
));
998 rect
= getVisibleRect(table
);
1000 if (table
->drawsGrid
) {
1001 drawGrid(table
, rect
);
1004 rows
= rowsInRect(table
, rect
);
1005 for (i
= rows
.position
; i
< WMIN(rows
.position
+ rows
.count
+ 1, table
->rows
); i
++) {
1006 drawRow(table
, i
, rect
);
1009 XSetWindowBackgroundPixmap(scr
->display
, table
->tableView
->window
, WMGetPixmapXID(table
->viewBuffer
));
1010 XClearWindow(scr
->display
, table
->tableView
->window
);
1013 static void stopRowEdit(WMTableView
* table
, int row
)
1016 WMTableColumn
*column
;
1018 table
->editingRow
= -1;
1019 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
1020 column
= WMGetFromArray(table
->columns
, i
);
1022 if (column
->delegate
&& column
->delegate
->endCellEdit
)
1023 (*column
->delegate
->endCellEdit
) (column
->delegate
, column
, row
);
1027 void WMEditTableViewRow(WMTableView
* table
, int row
)
1030 WMTableColumn
*column
;
1032 if (table
->editingRow
>= 0) {
1033 stopRowEdit(table
, table
->editingRow
);
1036 table
->editingRow
= row
;
1041 for (i
= 0; i
< WMGetArrayItemCount(table
->columns
); i
++) {
1042 column
= WMGetFromArray(table
->columns
, i
);
1044 if (column
->delegate
&& column
->delegate
->beginCellEdit
)
1045 (*column
->delegate
->beginCellEdit
) (column
->delegate
, column
, row
);
1049 void WMSelectTableViewRow(WMTableView
* table
, int row
)
1051 if (table
->clickedRow
>= 0)
1052 setRowSelected(table
, table
->clickedRow
, False
);
1054 if (row
>= table
->rows
) {
1058 setRowSelected(table
, row
, True
);
1059 table
->clickedRow
= row
;
1062 (*table
->action
) (table
, table
->clientData
);
1063 WMPostNotificationName(WMTableViewSelectionDidChangeNotification
, table
, NULL
);
1066 void WMReloadTableView(WMTableView
* table
)
1068 if (table
->editingRow
>= 0)
1069 stopRowEdit(table
, table
->editingRow
);
1071 /* when this is called, nothing in the table can be assumed to be
1072 * like the last time we accessed it (ie, rows might have disappeared) */
1074 WMEmptyArray(table
->selectedRows
);
1076 if (table
->clickedRow
>= 0) {
1078 (*table
->action
) (table
, table
->clientData
);
1079 WMPostNotificationName(WMTableViewSelectionDidChangeNotification
, table
, NULL
);
1080 table
->clickedRow
= -1;
1083 if (table
->delegate
&& table
->delegate
->numberOfRows
) {
1086 rows
= (*table
->delegate
->numberOfRows
) (table
->delegate
, table
);
1088 if (rows
!= table
->rows
) {
1090 handleResize(table
->view
->delegate
, table
->view
);
1092 repaintTable(table
);
1097 void WMNoteTableViewNumberOfRowsChanged(WMTableView
* table
)
1099 WMReloadTableView(table
);
1102 static void handleTableEvents(XEvent
* event
, void *data
)
1104 WMTableView
*table
= (WMTableView
*) data
;
1107 switch (event
->type
) {
1109 if (event
->xbutton
.button
== Button1
) {
1110 WMRect rect
= getVisibleRect(table
);
1112 row
= (event
->xbutton
.y
+ rect
.pos
.y
) / table
->rowHeight
;
1113 if (row
!= table
->clickedRow
) {
1114 setRowSelected(table
, table
->clickedRow
, False
);
1115 setRowSelected(table
, row
, True
);
1116 table
->clickedRow
= row
;
1117 table
->dragging
= 1;
1119 table
->dragging
= 1;
1125 if (table
->dragging
&& event
->xmotion
.y
>= 0) {
1126 WMRect rect
= getVisibleRect(table
);
1128 row
= (event
->xmotion
.y
+ rect
.pos
.y
) / table
->rowHeight
;
1129 if (table
->clickedRow
!= row
&& row
>= 0 && row
< table
->rows
) {
1130 setRowSelected(table
, table
->clickedRow
, False
);
1131 setRowSelected(table
, row
, True
);
1132 table
->clickedRow
= row
;
1138 if (event
->xbutton
.button
== Button1
) {
1140 (*table
->action
) (table
, table
->clientData
);
1141 WMPostNotificationName(WMTableViewSelectionDidChangeNotification
, table
, NULL
);
1142 table
->dragging
= 0;
1148 static void handleEvents(XEvent
* event
, void *data
)
1150 WMTableView
*table
= (WMTableView
*) data
;
1151 WMScreen
*scr
= WMWidgetScreen(table
);
1153 switch (event
->type
) {
1155 W_DrawRelief(scr
, W_VIEW_DRAWABLE(table
->view
), 0, 0,
1156 W_VIEW_WIDTH(table
->view
), W_VIEW_HEIGHT(table
->view
), WRSunken
);
1161 static void handleResize(W_ViewDelegate
* self
, WMView
* view
)
1165 reorganizeInterior(view
->self
);
1168 static void reorganizeInterior(WMTableView
* table
)
1172 WMSize size
= getTotalSize(table
);
1173 WMView
*view
= table
->view
;
1175 int hsThickness
= 0;
1176 int vsThickness
= 0;
1179 vsThickness
= WMWidgetWidth(table
->vscroll
);
1181 hsThickness
= WMWidgetHeight(table
->hscroll
);
1183 width
= W_VIEW_WIDTH(view
) - 2;
1184 height
= W_VIEW_HEIGHT(view
) - 3;
1186 height
-= table
->headerHeight
; /* table header */
1189 WMResizeWidget(table
->corner
, 20, table
->headerHeight
);
1191 WMMoveWidget(table
->vscroll
, 1, table
->headerHeight
+ 1);
1192 WMResizeWidget(table
->vscroll
, 20, height
+ 1);
1194 if (table
->hscroll
) {
1195 WMMoveWidget(table
->hscroll
, vsThickness
, W_VIEW_HEIGHT(view
) - hsThickness
- 1);
1196 WMResizeWidget(table
->hscroll
, width
- (vsThickness
+ 1), hsThickness
);
1200 WMResizeWidget(table
->header
, width
- (vsThickness
+ 1), table
->headerHeight
);
1202 if (table
->viewBuffer
) {
1203 WMReleasePixmap(table
->viewBuffer
);
1204 table
->viewBuffer
= NULL
;
1207 width
-= vsThickness
;
1208 height
-= hsThickness
;
1210 vw
= WMIN(size
.width
, width
);
1211 vh
= WMIN(size
.height
, height
);
1213 W_MoveView(table
->tableView
, vsThickness
+ 1, 1 + table
->headerHeight
+ 1);
1214 W_ResizeView(table
->tableView
, WMAX(vw
, 1), WMAX(vh
, 1) + 1);
1216 adjustScrollers(table
);
1218 repaintTable(table
);
1221 static void rearrangeHeader(WMTableView
* table
)
1226 /*WMRect rect = WMGetScrollViewVisibleRect(table->scrollView); */
1230 count
= WMGetArrayItemCount(table
->columns
);
1231 for (i
= 0; i
< count
; i
++) {
1232 WMTableColumn
*column
= WMGetFromArray(table
->columns
, i
);
1233 WMView
*splitter
= WMGetFromArray(table
->splitters
, i
);
1235 WMMoveWidget(column
->titleW
, width
, 0);
1236 WMResizeWidget(column
->titleW
, column
->width
- 1, table
->headerHeight
);
1238 width
+= column
->width
;
1239 W_MoveView(splitter
, width
- 1, 0);
1242 wassertr(table
->delegate
&& table
->delegate
->numberOfRows
);
1244 table
->rows
= table
->delegate
->numberOfRows(table
->delegate
, table
);
1246 table
->tableWidth
= width
+ 1;
1248 handleResize(table
->view
->delegate
, table
->view
);