6 #include <math.h> /* for : double rint (double) */
9 char *WMBrowserDidScrollNotification
= "WMBrowserDidScrollNotification";
12 typedef struct W_Browser
{
20 short usedColumnCount
; /* columns actually being used */
23 short maxVisibleColumns
;
24 short firstVisibleColumn
;
35 void *doubleClientData
;
36 WMAction
*doubleAction
;
38 WMBrowserFillColumnProc
*fillColumn
;
45 unsigned int isTitled
:1;
46 unsigned int allowMultipleSelection
:1;
47 unsigned int hasScroller
:1;
50 unsigned int loaded
:1;
51 unsigned int loadingColumn
:1;
56 #define COLUMN_SPACING 4
57 #define TITLE_SPACING 2
59 #define DEFAULT_WIDTH 305
60 #define DEFAULT_HEIGHT 200
61 #define DEFAULT_HAS_SCROLLER True
62 #define DEFAULT_TITLE_HEIGHT 20
63 #define DEFAULT_IS_TITLED True
64 #define DEFAULT_MAX_VISIBLE_COLUMNS 2
65 #define DEFAULT_SEPARATOR "/"
67 #define MIN_VISIBLE_COLUMNS 1
68 #define MAX_VISIBLE_COLUMNS 32
71 #define COLUMN_IS_VISIBLE(b, c) ((c) >= (b)->firstVisibleColumn \
72 && (c) < (b)->firstVisibleColumn + (b)->maxVisibleColumns)
75 static void handleEvents(XEvent
*event
, void *data
);
76 static void destroyBrowser(WMBrowser
*bPtr
);
78 static void setupScroller(WMBrowser
*bPtr
);
80 static void scrollToColumn(WMBrowser
*bPtr
, int column
, Bool updateScroller
);
82 static void paintItem(WMList
*lPtr
, int index
, Drawable d
, char *text
,
83 int state
, WMRect
*rect
);
85 static void loadColumn(WMBrowser
*bPtr
, int column
);
87 static void removeColumn(WMBrowser
*bPtr
, int column
);
90 createTruncatedString(WMFont
*font
, char *text
, int *textLen
, int width
);
92 static void resizeBrowser(WMWidget
*, unsigned int, unsigned int);
94 W_ViewProcedureTable _BrowserViewProcedures
= {
103 WMCreateBrowser(WMWidget
*parent
)
108 wassertrv(parent
, NULL
);
110 bPtr
= wmalloc(sizeof(WMBrowser
));
111 memset(bPtr
, 0, sizeof(WMBrowser
));
113 bPtr
->widgetClass
= WC_Browser
;
115 bPtr
->view
= W_CreateView(W_VIEW(parent
));
120 bPtr
->view
->self
= bPtr
;
122 WMCreateEventHandler(bPtr
->view
, ExposureMask
|StructureNotifyMask
123 |ClientMessageMask
, handleEvents
, bPtr
);
125 /* default configuration */
126 bPtr
->flags
.hasScroller
= DEFAULT_HAS_SCROLLER
;
128 bPtr
->titleHeight
= DEFAULT_TITLE_HEIGHT
;
129 bPtr
->flags
.isTitled
= DEFAULT_IS_TITLED
;
130 bPtr
->maxVisibleColumns
= DEFAULT_MAX_VISIBLE_COLUMNS
;
132 resizeBrowser(bPtr
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
134 bPtr
->pathSeparator
= wstrdup(DEFAULT_SEPARATOR
);
136 if (bPtr
->flags
.hasScroller
)
139 for (i
=0; i
<bPtr
->maxVisibleColumns
; i
++) {
140 WMAddBrowserColumn(bPtr
);
142 bPtr
->usedColumnCount
= 0;
144 bPtr
->selectedColumn
= -1;
151 WMGetBrowserMaxVisibleColumns(WMBrowser
*bPtr
)
153 return bPtr
->maxVisibleColumns
;
158 WMSetBrowserMaxVisibleColumns(WMBrowser
*bPtr
, int columns
)
160 int curMaxVisibleColumns
;
161 int newFirstVisibleColumn
= 0;
165 columns
= (columns
< MIN_VISIBLE_COLUMNS
) ? MIN_VISIBLE_COLUMNS
: columns
;
166 columns
= (columns
> MAX_VISIBLE_COLUMNS
) ? MAX_VISIBLE_COLUMNS
: columns
;
167 if (columns
== bPtr
->maxVisibleColumns
) {
170 curMaxVisibleColumns
= bPtr
->maxVisibleColumns
;
171 bPtr
->maxVisibleColumns
= columns
;
172 /* browser not loaded */
173 if (!bPtr
->flags
.loaded
) {
174 if ((columns
> curMaxVisibleColumns
) && (columns
> bPtr
->columnCount
)) {
175 int i
= columns
- bPtr
->columnCount
;
176 bPtr
->usedColumnCount
= bPtr
->columnCount
;
178 WMAddBrowserColumn(bPtr
);
180 bPtr
->usedColumnCount
= 0;
182 /* browser loaded and columns > curMaxVisibleColumns */
183 } else if (columns
> curMaxVisibleColumns
) {
184 if (bPtr
->usedColumnCount
> columns
) {
185 newFirstVisibleColumn
= bPtr
->usedColumnCount
- columns
;
187 if (newFirstVisibleColumn
> bPtr
->firstVisibleColumn
) {
188 newFirstVisibleColumn
= bPtr
->firstVisibleColumn
;
190 if (columns
> bPtr
->columnCount
) {
191 int i
= columns
- bPtr
->columnCount
;
192 int curUsedColumnCount
= bPtr
->usedColumnCount
;
193 bPtr
->usedColumnCount
= bPtr
->columnCount
;
195 WMAddBrowserColumn(bPtr
);
197 bPtr
->usedColumnCount
= curUsedColumnCount
;
199 /* browser loaded and columns < curMaxVisibleColumns */
201 newFirstVisibleColumn
= bPtr
->firstVisibleColumn
;
202 if (newFirstVisibleColumn
+ columns
>= bPtr
->usedColumnCount
) {
203 removeColumn(bPtr
, newFirstVisibleColumn
+ columns
);
206 resizeBrowser(bPtr
, bPtr
->view
->size
.width
, bPtr
->view
->size
.height
);
207 if (bPtr
->flags
.loaded
) {
208 XClearArea(bPtr
->view
->screen
->display
, bPtr
->view
->window
, 0, 0,
209 bPtr
->view
->size
.width
, bPtr
->titleHeight
, False
);
210 scrollToColumn (bPtr
, newFirstVisibleColumn
, True
);
216 WMGetBrowserNumberOfColumns(WMBrowser
*bPtr
)
218 return bPtr
->usedColumnCount
;
222 WMSetBrowserPathSeparator(WMBrowser
*bPtr
, char *separator
)
224 if (bPtr
->pathSeparator
)
225 free(bPtr
->pathSeparator
);
226 bPtr
->pathSeparator
= wstrdup(separator
);
232 drawTitleOfColumn(WMBrowser
*bPtr
, int column
)
234 WMScreen
*scr
= bPtr
->view
->screen
;
237 x
=(column
-bPtr
->firstVisibleColumn
)*(bPtr
->columnSize
.width
+COLUMN_SPACING
);
239 XFillRectangle(scr
->display
, bPtr
->view
->window
, WMColorGC(scr
->darkGray
), x
, 0,
240 bPtr
->columnSize
.width
, bPtr
->titleHeight
);
241 W_DrawRelief(scr
, bPtr
->view
->window
, x
, 0,
242 bPtr
->columnSize
.width
, bPtr
->titleHeight
, WRSunken
);
244 if (column
< bPtr
->usedColumnCount
&& bPtr
->titles
[column
]) {
245 int titleLen
= strlen(bPtr
->titles
[column
]);
246 int widthC
= bPtr
->columnSize
.width
-8;
248 if (WMWidthOfString(scr
->boldFont
, bPtr
->titles
[column
], titleLen
)
250 char *titleBuf
= createTruncatedString(scr
->boldFont
,
251 bPtr
->titles
[column
],
253 W_PaintText(bPtr
->view
, bPtr
->view
->window
, scr
->boldFont
, x
,
254 (bPtr
->titleHeight
-WMFontHeight(scr
->boldFont
))/2,
255 bPtr
->columnSize
.width
, WACenter
, WMColorGC(scr
->white
),
256 False
, titleBuf
, titleLen
);
259 W_PaintText(bPtr
->view
, bPtr
->view
->window
, scr
->boldFont
, x
,
260 (bPtr
->titleHeight
-WMFontHeight(scr
->boldFont
))/2,
261 bPtr
->columnSize
.width
, WACenter
, WMColorGC(scr
->white
),
262 False
, bPtr
->titles
[column
], titleLen
);
269 WMSetBrowserColumnTitle(WMBrowser
*bPtr
, int column
, char *title
)
272 assert(column
< bPtr
->usedColumnCount
);
274 if (bPtr
->titles
[column
])
275 free(bPtr
->titles
[column
]);
277 bPtr
->titles
[column
] = wstrdup(title
);
279 if (COLUMN_IS_VISIBLE(bPtr
, column
) && bPtr
->flags
.isTitled
) {
280 drawTitleOfColumn(bPtr
, column
);
286 WMGetBrowserListInColumn(WMBrowser
*bPtr
, int column
)
288 if (column
< 0 || column
>= bPtr
->usedColumnCount
)
291 return bPtr
->columns
[column
];
296 WMSetBrowserFillColumnProc(WMBrowser
*bPtr
, WMBrowserFillColumnProc
*proc
)
298 bPtr
->fillColumn
= proc
;
303 WMGetBrowserFirstVisibleColumn(WMBrowser
*bPtr
)
305 return bPtr
->firstVisibleColumn
;
310 removeColumn(WMBrowser
*bPtr
, int column
)
312 int i
, clearEnd
, destroyEnd
;
318 column
= (column
< 0) ? 0 : column
;
319 if (column
>= bPtr
->columnCount
) {
322 if (column
< bPtr
->maxVisibleColumns
) {
323 clearEnd
= bPtr
->maxVisibleColumns
;
324 destroyEnd
= bPtr
->columnCount
;
325 bPtr
->columnCount
= bPtr
->maxVisibleColumns
;
328 destroyEnd
= bPtr
->columnCount
;
329 bPtr
->columnCount
= column
;
331 if (column
< bPtr
->usedColumnCount
) {
332 bPtr
->usedColumnCount
= column
;
334 for (i
=column
; i
< clearEnd
; i
++) {
335 if (bPtr
->titles
[i
]) {
336 free(bPtr
->titles
[i
]);
337 bPtr
->titles
[i
] = NULL
;
339 WMClearList(bPtr
->columns
[i
]);
341 for (;i
< destroyEnd
; i
++) {
342 if (bPtr
->titles
[i
]) {
343 free(bPtr
->titles
[i
]);
344 bPtr
->titles
[i
] = NULL
;
346 WMRemoveNotificationObserverWithName(bPtr
,
347 WMListSelectionDidChangeNotification
,
349 WMDestroyWidget(bPtr
->columns
[i
]);
350 bPtr
->columns
[i
] = NULL
;
352 clist
= wmalloc(sizeof(WMList
*) * (bPtr
->columnCount
));
353 tlist
= wmalloc(sizeof(char*) * (bPtr
->columnCount
));
354 memcpy(clist
, bPtr
->columns
, sizeof(WMList
*) * (bPtr
->columnCount
));
355 memcpy(tlist
, bPtr
->titles
, sizeof(char*) * (bPtr
->columnCount
));
358 bPtr
->titles
= tlist
;
359 bPtr
->columns
= clist
;
364 WMGetBrowserSelectedItemInColumn(WMBrowser
*bPtr
, int column
)
366 if ((column
< 0) || (column
>= bPtr
->usedColumnCount
))
369 return WMGetListSelectedItem(bPtr
->columns
[column
]);
375 WMGetBrowserSelectedColumn(WMBrowser
*bPtr
)
377 return bPtr
->selectedColumn
;
382 WMGetBrowserSelectedRowInColumn(WMBrowser
*bPtr
, int column
)
384 if (column
>= 0 && column
< bPtr
->columnCount
) {
385 return WMGetListSelectedItemRow(bPtr
->columns
[column
]);
393 WMSetBrowserTitled(WMBrowser
*bPtr
, Bool flag
)
396 int columnX
, columnY
;
398 if (bPtr
->flags
.isTitled
== flag
)
403 if (!bPtr
->flags
.isTitled
) {
404 columnY
= TITLE_SPACING
+ bPtr
->titleHeight
;
406 bPtr
->columnSize
.height
-= columnY
;
408 for (i
=0; i
<bPtr
->columnCount
; i
++) {
409 WMResizeWidget(bPtr
->columns
[i
], bPtr
->columnSize
.width
,
410 bPtr
->columnSize
.height
);
412 columnX
= WMWidgetView(bPtr
->columns
[i
])->pos
.x
;
414 WMMoveWidget(bPtr
->columns
[i
], columnX
, columnY
);
417 bPtr
->columnSize
.height
+= TITLE_SPACING
+ bPtr
->titleHeight
;
419 for (i
=0; i
<bPtr
->columnCount
; i
++) {
420 WMResizeWidget(bPtr
->columns
[i
], bPtr
->columnSize
.width
,
421 bPtr
->columnSize
.height
);
423 columnX
= WMWidgetView(bPtr
->columns
[i
])->pos
.x
;
425 WMMoveWidget(bPtr
->columns
[i
], columnX
, 0);
429 bPtr
->flags
.isTitled
= flag
;
434 WMAddSortedBrowserItem(WMBrowser
*bPtr
, int column
, char *text
, Bool isBranch
)
438 if (column
< 0 || column
>= bPtr
->columnCount
)
441 item
= WMAddSortedListItem(bPtr
->columns
[column
], text
);
442 item
->isBranch
= isBranch
;
450 WMInsertBrowserItem(WMBrowser
*bPtr
, int column
, int row
, char *text
,
455 if (column
< 0 || column
>= bPtr
->columnCount
)
458 item
= WMInsertListItem(bPtr
->columns
[column
], row
, text
);
459 item
->isBranch
= isBranch
;
468 resizeBrowser(WMWidget
*w
, unsigned int width
, unsigned int height
)
470 WMBrowser
*bPtr
= (WMBrowser
*)w
;
471 int cols
= bPtr
->maxVisibleColumns
;
478 bPtr
->columnSize
.width
= (width
-(cols
-1)*COLUMN_SPACING
) / cols
;
479 bPtr
->columnSize
.height
= height
;
481 if (bPtr
->flags
.isTitled
) {
482 colY
= TITLE_SPACING
+ bPtr
->titleHeight
;
483 bPtr
->columnSize
.height
-= colY
;
488 if (bPtr
->flags
.hasScroller
) {
489 bPtr
->columnSize
.height
-= SCROLLER_WIDTH
+ 4;
491 if (bPtr
->scroller
) {
492 WMResizeWidget(bPtr
->scroller
, width
-2, 1);
493 WMMoveWidget(bPtr
->scroller
, 1, height
-SCROLLER_WIDTH
-1);
498 for (i
= 0; i
< bPtr
->columnCount
; i
++) {
499 WMResizeWidget(bPtr
->columns
[i
], bPtr
->columnSize
.width
,
500 bPtr
->columnSize
.height
);
502 WMMoveWidget(bPtr
->columns
[i
], colX
, colY
);
504 if (COLUMN_IS_VISIBLE(bPtr
, i
)) {
505 colX
+= bPtr
->columnSize
.width
+COLUMN_SPACING
;
509 W_ResizeView(bPtr
->view
, width
, height
);
514 paintItem(WMList
*lPtr
, int index
, Drawable d
, char *text
, int state
,
517 WMView
*view
= W_VIEW(lPtr
);
518 W_Screen
*scr
= view
->screen
;
519 int width
, height
, x
, y
;
521 width
= rect
->size
.width
;
522 height
= rect
->size
.height
;
526 if (state
& WLDSSelected
)
527 XFillRectangle(scr
->display
, d
, WMColorGC(scr
->white
), x
, y
,
530 XClearArea(scr
->display
, d
, x
, y
, width
, height
, False
);
533 /* Avoid overlaping... */
534 int textLen
= strlen(text
);
535 int widthC
= (state
& WLDSIsBranch
) ? width
-20 : width
-8;
536 if (WMWidthOfString(scr
->normalFont
, text
, textLen
) > widthC
) {
537 char *textBuf
= createTruncatedString(scr
->normalFont
,
538 text
, &textLen
, widthC
);
539 W_PaintText(view
, d
, scr
->normalFont
, x
+4, y
, widthC
,
540 WALeft
, WMColorGC(scr
->black
), False
, textBuf
, textLen
);
543 W_PaintText(view
, d
, scr
->normalFont
, x
+4, y
, widthC
,
544 WALeft
, WMColorGC(scr
->black
), False
, text
, textLen
);
548 if (state
& WLDSIsBranch
) {
549 XDrawLine(scr
->display
, d
, WMColorGC(scr
->darkGray
), x
+width
-11, y
+3,
550 x
+width
-6, y
+height
/2);
551 if (state
& WLDSSelected
)
552 XDrawLine(scr
->display
, d
,WMColorGC(scr
->gray
), x
+width
-11, y
+height
-5,
553 x
+width
-6, y
+height
/2);
555 XDrawLine(scr
->display
, d
,WMColorGC(scr
->white
), x
+width
-11, y
+height
-5,
556 x
+width
-6, y
+height
/2);
557 XDrawLine(scr
->display
, d
, WMColorGC(scr
->black
), x
+width
-12, y
+3,
558 x
+width
-12, y
+height
-5);
564 scrollCallback(WMWidget
*scroller
, void *self
)
566 WMBrowser
*bPtr
= (WMBrowser
*)self
;
567 WMScroller
*sPtr
= (WMScroller
*)scroller
;
569 #define LAST_VISIBLE_COLUMN bPtr->firstVisibleColumn+bPtr->maxVisibleColumns
571 switch (WMGetScrollerHitPart(sPtr
)) {
572 case WSDecrementLine
:
573 if (bPtr
->firstVisibleColumn
> 0) {
574 scrollToColumn(bPtr
, bPtr
->firstVisibleColumn
-1, True
);
578 case WSDecrementPage
:
579 if (bPtr
->firstVisibleColumn
> 0) {
580 newFirst
= bPtr
->firstVisibleColumn
- bPtr
->maxVisibleColumns
;
582 scrollToColumn(bPtr
, newFirst
, True
);
587 case WSIncrementLine
:
588 if (LAST_VISIBLE_COLUMN
< bPtr
->usedColumnCount
) {
589 scrollToColumn(bPtr
, bPtr
->firstVisibleColumn
+1, True
);
593 case WSIncrementPage
:
594 if (LAST_VISIBLE_COLUMN
< bPtr
->usedColumnCount
) {
595 newFirst
= bPtr
->firstVisibleColumn
+ bPtr
->maxVisibleColumns
;
597 if (newFirst
+bPtr
->maxVisibleColumns
>= bPtr
->columnCount
)
598 newFirst
= bPtr
->columnCount
- bPtr
->maxVisibleColumns
;
600 scrollToColumn(bPtr
, newFirst
, True
);
607 double value
= bPtr
->columnCount
- bPtr
->maxVisibleColumns
;
609 floatValue
= WMGetScrollerValue(bPtr
->scroller
);
611 floatValue
= (floatValue
*value
)/value
;
613 newFirst
= rint(floatValue
*(float)(bPtr
->columnCount
- bPtr
->maxVisibleColumns
));
615 if (bPtr
->firstVisibleColumn
!= newFirst
)
616 scrollToColumn(bPtr
, newFirst
, False
);
618 WMSetScrollerParameters(bPtr->scroller, floatValue,
619 bPtr->maxVisibleColumns/(float)bPtr->columnCount);
630 #undef LAST_VISIBLE_COLUMN
635 setupScroller(WMBrowser
*bPtr
)
640 y
= bPtr
->view
->size
.height
- SCROLLER_WIDTH
- 1;
642 sPtr
= WMCreateScroller(bPtr
);
643 WMSetScrollerAction(sPtr
, scrollCallback
, bPtr
);
644 WMMoveWidget(sPtr
, 1, y
);
645 WMResizeWidget(sPtr
, bPtr
->view
->size
.width
-2, SCROLLER_WIDTH
);
647 bPtr
->scroller
= sPtr
;
654 WMSetBrowserAction(WMBrowser
*bPtr
, WMAction
*action
, void *clientData
)
656 bPtr
->action
= action
;
657 bPtr
->clientData
= clientData
;
662 WMSetBrowserDoubleAction(WMBrowser
*bPtr
, WMAction
*action
, void *clientData
)
664 bPtr
->doubleAction
= action
;
665 bPtr
->doubleClientData
= clientData
;
670 WMSetBrowserHasScroller(WMBrowser
*bPtr
, int hasScroller
)
672 bPtr
->flags
.hasScroller
= hasScroller
;
678 WMSetBrowserPath(WMBrowser
*bPtr
, char *path
)
681 char *str
= wstrdup(path
);
682 char *tmp
, *retPtr
= NULL
;
684 WMListItem
*listItem
;
686 /* WMLoadBrowserColumnZero must be call first */
687 if (!bPtr
->flags
.loaded
) {
691 removeColumn(bPtr
, 1);
693 WMSelectListItem(bPtr
->columns
[0], -1);
694 WMSetListPosition(bPtr
->columns
[0], 0);
697 tmp
= strtok(str
, bPtr
->pathSeparator
);
699 /* select it in the column */
700 item
= WMFindRowOfListItemWithTitle(bPtr
->columns
[i
], tmp
);
702 retPtr
= &path
[(int)(tmp
- str
)];
705 WMSelectListItem(bPtr
->columns
[i
], item
);
706 WMSetListPosition(bPtr
->columns
[i
], item
);
708 listItem
= WMGetListItem(bPtr
->columns
[i
], item
);
709 if (!listItem
|| !listItem
->isBranch
) {
713 /* load next column */
714 WMAddBrowserColumn(bPtr
);
716 loadColumn(bPtr
, i
+1);
718 tmp
= strtok(NULL
, bPtr
->pathSeparator
);
724 for (i
= bPtr
->usedColumnCount
- 1;
725 (i
> -1) && !WMGetListSelectedItem(bPtr
->columns
[i
]);
728 bPtr
->selectedColumn
= i
;
730 if (bPtr
->columnCount
< bPtr
->maxVisibleColumns
) {
731 int i
= bPtr
->maxVisibleColumns
- bPtr
->columnCount
;
732 int curUsedColumnCount
= bPtr
->usedColumnCount
;
733 bPtr
->usedColumnCount
= bPtr
->columnCount
;
735 WMAddBrowserColumn(bPtr
);
737 bPtr
->usedColumnCount
= curUsedColumnCount
;
740 scrollToColumn(bPtr
, bPtr
->columnCount
- bPtr
->maxVisibleColumns
, True
);
747 WMGetBrowserPath(WMBrowser
*bPtr
)
749 return WMGetBrowserPathToColumn(bPtr
, bPtr
->columnCount
);
754 WMGetBrowserPathToColumn(WMBrowser
*bPtr
, int column
)
760 if (column
>= bPtr
->usedColumnCount
)
761 column
= bPtr
->usedColumnCount
-1;
764 return wstrdup(bPtr
->pathSeparator
);
767 /* calculate size of buffer */
769 for (i
= 0; i
<= column
; i
++) {
770 item
= WMGetListSelectedItem(bPtr
->columns
[i
]);
773 size
+= strlen(item
->text
);
777 path
= wmalloc(size
+(column
+1)*strlen(bPtr
->pathSeparator
)+1);
780 for (i
= 0; i
<= column
; i
++) {
781 strcat(path
, bPtr
->pathSeparator
);
782 item
= WMGetListSelectedItem(bPtr
->columns
[i
]);
785 strcat(path
, item
->text
);
793 loadColumn(WMBrowser
*bPtr
, int column
)
795 assert(bPtr
->fillColumn
);
797 bPtr
->flags
.loadingColumn
= 1;
798 (*bPtr
->fillColumn
)(bPtr
, column
);
799 bPtr
->flags
.loadingColumn
= 0;
804 paintBrowser(WMBrowser
*bPtr
)
808 if (!bPtr
->view
->flags
.mapped
)
811 W_DrawRelief(bPtr
->view
->screen
, bPtr
->view
->window
, 0,
812 bPtr
->view
->size
.height
-SCROLLER_WIDTH
-2,
813 bPtr
->view
->size
.width
, 22, WRSunken
);
815 if (bPtr
->flags
.isTitled
) {
816 for (i
=0; i
<bPtr
->maxVisibleColumns
; i
++) {
817 drawTitleOfColumn(bPtr
, i
+bPtr
->firstVisibleColumn
);
824 handleEvents(XEvent
*event
, void *data
)
826 WMBrowser
*bPtr
= (WMBrowser
*)data
;
828 CHECK_CLASS(data
, WC_Browser
);
831 switch (event
->type
) {
837 destroyBrowser(bPtr
);
846 scrollToColumn(WMBrowser
*bPtr
, int column
, Bool updateScroller
)
853 if (column
!= bPtr
->firstVisibleColumn
)
860 bPtr
->firstVisibleColumn
= column
;
861 for (i
= 0; i
< bPtr
->columnCount
; i
++) {
862 if (COLUMN_IS_VISIBLE(bPtr
, i
)) {
863 WMMoveWidget(bPtr
->columns
[i
], x
,
864 WMWidgetView(bPtr
->columns
[i
])->pos
.y
);
865 if (!WMWidgetView(bPtr
->columns
[i
])->flags
.realized
)
866 WMRealizeWidget(bPtr
->columns
[i
]);
867 WMMapWidget(bPtr
->columns
[i
]);
868 x
+= bPtr
->columnSize
.width
+ COLUMN_SPACING
;
870 WMUnmapWidget(bPtr
->columns
[i
]);
874 /* update the scroller */
875 if (updateScroller
) {
876 if (bPtr
->columnCount
> bPtr
->maxVisibleColumns
) {
877 float value
, proportion
;
879 value
= bPtr
->firstVisibleColumn
880 /(float)(bPtr
->columnCount
-bPtr
->maxVisibleColumns
);
881 proportion
= bPtr
->maxVisibleColumns
/(float)bPtr
->columnCount
;
882 WMSetScrollerParameters(bPtr
->scroller
, value
, proportion
);
884 WMSetScrollerParameters(bPtr
->scroller
, 0, 1);
888 if (bPtr
->view
->flags
.mapped
)
892 WMPostNotificationName(WMBrowserDidScrollNotification
, bPtr
, NULL
);
897 listCallback(void *self
, void *clientData
)
899 WMBrowser
*bPtr
= (WMBrowser
*)clientData
;
900 WMList
*lPtr
= (WMList
*)self
;
902 static WMListItem
*oldItem
= NULL
;
905 item
= WMGetListSelectedItem(lPtr
);
911 if (oldItem
!= item
) {
912 for (i
=0; i
<bPtr
->columnCount
; i
++) {
913 if (lPtr
== bPtr
->columns
[i
])
916 assert(i
<bPtr
->columnCount
);
918 bPtr
->selectedColumn
= i
;
920 /* columns at right must be cleared */
921 removeColumn(bPtr
, i
+1);
923 if (item
->isBranch
) {
924 WMAddBrowserColumn(bPtr
);
926 if (bPtr
->usedColumnCount
< bPtr
->maxVisibleColumns
)
929 i
= bPtr
->usedColumnCount
-bPtr
->maxVisibleColumns
;
930 scrollToColumn(bPtr
, i
, True
);
931 if (item
->isBranch
) {
932 loadColumn(bPtr
, bPtr
->usedColumnCount
-1);
937 /* call callback for click */
939 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
946 listDoubleCallback(void *self
, void *clientData
)
948 WMBrowser
*bPtr
= (WMBrowser
*)clientData
;
949 WMList
*lPtr
= (WMList
*)self
;
952 item
= WMGetListSelectedItem(lPtr
);
956 /* call callback for double click */
957 if (bPtr
->doubleAction
)
958 (*bPtr
->doubleAction
)(bPtr
, bPtr
->doubleClientData
);
963 WMLoadBrowserColumnZero(WMBrowser
*bPtr
)
965 if (!bPtr
->flags
.loaded
) {
966 /* create column 0 */
967 WMAddBrowserColumn(bPtr
);
971 /* make column 0 visible */
972 scrollToColumn(bPtr
, 0, True
);
974 bPtr
->flags
.loaded
= 1;
980 WMRemoveBrowserItem(WMBrowser
*bPtr
, int column
, int row
)
984 if (column
< 0 || column
>= bPtr
->usedColumnCount
)
987 list
= WMGetBrowserListInColumn(bPtr
, column
);
989 if (row
< 0 || row
>= WMGetListNumberOfRows(list
))
992 removeColumn(bPtr
, column
+1);
993 if (bPtr
->usedColumnCount
< bPtr
->maxVisibleColumns
)
994 scrollToColumn(bPtr
, 0, True
);
996 scrollToColumn(bPtr
, bPtr
->usedColumnCount
-bPtr
->maxVisibleColumns
,
999 WMRemoveListItem(list
, row
);
1004 listSelectionObserver(void *observerData
, WMNotification
*notification
)
1006 WMBrowser
*bPtr
= (WMBrowser
*)observerData
;
1007 int column
, item
= (int)WMGetNotificationClientData(notification
);
1008 WMList
*lPtr
= (WMList
*)WMGetNotificationObject(notification
);
1010 for (column
=0; column
<bPtr
->usedColumnCount
; column
++)
1011 if (bPtr
->columns
[column
] == lPtr
)
1014 /* this can happen when a list is being cleared with WMClearList
1015 * after the column was removed */
1016 if (column
>= bPtr
->usedColumnCount
) {
1023 bPtr
->selectedColumn
= column
;
1028 WMAddBrowserColumn(WMBrowser
*bPtr
)
1037 if (bPtr
->usedColumnCount
< bPtr
->columnCount
) {
1038 return bPtr
->usedColumnCount
++;
1041 bPtr
->usedColumnCount
++;
1043 if (bPtr
->flags
.isTitled
) {
1044 colY
= TITLE_SPACING
+ bPtr
->titleHeight
;
1049 index
= bPtr
->columnCount
;
1050 bPtr
->columnCount
++;
1051 clist
= wmalloc(sizeof(WMList
*)*bPtr
->columnCount
);
1052 tlist
= wmalloc(sizeof(char*)*bPtr
->columnCount
);
1053 memcpy(clist
, bPtr
->columns
, sizeof(WMList
*)*(bPtr
->columnCount
-1));
1054 memcpy(tlist
, bPtr
->titles
, sizeof(char*)*(bPtr
->columnCount
-1));
1056 free(bPtr
->columns
);
1059 bPtr
->columns
= clist
;
1060 bPtr
->titles
= tlist
;
1062 bPtr
->titles
[index
] = NULL
;
1064 list
= WMCreateList(bPtr
);
1065 WMSetListAction(list
, listCallback
, bPtr
);
1066 WMSetListDoubleAction(list
, listDoubleCallback
, bPtr
);
1067 WMSetListUserDrawProc(list
, paintItem
);
1068 WMAddNotificationObserver(listSelectionObserver
, bPtr
,
1069 WMListSelectionDidChangeNotification
, list
);
1071 bPtr
->columns
[index
] = list
;
1073 WMResizeWidget(list
, bPtr
->columnSize
.width
, bPtr
->columnSize
.height
);
1074 WMMoveWidget(list
, (bPtr
->columnSize
.width
+COLUMN_SPACING
)*index
, colY
);
1075 if (COLUMN_IS_VISIBLE(bPtr
, index
))
1078 /* update the scroller */
1079 if (bPtr
->columnCount
> bPtr
->maxVisibleColumns
) {
1080 float value
, proportion
;
1082 value
= bPtr
->firstVisibleColumn
1083 /(float)(bPtr
->columnCount
-bPtr
->maxVisibleColumns
);
1084 proportion
= bPtr
->maxVisibleColumns
/(float)bPtr
->columnCount
;
1085 WMSetScrollerParameters(bPtr
->scroller
, value
, proportion
);
1094 destroyBrowser(WMBrowser
*bPtr
)
1098 for (i
=0; i
<bPtr
->columnCount
; i
++) {
1099 if (bPtr
->titles
[i
])
1100 free(bPtr
->titles
[i
]);
1104 free(bPtr
->pathSeparator
);
1106 WMRemoveNotificationObserver(bPtr
);
1113 createTruncatedString(WMFont
*font
, char *text
, int *textLen
, int width
)
1115 int dLen
= WMWidthOfString(font
, ".", 1);
1116 char *textBuf
= (char*)wmalloc((*textLen
)+4);
1118 if (width
>= 3*dLen
) {
1119 int dddLen
= 3*dLen
;
1120 int tmpTextLen
= *textLen
;
1122 strcpy(textBuf
, text
);
1124 && (WMWidthOfString(font
, textBuf
, tmpTextLen
)+dddLen
> width
))
1126 strcpy(textBuf
+tmpTextLen
, "...");
1127 *textLen
= tmpTextLen
+3;
1128 } else if (width
>= 2*dLen
) {
1129 strcpy(textBuf
, "..");
1131 } else if (width
>= dLen
) {
1132 strcpy(textBuf
, ".");