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 allowEmptySelection:1;
46
unsigned int hasScroller:1;
49
unsigned int loaded:1;
50
unsigned int loadingColumn:1;
55
#define COLUMN_SPACING 4
56
#define TITLE_SPACING 2
58
#define DEFAULT_WIDTH 305
59
#define DEFAULT_HEIGHT 200
60
#define DEFAULT_HAS_SCROLLER True
61
#define DEFAULT_TITLE_HEIGHT 20
62
#define DEFAULT_IS_TITLED True
63
#define DEFAULT_MAX_VISIBLE_COLUMNS 2
64
#define DEFAULT_SEPARATOR "/"
66
#define MIN_VISIBLE_COLUMNS 1
67
#define MAX_VISIBLE_COLUMNS 32
70
#define COLUMN_IS_VISIBLE(b, c) ((c) >= (b)->firstVisibleColumn \
71
&& (c) < (b)->firstVisibleColumn + (b)->maxVisibleColumns)
74
static void handleEvents(XEvent *event, void *data);
75
static void destroyBrowser(WMBrowser *bPtr);
77
static void setupScroller(WMBrowser *bPtr);
79
static void scrollToColumn(WMBrowser *bPtr, int column, Bool updateScroller);
81
static void paintItem(WMList *lPtr, int index, Drawable d, char *text,
82
int state, WMRect *rect);
84
static void loadColumn(WMBrowser *bPtr, int column);
86
static void removeColumn(WMBrowser *bPtr, int column);
88
static char* createTruncatedString(WMFont *font, char *text, int *textLen,
91
static void willResizeBrowser(W_ViewDelegate*, WMView*,
92
unsigned int*, unsigned int*);
94
W_ViewDelegate _BrowserViewDelegate = {
105
WMCreateBrowser(WMWidget *parent)
110
wassertrv(parent, NULL);
112
bPtr = wmalloc(sizeof(WMBrowser));
113
memset(bPtr, 0, sizeof(WMBrowser));
115
bPtr->widgetClass = WC_Browser;
117
bPtr->view = W_CreateView(W_VIEW(parent));
122
bPtr->view->self = bPtr;
124
bPtr->view->delegate = &_BrowserViewDelegate;
126
WMCreateEventHandler(bPtr->view, ExposureMask|StructureNotifyMask
127
|ClientMessageMask, handleEvents, bPtr);
129
/* default configuration */
130
bPtr->flags.hasScroller = DEFAULT_HAS_SCROLLER;
132
bPtr->titleHeight = DEFAULT_TITLE_HEIGHT;
133
bPtr->flags.isTitled = DEFAULT_IS_TITLED;
134
bPtr->maxVisibleColumns = DEFAULT_MAX_VISIBLE_COLUMNS;
136
WMResizeWidget(bPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT);
138
bPtr->pathSeparator = wstrdup(DEFAULT_SEPARATOR);
140
if (bPtr->flags.hasScroller)
143
for (i=0; i<bPtr->maxVisibleColumns; i++) {
144
WMAddBrowserColumn(bPtr);
146
bPtr->usedColumnCount = 0;
148
bPtr->selectedColumn = -1;
155
WMSetBrowserAllowMultipleSelection(WMBrowser *bPtr, Bool flag)
159
bPtr->flags.allowMultipleSelection = ((flag==0) ? 0 : 1);
160
for (i=0; i<bPtr->columnCount; i++) {
161
WMSetListAllowMultipleSelection(bPtr->columns[i], flag);
167
WMSetBrowserAllowEmptySelection(WMBrowser *bPtr, Bool flag)
171
bPtr->flags.allowEmptySelection = ((flag==0) ? 0 : 1);
172
for (i=0; i<bPtr->columnCount; i++) {
173
WMSetListAllowEmptySelection(bPtr->columns[i], flag);
179
WMGetBrowserMaxVisibleColumns(WMBrowser *bPtr)
181
return bPtr->maxVisibleColumns;
186
WMSetBrowserMaxVisibleColumns(WMBrowser *bPtr, int columns)
188
int curMaxVisibleColumns;
189
int newFirstVisibleColumn = 0;
193
columns = (columns < MIN_VISIBLE_COLUMNS) ? MIN_VISIBLE_COLUMNS : columns;
194
columns = (columns > MAX_VISIBLE_COLUMNS) ? MAX_VISIBLE_COLUMNS : columns;
195
if (columns == bPtr->maxVisibleColumns) {
198
curMaxVisibleColumns = bPtr->maxVisibleColumns;
199
bPtr->maxVisibleColumns = columns;
200
/* browser not loaded */
201
if (!bPtr->flags.loaded) {
202
if ((columns > curMaxVisibleColumns) && (columns > bPtr->columnCount)) {
203
int i = columns - bPtr->columnCount;
204
bPtr->usedColumnCount = bPtr->columnCount;
206
WMAddBrowserColumn(bPtr);
208
bPtr->usedColumnCount = 0;
210
/* browser loaded and columns > curMaxVisibleColumns */
211
} else if (columns > curMaxVisibleColumns) {
212
if (bPtr->usedColumnCount > columns) {
213
newFirstVisibleColumn = bPtr->usedColumnCount - columns;
215
if (newFirstVisibleColumn > bPtr->firstVisibleColumn) {
216
newFirstVisibleColumn = bPtr->firstVisibleColumn;
218
if (columns > bPtr->columnCount) {
219
int i = columns - bPtr->columnCount;
220
int curUsedColumnCount = bPtr->usedColumnCount;
221
bPtr->usedColumnCount = bPtr->columnCount;
223
WMAddBrowserColumn(bPtr);
225
bPtr->usedColumnCount = curUsedColumnCount;
227
/* browser loaded and columns < curMaxVisibleColumns */
229
newFirstVisibleColumn = bPtr->firstVisibleColumn;
230
if (newFirstVisibleColumn + columns >= bPtr->usedColumnCount) {
231
removeColumn(bPtr, newFirstVisibleColumn + columns);
234
WMResizeWidget(bPtr, bPtr->view->size.width, bPtr->view->size.height);
235
if (bPtr->flags.loaded) {
236
XClearArea(bPtr->view->screen->display, bPtr->view->window, 0, 0,
237
bPtr->view->size.width, bPtr->titleHeight, False);
238
scrollToColumn (bPtr, newFirstVisibleColumn, True);
244
WMGetBrowserNumberOfColumns(WMBrowser *bPtr)
246
return bPtr->usedColumnCount;
250
WMSetBrowserPathSeparator(WMBrowser *bPtr, char *separator)
252
if (bPtr->pathSeparator)
253
wfree(bPtr->pathSeparator);
254
bPtr->pathSeparator = wstrdup(separator);
260
drawTitleOfColumn(WMBrowser *bPtr, int column)
262
WMScreen *scr = bPtr->view->screen;
265
x=(column-bPtr->firstVisibleColumn)*(bPtr->columnSize.width+COLUMN_SPACING);
267
XFillRectangle(scr->display, bPtr->view->window, WMColorGC(scr->darkGray), x, 0,
268
bPtr->columnSize.width, bPtr->titleHeight);
269
W_DrawRelief(scr, bPtr->view->window, x, 0,
270
bPtr->columnSize.width, bPtr->titleHeight, WRSunken);
272
if (column < bPtr->usedColumnCount && bPtr->titles[column]) {
273
int titleLen = strlen(bPtr->titles[column]);
274
int widthC = bPtr->columnSize.width-8;
276
if (WMWidthOfString(scr->boldFont, bPtr->titles[column], titleLen)
278
char *titleBuf = createTruncatedString(scr->boldFont,
279
bPtr->titles[column],
281
W_PaintText(bPtr->view, bPtr->view->window, scr->boldFont, x,
282
(bPtr->titleHeight-WMFontHeight(scr->boldFont))/2,
283
bPtr->columnSize.width, WACenter, scr->white,
284
False, titleBuf, titleLen);
287
W_PaintText(bPtr->view, bPtr->view->window, scr->boldFont, x,
288
(bPtr->titleHeight-WMFontHeight(scr->boldFont))/2,
289
bPtr->columnSize.width, WACenter, scr->white,
290
False, bPtr->titles[column], titleLen);
297
WMGetBrowserListInColumn(WMBrowser *bPtr, int column)
299
if (column < 0 || column >= bPtr->usedColumnCount)
302
return bPtr->columns[column];
307
WMSetBrowserDelegate(WMBrowser *bPtr, WMBrowserDelegate *delegate)
309
bPtr->delegate = delegate;
314
WMGetBrowserFirstVisibleColumn(WMBrowser *bPtr)
316
return bPtr->firstVisibleColumn;
321
removeColumn(WMBrowser *bPtr, int column)
323
int i, clearEnd, destroyEnd;
329
column = (column < 0) ? 0 : column;
330
if (column >= bPtr->columnCount) {
333
if (column < bPtr->maxVisibleColumns) {
334
clearEnd = bPtr->maxVisibleColumns;
335
destroyEnd = bPtr->columnCount;
336
bPtr->columnCount = bPtr->maxVisibleColumns;
339
destroyEnd = bPtr->columnCount;
340
bPtr->columnCount = column;
342
if (column < bPtr->usedColumnCount) {
343
bPtr->usedColumnCount = column;
345
for (i=column; i < clearEnd; i++) {
346
if (bPtr->titles[i]) {
347
wfree(bPtr->titles[i]);
348
bPtr->titles[i] = NULL;
350
WMClearList(bPtr->columns[i]);
352
for (;i < destroyEnd; i++) {
353
if (bPtr->titles[i]) {
354
wfree(bPtr->titles[i]);
355
bPtr->titles[i] = NULL;
357
WMRemoveNotificationObserverWithName(bPtr,
358
WMListSelectionDidChangeNotification,
360
WMDestroyWidget(bPtr->columns[i]);
361
bPtr->columns[i] = NULL;
363
clist = wmalloc(sizeof(WMList*) * (bPtr->columnCount));
364
tlist = wmalloc(sizeof(char*) * (bPtr->columnCount));
365
memcpy(clist, bPtr->columns, sizeof(WMList*) * (bPtr->columnCount));
366
memcpy(tlist, bPtr->titles, sizeof(char*) * (bPtr->columnCount));
368
wfree(bPtr->columns);
369
bPtr->titles = tlist;
370
bPtr->columns = clist;
375
WMGetBrowserSelectedItemInColumn(WMBrowser *bPtr, int column)
377
if ((column < 0) || (column >= bPtr->usedColumnCount))
380
return WMGetListSelectedItem(bPtr->columns[column]);
386
WMGetBrowserSelectedColumn(WMBrowser *bPtr)
388
return bPtr->selectedColumn;
393
WMGetBrowserSelectedRowInColumn(WMBrowser *bPtr, int column)
395
if (column >= 0 && column < bPtr->columnCount) {
396
return WMGetListSelectedItemRow(bPtr->columns[column]);
404
WMSetBrowserColumnTitle(WMBrowser *bPtr, int column, char *title)
407
assert(column < bPtr->usedColumnCount);
409
if (bPtr->titles[column])
410
wfree(bPtr->titles[column]);
412
bPtr->titles[column] = wstrdup(title);
414
if (COLUMN_IS_VISIBLE(bPtr, column) && bPtr->flags.isTitled) {
415
drawTitleOfColumn(bPtr, column);
421
WMSetBrowserTitled(WMBrowser *bPtr, Bool flag)
424
int columnX, columnY;
426
flag = ((flag==0) ? 0 : 1);
428
if (bPtr->flags.isTitled == flag)
433
if (!bPtr->flags.isTitled) {
434
columnY = TITLE_SPACING + bPtr->titleHeight;
436
bPtr->columnSize.height -= columnY;
438
for (i=0; i<bPtr->columnCount; i++) {
439
WMResizeWidget(bPtr->columns[i], bPtr->columnSize.width,
440
bPtr->columnSize.height);
442
columnX = WMWidgetView(bPtr->columns[i])->pos.x;
444
WMMoveWidget(bPtr->columns[i], columnX, columnY);
447
bPtr->columnSize.height += TITLE_SPACING + bPtr->titleHeight;
449
for (i=0; i<bPtr->columnCount; i++) {
450
WMResizeWidget(bPtr->columns[i], bPtr->columnSize.width,
451
bPtr->columnSize.height);
453
columnX = WMWidgetView(bPtr->columns[i])->pos.x;
455
WMMoveWidget(bPtr->columns[i], columnX, 0);
459
bPtr->flags.isTitled = flag;
464
WMSortBrowserColumn(WMBrowser *bPtr, int column)
466
WMSortListItems(bPtr->columns[column]);
471
WMSortBrowserColumnWithComparer(WMBrowser *bPtr, int column,
472
WMCompareDataProc *func)
474
WMSortListItemsWithComparer(bPtr->columns[column], func);
480
WMInsertBrowserItem(WMBrowser *bPtr, int column, int row, char *text,
485
if (column < 0 || column >= bPtr->columnCount)
488
item = WMInsertListItem(bPtr->columns[column], row, text);
489
item->isBranch = isBranch;
498
willResizeBrowser(W_ViewDelegate *self, WMView *view,
499
unsigned int *width, unsigned int *height)
501
WMBrowser *bPtr = (WMBrowser*)view->self;
502
int cols = bPtr->maxVisibleColumns;
509
bPtr->columnSize.width = (*width-(cols-1)*COLUMN_SPACING) / cols;
510
bPtr->columnSize.height = *height;
512
if (bPtr->flags.isTitled) {
513
colY = TITLE_SPACING + bPtr->titleHeight;
514
bPtr->columnSize.height -= colY;
519
if (bPtr->flags.hasScroller) {
520
bPtr->columnSize.height -= SCROLLER_WIDTH + 4;
522
if (bPtr->scroller) {
523
WMResizeWidget(bPtr->scroller, *width-2, 1);
524
WMMoveWidget(bPtr->scroller, 1, *height-SCROLLER_WIDTH-1);
529
for (i = 0; i < bPtr->columnCount; i++) {
530
WMResizeWidget(bPtr->columns[i], bPtr->columnSize.width,
531
bPtr->columnSize.height);
533
WMMoveWidget(bPtr->columns[i], colX, colY);
535
if (COLUMN_IS_VISIBLE(bPtr, i)) {
536
colX += bPtr->columnSize.width+COLUMN_SPACING;
543
paintItem(WMList *lPtr, int index, Drawable d, char *text, int state, WMRect *rect)
545
WMView *view = W_VIEW(lPtr);
546
W_Screen *scr = view->screen;
547
Display *display = scr->display;
548
WMFont *font = ((state & WLDSIsBranch) ? scr->boldFont : scr->normalFont);
549
WMColor *backColor = ((state & WLDSSelected) ? scr->white : view->backColor);
550
int width, height, x, y, textLen;
552
width = rect->size.width;
553
height = rect->size.height;
556
textLen = strlen(text);
558
XFillRectangle(display, d, WMColorGC(backColor), x, y, width, height);
561
/* Avoid overlaping... */
562
int widthC = (state & WLDSIsBranch) ? width-20 : width-8;
563
if (WMWidthOfString(font, text, textLen) > widthC) {
564
char *textBuf = createTruncatedString(font, text, &textLen, widthC);
565
W_PaintText(view, d, font, x+4, y, widthC,
566
WALeft, scr->black, False, textBuf, textLen);
569
W_PaintText(view, d, font, x+4, y, widthC,
570
WALeft, scr->black, False, text, textLen);
574
if (state & WLDSIsBranch) {
575
WMColor *lineColor = ((state & WLDSSelected) ? scr->gray : scr->white);
577
XDrawLine(display, d, WMColorGC(scr->darkGray), x+width-11, y+3,
578
x+width-6, y+height/2);
579
XDrawLine(display, d, WMColorGC(lineColor), x+width-11, y+height-5,
580
x+width-6, y+height/2);
581
XDrawLine(display, d, WMColorGC(scr->black), x+width-12, y+3,
582
x+width-12, y+height-5);
588
scrollCallback(WMWidget *scroller, void *self)
590
WMBrowser *bPtr = (WMBrowser*)self;
591
WMScroller *sPtr = (WMScroller*)scroller;
593
#define LAST_VISIBLE_COLUMN bPtr->firstVisibleColumn+bPtr->maxVisibleColumns
595
switch (WMGetScrollerHitPart(sPtr)) {
596
case WSDecrementLine:
597
if (bPtr->firstVisibleColumn > 0) {
598
scrollToColumn(bPtr, bPtr->firstVisibleColumn-1, True);
602
case WSDecrementPage:
603
case WSDecrementWheel:
604
if (bPtr->firstVisibleColumn > 0) {
605
newFirst = bPtr->firstVisibleColumn - bPtr->maxVisibleColumns;
607
scrollToColumn(bPtr, newFirst, True);
612
case WSIncrementLine:
613
if (LAST_VISIBLE_COLUMN < bPtr->usedColumnCount) {
614
scrollToColumn(bPtr, bPtr->firstVisibleColumn+1, True);
618
case WSIncrementPage:
619
case WSIncrementWheel:
620
if (LAST_VISIBLE_COLUMN < bPtr->usedColumnCount) {
621
newFirst = bPtr->firstVisibleColumn + bPtr->maxVisibleColumns;
623
if (newFirst+bPtr->maxVisibleColumns >= bPtr->columnCount)
624
newFirst = bPtr->columnCount - bPtr->maxVisibleColumns;
626
scrollToColumn(bPtr, newFirst, True);
633
double value = bPtr->columnCount - bPtr->maxVisibleColumns;
635
floatValue = WMGetScrollerValue(bPtr->scroller);
637
floatValue = (floatValue*value)/value;
639
newFirst = rint(floatValue*(float)(bPtr->columnCount - bPtr->maxVisibleColumns));
641
if (bPtr->firstVisibleColumn != newFirst)
642
scrollToColumn(bPtr, newFirst, False);
644
WMSetScrollerParameters(bPtr->scroller, floatValue,
645
bPtr->maxVisibleColumns/(float)bPtr->columnCount);
656
#undef LAST_VISIBLE_COLUMN
661
setupScroller(WMBrowser *bPtr)
666
y = bPtr->view->size.height - SCROLLER_WIDTH - 1;
668
sPtr = WMCreateScroller(bPtr);
669
WMSetScrollerAction(sPtr, scrollCallback, bPtr);
670
WMMoveWidget(sPtr, 1, y);
671
WMResizeWidget(sPtr, bPtr->view->size.width-2, SCROLLER_WIDTH);
673
bPtr->scroller = sPtr;
680
WMSetBrowserAction(WMBrowser *bPtr, WMAction *action, void *clientData)
682
bPtr->action = action;
683
bPtr->clientData = clientData;
688
WMSetBrowserDoubleAction(WMBrowser *bPtr, WMAction *action, void *clientData)
690
bPtr->doubleAction = action;
691
bPtr->doubleClientData = clientData;
696
WMSetBrowserHasScroller(WMBrowser *bPtr, int hasScroller)
698
bPtr->flags.hasScroller = hasScroller;
703
WMSetBrowserPath(WMBrowser *bPtr, char *path)
707
char *tmp, *retPtr = NULL;
709
WMListItem *listItem;
711
/* WMLoadBrowserColumnZero must be call first */
712
if (!bPtr->flags.loaded) {
716
removeColumn(bPtr, 1);
718
WMSelectListItem(bPtr->columns[0], -1);
719
WMSetListPosition(bPtr->columns[0], 0);
723
tmp = strtok(str, bPtr->pathSeparator);
725
/* select it in the column */
726
item = WMFindRowOfListItemWithTitle(bPtr->columns[i], tmp);
728
retPtr = &path[(int)(tmp - str)];
731
WMSelectListItem(bPtr->columns[i], item);
732
WMSetListPosition(bPtr->columns[i], item);
734
listItem = WMGetListItem(bPtr->columns[i], item);
735
if (!listItem || !listItem->isBranch) {
739
/* load next column */
740
WMAddBrowserColumn(bPtr);
742
loadColumn(bPtr, i+1);
744
tmp = strtok(NULL, bPtr->pathSeparator);
751
for (i = bPtr->usedColumnCount - 1;
752
(i > -1) && !WMGetListSelectedItem(bPtr->columns[i]);
755
bPtr->selectedColumn = i;
757
if (bPtr->columnCount < bPtr->maxVisibleColumns) {
758
int i = bPtr->maxVisibleColumns - bPtr->columnCount;
759
int curUsedColumnCount = bPtr->usedColumnCount;
760
bPtr->usedColumnCount = bPtr->columnCount;
762
WMAddBrowserColumn(bPtr);
764
bPtr->usedColumnCount = curUsedColumnCount;
767
scrollToColumn(bPtr, bPtr->columnCount - bPtr->maxVisibleColumns, True);
774
WMGetBrowserPath(WMBrowser *bPtr)
776
return WMGetBrowserPathToColumn(bPtr, bPtr->columnCount);
781
WMGetBrowserPathToColumn(WMBrowser *bPtr, int column)
787
if (column >= bPtr->usedColumnCount)
788
column = bPtr->usedColumnCount-1;
791
return wstrdup(bPtr->pathSeparator);
794
/* calculate size of buffer */
796
for (i = 0; i <= column; i++) {
797
item = WMGetListSelectedItem(bPtr->columns[i]);
800
size += strlen(item->text);
804
path = wmalloc(size+(column+1)*strlen(bPtr->pathSeparator)+1);
807
for (i = 0; i <= column; i++) {
808
strcat(path, bPtr->pathSeparator);
809
item = WMGetListSelectedItem(bPtr->columns[i]);
812
strcat(path, item->text);
820
WMGetBrowserPaths(WMBrowser *bPtr)
822
int column, i, k, size, selNo;
824
WMListItem *item, *lastItem;
825
WMArray *paths, *items;
827
column = bPtr->usedColumnCount-1;
830
paths = WMCreateArrayWithDestructor(1, wfree);
831
WMAddToArray(paths, wstrdup(bPtr->pathSeparator));
835
items = WMGetListSelectedItems(bPtr->columns[column]);
836
selNo = WMGetArrayItemCount(items);
837
paths = WMCreateArrayWithDestructor(selNo, wfree);
840
WMAddToArray(paths, WMGetBrowserPath(bPtr));
844
/* calculate size of buffer */
846
for (i=0; i<column; i++) {
847
item = WMGetListSelectedItem(bPtr->columns[i]);
850
size += strlen(item->text);
853
size += (column+1)*strlen(bPtr->pathSeparator)+1;
855
for (k=0; k<selNo; k++) {
857
lastItem = WMGetFromArray(items, k);
858
path = wmalloc(size + (lastItem!=NULL ? strlen(lastItem->text) : 0));
861
for (i=0; i<=column; i++) {
862
strcat(path, bPtr->pathSeparator);
866
item = WMGetListSelectedItem(bPtr->columns[i]);
870
strcat(path, item->text);
872
WMAddToArray(paths, path);
880
WMBrowserAllowsMultipleSelection(WMBrowser *bPtr)
882
return bPtr->flags.allowMultipleSelection;
887
WMBrowserAllowsEmptySelection(WMBrowser *bPtr)
889
return bPtr->flags.allowEmptySelection;
894
loadColumn(WMBrowser *bPtr, int column)
896
assert(bPtr->delegate);
897
assert(bPtr->delegate->createRowsForColumn);
899
bPtr->flags.loadingColumn = 1;
900
(*bPtr->delegate->createRowsForColumn)(bPtr->delegate, bPtr, column,
901
bPtr->columns[column]);
902
bPtr->flags.loadingColumn = 0;
904
if (bPtr->delegate->titleOfColumn) {
907
title = (*bPtr->delegate->titleOfColumn)(bPtr->delegate, bPtr, column);
909
if (bPtr->titles[column])
910
wfree(bPtr->titles[column]);
912
bPtr->titles[column] = wstrdup(title);
914
if (COLUMN_IS_VISIBLE(bPtr, column) && bPtr->flags.isTitled) {
915
drawTitleOfColumn(bPtr, column);
922
paintBrowser(WMBrowser *bPtr)
926
if (!bPtr->view->flags.mapped)
929
W_DrawRelief(bPtr->view->screen, bPtr->view->window, 0,
930
bPtr->view->size.height-SCROLLER_WIDTH-2,
931
bPtr->view->size.width, 22, WRSunken);
933
if (bPtr->flags.isTitled) {
934
for (i=0; i<bPtr->maxVisibleColumns; i++) {
935
drawTitleOfColumn(bPtr, i+bPtr->firstVisibleColumn);
942
handleEvents(XEvent *event, void *data)
944
WMBrowser *bPtr = (WMBrowser*)data;
946
CHECK_CLASS(data, WC_Browser);
949
switch (event->type) {
955
destroyBrowser(bPtr);
964
scrollToColumn(WMBrowser *bPtr, int column, Bool updateScroller)
971
if (column != bPtr->firstVisibleColumn) {
978
if (notify && bPtr->delegate && bPtr->delegate->willScroll) {
979
(*bPtr->delegate->willScroll)(bPtr->delegate, bPtr);
983
bPtr->firstVisibleColumn = column;
984
for (i = 0; i < bPtr->columnCount; i++) {
985
if (COLUMN_IS_VISIBLE(bPtr, i)) {
986
WMMoveWidget(bPtr->columns[i], x,
987
WMWidgetView(bPtr->columns[i])->pos.y);
988
if (!WMWidgetView(bPtr->columns[i])->flags.realized)
989
WMRealizeWidget(bPtr->columns[i]);
990
WMMapWidget(bPtr->columns[i]);
991
x += bPtr->columnSize.width + COLUMN_SPACING;
993
WMUnmapWidget(bPtr->columns[i]);
997
/* update the scroller */
998
if (updateScroller) {
999
if (bPtr->columnCount > bPtr->maxVisibleColumns) {
1000
float value, proportion;
1002
value = bPtr->firstVisibleColumn
1003
/(float)(bPtr->columnCount-bPtr->maxVisibleColumns);
1004
proportion = bPtr->maxVisibleColumns/(float)bPtr->columnCount;
1005
WMSetScrollerParameters(bPtr->scroller, value, proportion);
1007
WMSetScrollerParameters(bPtr->scroller, 0, 1);
1011
if (bPtr->view->flags.mapped)
1014
if (notify && bPtr->delegate && bPtr->delegate->didScroll) {
1015
(*bPtr->delegate->didScroll)(bPtr->delegate, bPtr);
1021
listCallback(void *self, void *clientData)
1023
WMBrowser *bPtr = (WMBrowser*)clientData;
1024
WMList *lPtr = (WMList*)self;
1027
static WMListItem *oldItem = NULL;
1028
static int oldSelNo = 0;
1030
item = WMGetListSelectedItem(lPtr);
1031
selNo = WMGetArrayItemCount(WMGetListSelectedItems(lPtr));
1033
if (oldItem==NULL || oldItem!=item || oldSelNo!=selNo) {
1034
for (i=0; i<bPtr->columnCount; i++) {
1035
if (lPtr == bPtr->columns[i])
1038
assert(i<bPtr->columnCount);
1040
bPtr->selectedColumn = i;
1042
/* columns at right must be cleared */
1043
removeColumn(bPtr, i+1);
1044
/* open directory */
1045
if (item && item->isBranch && selNo==1) {
1046
WMAddBrowserColumn(bPtr);
1048
if (bPtr->usedColumnCount < bPtr->maxVisibleColumns)
1051
i = bPtr->usedColumnCount-bPtr->maxVisibleColumns;
1052
scrollToColumn(bPtr, i, True);
1053
if (item && item->isBranch && selNo==1) {
1054
loadColumn(bPtr, bPtr->usedColumnCount-1);
1058
/* call callback for click */
1060
(*bPtr->action)(bPtr, bPtr->clientData);
1068
listDoubleCallback(void *self, void *clientData)
1070
WMBrowser *bPtr = (WMBrowser*)clientData;
1071
WMList *lPtr = (WMList*)self;
1074
item = WMGetListSelectedItem(lPtr);
1078
/* call callback for double click */
1079
if (bPtr->doubleAction)
1080
(*bPtr->doubleAction)(bPtr, bPtr->doubleClientData);
1085
WMLoadBrowserColumnZero(WMBrowser *bPtr)
1087
if (!bPtr->flags.loaded) {
1088
/* create column 0 */
1089
WMAddBrowserColumn(bPtr);
1091
loadColumn(bPtr, 0);
1093
/* make column 0 visible */
1094
scrollToColumn(bPtr, 0, True);
1096
bPtr->flags.loaded = 1;
1102
WMRemoveBrowserItem(WMBrowser *bPtr, int column, int row)
1106
if (column < 0 || column >= bPtr->usedColumnCount)
1109
list = WMGetBrowserListInColumn(bPtr, column);
1111
if (row < 0 || row >= WMGetListNumberOfRows(list))
1114
removeColumn(bPtr, column+1);
1115
if (bPtr->usedColumnCount < bPtr->maxVisibleColumns)
1116
scrollToColumn(bPtr, 0, True);
1118
scrollToColumn(bPtr, bPtr->usedColumnCount-bPtr->maxVisibleColumns,
1121
WMRemoveListItem(list, row);
1126
listSelectionObserver(void *observerData, WMNotification *notification)
1128
WMBrowser *bPtr = (WMBrowser*)observerData;
1130
WMList *lPtr = (WMList*)WMGetNotificationObject(notification);
1132
for (column = 0; column < bPtr->usedColumnCount; column++)
1133
if (bPtr->columns[column] == lPtr)
1136
/* this can happen when a list is being cleared with WMClearList
1137
* after the column was removed */
1138
if (column >= bPtr->usedColumnCount) {
1142
if (WMGetArrayItemCount(WMGetListSelectedItems(lPtr)) == 0)
1145
bPtr->selectedColumn = column;
1150
WMAddBrowserColumn(WMBrowser *bPtr)
1159
if (bPtr->usedColumnCount < bPtr->columnCount) {
1160
return bPtr->usedColumnCount++;
1163
bPtr->usedColumnCount++;
1165
if (bPtr->flags.isTitled) {
1166
colY = TITLE_SPACING + bPtr->titleHeight;
1171
index = bPtr->columnCount;
1172
bPtr->columnCount++;
1173
clist = wmalloc(sizeof(WMList*)*bPtr->columnCount);
1174
tlist = wmalloc(sizeof(char*)*bPtr->columnCount);
1175
memcpy(clist, bPtr->columns, sizeof(WMList*)*(bPtr->columnCount-1));
1176
memcpy(tlist, bPtr->titles, sizeof(char*)*(bPtr->columnCount-1));
1178
wfree(bPtr->columns);
1180
wfree(bPtr->titles);
1181
bPtr->columns = clist;
1182
bPtr->titles = tlist;
1184
bPtr->titles[index] = NULL;
1186
list = WMCreateList(bPtr);
1187
WMSetListAllowMultipleSelection(list, bPtr->flags.allowMultipleSelection);
1188
WMSetListAllowEmptySelection(list, bPtr->flags.allowEmptySelection);
1189
WMSetListAction(list, listCallback, bPtr);
1190
WMSetListDoubleAction(list, listDoubleCallback, bPtr);
1191
WMSetListUserDrawProc(list, paintItem);
1192
WMAddNotificationObserver(listSelectionObserver, bPtr,
1193
WMListSelectionDidChangeNotification, list);
1195
bPtr->columns[index] = list;
1197
WMResizeWidget(list, bPtr->columnSize.width, bPtr->columnSize.height);
1198
WMMoveWidget(list, (bPtr->columnSize.width+COLUMN_SPACING)*index, colY);
1199
if (COLUMN_IS_VISIBLE(bPtr, index))
1202
/* update the scroller */
1203
if (bPtr->columnCount > bPtr->maxVisibleColumns) {
1204
float value, proportion;
1206
value = bPtr->firstVisibleColumn
1207
/(float)(bPtr->columnCount-bPtr->maxVisibleColumns);
1208
proportion = bPtr->maxVisibleColumns/(float)bPtr->columnCount;
1209
WMSetScrollerParameters(bPtr->scroller, value, proportion);
1218
destroyBrowser(WMBrowser *bPtr)
1222
for (i = 0; i < bPtr->columnCount; i++) {
1223
if (bPtr->titles[i])
1224
wfree(bPtr->titles[i]);
1226
wfree(bPtr->titles);
1228
wfree(bPtr->pathSeparator);
1230
WMRemoveNotificationObserver(bPtr);
1237
createTruncatedString(WMFont *font, char *text, int *textLen, int width)
1239
int dLen = WMWidthOfString(font, ".", 1);
1240
char *textBuf = (char*)wmalloc((*textLen)+4);
1242
if (width >= 3*dLen) {
1243
int dddLen = 3*dLen;
1244
int tmpTextLen = *textLen;
1246
strcpy(textBuf, text);
1248
&& (WMWidthOfString(font, textBuf, tmpTextLen)+dddLen > width))
1250
strcpy(textBuf+tmpTextLen, "...");
1251
*textLen = tmpTextLen+3;
1252
} else if (width >= 2*dLen) {
1253
strcpy(textBuf, "..");
1255
} else if (width >= dLen) {
1256
strcpy(textBuf, ".");