ui/motif/Fsb.c

changeset 115
e57ca2747782
equal deleted inserted replaced
114:3da24640513a 115:e57ca2747782
1 /*
2 * Copyright 2021 Olaf Wintermann
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23 //define FSB_ENABLE_DETAIL
24
25 #include "Fsb.h"
26 #include "FsbP.h"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <time.h>
33 #include <inttypes.h>
34 #include <errno.h>
35
36 #include <sys/stat.h>
37 #include <limits.h>
38 #include <dirent.h>
39 #include <fnmatch.h>
40
41 #include <Xm/XmAll.h>
42 #include <Xm/DropDown.h>
43
44 #include "pathbar.h"
45
46 #include "../common/utils.h"
47
48 #ifdef FSB_ENABLE_DETAIL
49 #include <XmL/Grid.h>
50 #endif
51
52 #define WIDGET_SPACING 5
53 #define WINDOW_SPACING 8
54
55 #define BUTTON_EXTRA_SPACE 4
56
57 #define DATE_FORMAT_SAME_YEAR "%b %d %H:%M"
58 #define DATE_FORMAT_OTHER_YEAR "%b %d %Y"
59
60 #define KB_SUFFIX "KiB"
61 #define MB_SUFFIX "MiB"
62 #define GB_SUFFIX "GiB"
63 #define TB_SUFFIX "TiB"
64
65 #define FSB_ERROR_TITLE "Error"
66 #define FSB_ERROR_CHAR "Character '/' is not allowed in file names"
67 #define FSB_ERROR_RENAME "Cannot rename file: %s"
68 #define FSB_ERROR_DELETE "Cannot delete file: %s"
69 #define FSB_ERROR_CREATE_FOLDER "Cannot create folder: %s"
70 #define FSB_ERROR_OPEN_DIR "Cannot open directory: %s"
71
72 #define FSB_DETAIL_HEADINGS "Name|Size|Last Modified"
73
74 static void fsb_class_init(void);
75 static void fsb_class_part_init (WidgetClass wc);
76 static void fsb_init(Widget request, Widget neww, ArgList args, Cardinal *num_args);
77 static void fsb_resize(Widget widget);
78 static void fsb_realize(Widget widget, XtValueMask *mask, XSetWindowAttributes *attributes);
79 static void fsb_destroy(Widget widget);
80 static Boolean fsb_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args);
81 static Boolean fsb_acceptfocus(Widget widget, Time *time);
82
83 static void fsb_insert_child(Widget child);
84
85 static void fsb_mapcb(Widget widget, XtPointer u, XtPointer cb);
86
87 static int FSBGlobFilter(const char *a, const char *b);
88
89 static void FSBUpdateTitle(Widget w);
90
91 static void FocusInAP(Widget w, XEvent *event, String *args, Cardinal *nArgs);
92
93 static void ErrDialog(XnFileSelectionBox w, const char *title, const char *errmsg);
94
95 static void FSBRename(XnFileSelectionBox fsb, const char *path);
96 static void FSBDelete(XnFileSelectionBox fsb, const char *path);
97
98 static void FSBSelectItem(XnFileSelectionBox fsb, const char *item);
99
100 static char* set_selected_path(XnFileSelectionBox data, XmString item);
101
102 static void FileContextMenuCB(Widget item, XtPointer index, XtPointer cd);
103
104 static Widget CreateContextMenu(XnFileSelectionBox fsb, Widget parent, XtCallbackProc callback);
105
106 static void FileListUpdate(Widget fsb, Widget view, FileElm *dirlist, int dircount, FileElm *files, int filecount, const char *filter, int maxnamelen, void *userData);
107 static void FileListSelect(Widget fsb, Widget view, const char *item);
108 static void FileListCleanup(Widget fsb, Widget view, void *userData);
109 static void FileListDestroy(Widget fsb, Widget view, void *userData);
110
111 static void FileListActivateCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb);
112 static void FileListSelectCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb);
113
114 static void FileListWidgetAdd(XnFileSelectionBox fsb, Widget w, int showHidden, const char *filter, FileElm *ls, int count);
115
116 #ifdef FSB_ENABLE_DETAIL
117 static void FileListDetailUpdate(Widget fsb, Widget view, FileElm *dirlist, int dircount, FileElm *files, int filecount, const char *filter, int maxnamelen, void *userData);
118 static void FileListDetailSelect(Widget fsb, Widget view, const char *item);
119 static void FileListDetailCleanup(Widget fsb, Widget view, void *userData);
120 static void FileListDetailDestroy(Widget fsb, Widget view, void *userData);
121 static void FileListDetailAdjustColWidth(Widget grid);
122 static void FileListDetailAdd(XnFileSelectionBox fsb, Widget grid, int showHidden, const char *filter, FileElm *ls, int count, int maxWidth);
123 #endif
124
125 static void FSBNewFolder(Widget w, XnFileSelectionBox data, XtPointer u);
126
127 static void FSBHome(Widget w, XnFileSelectionBox data, XtPointer u);
128
129 static void FileSelectionCallback(XnFileSelectionBox fsb, XtCallbackList cb, int reason, const char *value);
130
131 static void CreateUI(XnFileSelectionBox w);
132 static FSBViewWidgets CreateView(XnFileSelectionBox w, FSBViewCreateProc createProc, void *userData, Boolean useDirList);
133 static void AddViewMenuItem(XnFileSelectionBox w, const char *name, int viewIndex);
134 static void SelectView(XnFileSelectionBox f, int view);
135
136 static char* FSBDialogTitle(Widget w);
137
138 static FSBViewWidgets CreateListView(Widget fsb, ArgList args, int n, void *userData);
139 static FSBViewWidgets CreateDetailView(Widget fsb, ArgList args, int n, void *userData);
140
141 static const char* GetHomeDir(void);
142
143 static char* ConcatPath(const char *parent, const char *name);
144 static char* FileName(char *path);
145 static char* ParentPath(const char *path);
146 //static int CheckFileName(const char *name);
147
148 static int filedialog_update_dir(XnFileSelectionBox data, const char *path);
149 static void filedialog_cleanup_filedata(XnFileSelectionBox data);
150
151
152 static XtResource resources[] = {
153 {XmNokCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XnFileSelectionBox, fsb.okCallback), XmRCallback, NULL},
154 {XmNcancelCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XnFileSelectionBox, fsb.cancelCallback), XmRCallback, NULL},
155 {XnNwidgetSpacing, XmCSpacing, XmRDimension, sizeof(Dimension), XtOffset(XnFileSelectionBox, fsb.widgetSpacing), XmRImmediate, (XtPointer)WIDGET_SPACING},
156 {XnNwindowSpacing, XmCSpacing, XmRDimension, sizeof(Dimension), XtOffset(XnFileSelectionBox, fsb.windowSpacing), XmRImmediate, (XtPointer)WINDOW_SPACING},
157 {XnNfsbType, XnCfsbType, XmRInt, sizeof(int), XtOffset(XnFileSelectionBox, fsb.type), XmRImmediate, (XtPointer)FILEDIALOG_OPEN},
158 {XnNshowHidden, XnCshowHidden, XmRBoolean, sizeof(Boolean), XtOffset(XnFileSelectionBox, fsb.showHidden), XmRImmediate, (XtPointer)False},
159 {XnNshowHiddenButton, XnCshowHiddenButton, XmRBoolean, sizeof(Boolean), XtOffset(XnFileSelectionBox, fsb.showHiddenButton), XmRImmediate, (XtPointer)True},
160 {XnNshowViewMenu, XnCshowViewMenu, XmRBoolean, sizeof(Boolean), XtOffset(XnFileSelectionBox, fsb.showViewMenu), XmRImmediate, (XtPointer)False},
161 {XnNselectedView, XnCselectedView, XmRInt, sizeof(int), XtOffset(XnFileSelectionBox, fsb.selectedview), XmRImmediate, (XtPointer)0},
162
163 {XnNdirectory, XnCdirectory, XmRString, sizeof(XmString), XtOffset(XnFileSelectionBox, fsb.currentPath), XmRString, NULL},
164 {XnNselectedPath, XnCselectedPath, XmRString, sizeof(XmString), XtOffset(XnFileSelectionBox, fsb.selectedPath), XmRString, NULL},
165 {XnNhomePath, XnChomePath, XmRString, sizeof(XmString), XtOffset(XnFileSelectionBox, fsb.homePath), XmRString, NULL},
166
167 {XnNfilter,XnCfilter,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.filterStr), XmRString, "*"},
168 {XnNfilterFunc,XnCfilterFunc,XmRFunction,sizeof(FSBFilterFunc),XtOffset(XnFileSelectionBox, fsb.filterFunc), XmRFunction, NULL},
169
170 {XnNlabelListView,XnClabelListView,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelListView), XmRString, "List"},
171 {XnNlabelDetailView,XnClabelDetailView,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDetailView), XmRString, "Detail"},
172 {XnNlabelOpenFileTitle,XnClabelOpenFileTitle,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelOpenFileTitle), XmRString, "Open File"},
173 {XnNlabelSaveFileTitle,XnClabelSaveFileTitle,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelSaveFileTitle), XmRString, "Save File"},
174 {XnNlabelDirUp,XnClabelDirUp,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDirUp), XmRString, "Dir Up"},
175 {XnNlabelHome,XnClabelHome,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelHome), XmRString, "Home"},
176 {XnNlabelNewFolder,XnClabelNewFolder,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelNewFolder), XmRString, "New Folder"},
177 {XnNlabelFilterButton,XnClabelFilterButton,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelFilterButton), XmRString, "Filter"},
178 {XnNlabelShowHiddenFiles,XnClabelShowHiddenFiles,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelShowHiddenFiles), XmRString, "Show hiden files"},
179 {XnNlabelDirectories,XnClabelDirectories,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDirectories), XmRString, "Directories"},
180 {XnNlabelFiles,XnClabelFiles,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelFiles), XmRString, "Files"},
181 {XnNlabelRename,XnClabelRename,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelRename), XmRString, "Rename"},
182 {XnNlabelDelete,XnClabelDelete,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDelete), XmRString, "Delete"},
183 {XnNlabelOpen,XnClabelOpen,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelOpen), XmRString, "Open"},
184 {XnNlabelSave,XnClabelSave,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelSave), XmRString, "Save"},
185 {XnNlabelOk,XnClabelOk,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelOk), XmRString, "OK"},
186 {XnNlabelCancel,XnClabelCancel,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelCancel), XmRString, "Cancel"},
187 {XnNlabelHelp,XnClabelHelp,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelHelp), XmRString, "Help"},
188 {XnNlabelFileName,XnClabelFileName,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelFileName), XmRString, "New File Name"},
189 {XnNlabelDirectoryName,XnClabelDirectoryName,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDirectoryName), XmRString, "Directory name:"},
190 {XnNlabelNewFileName,XnClabelNewFileName,XmRXmString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelNewFileName), XmRString, "New file name:"},
191 {XnNlabelDeleteFile,XnClabelDeleteFile,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.labelDeleteFile), XmRString, "Delete file '%s'?"},
192 {XnNdetailHeadings,XnCdetailHeadings,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.detailHeadings), XmRString,FSB_DETAIL_HEADINGS},
193 {XnNdateFormatSameYear,XnCdateFormatSameYear,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.dateFormatSameYear), XmRString,DATE_FORMAT_SAME_YEAR},
194 {XnNdateFormatOtherYear,XnNdateFormatOtherYear,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.dateFormatOtherYear), XmRString,DATE_FORMAT_OTHER_YEAR},
195 {XnNsuffixBytes,XnCsuffixBytes,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixBytes), XmRString,"bytes"},
196 {XnNsuffixKB,XnCsuffixKB,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixKB), XmRString,KB_SUFFIX},
197 {XnNsuffixMB,XnCsuffixKB,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixMB), XmRString,MB_SUFFIX},
198 {XnNsuffixGB,XnCsuffixKB,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixGB), XmRString,GB_SUFFIX},
199 {XnNsuffixTB,XnCsuffixKB,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.suffixTB), XmRString,TB_SUFFIX},
200
201 {XnNerrorTitle,XnCerrorTitle,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorTitle), XmRString,FSB_ERROR_TITLE},
202 {XnNerrorIllegalChar,XnCerrorIllegalChar,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorIllegalChar), XmRString,FSB_ERROR_CHAR},
203 {XnNerrorRename,XnCerrorRename,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorRename), XmRString,FSB_ERROR_RENAME},
204 {XnNerrorCreateFolder,XnCerrorCreateFolder,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorFolder), XmRString,FSB_ERROR_CREATE_FOLDER},
205 {XnNerrorDelete,XnCerrorDelete,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorDelete), XmRString,FSB_ERROR_DELETE},
206 {XnNerrorOpenDir,XnCerrorOpenDir,XmRString,sizeof(XmString),XtOffset(XnFileSelectionBox, fsb.errorOpenDir), XmRString,FSB_ERROR_OPEN_DIR}
207 };
208
209 static XtActionsRec actionslist[] = {
210 {"focusIn", FocusInAP},
211 {"NULL", NULL}
212 };
213
214
215 static char defaultTranslations[] = "<FocusIn>: focusIn()";
216
217 static XtResource constraints[] = {};
218
219 FSBClassRec fsbWidgetClassRec = {
220 // Core Class
221 {
222 (WidgetClass)&xmFormClassRec,
223 "XnFSB", // class_name
224 sizeof(FSBRec), // widget_size
225 fsb_class_init, // class_initialize
226 fsb_class_part_init, // class_part_initialize
227 FALSE, // class_inited
228 fsb_init, // initialize
229 NULL, // initialize_hook
230 fsb_realize, // realize
231 actionslist, // actions
232 XtNumber(actionslist), // num_actions
233 resources, // resources
234 XtNumber(resources), // num_resources
235 NULLQUARK, // xrm_class
236 True, // compress_motion
237 True, // compress_exposure
238 True, // compress_enterleave
239 False, // visible_interest
240 fsb_destroy, // destroy
241 fsb_resize, // resize
242 XtInheritExpose, // expose
243 fsb_set_values, // set_values
244 NULL, // set_values_hook
245 XtInheritSetValuesAlmost, // set_values_almost
246 NULL, // get_values_hook
247 fsb_acceptfocus, // accept_focus
248 XtVersion, // version
249 NULL, // callback_offsets
250 defaultTranslations, // tm_table
251 XtInheritQueryGeometry, // query_geometry
252 XtInheritDisplayAccelerator, // display_accelerator
253 NULL, // extension
254 },
255 // Composite Class
256 {
257 XtInheritGeometryManager, // geometry_manager
258 XtInheritChangeManaged, // change_managed
259 fsb_insert_child, // insert_child
260 XtInheritDeleteChild, // delete_child
261 NULL, // extension
262 },
263 // Constraint Class
264 {
265 constraints, // resources
266 XtNumber(constraints), // num_resources
267 sizeof(XmFormConstraintRec), // constraint_size
268 NULL, // initialize
269 NULL, // destroy
270 NULL, // set_value
271 NULL, // extension
272 },
273 // XmManager Class
274 {
275 XtInheritTranslations, // translations
276 NULL, // syn_resources
277 0, // num_syn_resources
278 NULL, // syn_constraint_resources
279 0, // num_syn_constraint_resources
280 XmInheritParentProcess, // parent_process
281 NULL // extension
282 },
283 // XmBulletinBoard
284 {
285 FALSE,
286 NULL,
287 XmInheritFocusMovedProc,
288 NULL
289 },
290 // XmForm Class
291 {
292 NULL
293 },
294 // FSB Class
295 {
296 0
297 }
298 };
299
300 WidgetClass xnFsbWidgetClass = (WidgetClass)&fsbWidgetClassRec;
301
302
303 static void fsb_class_init(void) {
304
305 }
306
307 static void fsb_class_part_init (WidgetClass wc) {
308 FSBClassRec *fsbClass = (FSBClassRec*)wc;
309 XmFormClassRec *formClass = (XmFormClassRec*)xmFormWidgetClass;
310
311 fsbClass->constraint_class.initialize = formClass->constraint_class.initialize;
312 fsbClass->constraint_class.set_values = formClass->constraint_class.set_values;
313 }
314
315
316 #define STRDUP_RES(a) if(a) a = strdup(a)
317 #define XMS_STRDUP_RES(a) if(a) a = XmStringCopy(a)
318
319 static void fsb_init(Widget request, Widget neww, ArgList args, Cardinal *num_args) {
320 XnFileSelectionBox fsb = (XnFileSelectionBox)neww;
321 (xmFormClassRec.core_class.initialize)(request, neww, args, num_args);
322
323 fsb->fsb.disable_set_values = 0;
324
325 STRDUP_RES(fsb->fsb.homePath);
326 STRDUP_RES(fsb->fsb.selectedPath);
327 STRDUP_RES(fsb->fsb.currentPath);
328 STRDUP_RES(fsb->fsb.filterStr);
329 STRDUP_RES(fsb->fsb.labelListView);
330 STRDUP_RES(fsb->fsb.labelDetailView);
331 STRDUP_RES(fsb->fsb.labelOpenFileTitle);
332 STRDUP_RES(fsb->fsb.labelSaveFileTitle);
333 XMS_STRDUP_RES(fsb->fsb.labelDirUp);
334 XMS_STRDUP_RES(fsb->fsb.labelHome);
335 XMS_STRDUP_RES(fsb->fsb.labelNewFolder);
336 XMS_STRDUP_RES(fsb->fsb.labelFilterButton);
337 XMS_STRDUP_RES(fsb->fsb.labelShowHiddenFiles);
338 XMS_STRDUP_RES(fsb->fsb.labelDirectories);
339 XMS_STRDUP_RES(fsb->fsb.labelFiles);
340 XMS_STRDUP_RES(fsb->fsb.labelRename);
341 XMS_STRDUP_RES(fsb->fsb.labelDelete);
342 XMS_STRDUP_RES(fsb->fsb.labelOpen);
343 XMS_STRDUP_RES(fsb->fsb.labelSave);
344 XMS_STRDUP_RES(fsb->fsb.labelCancel);
345 XMS_STRDUP_RES(fsb->fsb.labelHelp);
346 XMS_STRDUP_RES(fsb->fsb.labelFileName);
347 XMS_STRDUP_RES(fsb->fsb.labelDirectoryName);
348 XMS_STRDUP_RES(fsb->fsb.labelNewFileName);
349 STRDUP_RES(fsb->fsb.labelDeleteFile);
350 STRDUP_RES(fsb->fsb.detailHeadings);
351 STRDUP_RES(fsb->fsb.dateFormatSameYear);
352 STRDUP_RES(fsb->fsb.dateFormatOtherYear);
353 STRDUP_RES(fsb->fsb.suffixBytes);
354 STRDUP_RES(fsb->fsb.suffixKB);
355 STRDUP_RES(fsb->fsb.suffixMB);
356 STRDUP_RES(fsb->fsb.suffixGB);
357 STRDUP_RES(fsb->fsb.suffixTB);
358 STRDUP_RES(fsb->fsb.errorTitle);
359 STRDUP_RES(fsb->fsb.errorIllegalChar);
360 STRDUP_RES(fsb->fsb.errorRename);
361 STRDUP_RES(fsb->fsb.errorFolder);
362 STRDUP_RES(fsb->fsb.errorDelete);
363 STRDUP_RES(fsb->fsb.errorOpenDir);
364
365 CreateUI((XnFileSelectionBox)fsb);
366
367 XtAddCallback(neww, XmNmapCallback, fsb_mapcb, NULL);
368 }
369
370 #define STR_FREE(a) if(a) free(a)
371 #define XMSTR_FREE(a) if(a) XmStringFree(a)
372
373 static void fsb_destroy(Widget widget) {
374 XnFileSelectionBox w = (XnFileSelectionBox)widget;
375
376 // destroy all views
377 for(int i=0;i<w->fsb.numviews;i++) {
378 FSBView v = w->fsb.view[i];
379 v.destroy(widget, v.widget, v.userData);
380 }
381
382 STR_FREE(w->fsb.homePath);
383
384 // free filelists
385 filedialog_cleanup_filedata(w);
386 STR_FREE(w->fsb.currentPath);
387 STR_FREE(w->fsb.selectedPath);
388 STR_FREE(w->fsb.filterStr);
389
390 PathBarDestroy(w->fsb.pathBar);
391
392 // free strings
393 STR_FREE(w->fsb.labelListView);
394 STR_FREE(w->fsb.labelDetailView);
395 STR_FREE(w->fsb.labelOpenFileTitle);
396 STR_FREE(w->fsb.labelSaveFileTitle);
397
398 XMSTR_FREE(w->fsb.labelDirUp);
399 XMSTR_FREE(w->fsb.labelHome);
400 XMSTR_FREE(w->fsb.labelNewFolder);
401 XMSTR_FREE(w->fsb.labelFilterButton);
402 XMSTR_FREE(w->fsb.labelShowHiddenFiles);
403 XMSTR_FREE(w->fsb.labelDirectories);
404 XMSTR_FREE(w->fsb.labelFiles);
405 XMSTR_FREE(w->fsb.labelRename);
406 XMSTR_FREE(w->fsb.labelDelete);
407 XMSTR_FREE(w->fsb.labelOpen);
408 XMSTR_FREE(w->fsb.labelSave);
409 XMSTR_FREE(w->fsb.labelCancel);
410 XMSTR_FREE(w->fsb.labelHelp);
411 XMSTR_FREE(w->fsb.labelFileName);
412 XMSTR_FREE(w->fsb.labelDirectoryName);
413 XMSTR_FREE(w->fsb.labelNewFileName);
414 STR_FREE(w->fsb.labelDeleteFile);
415 STR_FREE(w->fsb.detailHeadings);
416
417 STR_FREE(w->fsb.dateFormatSameYear);
418 STR_FREE(w->fsb.dateFormatOtherYear);
419 STR_FREE(w->fsb.suffixBytes);
420 STR_FREE(w->fsb.suffixKB);
421 STR_FREE(w->fsb.suffixMB);
422 STR_FREE(w->fsb.suffixGB);
423 STR_FREE(w->fsb.suffixTB);
424
425 STR_FREE(w->fsb.errorTitle);
426 STR_FREE(w->fsb.errorIllegalChar);
427 STR_FREE(w->fsb.errorRename);
428 STR_FREE(w->fsb.errorFolder);
429 STR_FREE(w->fsb.errorDelete);
430 STR_FREE(w->fsb.errorOpenDir);
431 }
432
433 static void fsb_resize(Widget widget) {
434 XnFileSelectionBox w = (XnFileSelectionBox)widget;
435 (xmFormClassRec.core_class.resize)(widget);
436
437 #ifdef FSB_ENABLE_DETAIL
438 if(w->fsb.view[w->fsb.selectedview].update == FileListDetailUpdate) {
439 FileListDetailAdjustColWidth(w->fsb.grid);
440 }
441 #endif
442 }
443
444 static void fsb_realize(Widget widget, XtValueMask *mask, XSetWindowAttributes *attributes) {
445 XnFileSelectionBox w = (XnFileSelectionBox)widget;
446 (xmFormClassRec.core_class.realize)(widget, mask, attributes);
447
448 FSBView view = w->fsb.view[w->fsb.selectedview];
449 XmProcessTraversal(view.focus, XmTRAVERSE_CURRENT);
450
451 #ifdef FSB_ENABLE_DETAIL
452 if(w->fsb.view[w->fsb.selectedview].update == FileListDetailUpdate) {
453 FileListDetailAdjustColWidth(w->fsb.grid);
454 }
455 #endif
456 }
457
458 static void FSBUpdateTitle(Widget w) {
459 if(XtParent(w)->core.widget_class == xmDialogShellWidgetClass) {
460 char *title = FSBDialogTitle(w);
461 XtVaSetValues(XtParent(w), XmNtitle, title, NULL);
462 }
463 }
464
465 static Boolean fsb_set_values(Widget old, Widget request, Widget neww, ArgList args, Cardinal *num_args) {
466 Boolean r = False;
467
468 XnFileSelectionBox o = (XnFileSelectionBox)old;
469 XnFileSelectionBox n = (XnFileSelectionBox)neww;
470
471 int setOkBtnLabel = 0;
472 int ismanaged = XtIsManaged(neww);
473 Dimension width, height;
474 if(!ismanaged) {
475 width = n->core.width;
476 height = n->core.height;
477 if(n->fsb.pathBar) {
478 n->fsb.pathBar->disableResize = True;
479 }
480 }
481
482 if(o->fsb.selectedview != n->fsb.selectedview) {
483 int selectedview = n->fsb.selectedview;
484 n->fsb.selectedview = o->fsb.selectedview;
485 SelectView(n, selectedview);
486 }
487
488 char *updateDir = NULL;
489 int selectItem = 0;
490 if(o->fsb.selectedPath != n->fsb.selectedPath) {
491 STR_FREE(o->fsb.selectedPath);
492 STRDUP_RES(n->fsb.selectedPath);
493 XmTextFieldSetString(n->fsb.name, FileName(n->fsb.selectedPath));
494 // also update current directory
495 updateDir = ParentPath(n->fsb.selectedPath);
496 selectItem = 1;
497 }
498 if(o->fsb.currentPath != n->fsb.currentPath) {
499 STR_FREE(o->fsb.currentPath);
500 updateDir = strdup(n->fsb.currentPath);
501 n->fsb.currentPath = NULL;
502 }
503
504 if(o->fsb.filterStr != n->fsb.filterStr) {
505 STR_FREE(o->fsb.filterStr);
506 STRDUP_RES(n->fsb.filterStr);
507 XmTextFieldSetString(XmDropDownGetText(n->fsb.filter), n->fsb.filterStr);
508 if(!updateDir) {
509 filedialog_update_dir(n, NULL);
510 }
511 }
512
513 if(updateDir) {
514 filedialog_update_dir(n, updateDir);
515 PathBarSetPath(n->fsb.pathBar, updateDir);
516 free(updateDir);
517 }
518
519 if(o->fsb.type != n->fsb.type) {
520 if(n->fsb.type == FILEDIALOG_OPEN) {
521 XtVaSetValues(n->fsb.workarea, XmNbottomWidget, n->fsb.separator, NULL);
522 XtUnmanageChild(n->fsb.name);
523 XtUnmanageChild(n->fsb.nameLabel);
524 } else {
525 XtManageChild(n->fsb.name);
526 XtManageChild(n->fsb.nameLabel);
527 XtVaSetValues(n->fsb.workarea, XmNbottomWidget, n->fsb.nameLabel, NULL);
528 }
529 FSBUpdateTitle(neww);
530 setOkBtnLabel = 1;
531 }
532
533 // label strings
534 int updateTitle = 0;
535 if(o->fsb.labelListView != n->fsb.labelListView) {
536 STR_FREE(o->fsb.labelListView);
537 STRDUP_RES(n->fsb.labelListView);
538 XmString label = XmStringCreateLocalized(n->fsb.labelListView);
539 XtVaSetValues(n->fsb.viewSelectorList, XmNlabelString, label, NULL);
540 XmStringFree(label);
541 }
542 if(o->fsb.labelDetailView != n->fsb.labelDetailView) {
543 STR_FREE(o->fsb.labelDetailView);
544 STRDUP_RES(n->fsb.labelDetailView);
545 XmString label = XmStringCreateLocalized(n->fsb.labelDetailView);
546 XtVaSetValues(n->fsb.viewSelectorDetail, XmNlabelString, label, NULL);
547 if(n->fsb.detailToggleButton) {
548 XtVaSetValues(n->fsb.detailToggleButton, XmNlabelString, label, NULL);
549 }
550 XmStringFree(label);
551 }
552 if(o->fsb.labelOpenFileTitle != n->fsb.labelOpenFileTitle) {
553 STR_FREE(o->fsb.labelOpenFileTitle);
554 STRDUP_RES(n->fsb.labelOpenFileTitle);
555 updateTitle = 1;
556 }
557 if(o->fsb.labelSaveFileTitle != n->fsb.labelSaveFileTitle) {
558 STR_FREE(o->fsb.labelSaveFileTitle);
559 STRDUP_RES(n->fsb.labelSaveFileTitle);
560 updateTitle = 1;
561 }
562
563 if(o->fsb.labelDirUp != n->fsb.labelDirUp) {
564 XMSTR_FREE(o->fsb.labelDirUp);
565 XMS_STRDUP_RES(n->fsb.labelDirUp);
566 XtVaSetValues(n->fsb.dirUp, XmNlabelString, n->fsb.labelDirUp, NULL);
567 }
568 if(o->fsb.labelHome != n->fsb.labelHome) {
569 XMSTR_FREE(o->fsb.labelHome);
570 XMS_STRDUP_RES(n->fsb.labelHome);
571 XtVaSetValues(n->fsb.dirUp, XmNlabelString, n->fsb.labelHome, NULL);
572 }
573 if(o->fsb.labelNewFolder != n->fsb.labelNewFolder) {
574 XMSTR_FREE(o->fsb.labelNewFolder);
575 XMS_STRDUP_RES(n->fsb.labelNewFolder);
576 XtVaSetValues(n->fsb.newFolder, XmNlabelString, n->fsb.labelNewFolder, NULL);
577 }
578 if(o->fsb.labelFilterButton != n->fsb.labelFilterButton) {
579 XMSTR_FREE(o->fsb.labelFilterButton);
580 XMS_STRDUP_RES(n->fsb.labelFilterButton);
581 XtVaSetValues(n->fsb.filterButton, XmNlabelString, n->fsb.labelFilterButton, NULL);
582 }
583 if(o->fsb.labelShowHiddenFiles != n->fsb.labelShowHiddenFiles) {
584 XMSTR_FREE(o->fsb.labelShowHiddenFiles);
585 XMS_STRDUP_RES(n->fsb.labelShowHiddenFiles);
586 XtVaSetValues(n->fsb.showHiddenButtonW, XmNlabelString, n->fsb.labelShowHiddenFiles, NULL);
587 }
588 if(o->fsb.labelDirectories != n->fsb.labelDirectories) {
589 XMSTR_FREE(o->fsb.labelDirectories);
590 XMS_STRDUP_RES(n->fsb.labelDirectories);
591 XtVaSetValues(n->fsb.lsDirLabel, XmNlabelString, n->fsb.labelDirectories, NULL);
592 }
593 if(o->fsb.labelFiles != n->fsb.labelFiles) {
594 XMSTR_FREE(o->fsb.labelFiles);
595 XMS_STRDUP_RES(n->fsb.labelFiles);
596 XtVaSetValues(n->fsb.lsFileLabel, XmNlabelString, n->fsb.labelFiles, NULL);
597 }
598 int recreateContextMenu = 0;
599 if(o->fsb.labelRename != n->fsb.labelRename) {
600 XMSTR_FREE(o->fsb.labelRename);
601 XMS_STRDUP_RES(n->fsb.labelRename);
602 recreateContextMenu = 1;
603 }
604 if(o->fsb.labelDelete != n->fsb.labelDelete) {
605 XMSTR_FREE(o->fsb.labelDelete);
606 XMS_STRDUP_RES(n->fsb.labelDelete);
607 recreateContextMenu = 1;
608 }
609
610 if(o->fsb.labelOpen != n->fsb.labelOpen) {
611 XMSTR_FREE(o->fsb.labelOpen);
612 XMS_STRDUP_RES(n->fsb.labelOpen);
613 setOkBtnLabel = 1;
614 }
615 if(o->fsb.labelSave != n->fsb.labelSave) {
616 XMSTR_FREE(o->fsb.labelSave);
617 XMS_STRDUP_RES(n->fsb.labelSave);
618 setOkBtnLabel = 1;
619 }
620 if(o->fsb.labelCancel != n->fsb.labelCancel) {
621 XMSTR_FREE(o->fsb.labelCancel);
622 XMS_STRDUP_RES(n->fsb.labelCancel);
623 XtVaSetValues(n->fsb.cancelBtn, XmNlabelString, n->fsb.labelCancel, NULL);
624 }
625 if(o->fsb.labelHelp != n->fsb.labelHelp) {
626 XMSTR_FREE(o->fsb.labelHelp);
627 XMS_STRDUP_RES(n->fsb.labelHelp);
628 XtVaSetValues(n->fsb.helpBtn, XmNlabelString, n->fsb.labelHelp, NULL);
629 }
630 if(o->fsb.labelFileName != n->fsb.labelFileName) {
631 XMSTR_FREE(o->fsb.labelFileName);
632 XMS_STRDUP_RES(n->fsb.labelFileName);
633 XtVaSetValues(n->fsb.nameLabel, XmNlabelString, n->fsb.labelFileName, NULL);
634 }
635 if(o->fsb.labelDirectoryName != n->fsb.labelDirectoryName) {
636 XMSTR_FREE(o->fsb.labelDirectoryName);
637 XMS_STRDUP_RES(n->fsb.labelDirectoryName);
638 }
639 if(o->fsb.labelNewFileName != n->fsb.labelNewFileName) {
640 XMSTR_FREE(o->fsb.labelNewFileName);
641 XMS_STRDUP_RES(n->fsb.labelNewFileName);
642 }
643
644 if(o->fsb.labelDeleteFile != n->fsb.labelDeleteFile) {
645 STR_FREE(o->fsb.labelDeleteFile);
646 STRDUP_RES(n->fsb.labelDeleteFile);
647 }
648 #ifdef FSB_ENABLE_DETAIL
649 if(o->fsb.detailHeadings != n->fsb.detailHeadings) {
650 STR_FREE(o->fsb.detailHeadings);
651 STRDUP_RES(n->fsb.detailHeadings);
652 XtVaSetValues(n->fsb.grid, XmNsimpleHeadings, n->fsb.detailHeadings, NULL);
653 }
654 #endif
655 if(o->fsb.dateFormatSameYear != n->fsb.dateFormatSameYear) {
656 STR_FREE(o->fsb.dateFormatSameYear);
657 STRDUP_RES(n->fsb.dateFormatSameYear);
658 }
659 if(o->fsb.dateFormatOtherYear != n->fsb.dateFormatOtherYear) {
660 STR_FREE(o->fsb.dateFormatOtherYear);
661 STRDUP_RES(n->fsb.dateFormatOtherYear);
662 }
663 if(o->fsb.suffixBytes != n->fsb.suffixBytes) {
664 STR_FREE(o->fsb.suffixBytes);
665 STRDUP_RES(n->fsb.suffixBytes);
666 }
667 if(o->fsb.suffixMB != n->fsb.suffixMB) {
668 STR_FREE(o->fsb.suffixMB);
669 STRDUP_RES(n->fsb.suffixMB);
670 }
671 if(o->fsb.suffixGB != n->fsb.suffixGB) {
672 STR_FREE(o->fsb.suffixGB);
673 STRDUP_RES(n->fsb.suffixGB);
674 }
675 if(o->fsb.suffixTB != n->fsb.suffixTB) {
676 STR_FREE(o->fsb.suffixTB);
677 STRDUP_RES(n->fsb.suffixTB);
678 }
679 if(o->fsb.errorTitle != n->fsb.errorTitle) {
680 STR_FREE(o->fsb.errorTitle);
681 STRDUP_RES(n->fsb.errorTitle);
682 }
683 if(o->fsb.errorIllegalChar != n->fsb.errorIllegalChar) {
684 STR_FREE(o->fsb.errorIllegalChar);
685 STRDUP_RES(n->fsb.errorIllegalChar);
686 }
687 if(o->fsb.errorRename != n->fsb.errorRename) {
688 STR_FREE(o->fsb.errorRename);
689 STRDUP_RES(n->fsb.errorRename);
690 }
691 if(o->fsb.errorFolder != n->fsb.errorFolder) {
692 STR_FREE(o->fsb.errorFolder);
693 STRDUP_RES(n->fsb.errorFolder);
694 }
695 if(o->fsb.errorDelete != n->fsb.errorDelete) {
696 STR_FREE(o->fsb.errorDelete);
697 STRDUP_RES(n->fsb.errorDelete);
698 }
699 if(o->fsb.errorOpenDir != n->fsb.errorOpenDir) {
700 STR_FREE(o->fsb.errorOpenDir);
701 STRDUP_RES(n->fsb.errorOpenDir);
702 }
703
704 if(updateTitle) {
705 FSBUpdateTitle(neww);
706 }
707 if(recreateContextMenu) {
708 XtDestroyWidget(n->fsb.listContextMenu);
709 XtDestroyWidget(n->fsb.gridContextMenu);
710 n->fsb.listContextMenu = CreateContextMenu(n, n->fsb.filelist, FileContextMenuCB);
711 n->fsb.gridContextMenu = CreateContextMenu(n, n->fsb.grid, FileContextMenuCB);
712 }
713 if(setOkBtnLabel) {
714 XtVaSetValues(n->fsb.okBtn, XmNlabelString, n->fsb.type == FILEDIALOG_OPEN ? n->fsb.labelOpen : n->fsb.labelSave, NULL);
715 }
716
717 if(!ismanaged && !n->fsb.disable_set_values) {
718 n->fsb.disable_set_values = 1;
719 XtVaSetValues(neww, XmNwidth, width, XmNheight, height, NULL);
720 n->fsb.disable_set_values = 0;
721
722 if(n->fsb.pathBar)
723 n->fsb.pathBar->disableResize = False;
724 }
725
726 if(selectItem) {
727 if(ismanaged) {
728 FSBSelectItem(n, FileName(n->fsb.selectedPath));
729 }
730 }
731
732 Boolean fr = (xmFormClassRec.core_class.set_values)(old, request, neww, args, num_args);
733 return fr ? fr : r;
734 }
735
736 static void fsb_insert_child(Widget child) {
737 XnFileSelectionBox p = (XnFileSelectionBox)XtParent(child);
738 (xmFormClassRec.composite_class.insert_child)(child);
739
740 if(!p->fsb.gui_created) {
741 return;
742 }
743
744 // custom child widget insert
745 XtVaSetValues(child,
746 XmNbottomAttachment, XmATTACH_WIDGET,
747 XmNbottomWidget, p->fsb.bottom_widget,
748 XmNbottomOffset, p->fsb.widgetSpacing,
749 XmNleftAttachment, XmATTACH_FORM,
750 XmNleftOffset, p->fsb.windowSpacing,
751 XmNrightAttachment, XmATTACH_FORM,
752 XmNrightAttachment, XmATTACH_FORM,
753 XmNrightOffset, p->fsb.windowSpacing,
754 NULL);
755
756
757 XtVaSetValues(p->fsb.listform,
758 XmNbottomWidget, child,
759 XmNbottomOffset, 0,
760 NULL);
761
762 p->fsb.workarea = child;
763 }
764
765 Boolean fsb_acceptfocus(Widget widget, Time *time) {
766 return 0;
767 }
768
769 static void fsb_mapcb(Widget widget, XtPointer u, XtPointer cb) {
770 XnFileSelectionBox w = (XnFileSelectionBox)widget;
771 pathbar_resize(w->fsb.pathBar->widget, w->fsb.pathBar, NULL);
772
773 if(w->fsb.type == FILEDIALOG_OPEN) {
774 FSBView view = w->fsb.view[w->fsb.selectedview];
775 XmProcessTraversal(view.focus, XmTRAVERSE_CURRENT);
776 } else {
777 XmProcessTraversal(w->fsb.name, XmTRAVERSE_CURRENT);
778 }
779
780
781 if(w->fsb.selectedPath) {
782 FSBSelectItem(w, FileName(w->fsb.selectedPath));
783 }
784 }
785
786 static void FocusInAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) {
787
788 }
789
790 static int apply_filter(XnFileSelectionBox w, const char *pattern, const char *string) {
791 if(!pattern) return 0;
792
793 FSBFilterFunc func = w->fsb.filterFunc ? w->fsb.filterFunc : FSBGlobFilter;
794 return func(pattern, string);
795 }
796
797 static int FSBGlobFilter(const char *a, const char *b) {
798 return fnmatch(a, b, 0);
799 }
800
801
802 static void errCB(Widget w, XtPointer d, XtPointer cbs) {
803 XtDestroyWidget(w);
804 }
805
806 static void ErrDialog(XnFileSelectionBox w, const char *title, const char *errmsg) {
807 Arg args[16];
808 int n = 0;
809
810 XmString titleStr = XmStringCreateLocalized((char*)title);
811 XmString msg = XmStringCreateLocalized((char*)errmsg);
812
813 XtSetArg(args[n], XmNdialogTitle, titleStr); n++;
814 XtSetArg(args[n], XmNselectionLabelString, msg); n++;
815 XtSetArg(args[n], XmNokLabelString, w->fsb.labelOk); n++;
816 XtSetArg(args[n], XmNcancelLabelString, w->fsb.labelCancel); n++;
817
818 Widget dialog = XmCreatePromptDialog ((Widget)w, "NewFolderPrompt", args, n);
819
820 Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
821 XtUnmanageChild(help);
822 Widget cancel = XmSelectionBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON);
823 XtUnmanageChild(cancel);
824 Widget text = XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT);
825 XtUnmanageChild(text);
826
827 XtAddCallback(dialog, XmNokCallback, errCB, NULL);
828
829 XtManageChild(dialog);
830
831 XmStringFree(titleStr);
832 XmStringFree(msg);
833 }
834
835 static void rename_file_cb(Widget w, const char *path, XmSelectionBoxCallbackStruct *cb) {
836 XnFileSelectionBox fsb = NULL;
837 XtVaGetValues(w, XmNuserData, &fsb, NULL);
838
839 char *fileName = NULL;
840 XmStringGetLtoR(cb->value, XmSTRING_DEFAULT_CHARSET, &fileName);
841
842 // make sure the new file name doesn't contain a path separator
843 if(strchr(fileName, '/')) {
844 ErrDialog(fsb, fsb->fsb.errorTitle, fsb->fsb.errorIllegalChar);
845 XtFree(fileName);
846 return;
847 }
848
849 char *parentPath = ParentPath(path);
850 char *newPath = ConcatPath(parentPath, fileName);
851
852 if(rename(path, newPath)) {
853 char errmsg[256];
854 snprintf(errmsg, 256, fsb->fsb.errorRename, strerror(errno));
855 ErrDialog(fsb, fsb->fsb.errorTitle, errmsg);
856 } else {
857 filedialog_update_dir(fsb, parentPath);
858 }
859
860 free(parentPath);
861 free(newPath);
862 XtFree(fileName);
863 XtDestroyWidget(XtParent(w));
864 }
865
866 static void selectionbox_cancel(Widget w, XtPointer data, XtPointer d) {
867 XtDestroyWidget(XtParent(w));
868 }
869
870 static void FSBRename(XnFileSelectionBox fsb, const char *path) {
871 Arg args[16];
872 int n = 0;
873 Widget w = (Widget)fsb;
874
875 char *name = FileName((char*)path);
876
877 XmString filename = XmStringCreateLocalized(name);
878 XtSetArg(args[n], XmNselectionLabelString,fsb->fsb.labelNewFileName); n++;
879 XtSetArg(args[n], XmNtextString, filename); n++;
880 XtSetArg(args[n], XmNuserData, fsb); n++;
881 XtSetArg(args[n], XmNdialogTitle, fsb->fsb.labelRename); n++;
882 XtSetArg(args[n], XmNokLabelString, fsb->fsb.labelOk); n++;
883 XtSetArg(args[n], XmNcancelLabelString, fsb->fsb.labelCancel); n++;
884 Widget dialog = XmCreatePromptDialog (w, "RenameFilePrompt", args, n);
885
886 Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
887 XtUnmanageChild(help);
888
889 XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)rename_file_cb, (char*)path);
890 XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)selectionbox_cancel, NULL);
891
892 XmStringFree(filename);
893 XtManageChild(dialog);
894 }
895
896 static void delete_file_cb(Widget w, const char *path, XmSelectionBoxCallbackStruct *cb) {
897 XnFileSelectionBox fsb = NULL;
898 XtVaGetValues(w, XmNuserData, &fsb, NULL);
899
900 if(unlink(path)) {
901 char errmsg[256];
902 snprintf(errmsg, 256, fsb->fsb.errorDelete, strerror(errno));
903 ErrDialog(fsb, fsb->fsb.errorTitle, errmsg);
904 } else {
905 char *parentPath = ParentPath(path);
906 filedialog_update_dir(fsb, parentPath);
907 free(parentPath);
908 }
909
910 XtDestroyWidget(XtParent(w));
911 }
912
913 static void FSBDelete(XnFileSelectionBox fsb, const char *path) {
914 Arg args[16];
915 int n = 0;
916 Widget w = (Widget)fsb;
917
918 char *name = FileName((char*)path);
919 size_t len = strlen(name);
920 size_t msglen = len + strlen(fsb->fsb.labelDeleteFile) + 4;
921 char *msg = malloc(msglen);
922 snprintf(msg, msglen, fsb->fsb.labelDeleteFile, name);
923
924 XmString prompt = XmStringCreateLocalized(msg);
925 XtSetArg(args[n], XmNselectionLabelString, prompt); n++;
926 XtSetArg(args[n], XmNuserData, fsb); n++;
927 XtSetArg(args[n], XmNdialogTitle, fsb->fsb.labelDelete); n++;
928 XtSetArg(args[n], XmNokLabelString, fsb->fsb.labelOk); n++;
929 XtSetArg(args[n], XmNcancelLabelString, fsb->fsb.labelCancel); n++;
930 Widget dialog = XmCreatePromptDialog (w, "DeleteFilePrompt", args, n);
931
932 Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
933 XtUnmanageChild(help);
934 Widget text = XmSelectionBoxGetChild(dialog, XmDIALOG_TEXT);
935 XtUnmanageChild(text);
936
937 XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)delete_file_cb, (char*)path);
938 XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)selectionbox_cancel, NULL);
939
940 free(msg);
941 XmStringFree(prompt);
942 XtManageChild(dialog);
943 }
944
945 static void FSBSelectItem(XnFileSelectionBox fsb, const char *item) {
946 FSBView view = fsb->fsb.view[fsb->fsb.selectedview];
947 if(view.select) {
948 view.select((Widget)fsb, view.widget, item);
949 }
950 }
951
952 static char* set_selected_path(XnFileSelectionBox data, XmString item)
953 {
954 char *name = NULL;
955 XmStringGetLtoR(item, XmFONTLIST_DEFAULT_TAG, &name);
956 if(!name) {
957 return NULL;
958 }
959 char *path = ConcatPath(data->fsb.currentPath, name);
960 XtFree(name);
961
962 if(data->fsb.selectedPath) {
963 free(data->fsb.selectedPath);
964 }
965 data->fsb.selectedPath = path;
966
967 return path;
968 }
969
970 // item0: rename
971 // item1: delete
972 static void FileContextMenuCB(Widget item, XtPointer index, XtPointer cd) {
973 intptr_t i = (intptr_t)index;
974 Widget parent = XtParent(item);
975 XnFileSelectionBox fsb = NULL;
976 XtVaGetValues(parent, XmNuserData, &fsb, NULL);
977
978 const char *path = fsb->fsb.selectedPath;
979 if(path) {
980 if(i == 0) {
981 FSBRename(fsb, path);
982 } else if(i == 1) {
983 FSBDelete(fsb, path);
984 }
985 }
986 }
987
988 static Widget CreateContextMenu(XnFileSelectionBox fsb, Widget parent, XtCallbackProc callback) {
989 return XmVaCreateSimplePopupMenu(
990 parent, "popup", callback, XmNpopupEnabled, XmPOPUP_AUTOMATIC,
991 XmNuserData, fsb,
992 XmVaPUSHBUTTON, fsb->fsb.labelRename, 'R', NULL, NULL,
993 XmVaPUSHBUTTON, fsb->fsb.labelDelete, 'D', NULL, NULL,
994 NULL);
995 }
996
997
998 static void FileListUpdate(Widget fsb, Widget view, FileElm *dirs, int dircount, FileElm *files, int filecount, const char *filter, int maxnamelen, void *userData) {
999 XnFileSelectionBox data = userData;
1000 FileListWidgetAdd(data, data->fsb.filelist, data->fsb.showHidden, filter, files, filecount);
1001 }
1002
1003 static void FileListSelect(Widget fsb, Widget view, const char *item) {
1004 XnFileSelectionBox w = (XnFileSelectionBox)fsb;
1005
1006 int numItems = 0;
1007 XmStringTable items = NULL;
1008 XtVaGetValues(w->fsb.filelist, XmNitemCount, &numItems, XmNitems, &items, NULL);
1009
1010 for(int i=0;i<numItems;i++) {
1011 char *str = NULL;
1012 XmStringGetLtoR(items[i], XmFONTLIST_DEFAULT_TAG, &str);
1013 if(!strcmp(str, item)) {
1014 XmListSelectPos(w->fsb.filelist, i+1, False);
1015 break;
1016 }
1017 XtFree(str);
1018 }
1019 }
1020
1021 static void FileListCleanup(Widget fsb, Widget view, void *userData) {
1022 XnFileSelectionBox data = userData;
1023 XmListDeleteAllItems(data->fsb.filelist);
1024 }
1025
1026 static void FileListDestroy(Widget fsb, Widget view, void *userData) {
1027 // unused
1028 }
1029
1030 static void FileListActivateCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
1031 {
1032 char *path = set_selected_path(data, cb->item);
1033 if(path) {
1034 data->fsb.end = True;
1035 data->fsb.status = FILEDIALOG_OK;
1036 data->fsb.selIsDir = False;
1037 FileSelectionCallback(data, data->fsb.okCallback, XmCR_OK, data->fsb.selectedPath);
1038 }
1039 }
1040
1041 static void FileListSelectCB(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
1042 {
1043 if(data->fsb.type == FILEDIALOG_SAVE) {
1044 char *name = NULL;
1045 XmStringGetLtoR(cb->item, XmFONTLIST_DEFAULT_TAG, &name);
1046 XmTextFieldSetString(data->fsb.name, name);
1047 XtFree(name);
1048 } else {
1049 char *path = set_selected_path(data, cb->item);
1050 if(path) {
1051 data->fsb.selIsDir = False;
1052 }
1053 }
1054 }
1055
1056
1057 static void FileListWidgetAdd(XnFileSelectionBox fsb, Widget w, int showHidden, const char *filter, FileElm *ls, int count)
1058 {
1059 if(count > 0) {
1060 XmStringTable items = calloc(count, sizeof(XmString));
1061 int i = 0;
1062
1063 for(int j=0;j<count;j++) {
1064 FileElm *e = &ls[j];
1065
1066 char *name = FileName(e->path);
1067 if((!showHidden && name[0] == '.') || apply_filter(fsb, filter, name)) {
1068 continue;
1069 }
1070
1071 items[i] = XmStringCreateLocalized(name);
1072 i++;
1073 }
1074 XmListAddItems(w, items, i, 0);
1075 for(i=0;i<count;i++) {
1076 XmStringFree(items[i]);
1077 }
1078 free(items);
1079 }
1080 }
1081
1082 #ifdef FSB_ENABLE_DETAIL
1083 static void FileListDetailUpdate(Widget fsb, Widget view, FileElm *dirs, int dircount, FileElm *files, int filecount, const char *filter, int maxnamelen, void *userData) {
1084 XnFileSelectionBox data = userData;
1085 FileListDetailAdd(data, data->fsb.grid, data->fsb.showHidden, filter, files, filecount, maxnamelen);
1086 }
1087 #endif
1088
1089 /*
1090 * create file size string with kb/mb/gb/tb suffix
1091 */
1092 static char* size_str(XnFileSelectionBox fsb, FileElm *f) {
1093 char *str = malloc(16);
1094 uint64_t size = f->size;
1095
1096 if(f->isDirectory) {
1097 str[0] = '\0';
1098 } else if(size < 0x400) {
1099 snprintf(str, 16, "%d %s", (int)size, fsb->fsb.suffixBytes);
1100 } else if(size < 0x100000) {
1101 float s = (float)size/0x400;
1102 int diff = (s*100 - (int)s*100);
1103 if(diff > 90) {
1104 diff = 0;
1105 s += 0.10f;
1106 }
1107 if(size < 0x2800 && diff != 0) {
1108 // size < 10 KiB
1109 snprintf(str, 16, "%.1f %s", s, fsb->fsb.suffixKB);
1110 } else {
1111 snprintf(str, 16, "%.0f %s", s, fsb->fsb.suffixKB);
1112 }
1113 } else if(size < 0x40000000) {
1114 float s = (float)size/0x100000;
1115 int diff = (s*100 - (int)s*100);
1116 if(diff > 90) {
1117 diff = 0;
1118 s += 0.10f;
1119 }
1120 if(size < 0xa00000 && diff != 0) {
1121 // size < 10 MiB
1122 snprintf(str, 16, "%.1f %s", s, fsb->fsb.suffixMB);
1123 } else {
1124 snprintf(str, 16, "%.0f %s", s, fsb->fsb.suffixMB);
1125 }
1126 } else if(size < 0x1000000000ULL) {
1127 float s = (float)size/0x40000000;
1128 int diff = (s*100 - (int)s*100);
1129 if(diff > 90) {
1130 diff = 0;
1131 s += 0.10f;
1132 }
1133 if(size < 0x280000000 && diff != 0) {
1134 // size < 10 GiB
1135 snprintf(str, 16, "%.1f %s", s, fsb->fsb.suffixGB);
1136 } else {
1137 snprintf(str, 16, "%.0f %s", s, fsb->fsb.suffixGB);
1138 }
1139 } else {
1140 size /= 1024;
1141 float s = (float)size/0x40000000;
1142 int diff = (s*100 - (int)s*100);
1143 if(diff > 90) {
1144 diff = 0;
1145 s += 0.10f;
1146 }
1147 if(size < 0x280000000 && diff != 0) {
1148 // size < 10 TiB
1149 snprintf(str, 16, "%.1f %s", s, fsb->fsb.suffixTB);
1150 } else {
1151 snprintf(str, 16, "%.0f %s", s, fsb->fsb.suffixTB);
1152 }
1153 }
1154 return str;
1155 }
1156
1157 static char* date_str(XnFileSelectionBox fsb, time_t tm) {
1158 struct tm t;
1159 struct tm n;
1160 time_t now = time(NULL);
1161
1162 localtime_r(&tm, &t);
1163 localtime_r(&now, &n);
1164
1165 char *str = malloc(24);
1166 if(t.tm_year == n.tm_year) {
1167 strftime(str, 24, fsb->fsb.dateFormatSameYear, &t);
1168 } else {
1169 strftime(str, 24, fsb->fsb.dateFormatOtherYear, &t);
1170 }
1171 return str;
1172 }
1173
1174 #ifdef FSB_ENABLE_DETAIL
1175 static void FileListDetailAdjustColWidth(Widget grid) {
1176 XmLGridColumn column0 = XmLGridGetColumn(grid, XmCONTENT, 0);
1177 XmLGridColumn column1 = XmLGridGetColumn(grid, XmCONTENT, 1);
1178 XmLGridColumn column2 = XmLGridGetColumn(grid, XmCONTENT, 2);
1179
1180 Dimension col0Width = XmLGridColumnWidthInPixels(column0);
1181 Dimension col1Width = XmLGridColumnWidthInPixels(column1);
1182 Dimension col2Width = XmLGridColumnWidthInPixels(column2);
1183
1184 Dimension totalWidth = col0Width + col1Width + col2Width;
1185
1186 Dimension gridWidth = 0;
1187 Dimension gridShadow = 0;
1188 XtVaGetValues(grid, XmNwidth, &gridWidth, XmNshadowThickness, &gridShadow, NULL);
1189
1190 Dimension widthDiff = gridWidth - totalWidth - gridShadow - gridShadow;
1191
1192 if(gridWidth > totalWidth) {
1193 XtVaSetValues(grid,
1194 XmNcolumnRangeStart, 0,
1195 XmNcolumnRangeEnd, 0,
1196 XmNcolumnWidth, col0Width + widthDiff - XmLGridVSBWidth(grid) - 2,
1197 XmNcolumnSizePolicy, XmCONSTANT,
1198 NULL);
1199 }
1200 }
1201
1202 static void FileListDetailAdd(XnFileSelectionBox fsb, Widget grid, int showHidden, const char *filter, FileElm *ls, int count, int maxWidth)
1203 {
1204 XmLGridAddRows(grid, XmCONTENT, 1, count);
1205
1206 int row = 0;
1207 for(int i=0;i<count;i++) {
1208 FileElm *e = &ls[i];
1209
1210 char *name = FileName(e->path);
1211 if((!showHidden && name[0] == '.') || (!e->isDirectory && apply_filter(fsb, filter, name))) {
1212 continue;
1213 }
1214
1215 // name
1216 XmString str = XmStringCreateLocalized(name);
1217 XtVaSetValues(grid,
1218 XmNcolumn, 0,
1219 XmNrow, row,
1220 XmNcellString, str, NULL);
1221 XmStringFree(str);
1222 // size
1223 char *szbuf = size_str(fsb, e);
1224 str = XmStringCreateLocalized(szbuf);
1225 XtVaSetValues(grid,
1226 XmNcolumn, 1,
1227 XmNrow, row,
1228 XmNcellString, str, NULL);
1229 free(szbuf);
1230 XmStringFree(str);
1231 // date
1232 char *datebuf = date_str(fsb, e->lastModified);
1233 str = XmStringCreateLocalized(datebuf);
1234 XtVaSetValues(grid,
1235 XmNcolumn, 2,
1236 XmNrow, row,
1237 XmNcellString, str, NULL);
1238 free(datebuf);
1239 XmStringFree(str);
1240
1241 XtVaSetValues(grid, XmNrow, row, XmNrowUserData, e, NULL);
1242 row++;
1243 }
1244
1245 // remove unused rows
1246 if(count > row) {
1247 XmLGridDeleteRows(grid, XmCONTENT, row, count-row);
1248 }
1249
1250 if(maxWidth < 16) {
1251 maxWidth = 16;
1252 }
1253
1254 XtVaSetValues(grid,
1255 XmNcolumnRangeStart, 0,
1256 XmNcolumnRangeEnd, 0,
1257 XmNcolumnWidth, maxWidth,
1258 XmNcellAlignment, XmALIGNMENT_LEFT,
1259 XmNcolumnSizePolicy, XmVARIABLE,
1260 NULL);
1261 XtVaSetValues(grid,
1262 XmNcolumnRangeStart, 1,
1263 XmNcolumnRangeEnd, 1,
1264 XmNcolumnWidth, 9,
1265 XmNcellAlignment, XmALIGNMENT_LEFT,
1266 XmNcolumnSizePolicy, XmVARIABLE,
1267 NULL);
1268 XtVaSetValues(grid,
1269 XmNcolumnRangeStart, 2,
1270 XmNcolumnRangeEnd, 2,
1271 XmNcolumnWidth, 16,
1272 XmNcellAlignment, XmALIGNMENT_RIGHT,
1273 XmNcolumnSizePolicy, XmVARIABLE,
1274 NULL);
1275
1276 FileListDetailAdjustColWidth(grid);
1277 }
1278
1279 static void FileListDetailSelect(Widget fsb, Widget view, const char *item) {
1280 XnFileSelectionBox w = (XnFileSelectionBox)fsb;
1281
1282 int numRows = 0;
1283 XtVaGetValues(w->fsb.grid, XmNrows, &numRows, NULL);
1284
1285 XmLGridColumn col = XmLGridGetColumn(w->fsb.grid, XmCONTENT, 0);
1286 for(int i=0;i<numRows;i++) {
1287 XmLGridRow row = XmLGridGetRow(w->fsb.grid, XmCONTENT, i);
1288 FileElm *elm = NULL;
1289 XtVaGetValues(w->fsb.grid, XmNrowPtr, row, XmNcolumnPtr, col, XmNrowUserData, &elm, NULL);
1290 if(elm) {
1291 if(!strcmp(item, FileName(elm->path))) {
1292 XmLGridSelectRow(w->fsb.grid, i, False);
1293 XmLGridFocusAndShowRow(w->fsb.grid, i+1);
1294 break;
1295 }
1296 }
1297 }
1298 }
1299
1300 static void FileListDetailCleanup(Widget fsb, Widget view, void *userData) {
1301 XnFileSelectionBox data = userData;
1302 // cleanup grid
1303 Cardinal rows = 0;
1304 XtVaGetValues(data->fsb.grid, XmNrows, &rows, NULL);
1305 XmLGridDeleteRows(data->fsb.grid, XmCONTENT, 0, rows);
1306 }
1307
1308 static void FileListDetailDestroy(Widget fsb, Widget view, void *userData) {
1309 // unused
1310 }
1311 #endif
1312
1313 static void create_folder(Widget w, XnFileSelectionBox data, XmSelectionBoxCallbackStruct *cbs) {
1314 char *fileName = NULL;
1315 XmStringGetLtoR(cbs->value, XmSTRING_DEFAULT_CHARSET, &fileName);
1316
1317 char *newFolder = ConcatPath(data->fsb.currentPath ? data->fsb.currentPath : "", fileName);
1318 if(mkdir(newFolder, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
1319 char errmsg[256];
1320 snprintf(errmsg, 256, data->fsb.errorFolder, strerror(errno));
1321 ErrDialog(data, data->fsb.errorTitle, errmsg);
1322 } else {
1323 char *p = strdup(data->fsb.currentPath);
1324 filedialog_update_dir(data, p);
1325 free(p);
1326 }
1327 free(newFolder);
1328
1329 XtDestroyWidget(XtParent(w));
1330 }
1331
1332 static void new_folder_cancel(Widget w, XnFileSelectionBox data, XtPointer d) {
1333 XtDestroyWidget(XtParent(w));
1334 }
1335
1336 static void FSBNewFolder(Widget w, XnFileSelectionBox data, XtPointer u)
1337 {
1338 Arg args[16];
1339 int n = 0;
1340
1341 XtSetArg(args[n], XmNdialogTitle, data->fsb.labelNewFolder); n++;
1342 XtSetArg (args[n], XmNselectionLabelString, data->fsb.labelDirectoryName); n++;
1343 XtSetArg(args[n], XmNokLabelString, data->fsb.labelOk); n++;
1344 XtSetArg(args[n], XmNcancelLabelString, data->fsb.labelCancel); n++;
1345 Widget dialog = XmCreatePromptDialog (w, "NewFolderPrompt", args, n);
1346
1347 Widget help = XmSelectionBoxGetChild(dialog, XmDIALOG_HELP_BUTTON);
1348 XtUnmanageChild(help);
1349
1350 XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)create_folder, data);
1351 XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)new_folder_cancel, data);
1352
1353 XtManageChild(dialog);
1354
1355 }
1356
1357 static void FSBHome(Widget w, XnFileSelectionBox data, XtPointer u) {
1358 const char *homePath = data->fsb.homePath ? data->fsb.homePath : GetHomeDir();
1359 filedialog_update_dir(data, homePath);
1360 PathBarSetPath(data->fsb.pathBar, homePath);
1361 }
1362
1363
1364 /*
1365 * file_cmp_field
1366 * 0: compare path
1367 * 1: compare size
1368 * 2: compare mtime
1369 */
1370 static int file_cmp_field = 0;
1371
1372 /*
1373 * 1 or -1
1374 */
1375 static int file_cmp_order = 1;
1376
1377 static int filecmp(const void *f1, const void *f2)
1378 {
1379 const FileElm *file1 = f1;
1380 const FileElm *file2 = f2;
1381 if(file1->isDirectory != file2->isDirectory) {
1382 return file1->isDirectory < file2->isDirectory;
1383 }
1384
1385 int cmp_field = file_cmp_field;
1386 int cmp_order = file_cmp_order;
1387 if(file1->isDirectory) {
1388 cmp_field = 0;
1389 cmp_order = 1;
1390 }
1391
1392 int ret = 0;
1393 switch(cmp_field) {
1394 case 0: {
1395 ret = strcmp(FileName(file1->path), FileName(file2->path));
1396 break;
1397 }
1398 case 1: {
1399 if(file1->size < file2->size) {
1400 ret = -1;
1401 } else if(file1->size == file2->size) {
1402 ret = 0;
1403 } else {
1404 ret = 1;
1405 }
1406 break;
1407 }
1408 case 2: {
1409 if(file1->lastModified < file2->lastModified) {
1410 ret = -1;
1411 } else if(file1->lastModified == file2->lastModified) {
1412 ret = 0;
1413 } else {
1414 ret = 1;
1415 }
1416 break;
1417 }
1418 }
1419
1420 return ret * cmp_order;
1421 }
1422
1423
1424 static void free_files(FileElm *ls, int count)
1425 {
1426 for(int i=0;i<count;i++) {
1427 if(ls[i].path) {
1428 free(ls[i].path);
1429 }
1430 }
1431 free(ls);
1432 }
1433
1434 static void filedialog_cleanup_filedata(XnFileSelectionBox data)
1435 {
1436 free_files(data->fsb.dirs, data->fsb.dircount);
1437 free_files(data->fsb.files, data->fsb.filecount);
1438 data->fsb.dirs = NULL;
1439 data->fsb.files = NULL;
1440 data->fsb.dircount = 0;
1441 data->fsb.filecount = 0;
1442 data->fsb.maxnamelen = 0;
1443 }
1444
1445 #define FILE_ARRAY_SIZE 1024
1446
1447 static void file_array_add(FileElm **files, int *alloc, int *count, FileElm elm) {
1448 int c = *count;
1449 int a = *alloc;
1450 if(c >= a) {
1451 a *= 2;
1452 FileElm *newarray = realloc(*files, sizeof(FileElm) * a);
1453
1454 *files = newarray;
1455 *alloc = a;
1456 }
1457
1458 (*files)[c] = elm;
1459 c++;
1460 *count = c;
1461 }
1462
1463 static int filedialog_update_dir(XnFileSelectionBox data, const char *path)
1464 {
1465 DIR *dir = NULL;
1466 if(path) {
1467 // try to check first, if we can open the path
1468 dir = opendir(path);
1469 if(!dir) {
1470 char errmsg[256];
1471 snprintf(errmsg, 256, data->fsb.errorOpenDir, strerror(errno));
1472
1473 ErrDialog(data, data->fsb.errorTitle, errmsg);
1474 return 1;
1475 }
1476 }
1477
1478 FSBView view = data->fsb.view[data->fsb.selectedview];
1479 view.cleanup((Widget)data, view.widget, view.userData);
1480
1481 if(view.useDirList) {
1482 XmListDeleteAllItems(data->fsb.dirlist);
1483 }
1484
1485 /* read dir and insert items */
1486 if(path) {
1487 int dircount = 0;
1488 int filecount = 0;
1489 size_t maxNameLen = 0;
1490
1491 FileElm *dirs = calloc(sizeof(FileElm), FILE_ARRAY_SIZE);
1492 FileElm *files = calloc(sizeof(FileElm), FILE_ARRAY_SIZE);
1493 int dirs_alloc = FILE_ARRAY_SIZE;
1494 int files_alloc = FILE_ARRAY_SIZE;
1495
1496 filedialog_cleanup_filedata(data);
1497
1498 /* dir reading complete - set the path textfield */
1499 XmTextFieldSetString(data->fsb.path, (char*)path);
1500 char *oldPath = data->fsb.currentPath;
1501 data->fsb.currentPath = strdup(path);
1502 if(oldPath) {
1503 free(oldPath);
1504 }
1505 path = data->fsb.currentPath;
1506
1507 struct dirent *ent;
1508 while((ent = readdir(dir)) != NULL) {
1509 if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
1510 continue;
1511 }
1512
1513 char *entpath = ConcatPath(path, ent->d_name);
1514
1515 struct stat s;
1516 if(stat(entpath, &s)) {
1517 free(entpath);
1518 continue;
1519 }
1520
1521 FileElm new_entry;
1522 new_entry.path = entpath;
1523 new_entry.isDirectory = S_ISDIR(s.st_mode);
1524 new_entry.size = (uint64_t)s.st_size;
1525 new_entry.lastModified = s.st_mtime;
1526
1527 size_t nameLen = strlen(ent->d_name);
1528 if(nameLen > maxNameLen) {
1529 maxNameLen = nameLen;
1530 }
1531
1532 if(new_entry.isDirectory) {
1533 file_array_add(&dirs, &dirs_alloc, &dircount, new_entry);
1534 } else {
1535 file_array_add(&files, &files_alloc, &filecount, new_entry);
1536 }
1537 }
1538 closedir(dir);
1539
1540 data->fsb.dirs = dirs;
1541 data->fsb.files = files;
1542 data->fsb.dircount = dircount;
1543 data->fsb.filecount = filecount;
1544 data->fsb.maxnamelen = maxNameLen;
1545
1546 // sort file arrays
1547 qsort(dirs, dircount, sizeof(FileElm), filecmp);
1548 qsort(files, filecount, sizeof(FileElm), filecmp);
1549 }
1550
1551 Widget filterTF = XmDropDownGetText(data->fsb.filter);
1552 char *filter = XmTextFieldGetString(filterTF);
1553 char *filterStr = filter;
1554 if(!filter || strlen(filter) == 0) {
1555 filterStr = "*";
1556 }
1557
1558 if(view.useDirList) {
1559 FileListWidgetAdd(data, data->fsb.dirlist, data->fsb.showHidden, NULL, data->fsb.dirs, data->fsb.dircount);
1560 view.update(
1561 (Widget)data,
1562 view.widget,
1563 NULL,
1564 0,
1565 data->fsb.files,
1566 data->fsb.filecount,
1567 filterStr,
1568 data->fsb.maxnamelen,
1569 view.userData);
1570 } else {
1571 view.update(
1572 (Widget)data,
1573 view.widget,
1574 data->fsb.dirs,
1575 data->fsb.dircount,
1576 data->fsb.files,
1577 data->fsb.filecount,
1578 filterStr,
1579 data->fsb.maxnamelen,
1580 view.userData);
1581 }
1582
1583 if(filter) {
1584 XtFree(filter);
1585 }
1586
1587 return 0;
1588 }
1589
1590
1591 static void dirlist_activate(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
1592 {
1593 char *path = set_selected_path(data, cb->item);
1594 if(path) {
1595 if(!filedialog_update_dir(data, path)) {
1596 PathBarSetPath(data->fsb.pathBar, path);
1597 data->fsb.selIsDir = TRUE;
1598 }
1599 }
1600 }
1601
1602 static void dirlist_select(Widget w, XnFileSelectionBox data, XmListCallbackStruct *cb)
1603 {
1604 char *path = set_selected_path(data, cb->item);
1605 if(path) {
1606 data->fsb.selIsDir = TRUE;
1607 }
1608 }
1609
1610 static void filedialog_enable_detailview(Widget w, XnFileSelectionBox data, XmToggleButtonCallbackStruct *tb) {
1611 SelectView(data, tb->set); // 0: list, 1: detail
1612 }
1613
1614
1615 static void filedialog_setshowhidden(
1616 Widget w,
1617 XnFileSelectionBox data,
1618 XmToggleButtonCallbackStruct *tb)
1619 {
1620 data->fsb.showHidden = tb->set;
1621 filedialog_update_dir(data, NULL);
1622 }
1623
1624 static void filedialog_filter(Widget w, XnFileSelectionBox data, XtPointer c)
1625 {
1626 filedialog_update_dir(data, NULL);
1627 }
1628
1629 static void filedialog_update_filter(Widget w, XnFileSelectionBox data, XtPointer c)
1630 {
1631 filedialog_update_dir(data, NULL);
1632
1633 }
1634
1635 static void filedialog_goup(Widget w, XnFileSelectionBox data, XtPointer d)
1636 {
1637 char *newPath = ParentPath(data->fsb.currentPath);
1638 filedialog_update_dir(data, newPath);
1639 PathBarSetPath(data->fsb.pathBar, newPath);
1640 free(newPath);
1641 }
1642
1643 static void filedialog_ok(Widget w, XnFileSelectionBox data, XtPointer d)
1644 {
1645 if(data->fsb.type == FILEDIALOG_SAVE) {
1646 char *newName = XmTextFieldGetString(data->fsb.name);
1647 if(newName) {
1648 if(strchr(newName, '/')) {
1649 ErrDialog(data, data->fsb.errorTitle, data->fsb.errorIllegalChar);
1650 XtFree(newName);
1651 return;
1652 }
1653
1654 if(strlen(newName) > 0) {
1655 char *selPath = ConcatPath(data->fsb.currentPath, newName);
1656 if(data->fsb.selectedPath) free(data->fsb.selectedPath);
1657 data->fsb.selectedPath = selPath;
1658 }
1659 XtFree(newName);
1660
1661 data->fsb.selIsDir = False;
1662 }
1663 }
1664
1665 if(data->fsb.selectedPath) {
1666 if(!data->fsb.selIsDir) {
1667 data->fsb.status = FILEDIALOG_OK;
1668 data->fsb.end = True;
1669 FileSelectionCallback(data, data->fsb.okCallback, XmCR_OK, data->fsb.selectedPath);
1670 }
1671 }
1672 }
1673
1674 static void filedialog_cancel(Widget w, XnFileSelectionBox data, XtPointer d)
1675 {
1676 data->fsb.end = 1;
1677 data->fsb.status = FILEDIALOG_CANCEL;
1678 FileSelectionCallback(data, data->fsb.cancelCallback, XmCR_CANCEL, data->fsb.currentPath);
1679 }
1680
1681 static void filedialog_help(Widget w, XnFileSelectionBox data, XtPointer d)
1682 {
1683 FileSelectionCallback(data, data->manager.help_callback, XmCR_HELP, data->fsb.currentPath);
1684 }
1685
1686 static void FileSelectionCallback(XnFileSelectionBox fsb, XtCallbackList cb, int reason, const char *value) {
1687 XmFileSelectionBoxCallbackStruct cbs;
1688 memset(&cbs, 0, sizeof(XmFileSelectionBoxCallbackStruct));
1689
1690 char *dir = fsb->fsb.currentPath;
1691 size_t dirlen = dir ? strlen(dir) : 0;
1692 if(dir && dirlen > 0) {
1693 char *dir2 = NULL;
1694 if(dir[dirlen-1] != '/') {
1695 // add a trailing / to the dir string
1696 dir2 = malloc(dirlen+2);
1697 memcpy(dir2, dir, dirlen);
1698 dir2[dirlen] = '/';
1699 dir2[dirlen+1] = '\0';
1700 dirlen++;
1701 dir = dir2;
1702 }
1703 cbs.dir = XmStringCreateLocalized(dir);
1704 cbs.dir_length = dirlen;
1705 if(dir2) {
1706 free(dir2);
1707 }
1708 } else {
1709 cbs.dir = XmStringCreateLocalized("");
1710 cbs.dir_length = 0;
1711 }
1712 cbs.reason = reason;
1713
1714 cbs.value = XmStringCreateLocalized((char*)value);
1715 cbs.length = strlen(value);
1716
1717 XtCallCallbackList((Widget)fsb, cb, (XtPointer)&cbs);
1718
1719 XmStringFree(cbs.dir);
1720 XmStringFree(cbs.value);
1721 }
1722
1723 static void CreateUI(XnFileSelectionBox w) {
1724 Arg args[32];
1725 int n = 0;
1726 XmString str;
1727
1728 int widget_spacing = w->fsb.widgetSpacing;
1729 int window_spacing = w->fsb.windowSpacing;
1730
1731 Widget form = (Widget)w;
1732 int type = w->fsb.type;
1733
1734 XtVaSetValues((Widget)w, XmNautoUnmanage, False, NULL);
1735
1736 /* upper part of the gui */
1737
1738 n = 0;
1739 XtSetArg(args[n], XmNlabelString, w->fsb.labelDirUp); n++;
1740 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1741 XtSetArg(args[n], XmNtopOffset, window_spacing); n++;
1742 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1743 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
1744 XtSetArg(args[n], XmNresizable, True); n++;
1745 XtSetArg(args[n], XmNarrowDirection, XmARROW_UP); n++;
1746 w->fsb.dirUp = XmCreatePushButton(form, "DirUp", args, n);
1747 XtManageChild(w->fsb.dirUp);
1748 XtAddCallback(w->fsb.dirUp, XmNactivateCallback,
1749 (XtCallbackProc)filedialog_goup, w);
1750
1751 // View Option Menu
1752 n = 0;
1753 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1754 XtSetArg(args[n], XmNtopOffset, window_spacing); n++;
1755 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1756 XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
1757 XtSetArg(args[n], XmNshadowThickness, 0); n++;
1758 Widget viewframe = XmCreateForm(form, "vframe", args, n);
1759 XtManageChild(viewframe);
1760
1761 w->fsb.viewMenu = XmCreatePulldownMenu(viewframe, "menu", NULL, 0);
1762
1763 Widget view;
1764 if(w->fsb.showViewMenu) {
1765 n = 0;
1766 XtSetArg(args[n], XmNsubMenuId, w->fsb.viewMenu); n++;
1767 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1768 XtSetArg(args[n], XmNmarginHeight, 0); n++;
1769 XtSetArg(args[n], XmNmarginWidth, 0); n++;
1770 view = XmCreateOptionMenu(viewframe, "option_menu", args, n);
1771 XtManageChild(view);
1772 w->fsb.viewOption = view;
1773 w->fsb.detailToggleButton = NULL;
1774 } else {
1775 n = 0;
1776 str = XmStringCreateLocalized(w->fsb.labelDetailView);
1777 XtSetArg(args[n], XmNlabelString, str); n++;
1778 XtSetArg(args[n], XmNfillOnSelect, True); n++;
1779 XtSetArg(args[n], XmNindicatorOn, False); n++;
1780 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1781 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1782 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1783 if(w->fsb.selectedview == 1) {
1784 XtSetArg(args[n], XmNset, 1); n++;
1785 }
1786 w->fsb.detailToggleButton = XmCreateToggleButton(viewframe, "ToggleDetailView", args, n);
1787 XtManageChild(w->fsb.detailToggleButton);
1788 view = w->fsb.detailToggleButton;
1789 XmStringFree(str);
1790
1791 XtAddCallback(
1792 w->fsb.detailToggleButton,
1793 XmNvalueChangedCallback,
1794 (XtCallbackProc)filedialog_enable_detailview,
1795 w);
1796
1797 w->fsb.viewOption = NULL;
1798 }
1799
1800 n = 0;
1801 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1802 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1803 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1804 XtSetArg(args[n], XmNrightWidget, view); n++;
1805 XtSetArg(args[n], XmNmarginHeight, 0); n++;
1806 XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
1807 XtSetArg(args[n], XmNlabelString, w->fsb.labelNewFolder); n++;
1808 w->fsb.newFolder = XmCreatePushButton(viewframe, "NewFolder", args, n);
1809 XtManageChild(w->fsb.newFolder);
1810 XtAddCallback(
1811 w->fsb.newFolder,
1812 XmNactivateCallback,
1813 (XtCallbackProc)FSBNewFolder,
1814 w);
1815
1816
1817 n = 0;
1818 XtSetArg(args[n], XmNlabelString, w->fsb.labelHome); n++;
1819 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1820 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1821 XtSetArg(args[n], XmNrightWidget, w->fsb.newFolder); n++;
1822 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1823 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1824 w->fsb.home = XmCreatePushButton(viewframe, "Home", args, n);
1825 XtManageChild(w->fsb.home);
1826 XtAddCallback(
1827 w->fsb.home,
1828 XmNactivateCallback,
1829 (XtCallbackProc)FSBHome,
1830 w);
1831
1832 // match visual appearance of detailToggleButton with the other buttons
1833 if(w->fsb.detailToggleButton) {
1834 Dimension highlight, shadow;
1835 XtVaGetValues(w->fsb.newFolder, XmNshadowThickness, &shadow, XmNhighlightThickness, &highlight, NULL);
1836 XtVaSetValues(w->fsb.detailToggleButton, XmNshadowThickness, shadow, XmNhighlightThickness, highlight, NULL);
1837 }
1838
1839 // pathbar
1840 n = 0;
1841 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1842 XtSetArg(args[n], XmNtopOffset, window_spacing); n++;
1843 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
1844 XtSetArg(args[n], XmNleftWidget, w->fsb.dirUp); n++;
1845 XtSetArg(args[n], XmNleftOffset, widget_spacing); n++;
1846 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1847 XtSetArg(args[n], XmNrightWidget, viewframe); n++;
1848 XtSetArg(args[n], XmNrightOffset, widget_spacing); n++;
1849 XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); n++;
1850 Widget pathBarFrame = XmCreateFrame(form, "pathbar_frame", args, n);
1851 XtManageChild(pathBarFrame);
1852 w->fsb.pathBar = CreatePathBar(pathBarFrame, args, 0);
1853 w->fsb.pathBar->getpathelm = ui_default_pathelm_func;
1854 w->fsb.pathBar->updateDir = (updatedir_callback)filedialog_update_dir;
1855 w->fsb.pathBar->updateDirData = w;
1856 XtManageChild(w->fsb.pathBar->widget);
1857 w->fsb.path = XmCreateTextField(form, "textfield", args, 0);
1858
1859 XtVaSetValues(w->fsb.dirUp, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, pathBarFrame, NULL);
1860 if(!w->fsb.showViewMenu) {
1861 XtVaSetValues(viewframe, XmNbottomAttachment, XmATTACH_OPPOSITE_WIDGET, XmNbottomWidget, pathBarFrame, NULL);
1862 }
1863
1864 n = 0;
1865 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1866 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
1867 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
1868 XtSetArg(args[n], XmNtopWidget, pathBarFrame); n++;
1869 XtSetArg(args[n], XmNtopOffset, 2*widget_spacing); n++;
1870 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1871 XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
1872 w->fsb.filterForm = XmCreateForm(form, "filterform", args, n);
1873 XtManageChild(w->fsb.filterForm);
1874
1875 n = 0;
1876 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1877 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1878 XtSetArg(args[n], XmNlabelString, w->fsb.labelDirectories); n++;
1879 w->fsb.lsDirLabel = XmCreateLabel(w->fsb.filterForm, "labelDirs", args, n);
1880 XtManageChild(w->fsb.lsDirLabel);
1881
1882 n = 0;
1883 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1884 XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
1885 XtSetArg(args[n], XmNleftPosition, 35); n++;
1886 XtSetArg(args[n], XmNleftOffset, widget_spacing); n++;
1887 XtSetArg(args[n], XmNlabelString, w->fsb.labelFiles); n++;
1888 w->fsb.lsFileLabel = XmCreateLabel(w->fsb.filterForm, "labelFiles", args, n);
1889 XtManageChild(w->fsb.lsFileLabel);
1890
1891 if(w->fsb.showHiddenButton) {
1892 n = 0;
1893 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1894 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1895 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1896 XtSetArg(args[n], XmNlabelString, w->fsb.labelShowHiddenFiles); n++;
1897 XtSetArg(args[n], XmNset, w->fsb.showHidden); n++;
1898 w->fsb.showHiddenButtonW = XmCreateToggleButton(w->fsb.filterForm, "showHidden", args, n);
1899 XtManageChild(w->fsb.showHiddenButtonW);
1900 XtAddCallback(w->fsb.showHiddenButtonW, XmNvalueChangedCallback,
1901 (XtCallbackProc)filedialog_setshowhidden, w);
1902 }
1903
1904 n = 0;
1905 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1906 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1907 XtSetArg(args[n], XmNlabelString, w->fsb.labelFilterButton); n++;
1908 if(w->fsb.showHiddenButton) {
1909 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1910 XtSetArg(args[n], XmNrightWidget, w->fsb.showHiddenButtonW); n++;
1911 } else {
1912 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1913 }
1914 w->fsb.filterButton = XmCreatePushButton(w->fsb.filterForm, "filedialog_filter", args, n);
1915 XtManageChild(w->fsb.filterButton);
1916 XtAddCallback(w->fsb.filterButton, XmNactivateCallback,
1917 (XtCallbackProc)filedialog_filter, w);
1918
1919 n = 0;
1920 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1921 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1922 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
1923 XtSetArg(args[n], XmNleftWidget, w->fsb.lsFileLabel); n++;
1924 XtSetArg(args[n], XmNleftOffset, widget_spacing); n++;
1925 XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
1926 XtSetArg(args[n], XmNrightWidget, w->fsb.filterButton); n++;
1927 XtSetArg(args[n], XmNrightOffset, widget_spacing); n++;
1928 XtSetArg(args[n], XmNshowLabel, False); n++;
1929 XtSetArg(args[n], XmNuseTextField, True); n++;
1930 XtSetArg(args[n], XmNverify, False); n++;
1931 w->fsb.filter = XmCreateDropDown(w->fsb.filterForm, "filedialog_filter_textfield", args, n);
1932 XtManageChild(w->fsb.filter);
1933 XmTextFieldSetString(XmDropDownGetText(w->fsb.filter), w->fsb.filterStr);
1934 XtAddCallback(XmDropDownGetText(w->fsb.filter), XmNactivateCallback,
1935 (XtCallbackProc)filedialog_filter, w);
1936 XtAddCallback(w->fsb.filter, XmNupdateTextCallback,
1937 (XtCallbackProc)filedialog_update_filter, w);
1938 Widget filterList = XmDropDownGetList(w->fsb.filter);
1939 str = XmStringCreateSimple("*");
1940 XmListAddItem(filterList, str, 0);
1941 XmStringFree(str);
1942
1943 /* lower part */
1944 n = 0;
1945 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1946 XtSetArg(args[n], XmNbottomOffset, window_spacing); n++;
1947 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1948 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
1949 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1950 XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
1951 XtSetArg(args[n], XmNtopOffset, widget_spacing * 2); n++;
1952 Widget buttons = XmCreateForm(form, "buttons", args, n);
1953 XtManageChild(buttons);
1954
1955 n = 0;
1956 str = type == FILEDIALOG_OPEN ? w->fsb.labelOpen : w->fsb.labelSave;
1957 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1958 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1959 XtSetArg(args[n], XmNlabelString, str); n++;
1960 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1961 XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
1962 XtSetArg(args[n], XmNrightPosition, 14); n++;
1963 w->fsb.okBtn = XmCreatePushButton(buttons, "filedialog_open", args, n);
1964 XtManageChild(w->fsb.okBtn);
1965 XmStringFree(str);
1966 XtAddCallback(w->fsb.okBtn, XmNactivateCallback,
1967 (XtCallbackProc)filedialog_ok, w);
1968
1969 n = 0;
1970 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1971 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1972 XtSetArg(args[n], XmNlabelString, w->fsb.labelHelp); n++;
1973 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
1974 XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
1975 XtSetArg(args[n], XmNleftPosition, 86); n++;
1976 w->fsb.helpBtn = XmCreatePushButton(buttons, "filedialog_help", args, n);
1977 XtManageChild(w->fsb.helpBtn);
1978 XtAddCallback(w->fsb.helpBtn, XmNactivateCallback,
1979 (XtCallbackProc)filedialog_help, w);
1980
1981 n = 0;
1982 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
1983 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
1984 XtSetArg(args[n], XmNleftAttachment, XmATTACH_POSITION); n++;
1985 XtSetArg(args[n], XmNleftPosition, 43); n++;
1986 XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
1987 XtSetArg(args[n], XmNrightPosition, 57); n++;
1988 XtSetArg(args[n], XmNlabelString, w->fsb.labelCancel); n++;
1989 w->fsb.cancelBtn = XmCreatePushButton(buttons, "filedialog_cancel", args, n);
1990 XtManageChild(w->fsb.cancelBtn);
1991 XtAddCallback(w->fsb.cancelBtn, XmNactivateCallback,
1992 (XtCallbackProc)filedialog_cancel, w);
1993
1994 n = 0;
1995 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
1996 XtSetArg(args[n], XmNbottomWidget, buttons); n++;
1997 XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
1998 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
1999 XtSetArg(args[n], XmNleftOffset, 1); n++;
2000 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2001 XtSetArg(args[n], XmNrightOffset, 1); n++;
2002 w->fsb.separator = XmCreateSeparator(form, "ofd_separator", args, n);
2003 XtManageChild(w->fsb.separator);
2004
2005 Widget bottomWidget = w->fsb.separator;
2006
2007 n = 0;
2008 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2009 XtSetArg(args[n], XmNbottomWidget, w->fsb.separator); n++;
2010 XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
2011 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2012 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
2013 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2014 XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
2015 w->fsb.name = XmCreateTextField(form, "textfield", args, n);
2016 XtAddCallback(w->fsb.name, XmNactivateCallback,
2017 (XtCallbackProc)filedialog_ok, w);
2018
2019 n = 0;
2020 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2021 XtSetArg(args[n], XmNbottomWidget, w->fsb.name); n++;
2022 XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
2023 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2024 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
2025 XtSetArg(args[n], XmNlabelString, w->fsb.labelFileName); n++;
2026 w->fsb.nameLabel = XmCreateLabel(form, "label", args, n);
2027
2028 if(type == FILEDIALOG_SAVE) {
2029 bottomWidget = w->fsb.nameLabel;
2030 XtManageChild(w->fsb.name);
2031 XtManageChild(w->fsb.nameLabel);
2032 }
2033 w->fsb.bottom_widget = bottomWidget;
2034
2035
2036 // middle
2037 // form for dir/file lists
2038 n = 0;
2039 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2040 XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
2041 XtSetArg(args[n], XmNtopWidget, w->fsb.filterForm); n++;
2042 XtSetArg(args[n], XmNtopOffset, widget_spacing); n++;
2043 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2044 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2045 XtSetArg(args[n], XmNbottomWidget, bottomWidget); n++;
2046 XtSetArg(args[n], XmNleftOffset, window_spacing); n++;
2047 XtSetArg(args[n], XmNrightOffset, window_spacing); n++;
2048 XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
2049 XtSetArg(args[n], XmNwidth, 580); n++;
2050 XtSetArg(args[n], XmNheight, 400); n++;
2051 w->fsb.listform = XmCreateForm(form, "fds_listform", args, n);
2052
2053 // dir/file lists
2054
2055 n = 0;
2056 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2057 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2058 XtSetArg(args[n], XmNtopWidget, w->fsb.lsDirLabel); n++;
2059 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2060 XtSetArg(args[n], XmNrightAttachment, XmATTACH_POSITION); n++;
2061 XtSetArg(args[n], XmNrightPosition, 35); n++;
2062 w->fsb.dirlist = XmCreateScrolledList(w->fsb.listform, "dirlist", args, n);
2063 Dimension width, height;
2064 XtMakeResizeRequest(w->fsb.dirlist, 150, 200, &width, &height);
2065 XtManageChild(w->fsb.dirlist);
2066
2067 XtAddCallback(
2068 w->fsb.dirlist,
2069 XmNdefaultActionCallback,
2070 (XtCallbackProc)dirlist_activate,
2071 w);
2072 XtAddCallback(
2073 w->fsb.dirlist,
2074 XmNbrowseSelectionCallback,
2075 (XtCallbackProc)dirlist_select,
2076 w);
2077
2078 // FileList
2079 XnFileSelectionBoxAddView(
2080 (Widget)w,
2081 w->fsb.labelListView,
2082 CreateListView,
2083 FileListUpdate,
2084 FileListSelect,
2085 FileListCleanup,
2086 FileListDestroy,
2087 True,
2088 w);
2089
2090 // Detail FileList
2091 #ifdef FSB_ENABLE_DETAIL
2092 XnFileSelectionBoxAddView(
2093 (Widget)w,
2094 w->fsb.labelDetailView,
2095 CreateDetailView,
2096 FileListDetailUpdate,
2097 FileListDetailSelect,
2098 FileListDetailCleanup,
2099 FileListDetailDestroy,
2100 True,
2101 w);
2102 #endif
2103
2104 /*
2105 n = 0;
2106 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
2107 XtSetArg(args[n], XmNleftWidget, w->fsb.dirlist); n++;
2108 XtSetArg(args[n], XmNleftOffset, widget_spacing); n++;
2109 //XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
2110 //XtSetArg(args[n], XmNbottomWidget, w->fsb.filelist); n++;
2111 XtSetArg(args[n], XmNbottomOffset, widget_spacing); n++;
2112 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2113 XtSetArg(args[n], XmNlabelString, w->fsb.labelFiles); n++;
2114 w->fsb.lsFileLabel = XmCreateLabel(w->fsb.listform, "label", args, n);
2115 XtManageChild(w->fsb.lsFileLabel);
2116 */
2117
2118 XtManageChild(w->fsb.listform);
2119
2120 int selview = w->fsb.selectedview;
2121 if(selview < 2) {
2122 XtManageChild(w->fsb.view[selview].widget);
2123 } else {
2124 w->fsb.selectedview = 0;
2125 }
2126
2127
2128 if(w->fsb.selectedPath) {
2129 char *parentPath = ParentPath(w->fsb.selectedPath);
2130 filedialog_update_dir(w, parentPath);
2131 PathBarSetPath(w->fsb.pathBar, parentPath);
2132 free(parentPath);
2133
2134 if(w->fsb.type == FILEDIALOG_SAVE) {
2135 XmTextFieldSetString(w->fsb.name, FileName(w->fsb.selectedPath));
2136 }
2137 } else {
2138 char cwd[PATH_MAX];
2139 const char *currentPath = w->fsb.currentPath;
2140 if(!currentPath) {
2141 if(getcwd(cwd, PATH_MAX)) {
2142 currentPath = cwd;
2143 } else {
2144 currentPath = GetHomeDir();
2145 }
2146 }
2147
2148 filedialog_update_dir(w, currentPath);
2149 PathBarSetPath(w->fsb.pathBar, w->fsb.currentPath);
2150 }
2151
2152
2153 w->fsb.selectedview = selview;
2154
2155 XtVaSetValues((Widget)w, XmNcancelButton, w->fsb.cancelBtn, NULL);
2156
2157 w->fsb.gui_created = 1;
2158 }
2159
2160 static char* FSBDialogTitle(Widget widget) {
2161 XnFileSelectionBox w = (XnFileSelectionBox)widget;
2162 if(w->fsb.type == FILEDIALOG_OPEN) {
2163 return w->fsb.labelOpenFileTitle;
2164 } else {
2165 return w->fsb.labelSaveFileTitle;
2166 }
2167 }
2168
2169 static FSBViewWidgets CreateView(XnFileSelectionBox w, FSBViewCreateProc create, void *userData, Boolean useDirList) {
2170 Arg args[64];
2171 int n = 0;
2172
2173 XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
2174 XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
2175 if(useDirList) {
2176 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2177 XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); n++;
2178 XtSetArg(args[n], XmNleftWidget, w->fsb.dirlist); n++;
2179 XtSetArg(args[n], XmNleftOffset, w->fsb.widgetSpacing); n++;
2180 } else {
2181 XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
2182 XtSetArg(args[n], XmNtopOffset, w->fsb.widgetSpacing); n++;
2183 XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
2184 }
2185
2186 return create(w->fsb.listform, args, n, userData);
2187 }
2188
2189
2190 typedef struct FSBViewSelection {
2191 XnFileSelectionBox fsb;
2192 int index;
2193 } FSBViewSelection;
2194
2195 static void SelectView(XnFileSelectionBox f, int view) {
2196 FSBView current = f->fsb.view[f->fsb.selectedview];
2197 FSBView newview = f->fsb.view[view];
2198
2199 XtUnmanageChild(current.widget);
2200 if(newview.useDirList != current.useDirList) {
2201 if(current.useDirList) {
2202 XtUnmanageChild(f->fsb.listform);
2203 } else {
2204 XtManageChild(f->fsb.listform);
2205 }
2206 }
2207
2208 current.cleanup((Widget)f, current.widget, current.userData);
2209 XtManageChild(newview.widget);
2210
2211 f->fsb.selectedview = view;
2212
2213 filedialog_update_dir(f, NULL);
2214 XmProcessTraversal(newview.focus, XmTRAVERSE_CURRENT);
2215 }
2216
2217 static void SelectViewCallback(Widget w, FSBViewSelection *data, XtPointer u) {
2218 SelectView(data->fsb, data->index);
2219 }
2220
2221 static void SelectViewItemDestroy(Widget w, FSBViewSelection *data, XtPointer u) {
2222 free(data);
2223 }
2224
2225 static void AddViewMenuItem(XnFileSelectionBox w, const char *name, int viewIndex) {
2226 Arg args[4];
2227 int n = 0;
2228
2229 XmString label = XmStringCreateLocalized((char*)name);
2230
2231 XtSetArg(args[n], XmNlabelString, label); n++;
2232 XtSetArg(args[1], XmNpositionIndex, w->fsb.selectedview == w->fsb.numviews ? 0 : w->fsb.numviews+1); n++;
2233 Widget item = XmCreatePushButton(w->fsb.viewMenu, "menuitem", args, n);
2234
2235 if(viewIndex == 0) {
2236 w->fsb.viewSelectorList = item;
2237 } else if(viewIndex == 1) {
2238 w->fsb.viewSelectorDetail = item;
2239 }
2240
2241 XtManageChild(item);
2242 XmStringFree(label);
2243
2244 FSBViewSelection *data = malloc(sizeof(FSBViewSelection));
2245 data->fsb = w;
2246 data->index = viewIndex;
2247
2248 XtAddCallback(
2249 item,
2250 XmNactivateCallback,
2251 (XtCallbackProc)SelectViewCallback,
2252 data);
2253 XtAddCallback(
2254 item,
2255 XmNdestroyCallback,
2256 (XtCallbackProc)SelectViewItemDestroy,
2257 data);
2258 }
2259
2260 static FSBViewWidgets CreateListView(Widget parent, ArgList args, int n, void *userData) {
2261 XnFileSelectionBox fsb = (XnFileSelectionBox)userData;
2262
2263 XtSetArg(args[n], XmNshadowThickness, 0); n++;
2264 Widget frame = XmCreateFrame(parent, "filelistframe", args, n);
2265
2266 fsb->fsb.filelist = XmCreateScrolledList(frame, "filelist", NULL, 0);
2267 XtManageChild(fsb->fsb.filelist);
2268
2269 XtAddCallback(
2270 fsb->fsb.filelist,
2271 XmNdefaultActionCallback,
2272 (XtCallbackProc)FileListActivateCB,
2273 userData);
2274 XtAddCallback(
2275 fsb->fsb.filelist,
2276 XmNbrowseSelectionCallback,
2277 (XtCallbackProc)FileListSelectCB,
2278 userData);
2279
2280 fsb->fsb.listContextMenu = CreateContextMenu(fsb, fsb->fsb.filelist, FileContextMenuCB);
2281
2282 FSBViewWidgets widgets;
2283 widgets.view = frame;
2284 widgets.focus = fsb->fsb.filelist;
2285 return widgets;
2286 }
2287
2288 #ifdef FSB_ENABLE_DETAIL
2289 static void set_path_from_row(XnFileSelectionBox data, int row) {
2290 FileElm *elm = NULL;
2291 XmLGridRow rowPtr = XmLGridGetRow(data->fsb.grid, XmCONTENT, row);
2292 XtVaGetValues(data->fsb.grid, XmNrowPtr, rowPtr, XmNrowUserData, &elm, NULL);
2293 if(!elm) {
2294 fprintf(stderr, "error: no row data\n");
2295 return;
2296 }
2297
2298 char *path = strdup(elm->path);
2299
2300 data->fsb.selIsDir = False;
2301 if(data->fsb.type == FILEDIALOG_SAVE) {
2302 XmTextFieldSetString(data->fsb.name, FileName(path));
2303 }
2304
2305 if(data->fsb.selectedPath) {
2306 free(data->fsb.selectedPath);
2307 }
2308 data->fsb.selectedPath = path;
2309 }
2310
2311 static void grid_select(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
2312 set_path_from_row(data, cb->row);
2313 }
2314
2315 static void grid_activate(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
2316 set_path_from_row(data, cb->row);
2317 data->fsb.end = True;
2318 data->fsb.status = FILEDIALOG_OK;
2319
2320 FileSelectionCallback(data, data->fsb.okCallback, XmCR_OK, data->fsb.selectedPath);
2321 }
2322
2323 static void grid_key_pressed(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
2324 char chars[16];
2325 KeySym keysym;
2326 int nchars;
2327
2328 nchars = XLookupString(&cb->event->xkey, chars, 15, &keysym, NULL);
2329
2330 if(nchars == 0) return;
2331
2332 // if data->showHidden is 0, data->files contains more items than the grid
2333 // this means SelectedRow might not be the correct index for data->files
2334 // we have to count files manually and increase 'row', if the file
2335 // is actually displayed in the grid
2336 int row = 0;
2337 int selectedRow = XmLGridGetSelectedRow(w);
2338
2339 int match = -1;
2340
2341 for(int i=0;i<data->fsb.filecount;i++) {
2342 const char *name = FileName(data->fsb.files[i].path);
2343 if(!data->fsb.showHidden && name[0] == '.') continue;
2344
2345 size_t namelen = strlen(name);
2346
2347 size_t cmplen = namelen < nchars ? namelen : nchars;
2348 if(!memcmp(name, chars, cmplen)) {
2349 if(row <= selectedRow) {
2350 if(match == -1) {
2351 match = row;
2352 }
2353 } else {
2354 match = row;
2355 break;
2356 }
2357 }
2358
2359 row++;
2360 }
2361
2362 if(match > -1) {
2363 XmLGridSelectRow(w, match, True);
2364 XmLGridFocusAndShowRow(w, match+1);
2365 } else {
2366 XBell(XtDisplay(w), 0);
2367 }
2368 }
2369
2370 static void grid_header_clicked(Widget w, XnFileSelectionBox data, XmLGridCallbackStruct *cb) {
2371 int new_cmp_field = 0;
2372 switch(cb->column) {
2373 case 0: {
2374 new_cmp_field = 0;
2375 break;
2376 }
2377 case 1: {
2378 new_cmp_field = 1;
2379 break;
2380 }
2381 case 2: {
2382 new_cmp_field = 2;
2383 break;
2384 }
2385 }
2386
2387 if(new_cmp_field == file_cmp_field) {
2388 file_cmp_order = -file_cmp_order; // revert sort order
2389 } else {
2390 file_cmp_field = new_cmp_field; // change file cmp order to new field
2391 file_cmp_order = 1;
2392 }
2393
2394 int sort_type = file_cmp_order == 1 ? XmSORT_ASCENDING : XmSORT_DESCENDING;
2395 XmLGridSetSort(data->fsb.grid, file_cmp_field, sort_type);
2396
2397 qsort(data->fsb.files, data->fsb.filecount, sizeof(FileElm), filecmp);
2398
2399 // refresh widget
2400 filedialog_update_dir(data, NULL);
2401 }
2402
2403 static FSBViewWidgets CreateDetailView(Widget parent, ArgList args, int n, void *userData) {
2404 XnFileSelectionBox w = userData;
2405
2406 XtSetArg(args[n], XmNshadowThickness, 0); n++;
2407 Widget gridcontainer = XmCreateFrame(parent, "gridcontainer", args, n);
2408 XtManageChild(gridcontainer);
2409
2410 n = 0;
2411 XtSetArg(args[n], XmNcolumns, 3); n++;
2412 XtSetArg(args[n], XmNheadingColumns, 0); n++;
2413 XtSetArg(args[n], XmNheadingRows, 1); n++;
2414 XtSetArg(args[n], XmNallowColumnResize, 1); n++;
2415 XtSetArg(args[n], XmNsimpleHeadings, w->fsb.detailHeadings); n++;
2416 XtSetArg(args[n], XmNhorizontalSizePolicy, XmCONSTANT); n++;
2417
2418 w->fsb.grid = XmLCreateGrid(gridcontainer, "grid", args, n);
2419 XmLGridSetIgnoreModifyVerify(w->fsb.grid, True);
2420 XtManageChild(w->fsb.grid);
2421
2422 XtVaSetValues(
2423 w->fsb.grid,
2424 XmNcellDefaults, True,
2425 XtVaTypedArg, XmNblankBackground, XmRString, "white", 6,
2426 XtVaTypedArg, XmNcellBackground, XmRString, "white", 6,
2427 NULL);
2428
2429 XtAddCallback(w->fsb.grid, XmNselectCallback, (XtCallbackProc)grid_select, w);
2430 XtAddCallback(w->fsb.grid, XmNactivateCallback, (XtCallbackProc)grid_activate, w);
2431 XtAddCallback(w->fsb.grid, XmNheaderClickCallback, (XtCallbackProc)grid_header_clicked, w);
2432 XtAddCallback(w->fsb.grid, XmNgridKeyPressedCallback, (XtCallbackProc)grid_key_pressed, w);
2433
2434 // context menu
2435 w->fsb.gridContextMenu = CreateContextMenu(w, w->fsb.grid, FileContextMenuCB);
2436
2437 FSBViewWidgets widgets;
2438 widgets.view = gridcontainer;
2439 widgets.focus = w->fsb.grid;
2440 return widgets;
2441 }
2442 #endif
2443
2444
2445 /* ------------------------------ Path Utils ------------------------------ */
2446
2447 const char* GetHomeDir(void) {
2448 char *home = getenv("HOME");
2449 if(!home) {
2450 home = getenv("USERPROFILE");
2451 if(!home) {
2452 home = "/";
2453 }
2454 }
2455 return home;
2456 }
2457
2458 static char* ConcatPath(const char *parent, const char *name)
2459 {
2460 size_t parentlen = strlen(parent);
2461 size_t namelen = strlen(name);
2462
2463 size_t pathlen = parentlen + namelen + 2;
2464 char *path = malloc(pathlen);
2465
2466 memcpy(path, parent, parentlen);
2467 if(parentlen > 0 && parent[parentlen-1] != '/') {
2468 path[parentlen] = '/';
2469 parentlen++;
2470 }
2471 if(name[0] == '/') {
2472 name++;
2473 namelen--;
2474 }
2475 memcpy(path+parentlen, name, namelen);
2476 path[parentlen+namelen] = '\0';
2477 return path;
2478 }
2479
2480 static char* FileName(char *path) {
2481 int si = 0;
2482 int osi = 0;
2483 int i = 0;
2484 int p = 0;
2485 char c;
2486 while((c = path[i]) != 0) {
2487 if(c == '/') {
2488 osi = si;
2489 si = i;
2490 p = 1;
2491 }
2492 i++;
2493 }
2494
2495 char *name = path + si + p;
2496 if(name[0] == 0) {
2497 name = path + osi + p;
2498 if(name[0] == 0) {
2499 return path;
2500 }
2501 }
2502
2503 return name;
2504 }
2505
2506 static char* ParentPath(const char *path) {
2507 char *name = FileName((char*)path);
2508 size_t namelen = strlen(name);
2509 size_t pathlen = strlen(path);
2510 size_t parentlen = pathlen - namelen;
2511 if(parentlen == 0) {
2512 parentlen++;
2513 }
2514 char *parent = malloc(parentlen + 1);
2515 memcpy(parent, path, parentlen);
2516 parent[parentlen] = '\0';
2517 return parent;
2518 }
2519
2520 // unused at the moment, maybe reactivate if more illegal characters
2521 // are defined
2522 /*
2523 static int CheckFileName(const char *fileName) {
2524 size_t len = strlen(fileName);
2525 for(int i=0;i<len;i++) {
2526 if(fileName[i] == '/') {
2527 return 0;
2528 }
2529 }
2530 return 1;
2531 }
2532 */
2533
2534
2535 /* ------------------------------ public API ------------------------------ */
2536
2537 Widget XnCreateFileSelectionDialog(
2538 Widget parent,
2539 String name,
2540 ArgList arglist,
2541 Cardinal argcount)
2542 {
2543 Widget dialog = XmCreateDialogShell(parent, "FileDialog", NULL, 0);
2544 Widget fsb = XnCreateFileSelectionBox(dialog, name, arglist, argcount);
2545 char *title = FSBDialogTitle(fsb);
2546 XtVaSetValues(dialog, XmNtitle, title, NULL);
2547 return fsb;
2548 }
2549
2550 Widget XnCreateFileSelectionBox(
2551 Widget parent,
2552 String name,
2553 ArgList arglist,
2554 Cardinal argcount)
2555 {
2556 Widget fsb = XtCreateWidget(name, xnFsbWidgetClass, parent, arglist, argcount);
2557 return fsb;
2558 }
2559
2560 void XnFileSelectionBoxAddView(
2561 Widget fsb,
2562 const char *name,
2563 FSBViewCreateProc create,
2564 FSBViewUpdateProc update,
2565 FSBViewSelectProc select,
2566 FSBViewCleanupProc cleanup,
2567 FSBViewDestroyProc destroy,
2568 Boolean useDirList,
2569 void *userData)
2570 {
2571 XnFileSelectionBox f = (XnFileSelectionBox)fsb;
2572 if(f->fsb.numviews >= FSB_MAX_VIEWS) {
2573 fprintf(stderr, "XnFileSelectionBox: too many views\n");
2574 return;
2575 }
2576
2577 FSBView view;
2578 view.update = update;
2579 view.select = select;
2580 view.cleanup = cleanup;
2581 view.destroy = destroy;
2582 view.useDirList = useDirList;
2583 view.userData = userData;
2584
2585 FSBViewWidgets widgets = CreateView(f, create, userData, useDirList);
2586 view.widget = widgets.view;
2587 view.focus = widgets.focus;
2588
2589 AddViewMenuItem(f, name, f->fsb.numviews);
2590
2591 f->fsb.view[f->fsb.numviews++] = view;
2592 }
2593
2594 /*
2595 void XnFileSelectionBoxSetDirList(Widget fsb, const char **dirlist, size_t nelm) {
2596 XnFileSelectionBox f = (XnFileSelectionBox)fsb;
2597 PathBarSetDirList(f->fsb.pathBar, dirlist, nelm);
2598 }
2599 */
2600
2601 Widget XnFileSelectionBoxWorkArea(Widget fsb) {
2602 XnFileSelectionBox f = (XnFileSelectionBox)fsb;
2603 return f->fsb.workarea;
2604 }
2605
2606 Widget XnFileSelectionBoxGetChild(Widget fsb, enum XnFSBChild child) {
2607 XnFileSelectionBox w = (XnFileSelectionBox)fsb;
2608 switch(child) {
2609 case XnFSB_DIR_UP_BUTTON: return w->fsb.dirUp;
2610 case XnFSB_HOME_BUTTON: return w->fsb.home;
2611 case XnFSB_NEW_FOLDER_BUTTON: return w->fsb.newFolder;
2612 case XnFSB_DETAIL_TOGGLE_BUTTON: return w->fsb.detailToggleButton;
2613 case XnFSB_VIEW_OPTION_BUTTON: return w->fsb.viewOption;
2614 case XnFSB_FILTER_DROPDOWN: return w->fsb.filter;
2615 case XnFSB_FILTER_BUTTON: return w->fsb.filterButton;
2616 case XnFSB_SHOW_HIDDEN_TOGGLE_BUTTON: return w->fsb.showHiddenButtonW;
2617 case XnFSB_DIRECTORIES_LABEL: return w->fsb.lsDirLabel;
2618 case XnFSB_FILES_LABEL: return w->fsb.lsFileLabel;
2619 case XnFSB_DIRLIST: return w->fsb.dirlist;
2620 case XnFSB_FILELIST: return w->fsb.filelist;
2621 case XnFSB_GRID: return w->fsb.grid;
2622 case XnFSB_OK_BUTTON: return w->fsb.okBtn;
2623 case XnFSB_CANCEL_BUTTON: return w->fsb.cancelBtn;
2624 case XnFSB_HELP_BUTTON: return w->fsb.helpBtn;
2625 }
2626 return NULL;
2627 }
2628
2629 void XnFileSelectionBoxDeleteFilters(Widget fsb) {
2630 XnFileSelectionBox w = (XnFileSelectionBox)fsb;
2631 Widget filterList = XmDropDownGetList(w->fsb.filter);
2632 XmListDeleteAllItems(filterList);
2633 }
2634
2635 void XnFileSelectionBoxAddFilter(Widget fsb, const char *filter) {
2636 XnFileSelectionBox w = (XnFileSelectionBox)fsb;
2637 Widget filterList = XmDropDownGetList(w->fsb.filter);
2638
2639 XmString str = XmStringCreateSimple((char*)filter);
2640 XmListAddItem(filterList, str, 0);
2641 XmStringFree(str);
2642 }

mercurial