2 #include <WINGs/WINGsP.h>
3 #include <math.h> /* for : double rint (double) */
7 char *FSBrowserDidScrollNotification
= "FSBrowserDidScrollNotification";
10 typedef struct W_FSBrowser
{
18 short usedColumnCount
; /* columns actually being used */
21 short maxVisibleColumns
;
22 short firstVisibleColumn
;
33 void *doubleClientData
;
34 WMAction
*doubleAction
;
36 FSBrowserFillColumnProc
*fillColumn
;
37 FSBrowserGetItemNameProc
*parseItem
;
44 WMReliefType relief
:3;
45 unsigned int isTitled
:1;
46 unsigned int allowMultipleSelection
:1;
47 unsigned int hasScroller
:1;
48 unsigned int emptyCol
:1;
51 unsigned int loaded
:1;
52 unsigned int loadingColumn
:1;
57 #define COLUMN_SPACING 4
58 #define TITLE_SPACING 2
60 #define DEFAULT_WIDTH 305
61 #define DEFAULT_HEIGHT 200
62 #define DEFAULT_HAS_SCROLLER True
63 #define DEFAULT_TITLE_HEIGHT 20
64 #define DEFAULT_IS_TITLED True
65 #define DEFAULT_MAX_VISIBLE_COLUMNS 2
66 #define DEFAULT_SEPARATOR "/"
67 #define DEFAULT_RELIEF WRSunken
69 #define MIN_VISIBLE_COLUMNS 1
70 #define MAX_VISIBLE_COLUMNS 32
73 #define COLUMN_IS_VISIBLE(b, c) ((c) >= (b)->firstVisibleColumn \
74 && (c) < (b)->firstVisibleColumn + (b)->maxVisibleColumns)
77 static void handleEvents(XEvent
*event
, void *data
);
78 static void destroyBrowser(FSBrowser
*bPtr
);
80 static void setupScroller(FSBrowser
*bPtr
);
82 static void scrollToColumn(FSBrowser
*bPtr
, int column
, Bool updateScroller
);
84 static void paintItem(WMList
*lPtr
, int index
, Drawable d
, char *text
,
85 int state
, WMRect
*rect
);
87 static void loadColumn(FSBrowser
*bPtr
, int column
);
89 static void removeColumn(FSBrowser
*bPtr
, int column
);
90 static void paintBrowser(FSBrowser
*bPtr
);
93 createTruncatedString(WMFont
*font
, char *text
, int *textLen
, int width
);
95 static void willResizeFSBrowser(W_ViewDelegate
*self
, WMView
*view
,
96 unsigned int *width
, unsigned int *height
);
97 /* static void resizeFSBrowser(WMWidget*, unsigned int, unsigned int); */
99 /* W_ViewProcedureTable _FSBrowserViewProcedures = { */
101 /* resizeFSBrowser, */
105 static W_ViewDelegate _FSBrowserViewDelegate
= {
116 static W_Class fsBrowserWidgetClass
= 0;
118 W_Class
InitFSBrowser(WMScreen
*scr
)
120 // Register the widget with WINGs and get the widget class ID.
121 if (!(fsBrowserWidgetClass
))
123 fsBrowserWidgetClass
=
124 /* W_RegisterUserWidget(&_FSBrowserViewProcedures); */
125 W_RegisterUserWidget();
128 return fsBrowserWidgetClass
;
132 FSCreateBrowser(WMWidget
*parent
)
137 wassertrv(parent
, NULL
);
139 bPtr
= wmalloc(sizeof(FSBrowser
));
140 memset(bPtr
, 0, sizeof(FSBrowser
));
142 bPtr
->widgetClass
= fsBrowserWidgetClass
/* WC_Browser */;
144 bPtr
->view
= W_CreateView(W_VIEW(parent
));
149 bPtr
->view
->self
= bPtr
;
150 bPtr
->view
->delegate
= &_FSBrowserViewDelegate
;
152 WMCreateEventHandler(bPtr
->view
, ExposureMask
|StructureNotifyMask
153 |ClientMessageMask
, handleEvents
, bPtr
);
155 /* default configuration */
156 bPtr
->flags
.hasScroller
= DEFAULT_HAS_SCROLLER
;
158 bPtr
->titleHeight
= DEFAULT_TITLE_HEIGHT
;
159 bPtr
->flags
.isTitled
= DEFAULT_IS_TITLED
;
160 bPtr
->flags
.emptyCol
= 1;
161 bPtr
->maxVisibleColumns
= DEFAULT_MAX_VISIBLE_COLUMNS
;
163 WMResizeWidget(bPtr
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
164 /* resizeFSBrowser(bPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT); */
166 bPtr
->pathSeparator
= wstrdup(DEFAULT_SEPARATOR
);
168 if (bPtr
->flags
.hasScroller
)
171 for (i
=0; i
<bPtr
->maxVisibleColumns
; i
++) {
172 FSAddBrowserColumn(bPtr
);
174 bPtr
->usedColumnCount
= 0;
176 bPtr
->selectedColumn
= -1;
183 FSSetBrowserMaxVisibleColumns(FSBrowser
*bPtr
, int columns
)
185 int curMaxVisibleColumns
;
186 int newFirstVisibleColumn
= 0;
190 columns
= (columns
< MIN_VISIBLE_COLUMNS
) ? MIN_VISIBLE_COLUMNS
: columns
;
191 columns
= (columns
> MAX_VISIBLE_COLUMNS
) ? MAX_VISIBLE_COLUMNS
: columns
;
192 if (columns
== bPtr
->maxVisibleColumns
) {
195 curMaxVisibleColumns
= bPtr
->maxVisibleColumns
;
196 bPtr
->maxVisibleColumns
= columns
;
197 /* browser not loaded */
198 if (!bPtr
->flags
.loaded
) {
199 if ((columns
> curMaxVisibleColumns
) && (columns
> bPtr
->columnCount
)) {
200 int i
= columns
- bPtr
->columnCount
;
201 bPtr
->usedColumnCount
= bPtr
->columnCount
;
203 FSAddBrowserColumn(bPtr
);
205 bPtr
->usedColumnCount
= 0;
207 /* browser loaded and columns > curMaxVisibleColumns */
208 } else if (columns
> curMaxVisibleColumns
) {
209 if (bPtr
->usedColumnCount
> columns
) {
210 newFirstVisibleColumn
= bPtr
->usedColumnCount
- columns
;
212 if (newFirstVisibleColumn
> bPtr
->firstVisibleColumn
) {
213 newFirstVisibleColumn
= bPtr
->firstVisibleColumn
;
215 if (columns
> bPtr
->columnCount
) {
216 int i
= columns
- bPtr
->columnCount
;
217 int curUsedColumnCount
= bPtr
->usedColumnCount
;
218 bPtr
->usedColumnCount
= bPtr
->columnCount
;
220 FSAddBrowserColumn(bPtr
);
222 bPtr
->usedColumnCount
= curUsedColumnCount
;
224 /* browser loaded and columns < curMaxVisibleColumns */
226 newFirstVisibleColumn
= bPtr
->firstVisibleColumn
;
227 if (newFirstVisibleColumn
+ columns
>= bPtr
->usedColumnCount
) {
228 removeColumn(bPtr
, newFirstVisibleColumn
+ columns
);
231 WMResizeWidget(bPtr
, bPtr
->view
->size
.width
, bPtr
->view
->size
.height
);
232 /* resizeFSBrowser(bPtr, bPtr->view->size.width, bPtr->view->size.height); */
233 if (bPtr
->flags
.loaded
) {
234 XClearArea(bPtr
->view
->screen
->display
, bPtr
->view
->window
, 0, 0,
235 bPtr
->view
->size
.width
, bPtr
->titleHeight
, False
);
236 scrollToColumn (bPtr
, newFirstVisibleColumn
, True
);
242 FSGetBrowserNumberOfColumns(FSBrowser
*bPtr
)
244 return bPtr
->usedColumnCount
;
248 FSSetBrowserPathSeparator(FSBrowser
*bPtr
, char *separator
)
250 if (bPtr
->pathSeparator
)
251 free(bPtr
->pathSeparator
);
252 bPtr
->pathSeparator
= wstrdup(separator
);
258 drawTitleOfColumn(FSBrowser
*bPtr
, int column
)
260 WMScreen
*scr
= bPtr
->view
->screen
;
263 x
=(column
-bPtr
->firstVisibleColumn
)*(bPtr
->columnSize
.width
+COLUMN_SPACING
);
265 XFillRectangle(scr
->display
, bPtr
->view
->window
, WMColorGC(scr
->darkGray
), x
, 0,
266 bPtr
->columnSize
.width
, bPtr
->titleHeight
);
267 W_DrawRelief(scr
, bPtr
->view
->window
, x
, 0,
268 bPtr
->columnSize
.width
, bPtr
->titleHeight
, WRSunken
);
270 if (column
< bPtr
->usedColumnCount
&& bPtr
->titles
[column
]) {
271 int titleLen
= strlen(bPtr
->titles
[column
]);
272 int widthC
= bPtr
->columnSize
.width
-8;
274 if (WMWidthOfString(scr
->boldFont
, bPtr
->titles
[column
], titleLen
)
276 char *titleBuf
= createTruncatedString(scr
->boldFont
,
277 bPtr
->titles
[column
],
279 W_PaintText(bPtr
->view
, bPtr
->view
->window
, scr
->boldFont
, x
,
280 (bPtr
->titleHeight
-WMFontHeight(scr
->boldFont
))/2,
281 bPtr
->columnSize
.width
, WACenter
, WMWhiteColor(scr
),
282 False
, titleBuf
, titleLen
);
285 W_PaintText(bPtr
->view
, bPtr
->view
->window
, scr
->boldFont
, x
,
286 (bPtr
->titleHeight
-WMFontHeight(scr
->boldFont
))/2,
287 bPtr
->columnSize
.width
, WACenter
, WMWhiteColor(scr
),
288 False
, bPtr
->titles
[column
], titleLen
);
295 FSSetBrowserColumnTitle(FSBrowser
*bPtr
, int column
, char *title
)
298 assert(column
< bPtr
->usedColumnCount
);
300 if (bPtr
->titles
[column
])
301 free(bPtr
->titles
[column
]);
303 bPtr
->titles
[column
] = wstrdup(title
);
305 if (COLUMN_IS_VISIBLE(bPtr
, column
) && bPtr
->flags
.isTitled
) {
306 drawTitleOfColumn(bPtr
, column
);
312 FSGetBrowserListInColumn(FSBrowser
*bPtr
, int column
)
314 if (column
< 0 || column
>= bPtr
->usedColumnCount
)
317 return bPtr
->columns
[column
];
322 FSSetBrowserFillColumnProc(FSBrowser
*bPtr
, FSBrowserFillColumnProc
*proc
)
324 bPtr
->fillColumn
= proc
;
329 FSSetBrowserGetItemNameProc(FSBrowser
*bPtr
, FSBrowserGetItemNameProc
*proc
)
331 bPtr
->parseItem
= proc
;
336 FSGetBrowserFirstVisibleColumn(FSBrowser
*bPtr
)
338 return bPtr
->firstVisibleColumn
;
343 removeColumn(FSBrowser
*bPtr
, int column
)
345 int i
, clearEnd
, destroyEnd
;
351 column
= (column
< 0) ? 0 : column
;
352 if (column
>= bPtr
->columnCount
) {
355 if (column
< bPtr
->maxVisibleColumns
) {
356 clearEnd
= bPtr
->maxVisibleColumns
;
357 destroyEnd
= bPtr
->columnCount
;
358 bPtr
->columnCount
= bPtr
->maxVisibleColumns
;
361 destroyEnd
= bPtr
->columnCount
;
362 bPtr
->columnCount
= column
;
364 if (column
< bPtr
->usedColumnCount
) {
365 bPtr
->usedColumnCount
= column
;
367 for (i
=column
; i
< clearEnd
; i
++) {
368 if (bPtr
->titles
[i
]) {
369 free(bPtr
->titles
[i
]);
370 bPtr
->titles
[i
] = NULL
;
372 WMClearList(bPtr
->columns
[i
]);
374 for (;i
< destroyEnd
; i
++)
378 WMListItem
*item
= NULL
;
380 if (bPtr
->titles
[i
]) {
381 free(bPtr
->titles
[i
]);
382 bPtr
->titles
[i
] = NULL
;
384 WMRemoveNotificationObserverWithName(bPtr
,
385 WMListSelectionDidChangeNotification
,
389 * Free the client data.
390 * This assumes is it a string or the like.
391 * Hopefully it won't slow things down too much.
392 * Should use a callback to allow for more complicated
393 * clientData structures.
395 /* numRows = WMGetListNumberOfRows(bPtr->columns[i]); */
396 /* for(j = 0; j < numRows; j++) */
399 /* item = WMGetListItem(bPtr->columns[i], j); */
400 /* if(item->clientData) */
402 /* free(item->clientData); */
403 /* item->clientData = NULL; */
406 WMDestroyWidget(bPtr
->columns
[i
]);
407 bPtr
->columns
[i
] = NULL
;
409 clist
= wmalloc(sizeof(WMList
*) * (bPtr
->columnCount
));
410 tlist
= wmalloc(sizeof(char*) * (bPtr
->columnCount
));
411 memcpy(clist
, bPtr
->columns
, sizeof(WMList
*) * (bPtr
->columnCount
));
412 memcpy(tlist
, bPtr
->titles
, sizeof(char*) * (bPtr
->columnCount
));
415 bPtr
->titles
= tlist
;
416 bPtr
->columns
= clist
;
421 FSGetBrowserSelectedItemInColumn(FSBrowser
*bPtr
, int column
)
423 if ((column
< 0) || (column
>= bPtr
->usedColumnCount
))
426 return WMGetListSelectedItem(bPtr
->columns
[column
]);
432 FSGetBrowserSelectedColumn(FSBrowser
*bPtr
)
434 return bPtr
->selectedColumn
;
439 FSGetBrowserSelectedRowInColumn(FSBrowser
*bPtr
, int column
)
441 if (column
>= 0 && column
< bPtr
->columnCount
) {
442 return WMGetListSelectedItemRow(bPtr
->columns
[column
]);
450 FSSetBrowserTitled(FSBrowser
*bPtr
, Bool flag
)
453 int columnX
, columnY
;
455 if (bPtr
->flags
.isTitled
== flag
)
460 if (!bPtr
->flags
.isTitled
) {
461 columnY
= TITLE_SPACING
+ bPtr
->titleHeight
;
463 bPtr
->columnSize
.height
-= columnY
;
465 for (i
=0; i
<bPtr
->columnCount
; i
++) {
466 WMResizeWidget(bPtr
->columns
[i
], bPtr
->columnSize
.width
,
467 bPtr
->columnSize
.height
);
469 columnX
= WMWidgetView(bPtr
->columns
[i
])->pos
.x
;
471 WMMoveWidget(bPtr
->columns
[i
], columnX
, columnY
);
474 bPtr
->columnSize
.height
+= TITLE_SPACING
+ bPtr
->titleHeight
;
476 for (i
=0; i
<bPtr
->columnCount
; i
++) {
477 WMResizeWidget(bPtr
->columns
[i
], bPtr
->columnSize
.width
,
478 bPtr
->columnSize
.height
);
480 columnX
= WMWidgetView(bPtr
->columns
[i
])->pos
.x
;
482 WMMoveWidget(bPtr
->columns
[i
], columnX
, 0);
486 bPtr
->flags
.isTitled
= flag
;
491 /* FSAddSortedBrowserItem(FSBrowser *bPtr, int column, char *text, Bool isBranch) */
493 /* WMListItem *item; */
495 /* if (column < 0 || column >= bPtr->columnCount) */
498 /* item = WMAddSortedListItem(bPtr->columns[column], text); */
499 /* item->isBranch = isBranch; */
507 FSInsertBrowserItem(FSBrowser
*bPtr
, int column
, int row
, char *text
,
512 if (column
< 0 || column
>= bPtr
->columnCount
)
515 item
= WMInsertListItem(bPtr
->columns
[column
], row
, text
);
516 item
->isBranch
= isBranch
;
523 FSSetBrowserRelief(FSBrowser
*bPtr
, WMReliefType relief
)
525 bPtr
->flags
.relief
= relief
;
526 if (bPtr
->view
->flags
.realized
) {
533 willResizeFSBrowser(W_ViewDelegate
*self
, WMView
*view
,
534 unsigned int *width
, unsigned int *height
)
536 FSBrowser
*bPtr
= (FSBrowser
*)view
->self
;
537 int cols
= bPtr
->maxVisibleColumns
;
544 bPtr
->columnSize
.width
= (*width
-(cols
-1)*COLUMN_SPACING
) / cols
;
545 bPtr
->columnSize
.height
= *height
;
547 if (bPtr
->flags
.isTitled
) {
548 colY
= TITLE_SPACING
+ bPtr
->titleHeight
;
549 bPtr
->columnSize
.height
-= colY
;
554 if (bPtr
->flags
.hasScroller
) {
555 bPtr
->columnSize
.height
-= SCROLLER_WIDTH
+ 4;
557 if (bPtr
->scroller
) {
558 WMResizeWidget(bPtr
->scroller
, *width
-2, 1);
559 WMMoveWidget(bPtr
->scroller
, 1, *height
-SCROLLER_WIDTH
-1);
564 for (i
= 0; i
< bPtr
->columnCount
; i
++) {
565 WMResizeWidget(bPtr
->columns
[i
], bPtr
->columnSize
.width
,
566 bPtr
->columnSize
.height
);
568 WMMoveWidget(bPtr
->columns
[i
], colX
, colY
);
570 if (COLUMN_IS_VISIBLE(bPtr
, i
)) {
571 colX
+= bPtr
->columnSize
.width
+COLUMN_SPACING
;
575 /* W_ResizeView(bPtr->view, *width, *height); */
578 /* resizeFSBrowser(WMWidget *w, unsigned int width, unsigned int height) */
580 /* FSBrowser *bPtr = (FSBrowser*)w; */
581 /* int cols = bPtr->maxVisibleColumns; */
582 /* int colX, colY; */
585 /* assert(width > 0); */
586 /* assert(height > 0); */
588 /* bPtr->columnSize.width = (width-(cols-1)*COLUMN_SPACING) / cols; */
589 /* bPtr->columnSize.height = height; */
591 /* if (bPtr->flags.isTitled) { */
592 /* colY = TITLE_SPACING + bPtr->titleHeight; */
593 /* bPtr->columnSize.height -= colY; */
598 /* if (bPtr->flags.hasScroller) { */
599 /* bPtr->columnSize.height -= SCROLLER_WIDTH + 4; */
601 /* if (bPtr->scroller) { */
602 /* WMResizeWidget(bPtr->scroller, width-2, 1); */
603 /* WMMoveWidget(bPtr->scroller, 1, height-SCROLLER_WIDTH-1); */
608 /* for (i = 0; i < bPtr->columnCount; i++) { */
609 /* WMResizeWidget(bPtr->columns[i], bPtr->columnSize.width, */
610 /* bPtr->columnSize.height); */
612 /* WMMoveWidget(bPtr->columns[i], colX, colY); */
614 /* if (COLUMN_IS_VISIBLE(bPtr, i)) { */
615 /* colX += bPtr->columnSize.width+COLUMN_SPACING; */
619 /* W_ResizeView(bPtr->view, width, height); */
624 paintItem(WMList
*lPtr
, int index
, Drawable d
, char *text
, int state
,
627 WMView
*view
= W_VIEW(lPtr
);
628 W_Screen
*scr
= view
->screen
;
629 int width
, height
, x
, y
;
630 /* WMListItem *item; */
632 /* item = WMGetListItem(lPtr, index); */
634 width
= rect
->size
.width
;
635 height
= rect
->size
.height
;
639 if (state
& WLDSSelected
)
640 WMPaintColorSwatch(WMWhiteColor(scr
), d
, x
, y
,
643 WMPaintColorSwatch(WMGetWidgetBackgroundColor(lPtr
), d
, x
, y
,
647 /* Avoid overlaping... */
648 int textLen
= strlen(text
);
649 int widthC
= (state
& WLDSIsBranch
) ? width
-20 : width
-8;
650 if (WMWidthOfString(scr
->normalFont
, text
, textLen
) > widthC
) {
651 char *textBuf
= createTruncatedString(scr
->normalFont
,
652 text
, &textLen
, widthC
);
653 W_PaintText(view
, d
, scr
->normalFont
, x
+4, y
, widthC
,
654 WALeft
, WMBlackColor(scr
), False
, textBuf
, textLen
);
657 W_PaintText(view
, d
, scr
->normalFont
, x
+4, y
, widthC
,
658 WALeft
, WMBlackColor(scr
), False
, text
, textLen
);
662 if (state
& WLDSIsBranch
) {
663 XDrawLine(scr
->display
, d
, WMColorGC(scr
->darkGray
), x
+width
-11, y
+3,
664 x
+width
-6, y
+height
/2);
665 if (state
& WLDSSelected
)
666 XDrawLine(scr
->display
, d
,WMColorGC(scr
->gray
), x
+width
-11, y
+height
-5,
667 x
+width
-6, y
+height
/2);
669 XDrawLine(scr
->display
, d
,WMColorGC(scr
->white
), x
+width
-11, y
+height
-5,
670 x
+width
-6, y
+height
/2);
671 XDrawLine(scr
->display
, d
, WMColorGC(scr
->black
), x
+width
-12, y
+3,
672 x
+width
-12, y
+height
-5);
678 scrollCallback(WMWidget
*scroller
, void *self
)
680 FSBrowser
*bPtr
= (FSBrowser
*)self
;
681 WMScroller
*sPtr
= (WMScroller
*)scroller
;
683 #define LAST_VISIBLE_COLUMN bPtr->firstVisibleColumn+bPtr->maxVisibleColumns
685 switch (WMGetScrollerHitPart(sPtr
)) {
686 case WSDecrementLine
:
687 if (bPtr
->firstVisibleColumn
> 0) {
688 scrollToColumn(bPtr
, bPtr
->firstVisibleColumn
-1, True
);
692 case WSDecrementPage
:
693 if (bPtr
->firstVisibleColumn
> 0) {
694 newFirst
= bPtr
->firstVisibleColumn
- bPtr
->maxVisibleColumns
;
696 scrollToColumn(bPtr
, newFirst
, True
);
701 case WSIncrementLine
:
702 if (LAST_VISIBLE_COLUMN
< bPtr
->usedColumnCount
) {
703 scrollToColumn(bPtr
, bPtr
->firstVisibleColumn
+1, True
);
707 case WSIncrementPage
:
708 if (LAST_VISIBLE_COLUMN
< bPtr
->usedColumnCount
) {
709 newFirst
= bPtr
->firstVisibleColumn
+ bPtr
->maxVisibleColumns
;
711 if (newFirst
+bPtr
->maxVisibleColumns
>= bPtr
->columnCount
)
712 newFirst
= bPtr
->columnCount
- bPtr
->maxVisibleColumns
;
714 scrollToColumn(bPtr
, newFirst
, True
);
721 double value
= bPtr
->columnCount
- bPtr
->maxVisibleColumns
;
723 floatValue
= WMGetScrollerValue(bPtr
->scroller
);
725 floatValue
= (floatValue
*value
)/value
;
727 newFirst
= rint(floatValue
*(float)(bPtr
->columnCount
- bPtr
->maxVisibleColumns
));
729 if (bPtr
->firstVisibleColumn
!= newFirst
)
730 scrollToColumn(bPtr
, newFirst
, False
);
732 WMSetScrollerParameters(bPtr->scroller, floatValue,
733 bPtr->maxVisibleColumns/(float)bPtr->columnCount);
744 #undef LAST_VISIBLE_COLUMN
749 setupScroller(FSBrowser
*bPtr
)
754 y
= bPtr
->view
->size
.height
- SCROLLER_WIDTH
- 1;
756 sPtr
= WMCreateScroller(bPtr
);
757 WMSetScrollerAction(sPtr
, scrollCallback
, bPtr
);
758 WMMoveWidget(sPtr
, 1, y
);
759 WMResizeWidget(sPtr
, bPtr
->view
->size
.width
-2, SCROLLER_WIDTH
);
761 bPtr
->scroller
= sPtr
;
768 FSSetBrowserAction(FSBrowser
*bPtr
, WMAction
*action
, void *clientData
)
770 bPtr
->action
= action
;
771 bPtr
->clientData
= clientData
;
776 FSSetBrowserDoubleAction(FSBrowser
*bPtr
, WMAction
*action
, void *clientData
)
778 bPtr
->doubleAction
= action
;
779 bPtr
->doubleClientData
= clientData
;
784 FSSetBrowserHasScroller(FSBrowser
*bPtr
, int hasScroller
)
786 bPtr
->flags
.hasScroller
= hasScroller
;
788 if(bPtr
->flags
.hasScroller
)
789 WMMapWidget(bPtr
->scroller
);
791 WMUnmapWidget(bPtr
->scroller
);
797 FSSetBrowserPath(FSBrowser
*bPtr
, char *path
)
800 char *str
= wstrdup(path
);
801 char *tmp
, *retPtr
= NULL
;
803 WMListItem
*listItem
;
805 /* WMLoadBrowserColumnZero must be call first */
806 if (!bPtr
->flags
.loaded
) {
810 removeColumn(bPtr
, 1);
813 tmp
= strtok(str
, bPtr
->pathSeparator
);
815 /* select it in the column */
816 item
= WMFindRowOfListItemWithTitle(bPtr
->columns
[i
], tmp
);
818 retPtr
= &path
[(int)(tmp
- str
)];
821 WMSelectListItem(bPtr
->columns
[i
], item
);
822 WMSetListPosition(bPtr
->columns
[i
], item
);
824 listItem
= WMGetListItem(bPtr
->columns
[i
], item
);
825 if (!listItem
|| (!listItem
->isBranch
&& !bPtr
->flags
.emptyCol
) ) {
829 /* load next column */
830 FSAddBrowserColumn(bPtr
);
832 loadColumn(bPtr
, i
+1);
834 tmp
= strtok(NULL
, bPtr
->pathSeparator
);
839 for (i
= bPtr
->usedColumnCount
- 1;
840 (i
> -1) && !WMGetListSelectedItem(bPtr
->columns
[i
]);
843 bPtr
->selectedColumn
= i
;
845 if (bPtr
->columnCount
< bPtr
->maxVisibleColumns
) {
846 int i
= bPtr
->maxVisibleColumns
- bPtr
->columnCount
;
847 int curUsedColumnCount
= bPtr
->usedColumnCount
;
848 bPtr
->usedColumnCount
= bPtr
->columnCount
;
850 FSAddBrowserColumn(bPtr
);
852 bPtr
->usedColumnCount
= curUsedColumnCount
;
855 scrollToColumn(bPtr
, bPtr
->columnCount
- bPtr
->maxVisibleColumns
, True
);
862 FSGetBrowserPath(FSBrowser
*bPtr
)
864 return FSGetBrowserPathToColumn(bPtr
, bPtr
->columnCount
);
869 FSGetBrowserPathToColumn(FSBrowser
*bPtr
, int column
)
875 if (column
>= bPtr
->usedColumnCount
)
876 column
= bPtr
->usedColumnCount
-1;
879 return wstrdup(bPtr
->pathSeparator
);
882 /* calculate size of buffer */
884 for (i
= 0; i
<= column
; i
++) {
885 item
= WMGetListSelectedItem(bPtr
->columns
[i
]);
888 /* if(bPtr->parseItem) */
889 /* size += strlen((*bPtr->parseItem)(item)); */
891 size
+= strlen(item
->text
);
895 path
= wmalloc(size
+(column
+1)*strlen(bPtr
->pathSeparator
)+1);
898 for (i
= 0; i
<= column
; i
++) {
899 strcat(path
, bPtr
->pathSeparator
);
900 item
= WMGetListSelectedItem(bPtr
->columns
[i
]);
903 /* if(bPtr->parseItem) */
904 /* strcat(path, (*bPtr->parseItem)(item)); */
906 strcat(path
, item
->text
);
914 loadColumn(FSBrowser
*bPtr
, int column
)
916 assert(bPtr
->fillColumn
);
917 bPtr
->flags
.loadingColumn
= 1;
918 (*bPtr
->fillColumn
)(bPtr
, column
);
919 bPtr
->flags
.loadingColumn
= 0;
924 paintBrowser(FSBrowser
*bPtr
)
928 if (!bPtr
->view
->flags
.mapped
)
931 if(bPtr
->flags
.hasScroller
)
932 W_DrawRelief(bPtr
->view
->screen
, bPtr
->view
->window
, 0,
933 bPtr
->view
->size
.height
-SCROLLER_WIDTH
-2,
934 bPtr
->view
->size
.width
, 22, bPtr
->flags
.relief
);
936 if (bPtr
->flags
.isTitled
) {
937 for (i
=0; i
<bPtr
->maxVisibleColumns
; i
++) {
938 drawTitleOfColumn(bPtr
, i
+bPtr
->firstVisibleColumn
);
945 handleEvents(XEvent
*event
, void *data
)
947 FSBrowser
*bPtr
= (FSBrowser
*)data
;
949 /* CHECK_CLASS(data, fsBrowserWidgetClass); */
952 switch (event
->type
) {
958 destroyBrowser(bPtr
);
967 scrollToColumn(FSBrowser
*bPtr
, int column
, Bool updateScroller
)
974 if (column
!= bPtr
->firstVisibleColumn
)
981 bPtr
->firstVisibleColumn
= column
;
982 for (i
= 0; i
< bPtr
->columnCount
; i
++) {
983 if (COLUMN_IS_VISIBLE(bPtr
, i
)) {
984 WMMoveWidget(bPtr
->columns
[i
], x
,
985 WMWidgetView(bPtr
->columns
[i
])->pos
.y
);
986 if (!WMWidgetView(bPtr
->columns
[i
])->flags
.realized
)
987 WMRealizeWidget(bPtr
->columns
[i
]);
988 WMMapWidget(bPtr
->columns
[i
]);
989 x
+= bPtr
->columnSize
.width
+ COLUMN_SPACING
;
991 WMUnmapWidget(bPtr
->columns
[i
]);
995 /* update the scroller */
996 if (updateScroller
) {
997 if (bPtr
->columnCount
> bPtr
->maxVisibleColumns
) {
998 float value
, proportion
;
1000 value
= bPtr
->firstVisibleColumn
1001 /(float)(bPtr
->columnCount
-bPtr
->maxVisibleColumns
);
1002 proportion
= bPtr
->maxVisibleColumns
/(float)bPtr
->columnCount
;
1003 WMSetScrollerParameters(bPtr
->scroller
, value
, proportion
);
1005 WMSetScrollerParameters(bPtr
->scroller
, 0, 1);
1009 if (bPtr
->view
->flags
.mapped
)
1014 WMPostNotificationName(FSBrowserDidScrollNotification
, bPtr
, NULL
);
1020 listCallback(void *self
, void *clientData
)
1022 FSBrowser
*bPtr
= (FSBrowser
*)clientData
;
1023 WMList
*lPtr
= (WMList
*)self
;
1025 static WMListItem
*oldItem
= NULL
;
1028 item
= WMGetListSelectedItem(lPtr
);
1034 if (oldItem
!= item
) {
1035 for (i
=0; i
<bPtr
->columnCount
; i
++) {
1036 if (lPtr
== bPtr
->columns
[i
])
1039 assert(i
<bPtr
->columnCount
);
1041 bPtr
->selectedColumn
= i
;
1043 /* columns at right must be cleared */
1044 removeColumn(bPtr
, i
+1);
1045 /* open directory */
1046 if (item
->isBranch
|| bPtr
->flags
.emptyCol
) {
1047 FSAddBrowserColumn(bPtr
);
1049 if(bPtr
->flags
.emptyCol
)
1051 if (bPtr
->usedColumnCount
< bPtr
->maxVisibleColumns
)
1054 if(!COLUMN_IS_VISIBLE(bPtr
, i
+1))
1056 scrollToColumn(bPtr
, bPtr
->firstVisibleColumn
+1, True
);
1060 scrollToColumn(bPtr
, bPtr
->firstVisibleColumn
, True
);
1063 loadColumn(bPtr
, bPtr
->usedColumnCount
-1);
1067 if (bPtr
->usedColumnCount
< bPtr
->maxVisibleColumns
)
1070 i
= bPtr
->usedColumnCount
-bPtr
->maxVisibleColumns
;
1072 scrollToColumn(bPtr
, i
, True
);
1075 loadColumn(bPtr
, bPtr
->usedColumnCount
-1);
1079 /* call callback for click */
1081 (*bPtr
->action
)(bPtr
, bPtr
->clientData
);
1091 listDoubleCallback(void *self
, void *clientData
)
1093 FSBrowser
*bPtr
= (FSBrowser
*)clientData
;
1094 WMList
*lPtr
= (WMList
*)self
;
1097 item
= WMGetListSelectedItem(lPtr
);
1101 /* call callback for double click */
1102 if (bPtr
->doubleAction
)
1103 (*bPtr
->doubleAction
)(bPtr
, bPtr
->doubleClientData
);
1108 FSLoadBrowserColumnZero(FSBrowser
*bPtr
)
1110 if (!bPtr
->flags
.loaded
) {
1111 /* create column 0 */
1112 FSAddBrowserColumn(bPtr
);
1114 loadColumn(bPtr
, 0);
1116 /* make column 0 visible */
1117 scrollToColumn(bPtr
, 0, True
);
1119 bPtr
->flags
.loaded
= 1;
1123 removeColumn(bPtr
, 0);
1124 FSAddBrowserColumn(bPtr
);
1126 loadColumn(bPtr
, 0);
1127 /* make column 0 visible */
1128 scrollToColumn(bPtr
, 0, True
);
1134 FSRemoveBrowserItem(FSBrowser
*bPtr
, int column
, int row
)
1138 if (column
< 0 || column
>= bPtr
->usedColumnCount
)
1141 list
= FSGetBrowserListInColumn(bPtr
, column
);
1143 if (row
< 0 || row
>= WMGetListNumberOfRows(list
))
1146 removeColumn(bPtr
, column
+1);
1147 if (bPtr
->usedColumnCount
< bPtr
->maxVisibleColumns
)
1148 scrollToColumn(bPtr
, 0, True
);
1150 scrollToColumn(bPtr
, bPtr
->usedColumnCount
-bPtr
->maxVisibleColumns
,
1153 WMRemoveListItem(list
, row
);
1158 listSelectionObserver(void *observerData
, WMNotification
*notification
)
1160 FSBrowser
*bPtr
= (FSBrowser
*)observerData
;
1161 int column
, item
= (int)WMGetNotificationClientData(notification
);
1162 WMList
*lPtr
= (WMList
*)WMGetNotificationObject(notification
);
1164 for (column
=0; column
<bPtr
->usedColumnCount
; column
++)
1165 if (bPtr
->columns
[column
] == lPtr
)
1168 /* this can happen when a list is being cleared with WMClearList
1169 * after the column was removed */
1170 if (column
>= bPtr
->usedColumnCount
) {
1177 bPtr
->selectedColumn
= column
;
1182 FSAddBrowserColumn(FSBrowser
*bPtr
)
1190 if (bPtr
->usedColumnCount
< bPtr
->columnCount
) {
1191 return bPtr
->usedColumnCount
++;
1194 bPtr
->usedColumnCount
++;
1196 if (bPtr
->flags
.isTitled
) {
1197 colY
= TITLE_SPACING
+ bPtr
->titleHeight
;
1202 index
= bPtr
->columnCount
;
1203 bPtr
->columnCount
++;
1204 clist
= wmalloc(sizeof(WMList
*)*bPtr
->columnCount
);
1205 tlist
= wmalloc(sizeof(char*)*bPtr
->columnCount
);
1206 memcpy(clist
, bPtr
->columns
, sizeof(WMList
*)*(bPtr
->columnCount
-1));
1207 memcpy(tlist
, bPtr
->titles
, sizeof(char*)*(bPtr
->columnCount
-1));
1209 free(bPtr
->columns
);
1212 bPtr
->columns
= clist
;
1213 bPtr
->titles
= tlist
;
1215 bPtr
->titles
[index
] = NULL
;
1217 list
= WMCreateList(bPtr
);
1218 WMSetListAction(list
, listCallback
, bPtr
);
1219 WMSetListDoubleAction(list
, listDoubleCallback
, bPtr
);
1220 WMSetListUserDrawProc(list
, paintItem
);
1221 WMAddNotificationObserver(listSelectionObserver
, bPtr
,
1222 WMListSelectionDidChangeNotification
, list
);
1224 bPtr
->columns
[index
] = list
;
1226 WMResizeWidget(list
, bPtr
->columnSize
.width
, bPtr
->columnSize
.height
);
1227 WMMoveWidget(list
, (bPtr
->columnSize
.width
+COLUMN_SPACING
)*index
, colY
);
1228 if (COLUMN_IS_VISIBLE(bPtr
, index
))
1231 /* update the scroller */
1232 if (bPtr
->columnCount
> bPtr
->maxVisibleColumns
)
1234 float value
, proportion
;
1236 value
= bPtr
->firstVisibleColumn
1237 /(float)(bPtr
->columnCount
-bPtr
->maxVisibleColumns
);
1238 proportion
= bPtr
->maxVisibleColumns
/(float)bPtr
->columnCount
;
1239 WMSetScrollerParameters(bPtr
->scroller
, value
, proportion
);
1248 destroyBrowser(FSBrowser
*bPtr
)
1252 for (i
=0; i
<bPtr
->columnCount
; i
++) {
1253 if (bPtr
->titles
[i
])
1254 free(bPtr
->titles
[i
]);
1258 free(bPtr
->pathSeparator
);
1260 WMRemoveNotificationObserver(bPtr
);
1267 createTruncatedString(WMFont
*font
, char *text
, int *textLen
, int width
)
1269 int dLen
= WMWidthOfString(font
, ".", 1);
1270 char *textBuf
= (char*)wmalloc((*textLen
)+4);
1272 if (width
>= 3*dLen
) {
1273 int dddLen
= 3*dLen
;
1274 int tmpTextLen
= *textLen
;
1276 strcpy(textBuf
, text
);
1278 && (WMWidthOfString(font
, textBuf
, tmpTextLen
)+dddLen
> width
))
1280 strcpy(textBuf
+tmpTextLen
, "...");
1281 *textLen
= tmpTextLen
+3;
1282 } else if (width
>= 2*dLen
) {
1283 strcpy(textBuf
, "..");
1285 } else if (width
>= dLen
) {
1286 strcpy(textBuf
, ".");
1296 FSScrollBrowserToColumn(FSBrowser
*bPtr
, int column
, Bool updateScroller
)
1298 scrollToColumn(bPtr
, column
, updateScroller
);
1301 void FSSetBrowserDisplayFileCol(FSBrowser
*bPtr
, unsigned int display
)
1303 bPtr
->flags
.emptyCol
= display
;