Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / wbrowser.c
Commit [+]AuthorDateLineData
9d2e6ef9 scottc1998-09-29 22:36:29 +00001
9d2e6ef9 scottc1998-09-29 22:36:29 +00002#include "WINGsP.h"
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02003#include <math.h> /* for : double rint (double) */
9d2e6ef9 scottc1998-09-29 22:36:29 +00004
5typedef struct W_Browser {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02006 W_Class widgetClass;
7 W_View *view;
9d2e6ef9 scottc1998-09-29 22:36:29 +00008
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02009 char **titles;
10 WMList **columns;
64fcfedd dan1999-05-16 12:40:47 +000011
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020012 short columnCount;
13 short usedColumnCount; /* columns actually being used */
14 short minColumnWidth;
9d2e6ef9 scottc1998-09-29 22:36:29 +000015
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020016 short maxVisibleColumns;
17 short firstVisibleColumn;
64fcfedd dan1999-05-16 12:40:47 +000018
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020019 short titleHeight;
9d2e6ef9 scottc1998-09-29 22:36:29 +000020
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020021 short selectedColumn;
64fcfedd dan1999-05-16 12:40:47 +000022
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020023 WMSize columnSize;
9d2e6ef9 scottc1998-09-29 22:36:29 +000024
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020025 void *clientData;
26 WMAction *action;
27 void *doubleClientData;
28 WMAction *doubleAction;
9d2e6ef9 scottc1998-09-29 22:36:29 +000029
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020030 WMBrowserDelegate *delegate;
64fcfedd dan1999-05-16 12:40:47 +000031
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020032 WMScroller *scroller;
9d2e6ef9 scottc1998-09-29 22:36:29 +000033
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020034 char *pathSeparator;
64fcfedd dan1999-05-16 12:40:47 +000035
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020036 struct {
37 unsigned int isTitled:1;
38 unsigned int allowMultipleSelection:1;
39 unsigned int allowEmptySelection:1;
40 unsigned int hasScroller:1;
64fcfedd dan1999-05-16 12:40:47 +000041
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020042 /* */
43 unsigned int loaded:1;
44 unsigned int loadingColumn:1;
45 } flags;
9d2e6ef9 scottc1998-09-29 22:36:29 +000046} Browser;
47
9d2e6ef9 scottc1998-09-29 22:36:29 +000048#define COLUMN_SPACING 4
49#define TITLE_SPACING 2
50
e7495baf dan1999-02-17 11:06:40 +000051#define DEFAULT_WIDTH 305
52#define DEFAULT_HEIGHT 200
53#define DEFAULT_HAS_SCROLLER True
54#define DEFAULT_TITLE_HEIGHT 20
55#define DEFAULT_IS_TITLED True
56#define DEFAULT_MAX_VISIBLE_COLUMNS 2
57#define DEFAULT_SEPARATOR "/"
58
59#define MIN_VISIBLE_COLUMNS 1
60#define MAX_VISIBLE_COLUMNS 32
9d2e6ef9 scottc1998-09-29 22:36:29 +000061
9d2e6ef9 scottc1998-09-29 22:36:29 +000062#define COLUMN_IS_VISIBLE(b, c) ((c) >= (b)->firstVisibleColumn \
6830b057 dan2004-10-12 21:28:27 +000063 && (c) < (b)->firstVisibleColumn + (b)->maxVisibleColumns)
9d2e6ef9 scottc1998-09-29 22:36:29 +000064
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020065static void handleEvents(XEvent * event, void *data);
66static void destroyBrowser(WMBrowser * bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +000067
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020068static void setupScroller(WMBrowser * bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +000069
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020070static void scrollToColumn(WMBrowser * bPtr, int column, Bool updateScroller);
9d2e6ef9 scottc1998-09-29 22:36:29 +000071
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020072static void paintItem(WMList * lPtr, int index, Drawable d, char *text, int state, WMRect * rect);
9d2e6ef9 scottc1998-09-29 22:36:29 +000073
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020074static void loadColumn(WMBrowser * bPtr, int column);
9d2e6ef9 scottc1998-09-29 22:36:29 +000075
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020076static void removeColumn(WMBrowser * bPtr, int column);
e7495baf dan1999-02-17 11:06:40 +000077
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020078static char *createTruncatedString(WMFont * font, char *text, int *textLen, int width);
9d2e6ef9 scottc1998-09-29 22:36:29 +000079
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020080static void willResizeBrowser(W_ViewDelegate *, WMView *, unsigned int *, unsigned int *);
9d2e6ef9 scottc1998-09-29 22:36:29 +000081
5e4625da kojima1999-05-29 21:41:25 +000082W_ViewDelegate _BrowserViewDelegate = {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020083 NULL,
84 NULL,
85 NULL,
86 NULL,
87 willResizeBrowser
9d2e6ef9 scottc1998-09-29 22:36:29 +000088};
89
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020090WMBrowser *WMCreateBrowser(WMWidget * parent)
9d2e6ef9 scottc1998-09-29 22:36:29 +000091{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020092 WMBrowser *bPtr;
93 int i;
9d2e6ef9 scottc1998-09-29 22:36:29 +000094
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020095 wassertrv(parent, NULL);
e7495baf dan1999-02-17 11:06:40 +000096
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020097 bPtr = wmalloc(sizeof(WMBrowser));
98 memset(bPtr, 0, sizeof(WMBrowser));
9d2e6ef9 scottc1998-09-29 22:36:29 +000099
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200100 bPtr->widgetClass = WC_Browser;
64fcfedd dan1999-05-16 12:40:47 +0000101
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200102 bPtr->view = W_CreateView(W_VIEW(parent));
103 if (!bPtr->view) {
104 wfree(bPtr);
105 return NULL;
106 }
107 bPtr->view->self = bPtr;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000108
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200109 bPtr->view->delegate = &_BrowserViewDelegate;
5e4625da kojima1999-05-29 21:41:25 +0000110
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200111 WMCreateEventHandler(bPtr->view, ExposureMask | StructureNotifyMask
112 | ClientMessageMask, handleEvents, bPtr);
64fcfedd dan1999-05-16 12:40:47 +0000113
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200114 /* default configuration */
115 bPtr->flags.hasScroller = DEFAULT_HAS_SCROLLER;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000116
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200117 bPtr->titleHeight = DEFAULT_TITLE_HEIGHT;
118 bPtr->flags.isTitled = DEFAULT_IS_TITLED;
119 bPtr->maxVisibleColumns = DEFAULT_MAX_VISIBLE_COLUMNS;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000120
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200121 WMResizeWidget(bPtr, DEFAULT_WIDTH, DEFAULT_HEIGHT);
64fcfedd dan1999-05-16 12:40:47 +0000122
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200123 bPtr->pathSeparator = wstrdup(DEFAULT_SEPARATOR);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000124
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200125 if (bPtr->flags.hasScroller)
126 setupScroller(bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000127
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200128 for (i = 0; i < bPtr->maxVisibleColumns; i++) {
129 WMAddBrowserColumn(bPtr);
130 }
131 bPtr->usedColumnCount = 0;
64fcfedd dan1999-05-16 12:40:47 +0000132
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200133 bPtr->selectedColumn = -1;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000134
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200135 return bPtr;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000136}
137
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200138void WMSetBrowserAllowMultipleSelection(WMBrowser * bPtr, Bool flag)
de991559 dan2000-10-02 06:59:18 +0000139{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200140 int i;
de991559 dan2000-10-02 06:59:18 +0000141
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200142 bPtr->flags.allowMultipleSelection = ((flag == 0) ? 0 : 1);
143 for (i = 0; i < bPtr->columnCount; i++) {
144 WMSetListAllowMultipleSelection(bPtr->columns[i], flag);
145 }
de991559 dan2000-10-02 06:59:18 +0000146}
147
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200148void WMSetBrowserAllowEmptySelection(WMBrowser * bPtr, Bool flag)
de991559 dan2000-10-02 06:59:18 +0000149{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200150 int i;
de991559 dan2000-10-02 06:59:18 +0000151
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200152 bPtr->flags.allowEmptySelection = ((flag == 0) ? 0 : 1);
153 for (i = 0; i < bPtr->columnCount; i++) {
154 WMSetListAllowEmptySelection(bPtr->columns[i], flag);
155 }
de991559 dan2000-10-02 06:59:18 +0000156}
157
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200158int WMGetBrowserMaxVisibleColumns(WMBrowser * bPtr)
4a473b8a kojima1999-04-10 18:27:21 +0000159{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200160 return bPtr->maxVisibleColumns;
4a473b8a kojima1999-04-10 18:27:21 +0000161}
162
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200163void WMSetBrowserMaxVisibleColumns(WMBrowser * bPtr, int columns)
345d980b dan1998-11-27 12:26:46 +0000164{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200165 int curMaxVisibleColumns;
166 int newFirstVisibleColumn = 0;
167
168 assert(bPtr != NULL);
169
170 columns = (columns < MIN_VISIBLE_COLUMNS) ? MIN_VISIBLE_COLUMNS : columns;
171 columns = (columns > MAX_VISIBLE_COLUMNS) ? MAX_VISIBLE_COLUMNS : columns;
172 if (columns == bPtr->maxVisibleColumns) {
173 return;
174 }
175 curMaxVisibleColumns = bPtr->maxVisibleColumns;
176 bPtr->maxVisibleColumns = columns;
177 /* browser not loaded */
178 if (!bPtr->flags.loaded) {
179 if ((columns > curMaxVisibleColumns) && (columns > bPtr->columnCount)) {
180 int i = columns - bPtr->columnCount;
181 bPtr->usedColumnCount = bPtr->columnCount;
182 while (i--) {
183 WMAddBrowserColumn(bPtr);
184 }
185 bPtr->usedColumnCount = 0;
186 }
187 /* browser loaded and columns > curMaxVisibleColumns */
188 } else if (columns > curMaxVisibleColumns) {
189 if (bPtr->usedColumnCount > columns) {
190 newFirstVisibleColumn = bPtr->usedColumnCount - columns;
191 }
192 if (newFirstVisibleColumn > bPtr->firstVisibleColumn) {
193 newFirstVisibleColumn = bPtr->firstVisibleColumn;
194 }
195 if (columns > bPtr->columnCount) {
196 int i = columns - bPtr->columnCount;
197 int curUsedColumnCount = bPtr->usedColumnCount;
198 bPtr->usedColumnCount = bPtr->columnCount;
199 while (i--) {
200 WMAddBrowserColumn(bPtr);
201 }
202 bPtr->usedColumnCount = curUsedColumnCount;
203 }
204 /* browser loaded and columns < curMaxVisibleColumns */
205 } else {
206 newFirstVisibleColumn = bPtr->firstVisibleColumn;
207 if (newFirstVisibleColumn + columns >= bPtr->usedColumnCount) {
208 removeColumn(bPtr, newFirstVisibleColumn + columns);
209 }
210 }
211 WMResizeWidget(bPtr, bPtr->view->size.width, bPtr->view->size.height);
212 if (bPtr->flags.loaded) {
213 XClearArea(bPtr->view->screen->display, bPtr->view->window, 0, 0,
214 bPtr->view->size.width, bPtr->titleHeight, False);
215 scrollToColumn(bPtr, newFirstVisibleColumn, True);
216 }
345d980b dan1998-11-27 12:26:46 +0000217}
218
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200219int WMGetBrowserNumberOfColumns(WMBrowser * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000220{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200221 return bPtr->usedColumnCount;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000222}
223
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200224void WMSetBrowserPathSeparator(WMBrowser * bPtr, char *separator)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000225{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200226 if (bPtr->pathSeparator)
227 wfree(bPtr->pathSeparator);
228 bPtr->pathSeparator = wstrdup(separator);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000229}
230
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200231static void drawTitleOfColumn(WMBrowser * bPtr, int column)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000232{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200233 WMScreen *scr = bPtr->view->screen;
234 int x;
235
236 x = (column - bPtr->firstVisibleColumn) * (bPtr->columnSize.width + COLUMN_SPACING);
237
238 XFillRectangle(scr->display, bPtr->view->window, WMColorGC(scr->darkGray), x, 0,
239 bPtr->columnSize.width, bPtr->titleHeight);
240 W_DrawRelief(scr, bPtr->view->window, x, 0, bPtr->columnSize.width, bPtr->titleHeight, WRSunken);
241
242 if (column < bPtr->usedColumnCount && bPtr->titles[column]) {
243 int titleLen = strlen(bPtr->titles[column]);
244 int widthC = bPtr->columnSize.width - 8;
245
246 if (WMWidthOfString(scr->boldFont, bPtr->titles[column], titleLen)
247 > widthC) {
248 char *titleBuf = createTruncatedString(scr->boldFont,
249 bPtr->titles[column],
250 &titleLen, widthC);
251 W_PaintText(bPtr->view, bPtr->view->window, scr->boldFont, x,
252 (bPtr->titleHeight - WMFontHeight(scr->boldFont)) / 2,
253 bPtr->columnSize.width, WACenter, scr->white, False, titleBuf, titleLen);
254 wfree(titleBuf);
255 } else {
256 W_PaintText(bPtr->view, bPtr->view->window, scr->boldFont, x,
257 (bPtr->titleHeight - WMFontHeight(scr->boldFont)) / 2,
258 bPtr->columnSize.width, WACenter, scr->white,
259 False, bPtr->titles[column], titleLen);
260 }
261 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000262}
263
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200264WMList *WMGetBrowserListInColumn(WMBrowser * bPtr, int column)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000265{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200266 if (column < 0 || column >= bPtr->usedColumnCount)
267 return NULL;
64fcfedd dan1999-05-16 12:40:47 +0000268
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200269 return bPtr->columns[column];
9d2e6ef9 scottc1998-09-29 22:36:29 +0000270}
271
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200272void WMSetBrowserDelegate(WMBrowser * bPtr, WMBrowserDelegate * delegate)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000273{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200274 bPtr->delegate = delegate;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000275}
276
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200277int WMGetBrowserFirstVisibleColumn(WMBrowser * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000278{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200279 return bPtr->firstVisibleColumn;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000280}
281
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200282static void removeColumn(WMBrowser * bPtr, int column)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000283{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200284 int i, clearEnd, destroyEnd;
285 WMList **clist;
286 char **tlist;
287
288 assert(bPtr != NULL);
289
290 column = (column < 0) ? 0 : column;
291 if (column >= bPtr->columnCount) {
292 return;
293 }
294 if (column < bPtr->maxVisibleColumns) {
295 clearEnd = bPtr->maxVisibleColumns;
296 destroyEnd = bPtr->columnCount;
297 bPtr->columnCount = bPtr->maxVisibleColumns;
298 } else {
299 clearEnd = column;
300 destroyEnd = bPtr->columnCount;
301 bPtr->columnCount = column;
302 }
303 if (column < bPtr->usedColumnCount) {
304 bPtr->usedColumnCount = column;
305 }
306 for (i = column; i < clearEnd; i++) {
307 if (bPtr->titles[i]) {
308 wfree(bPtr->titles[i]);
309 bPtr->titles[i] = NULL;
310 }
311 WMClearList(bPtr->columns[i]);
312 }
313 for (; i < destroyEnd; i++) {
314 if (bPtr->titles[i]) {
315 wfree(bPtr->titles[i]);
316 bPtr->titles[i] = NULL;
317 }
318 WMRemoveNotificationObserverWithName(bPtr, WMListSelectionDidChangeNotification, bPtr->columns[i]);
319 WMDestroyWidget(bPtr->columns[i]);
320 bPtr->columns[i] = NULL;
321 }
322 clist = wmalloc(sizeof(WMList *) * (bPtr->columnCount));
323 tlist = wmalloc(sizeof(char *) * (bPtr->columnCount));
324 memcpy(clist, bPtr->columns, sizeof(WMList *) * (bPtr->columnCount));
325 memcpy(tlist, bPtr->titles, sizeof(char *) * (bPtr->columnCount));
326 wfree(bPtr->titles);
327 wfree(bPtr->columns);
328 bPtr->titles = tlist;
329 bPtr->columns = clist;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000330}
331
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200332WMListItem *WMGetBrowserSelectedItemInColumn(WMBrowser * bPtr, int column)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000333{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200334 if ((column < 0) || (column >= bPtr->usedColumnCount))
335 return NULL;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000336
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200337 return WMGetListSelectedItem(bPtr->columns[column]);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000338}
339
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200340int WMGetBrowserSelectedColumn(WMBrowser * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000341{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200342 return bPtr->selectedColumn;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000343}
344
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200345int WMGetBrowserSelectedRowInColumn(WMBrowser * bPtr, int column)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000346{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200347 if (column >= 0 && column < bPtr->columnCount) {
348 return WMGetListSelectedItemRow(bPtr->columns[column]);
349 } else {
350 return -1;
351 }
64fcfedd dan1999-05-16 12:40:47 +0000352}
9d2e6ef9 scottc1998-09-29 22:36:29 +0000353
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200354void WMSetBrowserColumnTitle(WMBrowser * bPtr, int column, char *title)
dd2d71fc kojima1999-05-15 17:38:05 +0000355{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200356 assert(column >= 0);
357 assert(column < bPtr->usedColumnCount);
dd2d71fc kojima1999-05-15 17:38:05 +0000358
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200359 if (bPtr->titles[column])
360 wfree(bPtr->titles[column]);
dd2d71fc kojima1999-05-15 17:38:05 +0000361
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200362 bPtr->titles[column] = wstrdup(title);
64fcfedd dan1999-05-16 12:40:47 +0000363
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200364 if (COLUMN_IS_VISIBLE(bPtr, column) && bPtr->flags.isTitled) {
365 drawTitleOfColumn(bPtr, column);
366 }
dd2d71fc kojima1999-05-15 17:38:05 +0000367}
368
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200369void WMSetBrowserTitled(WMBrowser * bPtr, Bool flag)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000370{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200371 int i;
372 int columnX, columnY;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000373
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200374 flag = ((flag == 0) ? 0 : 1);
e4a53ba7 dan2002-03-28 04:20:30 +0000375
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200376 if (bPtr->flags.isTitled == flag)
377 return;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000378
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200379 columnX = 0;
64fcfedd dan1999-05-16 12:40:47 +0000380
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200381 if (!bPtr->flags.isTitled) {
382 columnY = TITLE_SPACING + bPtr->titleHeight;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000383
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200384 bPtr->columnSize.height -= columnY;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000385
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200386 for (i = 0; i < bPtr->columnCount; i++) {
387 WMResizeWidget(bPtr->columns[i], bPtr->columnSize.width, bPtr->columnSize.height);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000388
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200389 columnX = WMWidgetView(bPtr->columns[i])->pos.x;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000390
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200391 WMMoveWidget(bPtr->columns[i], columnX, columnY);
392 }
393 } else {
394 bPtr->columnSize.height += TITLE_SPACING + bPtr->titleHeight;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000395
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200396 for (i = 0; i < bPtr->columnCount; i++) {
397 WMResizeWidget(bPtr->columns[i], bPtr->columnSize.width, bPtr->columnSize.height);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000398
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200399 columnX = WMWidgetView(bPtr->columns[i])->pos.x;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000400
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200401 WMMoveWidget(bPtr->columns[i], columnX, 0);
402 }
403 }
64fcfedd dan1999-05-16 12:40:47 +0000404
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200405 bPtr->flags.isTitled = flag;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000406}
407
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200408void WMSortBrowserColumn(WMBrowser * bPtr, int column)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000409{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200410 WMSortListItems(bPtr->columns[column]);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000411}
412
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200413void WMSortBrowserColumnWithComparer(WMBrowser * bPtr, int column, WMCompareDataProc * func)
94f4483d kojima1999-10-27 22:32:12 +0000414{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200415 WMSortListItemsWithComparer(bPtr->columns[column], func);
94f4483d kojima1999-10-27 22:32:12 +0000416}
417
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200418WMListItem *WMInsertBrowserItem(WMBrowser * bPtr, int column, int row, char *text, Bool isBranch)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000419{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200420 WMListItem *item;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000421
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200422 if (column < 0 || column >= bPtr->columnCount)
423 return NULL;
6830b057 dan2004-10-12 21:28:27 +0000424
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200425 item = WMInsertListItem(bPtr->columns[column], row, text);
426 item->isBranch = isBranch;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000427
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200428 return item;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000429}
430
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200431static void willResizeBrowser(W_ViewDelegate * self, WMView * view, unsigned int *width, unsigned int *height)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000432{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200433 WMBrowser *bPtr = (WMBrowser *) view->self;
434 int cols = bPtr->maxVisibleColumns;
435 int colX, colY;
436 int i;
437
438 assert(*width > 0);
439 assert(*height > 0);
440
441 bPtr->columnSize.width = (*width - (cols - 1) * COLUMN_SPACING) / cols;
442 bPtr->columnSize.height = *height;
443
444 if (bPtr->flags.isTitled) {
445 colY = TITLE_SPACING + bPtr->titleHeight;
446 bPtr->columnSize.height -= colY;
447 } else {
448 colY = 0;
449 }
450
451 if (bPtr->flags.hasScroller) {
452 bPtr->columnSize.height -= SCROLLER_WIDTH + 4;
453
454 if (bPtr->scroller) {
455 WMResizeWidget(bPtr->scroller, *width - 2, 1);
456 WMMoveWidget(bPtr->scroller, 1, *height - SCROLLER_WIDTH - 1);
457 }
458 }
459
460 colX = 0;
461 for (i = 0; i < bPtr->columnCount; i++) {
462 WMResizeWidget(bPtr->columns[i], bPtr->columnSize.width, bPtr->columnSize.height);
463
464 WMMoveWidget(bPtr->columns[i], colX, colY);
465
466 if (COLUMN_IS_VISIBLE(bPtr, i)) {
467 colX += bPtr->columnSize.width + COLUMN_SPACING;
468 }
469 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000470}
471
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200472static void paintItem(WMList * lPtr, int index, Drawable d, char *text, int state, WMRect * rect)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000473{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200474 WMView *view = W_VIEW(lPtr);
475 W_Screen *scr = view->screen;
476 Display *display = scr->display;
477 WMFont *font = ((state & WLDSIsBranch) ? scr->boldFont : scr->normalFont);
478 WMColor *backColor = ((state & WLDSSelected) ? scr->white : view->backColor);
479 int width, height, x, y, textLen;
480
481 width = rect->size.width;
482 height = rect->size.height;
483 x = rect->pos.x;
484 y = rect->pos.y;
485 textLen = strlen(text);
486
487 XFillRectangle(display, d, WMColorGC(backColor), x, y, width, height);
488
489 if (text) {
490 /* Avoid overlaping... */
491 int widthC = (state & WLDSIsBranch) ? width - 20 : width - 8;
492 if (WMWidthOfString(font, text, textLen) > widthC) {
493 char *textBuf = createTruncatedString(font, text, &textLen, widthC);
494 W_PaintText(view, d, font, x + 4, y, widthC, WALeft, scr->black, False, textBuf, textLen);
495 wfree(textBuf);
496 } else {
497 W_PaintText(view, d, font, x + 4, y, widthC, WALeft, scr->black, False, text, textLen);
498 }
499 }
500
501 if (state & WLDSIsBranch) {
502 WMColor *lineColor = ((state & WLDSSelected) ? scr->gray : scr->white);
503
504 XDrawLine(display, d, WMColorGC(scr->darkGray), x + width - 11, y + 3,
505 x + width - 6, y + height / 2);
506 XDrawLine(display, d, WMColorGC(lineColor), x + width - 11, y + height - 5,
507 x + width - 6, y + height / 2);
508 XDrawLine(display, d, WMColorGC(scr->black), x + width - 12, y + 3,
509 x + width - 12, y + height - 5);
510 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000511}
512
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200513static void scrollCallback(WMWidget * scroller, void *self)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000514{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200515 WMBrowser *bPtr = (WMBrowser *) self;
516 WMScroller *sPtr = (WMScroller *) scroller;
517 int newFirst;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000518#define LAST_VISIBLE_COLUMN bPtr->firstVisibleColumn+bPtr->maxVisibleColumns
519
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200520 switch (WMGetScrollerHitPart(sPtr)) {
521 case WSDecrementLine:
522 if (bPtr->firstVisibleColumn > 0) {
523 scrollToColumn(bPtr, bPtr->firstVisibleColumn - 1, True);
524 }
525 break;
526
527 case WSDecrementPage:
528 case WSDecrementWheel:
529 if (bPtr->firstVisibleColumn > 0) {
530 newFirst = bPtr->firstVisibleColumn - bPtr->maxVisibleColumns;
531
532 scrollToColumn(bPtr, newFirst, True);
533 }
534 break;
535
536 case WSIncrementLine:
537 if (LAST_VISIBLE_COLUMN < bPtr->usedColumnCount) {
538 scrollToColumn(bPtr, bPtr->firstVisibleColumn + 1, True);
539 }
540 break;
541
542 case WSIncrementPage:
543 case WSIncrementWheel:
544 if (LAST_VISIBLE_COLUMN < bPtr->usedColumnCount) {
545 newFirst = bPtr->firstVisibleColumn + bPtr->maxVisibleColumns;
546
547 if (newFirst + bPtr->maxVisibleColumns >= bPtr->columnCount)
548 newFirst = bPtr->columnCount - bPtr->maxVisibleColumns;
549
550 scrollToColumn(bPtr, newFirst, True);
551 }
552 break;
553
554 case WSKnob:
555 {
556 double floatValue;
557 double value = bPtr->columnCount - bPtr->maxVisibleColumns;
558
559 floatValue = WMGetScrollerValue(bPtr->scroller);
560
561 floatValue = (floatValue * value) / value;
562
563 newFirst = rint(floatValue * (float)(bPtr->columnCount - bPtr->maxVisibleColumns));
564
565 if (bPtr->firstVisibleColumn != newFirst)
566 scrollToColumn(bPtr, newFirst, False);
567 /*else
568 WMSetScrollerParameters(bPtr->scroller, floatValue,
569 bPtr->maxVisibleColumns/(float)bPtr->columnCount);
570 */
571
572 }
573 break;
574
575 case WSKnobSlot:
576 case WSNoPart:
577 /* do nothing */
578 break;
579 }
580#undef LAST_VISIBLE_COLUMN
581}
64fcfedd dan1999-05-16 12:40:47 +0000582
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200583static void setupScroller(WMBrowser * bPtr)
584{
585 WMScroller *sPtr;
586 int y;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000587
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200588 y = bPtr->view->size.height - SCROLLER_WIDTH - 1;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000589
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200590 sPtr = WMCreateScroller(bPtr);
591 WMSetScrollerAction(sPtr, scrollCallback, bPtr);
592 WMMoveWidget(sPtr, 1, y);
593 WMResizeWidget(sPtr, bPtr->view->size.width - 2, SCROLLER_WIDTH);
64fcfedd dan1999-05-16 12:40:47 +0000594
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200595 bPtr->scroller = sPtr;
e7495baf dan1999-02-17 11:06:40 +0000596
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200597 WMMapWidget(sPtr);
598}
e7495baf dan1999-02-17 11:06:40 +0000599
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200600void WMSetBrowserAction(WMBrowser * bPtr, WMAction * action, void *clientData)
601{
602 bPtr->action = action;
603 bPtr->clientData = clientData;
604}
e7495baf dan1999-02-17 11:06:40 +0000605
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200606void WMSetBrowserDoubleAction(WMBrowser * bPtr, WMAction * action, void *clientData)
607{
608 bPtr->doubleAction = action;
609 bPtr->doubleClientData = clientData;
610}
9d2e6ef9 scottc1998-09-29 22:36:29 +0000611
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200612void WMSetBrowserHasScroller(WMBrowser * bPtr, int hasScroller)
613{
614 bPtr->flags.hasScroller = hasScroller;
615}
9d2e6ef9 scottc1998-09-29 22:36:29 +0000616
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200617char *WMSetBrowserPath(WMBrowser * bPtr, char *path)
618{
619 int i;
620 char *str;
621 char *tmp, *retPtr = NULL;
622 int item;
623 WMListItem *listItem;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000624
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200625 /* WMLoadBrowserColumnZero must be call first */
626 if (!bPtr->flags.loaded) {
627 return False;
628 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000629
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200630 removeColumn(bPtr, 1);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000631
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200632 WMSelectListItem(bPtr->columns[0], -1);
633 WMSetListPosition(bPtr->columns[0], 0);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000634
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200635 i = 0;
636 str = wstrdup(path);
637 tmp = strtok(str, bPtr->pathSeparator);
638 while (tmp) {
639 /* select it in the column */
640 item = WMFindRowOfListItemWithTitle(bPtr->columns[i], tmp);
641 if (item < 0) {
642 retPtr = &path[(int)(tmp - str)];
643 break;
644 }
645 WMSelectListItem(bPtr->columns[i], item);
646 WMSetListPosition(bPtr->columns[i], item);
64fcfedd dan1999-05-16 12:40:47 +0000647
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200648 listItem = WMGetListItem(bPtr->columns[i], item);
649 if (!listItem || !listItem->isBranch) {
650 break;
651 }
64fcfedd dan1999-05-16 12:40:47 +0000652
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200653 /* load next column */
654 WMAddBrowserColumn(bPtr);
64fcfedd dan1999-05-16 12:40:47 +0000655
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200656 loadColumn(bPtr, i + 1);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000657
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200658 tmp = strtok(NULL, bPtr->pathSeparator);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000659
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200660 i++;
661 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000662
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200663 wfree(str);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000664
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200665 for (i = bPtr->usedColumnCount - 1; (i > -1) && !WMGetListSelectedItem(bPtr->columns[i]); i--) ;
e7495baf dan1999-02-17 11:06:40 +0000666
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200667 bPtr->selectedColumn = i;
e7495baf dan1999-02-17 11:06:40 +0000668
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200669 if (bPtr->columnCount < bPtr->maxVisibleColumns) {
670 int i = bPtr->maxVisibleColumns - bPtr->columnCount;
671 int curUsedColumnCount = bPtr->usedColumnCount;
672 bPtr->usedColumnCount = bPtr->columnCount;
673 while (i--) {
674 WMAddBrowserColumn(bPtr);
675 }
676 bPtr->usedColumnCount = curUsedColumnCount;
677 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000678
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200679 scrollToColumn(bPtr, bPtr->columnCount - bPtr->maxVisibleColumns, True);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000680
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200681 return retPtr;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000682}
683
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200684char *WMGetBrowserPath(WMBrowser * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000685{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200686 return WMGetBrowserPathToColumn(bPtr, bPtr->columnCount);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000687}
688
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200689char *WMGetBrowserPathToColumn(WMBrowser * bPtr, int column)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000690{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200691 int i, size;
692 char *path;
693 WMListItem *item;
694
695 if (column >= bPtr->usedColumnCount)
696 column = bPtr->usedColumnCount - 1;
697
698 if (column < 0) {
699 return wstrdup(bPtr->pathSeparator);
700 }
701
702 /* calculate size of buffer */
703 size = 0;
704 for (i = 0; i <= column; i++) {
705 item = WMGetListSelectedItem(bPtr->columns[i]);
706 if (!item)
707 break;
708 size += strlen(item->text);
709 }
710
711 /* get the path */
712 path = wmalloc(size + (column + 1) * strlen(bPtr->pathSeparator) + 1);
713 /* ignore first / */
714 *path = 0;
715 for (i = 0; i <= column; i++) {
716 strcat(path, bPtr->pathSeparator);
717 item = WMGetListSelectedItem(bPtr->columns[i]);
718 if (!item)
719 break;
720 strcat(path, item->text);
721 }
722
723 return path;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000724}
725
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200726WMArray *WMGetBrowserPaths(WMBrowser * bPtr)
ed39c92d dan2000-10-03 20:52:15 +0000727{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200728 int column, i, k, size, selNo;
729 char *path;
730 WMListItem *item, *lastItem;
731 WMArray *paths, *items;
732
733 column = bPtr->usedColumnCount - 1;
734
735 if (column < 0) {
736 paths = WMCreateArrayWithDestructor(1, wfree);
737 WMAddToArray(paths, wstrdup(bPtr->pathSeparator));
738 return paths;
739 }
740
741 items = WMGetListSelectedItems(bPtr->columns[column]);
742 selNo = WMGetArrayItemCount(items);
743 paths = WMCreateArrayWithDestructor(selNo, wfree);
744
745 if (selNo <= 1) {
746 WMAddToArray(paths, WMGetBrowserPath(bPtr));
747 return paths;
748 }
749
750 /* calculate size of buffer */
751 size = 0;
752 for (i = 0; i < column; i++) {
753 item = WMGetListSelectedItem(bPtr->columns[i]);
754 if (!item)
755 break;
756 size += strlen(item->text);
757 }
758
759 size += (column + 1) * strlen(bPtr->pathSeparator) + 1;
760
761 for (k = 0; k < selNo; k++) {
762 /* get the path */
763 lastItem = WMGetFromArray(items, k);
764 path = wmalloc(size + (lastItem != NULL ? strlen(lastItem->text) : 0));
765 /* ignore first / */
766 *path = 0;
767 for (i = 0; i <= column; i++) {
768 strcat(path, bPtr->pathSeparator);
769 if (i == column) {
770 item = lastItem;
771 } else {
772 item = WMGetListSelectedItem(bPtr->columns[i]);
773 }
774 if (!item)
775 break;
776 strcat(path, item->text);
777 }
778 WMAddToArray(paths, path);
779 }
780
781 return paths;
ed39c92d dan2000-10-03 20:52:15 +0000782}
783
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200784Bool WMBrowserAllowsMultipleSelection(WMBrowser * bPtr)
de991559 dan2000-10-02 06:59:18 +0000785{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200786 return bPtr->flags.allowMultipleSelection;
de991559 dan2000-10-02 06:59:18 +0000787}
788
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200789Bool WMBrowserAllowsEmptySelection(WMBrowser * bPtr)
de991559 dan2000-10-02 06:59:18 +0000790{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200791 return bPtr->flags.allowEmptySelection;
de991559 dan2000-10-02 06:59:18 +0000792}
793
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200794static void loadColumn(WMBrowser * bPtr, int column)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000795{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200796 assert(bPtr->delegate);
797 assert(bPtr->delegate->createRowsForColumn);
dd2d71fc kojima1999-05-15 17:38:05 +0000798
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200799 bPtr->flags.loadingColumn = 1;
800 (*bPtr->delegate->createRowsForColumn) (bPtr->delegate, bPtr, column, bPtr->columns[column]);
801 bPtr->flags.loadingColumn = 0;
dd2d71fc kojima1999-05-15 17:38:05 +0000802
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200803 if (bPtr->delegate->titleOfColumn) {
804 char *title;
dd2d71fc kojima1999-05-15 17:38:05 +0000805
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200806 title = (*bPtr->delegate->titleOfColumn) (bPtr->delegate, bPtr, column);
dd2d71fc kojima1999-05-15 17:38:05 +0000807
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200808 if (bPtr->titles[column])
809 wfree(bPtr->titles[column]);
dd2d71fc kojima1999-05-15 17:38:05 +0000810
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200811 bPtr->titles[column] = wstrdup(title);
64fcfedd dan1999-05-16 12:40:47 +0000812
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200813 if (COLUMN_IS_VISIBLE(bPtr, column) && bPtr->flags.isTitled) {
814 drawTitleOfColumn(bPtr, column);
815 }
816 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000817}
818
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200819static void paintBrowser(WMBrowser * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000820{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200821 int i;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000822
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200823 if (!bPtr->view->flags.mapped)
824 return;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000825
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200826 W_DrawRelief(bPtr->view->screen, bPtr->view->window, 0,
827 bPtr->view->size.height - SCROLLER_WIDTH - 2, bPtr->view->size.width, 22, WRSunken);
64fcfedd dan1999-05-16 12:40:47 +0000828
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200829 if (bPtr->flags.isTitled) {
830 for (i = 0; i < bPtr->maxVisibleColumns; i++) {
831 drawTitleOfColumn(bPtr, i + bPtr->firstVisibleColumn);
832 }
833 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000834}
835
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200836static void handleEvents(XEvent * event, void *data)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000837{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200838 WMBrowser *bPtr = (WMBrowser *) data;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000839
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200840 CHECK_CLASS(data, WC_Browser);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000841
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200842 switch (event->type) {
843 case Expose:
844 paintBrowser(bPtr);
845 break;
64fcfedd dan1999-05-16 12:40:47 +0000846
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200847 case DestroyNotify:
848 destroyBrowser(bPtr);
849 break;
64fcfedd dan1999-05-16 12:40:47 +0000850
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200851 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000852}
853
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200854static void scrollToColumn(WMBrowser * bPtr, int column, Bool updateScroller)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000855{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200856 int i;
857 int x;
858 int notify = 0;
859
860 if (column != bPtr->firstVisibleColumn) {
861 notify = 1;
862 }
863
864 if (column < 0)
865 column = 0;
866
867 if (notify && bPtr->delegate && bPtr->delegate->willScroll) {
868 (*bPtr->delegate->willScroll) (bPtr->delegate, bPtr);
869 }
870
871 x = 0;
872 bPtr->firstVisibleColumn = column;
873 for (i = 0; i < bPtr->columnCount; i++) {
874 if (COLUMN_IS_VISIBLE(bPtr, i)) {
875 WMMoveWidget(bPtr->columns[i], x, WMWidgetView(bPtr->columns[i])->pos.y);
876 if (!WMWidgetView(bPtr->columns[i])->flags.realized)
877 WMRealizeWidget(bPtr->columns[i]);
878 WMMapWidget(bPtr->columns[i]);
879 x += bPtr->columnSize.width + COLUMN_SPACING;
880 } else {
881 WMUnmapWidget(bPtr->columns[i]);
882 }
883 }
884
885 /* update the scroller */
886 if (updateScroller) {
887 if (bPtr->columnCount > bPtr->maxVisibleColumns) {
888 float value, proportion;
889
890 value = bPtr->firstVisibleColumn / (float)(bPtr->columnCount - bPtr->maxVisibleColumns);
891 proportion = bPtr->maxVisibleColumns / (float)bPtr->columnCount;
892 WMSetScrollerParameters(bPtr->scroller, value, proportion);
893 } else {
894 WMSetScrollerParameters(bPtr->scroller, 0, 1);
895 }
896 }
897
898 if (bPtr->view->flags.mapped)
899 paintBrowser(bPtr);
900
901 if (notify && bPtr->delegate && bPtr->delegate->didScroll) {
902 (*bPtr->delegate->didScroll) (bPtr->delegate, bPtr);
903 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000904}
905
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200906static void listCallback(void *self, void *clientData)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000907{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200908 WMBrowser *bPtr = (WMBrowser *) clientData;
909 WMList *lPtr = (WMList *) self;
910 WMListItem *item;
911 int i, selNo;
912 static WMListItem *oldItem = NULL;
913 static int oldSelNo = 0;
914
915 item = WMGetListSelectedItem(lPtr);
916 selNo = WMGetArrayItemCount(WMGetListSelectedItems(lPtr));
917
918 if (oldItem == NULL || oldItem != item || oldSelNo != selNo) {
919 for (i = 0; i < bPtr->columnCount; i++) {
920 if (lPtr == bPtr->columns[i])
921 break;
922 }
923 assert(i < bPtr->columnCount);
924
925 bPtr->selectedColumn = i;
926
927 /* columns at right must be cleared */
928 removeColumn(bPtr, i + 1);
929 /* open directory */
930 if (item && item->isBranch && selNo == 1) {
931 WMAddBrowserColumn(bPtr);
932 }
933 if (bPtr->usedColumnCount < bPtr->maxVisibleColumns)
934 i = 0;
935 else
936 i = bPtr->usedColumnCount - bPtr->maxVisibleColumns;
937 scrollToColumn(bPtr, i, True);
938 if (item && item->isBranch && selNo == 1) {
939 loadColumn(bPtr, bPtr->usedColumnCount - 1);
940 }
941 }
942
943 /* call callback for click */
944 if (bPtr->action)
945 (*bPtr->action) (bPtr, bPtr->clientData);
946
947 oldItem = item;
948 oldSelNo = selNo;
e7495baf dan1999-02-17 11:06:40 +0000949}
950
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200951static void listDoubleCallback(void *self, void *clientData)
e7495baf dan1999-02-17 11:06:40 +0000952{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200953 WMBrowser *bPtr = (WMBrowser *) clientData;
954 WMList *lPtr = (WMList *) self;
955 WMListItem *item;
e7495baf dan1999-02-17 11:06:40 +0000956
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200957 item = WMGetListSelectedItem(lPtr);
958 if (!item)
959 return;
e7495baf dan1999-02-17 11:06:40 +0000960
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200961 /* call callback for double click */
962 if (bPtr->doubleAction)
963 (*bPtr->doubleAction) (bPtr, bPtr->doubleClientData);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000964}
965
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200966void WMLoadBrowserColumnZero(WMBrowser * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000967{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200968 if (!bPtr->flags.loaded) {
969 /* create column 0 */
970 WMAddBrowserColumn(bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000971
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200972 loadColumn(bPtr, 0);
64fcfedd dan1999-05-16 12:40:47 +0000973
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200974 /* make column 0 visible */
975 scrollToColumn(bPtr, 0, True);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000976
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200977 bPtr->flags.loaded = 1;
978 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000979}
980
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200981void WMRemoveBrowserItem(WMBrowser * bPtr, int column, int row)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000982{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200983 WMList *list;
e7495baf dan1999-02-17 11:06:40 +0000984
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200985 if (column < 0 || column >= bPtr->usedColumnCount)
986 return;
e7495baf dan1999-02-17 11:06:40 +0000987
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200988 list = WMGetBrowserListInColumn(bPtr, column);
e7495baf dan1999-02-17 11:06:40 +0000989
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200990 if (row < 0 || row >= WMGetListNumberOfRows(list))
991 return;
e7495baf dan1999-02-17 11:06:40 +0000992
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200993 removeColumn(bPtr, column + 1);
994 if (bPtr->usedColumnCount < bPtr->maxVisibleColumns)
995 scrollToColumn(bPtr, 0, True);
996 else
997 scrollToColumn(bPtr, bPtr->usedColumnCount - bPtr->maxVisibleColumns, True);
e7495baf dan1999-02-17 11:06:40 +0000998
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200999 WMRemoveListItem(list, row);
9d2e6ef9 scottc1998-09-29 22:36:29 +00001000}
1001
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001002static void listSelectionObserver(void *observerData, WMNotification * notification)
e7495baf dan1999-02-17 11:06:40 +00001003{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001004 WMBrowser *bPtr = (WMBrowser *) observerData;
1005 int column;
1006 WMList *lPtr = (WMList *) WMGetNotificationObject(notification);
e7495baf dan1999-02-17 11:06:40 +00001007
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001008 for (column = 0; column < bPtr->usedColumnCount; column++)
1009 if (bPtr->columns[column] == lPtr)
1010 break;
e7495baf dan1999-02-17 11:06:40 +00001011
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001012 /* this can happen when a list is being cleared with WMClearList
1013 * after the column was removed */
1014 if (column >= bPtr->usedColumnCount) {
1015 return;
1016 }
e7495baf dan1999-02-17 11:06:40 +00001017
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001018 if (WMGetArrayItemCount(WMGetListSelectedItems(lPtr)) == 0)
1019 column--;
e7495baf dan1999-02-17 11:06:40 +00001020
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001021 bPtr->selectedColumn = column;
e7495baf dan1999-02-17 11:06:40 +00001022}
1023
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001024int WMAddBrowserColumn(WMBrowser * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +00001025{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001026 WMList *list;
1027 WMList **clist;
1028 char **tlist;
1029 int colY;
1030 int index;
1031
1032 if (bPtr->usedColumnCount < bPtr->columnCount) {
1033 return bPtr->usedColumnCount++;
1034 }
1035
1036 bPtr->usedColumnCount++;
1037
1038 if (bPtr->flags.isTitled) {
1039 colY = TITLE_SPACING + bPtr->titleHeight;
1040 } else {
1041 colY = 0;
1042 }
1043
1044 index = bPtr->columnCount;
1045 bPtr->columnCount++;
1046 clist = wmalloc(sizeof(WMList *) * bPtr->columnCount);
1047 tlist = wmalloc(sizeof(char *) * bPtr->columnCount);
1048 memcpy(clist, bPtr->columns, sizeof(WMList *) * (bPtr->columnCount - 1));
1049 memcpy(tlist, bPtr->titles, sizeof(char *) * (bPtr->columnCount - 1));
1050 if (bPtr->columns)
1051 wfree(bPtr->columns);
1052 if (bPtr->titles)
1053 wfree(bPtr->titles);
1054 bPtr->columns = clist;
1055 bPtr->titles = tlist;
1056
1057 bPtr->titles[index] = NULL;
1058
1059 list = WMCreateList(bPtr);
1060 WMSetListAllowMultipleSelection(list, bPtr->flags.allowMultipleSelection);
1061 WMSetListAllowEmptySelection(list, bPtr->flags.allowEmptySelection);
1062 WMSetListAction(list, listCallback, bPtr);
1063 WMSetListDoubleAction(list, listDoubleCallback, bPtr);
1064 WMSetListUserDrawProc(list, paintItem);
1065 WMAddNotificationObserver(listSelectionObserver, bPtr, WMListSelectionDidChangeNotification, list);
1066
1067 bPtr->columns[index] = list;
1068
1069 WMResizeWidget(list, bPtr->columnSize.width, bPtr->columnSize.height);
1070 WMMoveWidget(list, (bPtr->columnSize.width + COLUMN_SPACING) * index, colY);
1071 if (COLUMN_IS_VISIBLE(bPtr, index))
1072 WMMapWidget(list);
1073
1074 /* update the scroller */
1075 if (bPtr->columnCount > bPtr->maxVisibleColumns) {
1076 float value, proportion;
1077
1078 value = bPtr->firstVisibleColumn / (float)(bPtr->columnCount - bPtr->maxVisibleColumns);
1079 proportion = bPtr->maxVisibleColumns / (float)bPtr->columnCount;
1080 WMSetScrollerParameters(bPtr->scroller, value, proportion);
1081 }
1082
1083 return index;
9d2e6ef9 scottc1998-09-29 22:36:29 +00001084}
1085
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001086static void destroyBrowser(WMBrowser * bPtr)
9d2e6ef9 scottc1998-09-29 22:36:29 +00001087{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001088 int i;
9d2e6ef9 scottc1998-09-29 22:36:29 +00001089
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001090 for (i = 0; i < bPtr->columnCount; i++) {
1091 if (bPtr->titles[i])
1092 wfree(bPtr->titles[i]);
1093 }
1094 wfree(bPtr->titles);
64fcfedd dan1999-05-16 12:40:47 +00001095
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001096 wfree(bPtr->pathSeparator);
64fcfedd dan1999-05-16 12:40:47 +00001097
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001098 WMRemoveNotificationObserver(bPtr);
64fcfedd dan1999-05-16 12:40:47 +00001099
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001100 wfree(bPtr);
9d2e6ef9 scottc1998-09-29 22:36:29 +00001101}
1102
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +02001103static char *createTruncatedString(WMFont * font, char *text, int *textLen, int width)
e7495baf dan1999-02-17 11:06:40 +00001104{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +02001105 int dLen = WMWidthOfString(font, ".", 1);
1106 char *textBuf = (char *)wmalloc((*textLen) + 4);
1107
1108 if (width >= 3 * dLen) {
1109 int dddLen = 3 * dLen;
1110 int tmpTextLen = *textLen;
1111
1112 strcpy(textBuf, text);
1113 while (tmpTextLen && (WMWidthOfString(font, textBuf, tmpTextLen) + dddLen > width))
1114 tmpTextLen--;
1115 strcpy(textBuf + tmpTextLen, "...");
1116 *textLen = tmpTextLen + 3;
1117 } else if (width >= 2 * dLen) {
1118 strcpy(textBuf, "..");
1119 *textLen = 2;
1120 } else if (width >= dLen) {
1121 strcpy(textBuf, ".");
1122 *textLen = 1;
1123 } else {
1124 *textBuf = '\0';
1125 *textLen = 0;
1126 }
1127 return textBuf;
e7495baf dan1999-02-17 11:06:40 +00001128}