6 #include <math.h> /* for : double rint (double) */
10 typedef struct W_Browser
{
18 short usedColumnCount
; /* columns actually being used */
21 short maxVisibleColumns
;
22 short firstVisibleColumn
;
33 void *doubleClientData
;
34 WMAction
*doubleAction
;
36 WMBrowserDelegate
*delegate
;
43 unsigned int isTitled
:1;
44 unsigned int allowMultipleSelection
:1;
45 unsigned int hasScroller
:1;
48 unsigned int loaded
:1;
49 unsigned int loadingColumn
:1;
54 #define COLUMN_SPACING 4
55 #define TITLE_SPACING 2
57 #define DEFAULT_WIDTH 305
58 #define DEFAULT_HEIGHT 200
59 #define DEFAULT_HAS_SCROLLER True
60 #define DEFAULT_TITLE_HEIGHT 20
61 #define DEFAULT_IS_TITLED True
62 #define DEFAULT_MAX_VISIBLE_COLUMNS 2
63 #define DEFAULT_SEPARATOR "/"
65 #define MIN_VISIBLE_COLUMNS 1
66 #define MAX_VISIBLE_COLUMNS 32
69 #define COLUMN_IS_VISIBLE(b, c) ((c) >= (b)->firstVisibleColumn \
70 && (c) < (b)->firstVisibleColumn + (b)->maxVisibleColumns)
73 static void handleEvents(XEvent
*event
, void *data
);
74 static void destroyBrowser(WMBrowser
*bPtr
);
76 static void setupScroller(WMBrowser
*bPtr
);
78 static void scrollToColumn(WMBrowser
*bPtr
, int column
, Bool updateScroller
);
80 static void paintItem(WMList
*lPtr
, int index
, Drawable d
, char *text
,
81 int state
, WMRect
*rect
);
83 static void loadColumn(WMBrowser
*bPtr
, int column
);
85 static void removeColumn(WMBrowser
*bPtr
, int column
);
88 createTruncatedString(WMFont
*font
, char *text
, int *textLen
, int width
);
90 static void resizeBrowser(WMWidget
*, unsigned int, unsigned int);
92 W_ViewProcedureTable _BrowserViewProcedures
= {
101 WMCreateBrowser(WMWidget
*parent
)
106 wassertrv(parent
, NULL
);
108 bPtr
= wmalloc(sizeof(WMBrowser
));
109 memset(bPtr
, 0, sizeof(WMBrowser
));
111 bPtr
->widgetClass
= WC_Browser
;
113 bPtr
->view
= W_CreateView(W_VIEW(parent
));
118 bPtr
->view
->self
= bPtr
;
120 WMCreateEventHandler(bPtr
->view
, ExposureMask
|StructureNotifyMask
121 |ClientMessageMask
, handleEvents
, bPtr
);
123 /* default configuration */
124 bPtr
->flags
.hasScroller
= DEFAULT_HAS_SCROLLER
;
126 bPtr
->titleHeight
= DEFAULT_TITLE_HEIGHT
;
127 bPtr
->flags
.isTitled
= DEFAULT_IS_TITLED
;
128 bPtr
->maxVisibleColumns
= DEFAULT_MAX_VISIBLE_COLUMNS
;
130 resizeBrowser(bPtr
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
132 bPtr
->pathSeparator
= wstrdup(DEFAULT_SEPARATOR
);
134 if (bPtr
->flags
.hasScroller
)
137 for (i
=0; i
<bPtr
->maxVisibleColumns
; i
++) {
138 WMAddBrowserColumn(bPtr
);
140 bPtr
->usedColumnCount
= 0;
142 bPtr
->selectedColumn
= -1;
149 WMGetBrowserMaxVisibleColumns(WMBrowser
*bPtr
)
151 return bPtr
->maxVisibleColumns
;
156 WMSetBrowserMaxVisibleColumns(WMBrowser
*bPtr
, int columns
)
158 int curMaxVisibleColumns
;
159 int newFirstVisibleColumn
= 0;
163 columns
= (columns
< MIN_VISIBLE_COLUMNS
) ? MIN_VISIBLE_COLUMNS
: columns
;
164 columns
= (columns
> MAX_VISIBLE_COLUMNS
) ? MAX_VISIBLE_COLUMNS
: columns
;
165 if (columns
== bPtr
->maxVisibleColumns
) {
168 curMaxVisibleColumns
= bPtr
->maxVisibleColumns
;
169 bPtr
->maxVisibleColumns
= columns
;
170 /* browser not loaded */
171 if (!bPtr
->flags
.loaded
) {
172 if ((columns
> curMaxVisibleColumns
) && (columns
> bPtr
->columnCount
)) {
173 int i
= columns
- bPtr
->columnCount
;
174 bPtr
->usedColumnCount
= bPtr
->columnCount
;
176 WMAddBrowserColumn(bPtr
);
178 bPtr
->usedColumnCount
= 0;
180 /* browser loaded and columns > curMaxVisibleColumns */
181 } else if (columns
> curMaxVisibleColumns
) {
182 if (bPtr
->usedColumnCount
> columns
) {
183 newFirstVisibleColumn
= bPtr
->usedColumnCount
- columns
;
185 if (newFirstVisibleColumn
> bPtr
->firstVisibleColumn
) {
186 newFirstVisibleColumn
= bPtr
->firstVisibleColumn
;
188 if (columns
> bPtr
->columnCount
) {
189 int i
= columns
- bPtr
->columnCount
;
190 int curUsedColumnCount
= bPtr
->usedColumnCount
;
191 bPtr
->usedColumnCount
= bPtr
->columnCount
;
193 WMAddBrowserColumn(bPtr
);
195 bPtr
->usedColumnCount
= curUsedColumnCount
;
197 /* browser loaded and columns < curMaxVisibleColumns */
199 newFirstVisibleColumn
= bPtr
->firstVisibleColumn
;
200 if (newFirstVisibleColumn
+ columns
>= bPtr
->usedColumnCount
) {
201 removeColumn(bPtr
, newFirstVisibleColumn
+ columns
);
204 resizeBrowser(bPtr
, bPtr
->view
->size
.width
, bPtr
->view
->size
.height
);
205 if (bPtr
->flags
.loaded
) {
206 XClearArea(bPtr
->view
->screen
->display
, bPtr
->view
->window
, 0, 0,
207 bPtr
->view
->size
.width
, bPtr
->titleHeight
, False
);
208 scrollToColumn (bPtr
, newFirstVisibleColumn
, True
);
214 WMGetBrowserNumberOfColumns(WMBrowser
*bPtr
)
216 return bPtr
->usedColumnCount
;
220 WMSetBrowserPathSeparator(WMBrowser
*bPtr
, char *separator
)
222 if (bPtr
->pathSeparator
)
223 free(bPtr
->pathSeparator
);
224 bPtr
->pathSeparator
= wstrdup(separator
);
230 drawTitleOfColumn(WMBrowser
*bPtr
, int column
)
232 WMScreen
*scr
= bPtr
->view
->screen
;
235 x
=(column
-bPtr
->firstVisibleColumn
)*(bPtr
->columnSize
.width
+COLUMN_SPACING
);
237 XFillRectangle(scr
->display
, bPtr
->view
->window
, WMColorGC(scr
->darkGray
), x
, 0,
238 bPtr
->columnSize
.width
, bPtr
->titleHeight
);
239 W_DrawRelief(scr
, bPtr
->view
->window
, x
, 0,
240 bPtr
->columnSize
.width
, bPtr
->titleHeight
, WRSunken
);
242 if (column
< bPtr
->usedColumnCount
&& bPtr
->titles
[column
]) {
243 int titleLen
= strlen(bPtr
->titles
[column
]);
244 int widthC
= bPtr
->columnSize
.width
-8;
246 if (WMWidthOfString(scr
->boldFont
, bPtr
->titles
[column
], titleLen
)
248 char *titleBuf
= createTruncatedString(scr
->boldFont
,
249 bPtr
->titles
[column
],
251 W_PaintText(bPtr
->view
, bPtr
->view
->window
, scr
->boldFont
, x
,
252 (bPtr
->titleHeight
-WMFontHeight(scr
->boldFont
))/2,
253 bPtr
->columnSize
.width
, WACenter
, WMColorGC(scr
->white
),
254 False
, titleBuf
, titleLen
);
257 W_PaintText(bPtr
->view
, bPtr
->view
->window
, scr
->boldFont
, x
,
258 (bPtr
->titleHeight
-WMFontHeight(scr
->boldFont
))/2,
259 bPtr
->columnSize
.width
, WACenter
, WMColorGC(scr
->white
),
260 False
, bPtr
->titles
[column
], titleLen
);
267 WMGetBrowserListInColumn(WMBrowser
*bPtr
, int column
)
269 if (column
< 0 || column
>= bPtr
->usedColumnCount
)
272 return bPtr
->columns
[column
];
277 WMSetBrowserDelegate(WMBrowser
*bPtr
, WMBrowserDelegate
*delegate
)
279 bPtr
->delegate
= delegate
;
284 WMGetBrowserFirstVisibleColumn(WMBrowser
*bPtr
)
286 return bPtr
->firstVisibleColumn
;
291 removeColumn(WMBrowser
*bPtr
, int column
)
293 int i
, clearEnd
, destroyEnd
;
299 column
= (column
< 0) ? 0 : column
;
300 if (column
>= bPtr
->columnCount
) {
303 if (column
< bPtr
->maxVisibleColumns
) {
304 clearEnd
= bPtr
->maxVisibleColumns
;
305 destroyEnd
= bPtr
->columnCount
;
306 bPtr
->columnCount
= bPtr
->maxVisibleColumns
;
309 destroyEnd
= bPtr
->columnCount
;
310 bPtr
->columnCount
= column
;
312 if (column
< bPtr
->usedColumnCount
) {
313 bPtr
->usedColumnCount
= column
;
315 for (i
=column
; i
< clearEnd
; i
++) {
316 if (bPtr
->titles
[i
]) {
317 free(bPtr
->titles
[i
]);
318 bPtr
->titles
[i
] = NULL
;
320 WMClearList(bPtr
->columns
[i
]);
322 for (;i
< destroyEnd
; i
++) {
323 if (bPtr
->titles
[i
]) {
324 free(bPtr
->titles
[i
]);
325 bPtr
->titles
[i
] = NULL
;
327 WMRemoveNotificationObserverWithName(bPtr
,
328 WMListSelectionDidChangeNotification
,
330 WMDestroyWidget(bPtr
->columns
[i
]);
331 bPtr
->columns
[i
] = NULL
;
333 clist
= wmalloc(sizeof(WMList
*) * (bPtr
->columnCount
));
334 tlist
= wmalloc(sizeof(char*) * (bPtr
->columnCount
));
335 memcpy(clist
, bPtr
->columns
, sizeof(WMList
*) * (bPtr
->columnCount
));
336 memcpy(tlist
, bPtr
->titles
, sizeof(char*) * (bPtr
->columnCount
));
339 bPtr
->titles
= tlist
;
340 bPtr
->columns
= clist
;
345 WMGetBrowserSelectedItemInColumn(WMBrowser
*bPtr
, int column
)
347 if ((column
< 0) || (column
>= bPtr
->usedColumnCount
))
350 return WMGetListSelectedItem(bPtr
->columns
[column
]);
356 WMGetBrowserSelectedColumn(WMBrowser
*bPtr
)
358 return bPtr
->selectedColumn
;
363 WMGetBrowserSelectedRowInColumn(WMBrowser
*bPtr
, int column
)
365 if (column
>= 0 && column
< bPtr
->columnCount
) {
366 return WMGetListSelectedItemRow(bPtr
->columns
[column
]);
374 WMSetBrowserColumnTitle(WMBrowser
*bPtr
, int column
, char *title
)
377 assert(column
< bPtr
->usedColumnCount
);
379 if (bPtr
->titles
[column
])
380 free(bPtr
->titles
[column
]);
382 bPtr
->titles
[column
] = wstrdup(title
);
384 if (COLUMN_IS_VISIBLE(bPtr
, column
) && bPtr
->flags
.isTitled
) {
385 drawTitleOfColumn(bPtr
, column
);
391 WMSetBrowserTitled(WMBrowser
*bPtr
, Bool flag
)
394 int columnX
, columnY
;
396 if (bPtr
->flags
.isTitled
== flag
)
401 if (!bPtr
->flags
.isTitled
) {
402 columnY
= TITLE_SPACING
+ bPtr
->titleHeight
;
404 bPtr
->columnSize
.height
-= columnY
;
406 for (i
=0; i
<bPtr
->columnCount
; i
++) {
407 WMResizeWidget(bPtr
->columns
[i
], bPtr
->columnSize
.width
,
408 bPtr
->columnSize
.height
);
410 columnX
= WMWidgetView(bPtr
->columns
[i
])->pos
.x
;
412 WMMoveWidget(bPtr
->columns
[i
], columnX
, columnY
);
415 bPtr
->columnSize
.height
+= TITLE_SPACING
+ bPtr
->titleHeight
;
417 for (i
=0; i
<bPtr
->columnCount
; i
++) {
418 WMResizeWidget(bPtr
->columns
[i
], bPtr
->columnSize
.width
,
419 bPtr
->columnSize
.height
);
421 columnX
= WMWidgetView(bPtr
->columns
[i
])->pos
.x
;
423 WMMoveWidget(bPtr
->columns
[i
], columnX
, 0);
427 bPtr
->flags
.isTitled
= flag
;
432 WMAddSortedBrowserItem(WMBrowser
*bPtr
, int column
, char *text
, Bool isBranch
)
436 if (column
< 0 || column
>= bPtr
->columnCount
)
439 item
= WMAddSortedListItem(bPtr
->columns
[column
], text
);
440 item
->isBranch
= isBranch
;
448 WMInsertBrowserItem(WMBrowser
*bPtr
, int column
, int row
, char *text
,
453 if (column
< 0 || column
>= bPtr
->columnCount
)
456 item
= WMInsertListItem(bPtr
->columns
[column
], row
, text
);
457 item
->isBranch
= isBranch
;
466 resizeBrowser(WMWidget
*w
, unsigned int width
, unsigned int height
)
468 WMBrowser
*bPtr
= (WMBrowser
*)w
;
469 int cols
= bPtr
->maxVisibleColumns
;
476 bPtr
->columnSize
.width
= (width
-(cols
-1)*COLUMN_SPACING
) / cols
;
477 bPtr
->columnSize
.height
= height
;
479 if (bPtr
->flags
.isTitled
) {
480 colY
= TITLE_SPACING
+ bPtr
->titleHeight
;
481 bPtr
->columnSize
.height
-= colY
;
486 if (bPtr
->flags
.hasScroller
) {
487 bPtr
->columnSize
.height
-= SCROLLER_WIDTH
+ 4;
489 if (bPtr
->scroller
) {
490 WMResizeWidget(bPtr
->scroller
, width
-2, 1);
491 WMMoveWidget(bPtr
->scroller
, 1, height
-SCROLLER_WIDTH
-1);
496 for (i
= 0; i
< bPtr
->columnCount
; i
++) {
497 WMResizeWidget(bPtr
->columns
[i
], bPtr
->columnSize
.width
,
498 bPtr
->columnSize
.height
);
500 WMMoveWidget(bPtr
->columns
[i
], colX
, colY
);
502 if (COLUMN_IS_VISIBLE(bPtr
, i
)) {
503 colX
+= bPtr
->columnSize
.width
+COLUMN_SPACING
;
507 W_ResizeView(bPtr
->view
, width
, height
);
512 paintItem(WMList
*lPtr
, int index
, Drawable d
, char *text
, int state
,
515 WMView
*view
= W_VIEW(lPtr
);
516 W_Screen
*scr
= view
->screen
;
517 int width
, height
, x
, y
;
519 width
= rect
->size
.width
;
520 height
= rect
->size
.height
;
524 if (state
& WLDSSelected
)
525 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
), x
, y
,
528 XClearArea(scr
->display
, d
, x
, y
, width
, height
, False
);
531 /* Avoid overlaping... */
532 int textLen
= strlen(text
);
533 int widthC
= (state
& WLDSIsBranch
) ? width
-20 : width
-8;
534 if (WMWidthOfString(scr
->normalFont
, text
, textLen
) > widthC
) {
535 char *textBuf
= createTruncatedString(scr
->normalFont
,
536 text
, &textLen
, widthC
);
537 W_PaintText(view
, d
, scr
->normalFont
, x
+4, y
, widthC
,
538 WALeft
, WMColorGC(scr
->black
), False
, textBuf
, textLen
);
541 W_PaintText(view
, d
, scr
->normalFont
, x
+4, y
, widthC
,
542 WALeft
, WMColorGC(scr
->black
), False
, text
, textLen
);
546 if (state
& WLDSIsBranch
) {
547 XDrawLine(scr
->display
, d
, WMColorGC(scr
->darkGray
), x
+width
-11, y
+3,
548 x
+width
-6, y
+height
/2);
549 if (state
& WLDSSelected
)
550 XDrawLine(scr
->display
, d
,WMColorGC(scr
->gray
), x
+width
-11, y
+height
-5,
551 x
+width
-6, y
+height
/2);
553 XDrawLine(scr
->display
, d
,WMColorGC(scr
->white
), x
+width
-11, y
+height
-5,
554 x
+width
-6, y
+height
/2);
555 XDrawLine(scr
->display
, d
, WMColorGC(scr
->black
), x
+width
-12, y
+3,
556 x
+width
-12, y
+height
-5);
562 scrollCallback(WMWidget
*scroller
, void *self
)
564 WMBrowser
*bPtr
= (WMBrowser
*)self
;
565 WMScroller
*sPtr
= (WMScroller
*)scroller
;
567 #define LAST_VISIBLE_COLUMN bPtr->firstVisibleColumn+bPtr->maxVisibleColumns
569 switch (WMGetScrollerHitPart(sPtr
)) {
570 case WSDecrementLine
:
571 if (bPtr
->firstVisibleColumn
> 0) {
572 scrollToColumn(bPtr
, bPtr
->firstVisibleColumn
-1, True
);
576 case WSDecrementPage
:
577 if (bPtr
->firstVisibleColumn
> 0) {
578 newFirst
= bPtr
->firstVisibleColumn
- bPtr
->maxVisibleColumns
;
580 scrollToColumn(bPtr
, newFirst
, True
);
585 case WSIncrementLine
:
586 if (LAST_VISIBLE_COLUMN
< bPtr
->usedColumnCount
) {
587 scrollToColumn(bPtr
, bPtr
->firstVisibleColumn
+1, True
);
591 case WSIncrementPage
:
592 if (LAST_VISIBLE_COLUMN
< bPtr
->usedColumnCount
) {
593 newFirst
= bPtr
->firstVisibleColumn
+ bPtr
->maxVisibleColumns
;
595 if (newFirst
+bPtr
->maxVisibleColumns
>= bPtr
->columnCount
)
596 newFirst
= bPtr
->columnCount
- bPtr
->maxVisibleColumns
;
598 scrollToColumn(bPtr
, newFirst
, True
);
605 double value
= bPtr
->columnCount
- bPtr
->maxVisibleColumns
;
607 floatValue
= WMGetScrollerValue(bPtr
->scroller
);
609 floatValue
= (floatValue
*value
)/value
;
611 newFirst
= rint(floatValue
*(float)(bPtr
->columnCount
- bPtr
->maxVisibleColumns
));
613 if (bPtr
->firstVisibleColumn
!= newFirst
)
614 scrollToColumn(bPtr
, newFirst
, False
);
616 WMSetScrollerParameters(bPtr->scroller, floatValue,
617 bPtr->maxVisibleColumns/(float)bPtr->columnCount);
628 #undef LAST_VISIBLE_COLUMN
633 setupScroller(WMBrowser
*bPtr
)
638 y
= bPtr
->view
->size
.height
- SCROLLER_WIDTH
- 1;
640 sPtr
= WMCreateScroller(bPtr
);
641 WMSetScrollerAction(sPtr
, scrollCallback
, bPtr
);
642 WMMoveWidget(sPtr
, 1, y
);
643 WMResizeWidget(sPtr
, bPtr
->view
->size
.width
-2, SCROLLER_WIDTH
);
645 bPtr
->scroller
= sPtr
;
652 WMSetBrowserAction(WMBrowser
*bPtr
, WMAction
*action
, void *clientData
)
654 bPtr
->action
= action
;
655 bPtr
->clientData
= clientData
;
660 WMSetBrowserDoubleAction(WMBrowser
*bPtr
, WMAction
*action
, void *clientData
)
662 bPtr
->doubleAction
= action
;
663 bPtr
->doubleClientData
= clientData
;
668 WMSetBrowserHasScroller(WMBrowser
*bPtr
, int hasScroller
)
670 bPtr
->flags
.hasScroller
= hasScroller
;
676 WMSetBrowserPath(WMBrowser
*bPtr
, char *path
)
679 char *str
= wstrdup(path
);
680 char *tmp
, *retPtr
= NULL
;
682 WMListItem
*listItem
;
684 /* WMLoadBrowserColumnZero must be call first */
685 if (!bPtr
->flags
.loaded
) {
689 removeColumn(bPtr
, 1);
691 WMSelectListItem(bPtr
->columns
[0], -1);
692 WMSetListPosition(bPtr
->columns
[0], 0);
695 tmp
= strtok(str
, bPtr
->pathSeparator
);
697 /* select it in the column */
698 item
= WMFindRowOfListItemWithTitle(bPtr
->columns
[i
], tmp
);
700 retPtr
= &path
[(int)(tmp
- str
)];
703 WMSelectListItem(bPtr
->columns
[i
], item
);
704 WMSetListPosition(bPtr
->columns
[i
], item
);
706 listItem
= WMGetListItem(bPtr
->columns
[i
], item
);
707 if (!listItem
|| !listItem
->isBranch
) {
711 /* load next column */
712 WMAddBrowserColumn(bPtr
);
714 loadColumn(bPtr
, i
+1);
716 tmp
= strtok(NULL
, bPtr
->pathSeparator
);
722 for (i
= bPtr
->usedColumnCount
- 1;
723 (i
> -1) && !WMGetListSelectedItem(bPtr
->columns
[i
]);
726 bPtr
->selectedColumn
= i
;
728 if (bPtr
->columnCount
< bPtr
->maxVisibleColumns
) {
729 int i
= bPtr
->maxVisibleColumns
- bPtr
->columnCount
;
730 int curUsedColumnCount
= bPtr
->usedColumnCount
;
731 bPtr
->usedColumnCount
= bPtr
->columnCount
;
733 WMAddBrowserColumn(bPtr
);
735 bPtr
->usedColumnCount
= curUsedColumnCount
;
738 scrollToColumn(bPtr
, bPtr
->columnCount
- bPtr
->maxVisibleColumns
, True
);
745 WMGetBrowserPath(WMBrowser
*bPtr
)
747 return WMGetBrowserPathToColumn(bPtr
, bPtr
->columnCount
);
753 WMGetBrowserPathToColumn(WMBrowser
*bPtr
, int column
)
759 if (column
>= bPtr
->usedColumnCount
)
760 column
= bPtr
->usedColumnCount
-1;
763 return wstrdup(bPtr
->pathSeparator
);
766 /* calculate size of buffer */
768 for (i
= 0; i
<= column
; i
++) {
769 item
= WMGetListSelectedItem(bPtr
->columns
[i
]);
772 size
+= strlen(item
->text
);
776 path
= wmalloc(size
+(column
+1)*strlen(bPtr
->pathSeparator
)+1);
779 for (i
= 0; i
<= column
; i
++) {
780 strcat(path
, bPtr
->pathSeparator
);
781 item
= WMGetListSelectedItem(bPtr
->columns
[i
]);
784 strcat(path
, item
->text
);
792 loadColumn(WMBrowser
*bPtr
, int column
)
794 assert(bPtr
->delegate
);
795 assert(bPtr
->delegate
->createRowsForColumn
);
797 bPtr
->flags
.loadingColumn
= 1;
798 (*bPtr
->delegate
->createRowsForColumn
)(bPtr
->delegate
, bPtr
, column
,
799 bPtr
->columns
[column
]);
800 bPtr
->flags
.loadingColumn
= 0;
802 if (bPtr
->delegate
->titleOfColumn
) {
805 title
= (*bPtr
->delegate
->titleOfColumn
)(bPtr
->delegate
, bPtr
, column
);
807 if (bPtr
->titles
[column
])
808 free(bPtr
->titles
[column
]);
810 bPtr
->titles
[column
] = title
;
816 paintBrowser(WMBrowser
*bPtr
)
820 if (!bPtr
->view
->flags
.mapped
)
823 W_DrawRelief(bPtr
->view
->screen
, bPtr
->view
->window
, 0,
824 bPtr
->view
->size
.height
-SCROLLER_WIDTH
-2,
825 bPtr
->view
->size
.width
, 22, WRSunken
);
827 if (bPtr
->flags
.isTitled
) {
828 for (i
=0; i
<bPtr
->maxVisibleColumns
; i
++) {
829 drawTitleOfColumn(bPtr
, i
+bPtr
->firstVisibleColumn
);
836 handleEvents(XEvent
*event
, void *data
)
838 WMBrowser
*bPtr
= (WMBrowser
*)data
;
840 CHECK_CLASS(data
, WC_Browser
);
843 switch (event
->type
) {
849 destroyBrowser(bPtr
);
858 scrollToColumn(WMBrowser
*bPtr
, int column
, Bool updateScroller
)
865 if (column
!= bPtr
->firstVisibleColumn
) {
872 if (notify
&& bPtr
->delegate
&& bPtr
->delegate
->willScroll
) {
873 (*bPtr
->delegate
->willScroll
)(bPtr
->delegate
, bPtr
);
877 bPtr
->firstVisibleColumn
= column
;
878 for (i
= 0; i
< bPtr
->columnCount
; i
++) {
879 if (COLUMN_IS_VISIBLE(bPtr
, i
)) {
880 WMMoveWidget(bPtr
->columns
[i
], x
,
881 WMWidgetView(bPtr
->columns
[i
])->pos
.y
);
882 if (!WMWidgetView(bPtr
->columns
[i
])->flags
.realized
)
883 WMRealizeWidget(bPtr
->columns
[i
]);
884 WMMapWidget(bPtr
->columns
[i
]);
885 x
+= bPtr
->columnSize
.width
+ COLUMN_SPACING
;
887 WMUnmapWidget(bPtr
->columns
[i
]);
891 /* update the scroller */
892 if (updateScroller
) {
893 if (bPtr
->columnCount
> bPtr
->maxVisibleColumns
) {
894 float value
, proportion
;
896 value
= bPtr
->firstVisibleColumn
897 /(float)(bPtr
->columnCount
-bPtr
->maxVisibleColumns
);
898 proportion
= bPtr
->maxVisibleColumns
/(float)bPtr
->columnCount
;
899 WMSetScrollerParameters(bPtr
->scroller
, value
, proportion
);
901 WMSetScrollerParameters(bPtr
->scroller
, 0, 1);
905 if (bPtr
->view
->flags
.mapped
)
908 if (notify
&& bPtr
->delegate
&& bPtr
->delegate
->didScroll
) {
909 (*bPtr
->delegate
->didScroll
)(bPtr
->delegate
, bPtr
);
915 listCallback(void *self
, void *clientData
)
917 WMBrowser
*bPtr
= (WMBrowser
*)clientData
;
918 WMList
*lPtr
= (WMList
*)self
;
920 static WMListItem
*oldItem
= NULL
;
923 item
= WMGetListSelectedItem(lPtr
);
929 if (oldItem
!= item
) {
930 for (i
=0; i
<bPtr
->columnCount
; i
++) {
931 if (lPtr
== bPtr
->columns
[i
])
934 assert(i
<bPtr
->columnCount
);
936 bPtr
->selectedColumn
= i
;
938 /* columns at right must be cleared */
939 removeColumn(bPtr
, i
+1);
941 if (item
->isBranch
) {
942 WMAddBrowserColumn(bPtr
);
944 if (bPtr
->usedColumnCount
< bPtr
->maxVisibleColumns
)
947 i
= bPtr
->usedColumnCount
-bPtr
->maxVisibleColumns
;
948 scrollToColumn(bPtr
, i
, True
);
949 if (item
->isBranch
) {
950 loadColumn(bPtr
, bPtr
->usedColumnCount
-1);
955 /* call callback for click */
957 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
964 listDoubleCallback(void *self
, void *clientData
)
966 WMBrowser
*bPtr
= (WMBrowser
*)clientData
;
967 WMList
*lPtr
= (WMList
*)self
;
970 item
= WMGetListSelectedItem(lPtr
);
974 /* call callback for double click */
975 if (bPtr
->doubleAction
)
976 (*bPtr
->doubleAction
)(bPtr
, bPtr
->doubleClientData
);
981 WMLoadBrowserColumnZero(WMBrowser
*bPtr
)
983 if (!bPtr
->flags
.loaded
) {
984 /* create column 0 */
985 WMAddBrowserColumn(bPtr
);
989 /* make column 0 visible */
990 scrollToColumn(bPtr
, 0, True
);
992 bPtr
->flags
.loaded
= 1;
998 WMRemoveBrowserItem(WMBrowser
*bPtr
, int column
, int row
)
1002 if (column
< 0 || column
>= bPtr
->usedColumnCount
)
1005 list
= WMGetBrowserListInColumn(bPtr
, column
);
1007 if (row
< 0 || row
>= WMGetListNumberOfRows(list
))
1010 removeColumn(bPtr
, column
+1);
1011 if (bPtr
->usedColumnCount
< bPtr
->maxVisibleColumns
)
1012 scrollToColumn(bPtr
, 0, True
);
1014 scrollToColumn(bPtr
, bPtr
->usedColumnCount
-bPtr
->maxVisibleColumns
,
1017 WMRemoveListItem(list
, row
);
1022 listSelectionObserver(void *observerData
, WMNotification
*notification
)
1024 WMBrowser
*bPtr
= (WMBrowser
*)observerData
;
1025 int column
, item
= (int)WMGetNotificationClientData(notification
);
1026 WMList
*lPtr
= (WMList
*)WMGetNotificationObject(notification
);
1028 for (column
= 0; column
< bPtr
->usedColumnCount
; column
++)
1029 if (bPtr
->columns
[column
] == lPtr
)
1032 /* this can happen when a list is being cleared with WMClearList
1033 * after the column was removed */
1034 if (column
>= bPtr
->usedColumnCount
) {
1041 bPtr
->selectedColumn
= column
;
1046 WMAddBrowserColumn(WMBrowser
*bPtr
)
1055 if (bPtr
->usedColumnCount
< bPtr
->columnCount
) {
1056 return bPtr
->usedColumnCount
++;
1059 bPtr
->usedColumnCount
++;
1061 if (bPtr
->flags
.isTitled
) {
1062 colY
= TITLE_SPACING
+ bPtr
->titleHeight
;
1067 index
= bPtr
->columnCount
;
1068 bPtr
->columnCount
++;
1069 clist
= wmalloc(sizeof(WMList
*)*bPtr
->columnCount
);
1070 tlist
= wmalloc(sizeof(char*)*bPtr
->columnCount
);
1071 memcpy(clist
, bPtr
->columns
, sizeof(WMList
*)*(bPtr
->columnCount
-1));
1072 memcpy(tlist
, bPtr
->titles
, sizeof(char*)*(bPtr
->columnCount
-1));
1074 free(bPtr
->columns
);
1077 bPtr
->columns
= clist
;
1078 bPtr
->titles
= tlist
;
1080 bPtr
->titles
[index
] = NULL
;
1082 list
= WMCreateList(bPtr
);
1083 WMSetListAction(list
, listCallback
, bPtr
);
1084 WMSetListDoubleAction(list
, listDoubleCallback
, bPtr
);
1085 WMSetListUserDrawProc(list
, paintItem
);
1086 WMAddNotificationObserver(listSelectionObserver
, bPtr
,
1087 WMListSelectionDidChangeNotification
, list
);
1089 bPtr
->columns
[index
] = list
;
1091 WMResizeWidget(list
, bPtr
->columnSize
.width
, bPtr
->columnSize
.height
);
1092 WMMoveWidget(list
, (bPtr
->columnSize
.width
+COLUMN_SPACING
)*index
, colY
);
1093 if (COLUMN_IS_VISIBLE(bPtr
, index
))
1096 /* update the scroller */
1097 if (bPtr
->columnCount
> bPtr
->maxVisibleColumns
) {
1098 float value
, proportion
;
1100 value
= bPtr
->firstVisibleColumn
1101 /(float)(bPtr
->columnCount
-bPtr
->maxVisibleColumns
);
1102 proportion
= bPtr
->maxVisibleColumns
/(float)bPtr
->columnCount
;
1103 WMSetScrollerParameters(bPtr
->scroller
, value
, proportion
);
1112 destroyBrowser(WMBrowser
*bPtr
)
1116 for (i
= 0; i
< bPtr
->columnCount
; i
++) {
1117 if (bPtr
->titles
[i
])
1118 free(bPtr
->titles
[i
]);
1122 free(bPtr
->pathSeparator
);
1124 WMRemoveNotificationObserver(bPtr
);
1131 createTruncatedString(WMFont
*font
, char *text
, int *textLen
, int width
)
1133 int dLen
= WMWidthOfString(font
, ".", 1);
1134 char *textBuf
= (char*)wmalloc((*textLen
)+4);
1136 if (width
>= 3*dLen
) {
1137 int dddLen
= 3*dLen
;
1138 int tmpTextLen
= *textLen
;
1140 strcpy(textBuf
, text
);
1142 && (WMWidthOfString(font
, textBuf
, tmpTextLen
)+dddLen
> width
))
1144 strcpy(textBuf
+tmpTextLen
, "...");
1145 *textLen
= tmpTextLen
+3;
1146 } else if (width
>= 2*dLen
) {
1147 strcpy(textBuf
, "..");
1149 } else if (width
>= dLen
) {
1150 strcpy(textBuf
, ".");