ui/motif/Fsb.c

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

mercurial