COMMON_OBJ += condvar$(OBJ_EXT)
COMMON_OBJ += args$(OBJ_EXT)
COMMON_OBJ += wrapper$(OBJ_EXT)
+COMMON_OBJ += utils$(OBJ_EXT)
TOOLKITOBJS += $(COMMON_OBJ:%=$(COMMON_OBJPRE)uic_%)
TOOLKITSOURCE += $(COMMON_OBJ:%$(OBJ_EXT)=common/%.c)
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2017 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "utils.h"
+
+#include <cx/string.h>
+
+UiPathElm* ui_default_pathelm_func(const char* full_path, size_t len, size_t* ret_nelm, void* data) {
+ cxstring *pathelms;
+ size_t nelm = cx_strsplit_a(cxDefaultAllocator, cx_strn(full_path, len), CX_STR("/"), 4096, &pathelms);
+
+ if (nelm == 0) {
+ *ret_nelm = 0;
+ return NULL;
+ }
+
+ UiPathElm* elms = (UiPathElm*)calloc(nelm, sizeof(UiPathElm));
+ size_t n = nelm;
+ int j = 0;
+ for (int i = 0; i < nelm; i++) {
+ cxstring c = pathelms[i];
+ if (c.length == 0) {
+ if (i == 0) {
+ c.length = 1;
+ }
+ else {
+ n--;
+ continue;
+ }
+ }
+
+ cxmutstr m = cx_strdup(c);
+ elms[j].name = m.ptr;
+ elms[j].name_len = m.length;
+
+ size_t elm_path_len = c.ptr + c.length - full_path;
+ cxmutstr elm_path = cx_strdup(cx_strn(full_path, elm_path_len));
+ elms[j].path = elm_path.ptr;
+ elms[j].path_len = elm_path.length;
+
+ j++;
+ }
+ *ret_nelm = n;
+
+ return elms;
+}
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2017 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef UIC_UTILS_H
+#define UIC_UTILS_H
+
+#include "../ui/toolkit.h"
+#include "../ui/text.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+UiPathElm* ui_default_pathelm_func(const char* full_path, size_t len, size_t* ret_nelm, void* data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UIC_UTILS_H */
+
#include <Xm/XmAll.h>
#include <Xm/DropDown.h>
+#include "pathbar.h"
+
+#include "../common/utils.h"
+
#ifdef FSB_ENABLE_DETAIL
#include <XmL/Grid.h>
#endif
static int filedialog_update_dir(XnFileSelectionBox data, const char *path);
static void filedialog_cleanup_filedata(XnFileSelectionBox data);
-static void pathbar_resize(Widget w, PathBar *p, XtPointer d);
static XtResource resources[] = {
{XmNokCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffset(XnFileSelectionBox, fsb.okCallback), XmRCallback, NULL},
Widget pathBarFrame = XmCreateFrame(form, "pathbar_frame", args, n);
XtManageChild(pathBarFrame);
w->fsb.pathBar = CreatePathBar(pathBarFrame, args, 0);
+ w->fsb.pathBar->getpathelm = ui_default_pathelm_func;
w->fsb.pathBar->updateDir = (updatedir_callback)filedialog_update_dir;
w->fsb.pathBar->updateDirData = w;
XtManageChild(w->fsb.pathBar->widget);
}
*/
-/* ------------------------------ PathBar ------------------------------ */
-
-static void pathbar_resize(Widget w, PathBar *p, XtPointer d)
-{
- if(p->disableResize) return;
-
- Dimension width, height;
- XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL);
-
- Dimension xoff;
- XtVaGetValues(p->down, XmNwidth, &xoff, NULL);
-
- Dimension *segW = calloc(p->numSegments, sizeof(Dimension));
-
- Dimension maxHeight = 0;
-
- /* get width/height from all widgets */
- Dimension pathWidth = 0;
- for(int i=0;i<p->numSegments;i++) {
- Dimension segWidth;
- Dimension segHeight;
- XtVaGetValues(p->pathSegments[i], XmNwidth, &segWidth, XmNheight, &segHeight, NULL);
- segW[i] = segWidth;
- pathWidth += segWidth;
- if(segHeight > maxHeight) {
- maxHeight = segHeight;
- }
- }
- Dimension tfHeight;
- XtVaGetValues(p->textfield, XmNheight, &tfHeight, NULL);
- if(tfHeight > maxHeight) {
- maxHeight = tfHeight;
- }
-
- Boolean arrows = False;
- if(pathWidth + xoff + 10 > width) {
- arrows = True;
- //pathWidth += p->lw + p->rw;
- }
-
- /* calc max visible widgets */
- int start = 0;
- if(arrows) {
- Dimension vis = p->lw+p->rw;
- for(int i=p->numSegments;i>0;i--) {
- Dimension segWidth = segW[i-1];
- if(vis + segWidth + xoff + 10 > width) {
- start = i;
- arrows = True;
- break;
- }
- vis += segWidth;
- }
- } else {
- p->shift = 0;
- }
-
- int leftShift = 0;
- if(p->shift < 0) {
- if(start + p->shift < 0) {
- leftShift = start;
- start = 0;
- p->shift = -leftShift;
- } else {
- leftShift = -p->shift; /* negative shift */
- start += p->shift;
- }
- }
-
- int x = 0;
- if(arrows) {
- XtManageChild(p->left);
- XtManageChild(p->right);
- x += p->lw;
- } else {
- XtUnmanageChild(p->left);
- XtUnmanageChild(p->right);
- }
-
- for(int i=0;i<p->numSegments;i++) {
- if(i >= start && i < p->numSegments - leftShift && !p->input) {
- XtVaSetValues(p->pathSegments[i], XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL);
- x += segW[i];
- XtManageChild(p->pathSegments[i]);
- } else {
- XtUnmanageChild(p->pathSegments[i]);
- }
- }
-
- if(arrows) {
- XtVaSetValues(p->left, XmNx, 0, XmNy, 0, XmNheight, maxHeight, NULL);
- XtVaSetValues(p->right, XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL);
- }
- XtVaSetValues(p->down, XmNx, width-xoff, XmNheight, maxHeight, NULL);
- free(segW);
-
- Dimension rw, rh;
- XtMakeResizeRequest(w, width, maxHeight, &rw, &rh);
- XtVaSetValues(p->textfield, XmNwidth, rw-xoff, XmNheight, rh, NULL);
-}
-
-static void pathbar_input(Widget w, PathBar *p, XtPointer c)
-{
- XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct*)c;
- XEvent *xevent = cbs->event;
-
- if (cbs->reason == XmCR_INPUT) {
- if (xevent->xany.type == ButtonPress) {
- XtUnmanageChild(p->left);
- XtUnmanageChild(p->right);
-
- XtManageChild(p->textfield);
- p->input = 1;
-
- XmProcessTraversal(p->textfield, XmTRAVERSE_CURRENT);
-
- pathbar_resize(p->widget, p, NULL);
- }
- }
-}
-
-static void pathbar_losingfocus(Widget w, PathBar *p, XtPointer c)
-{
- p->input = False;
- XtUnmanageChild(p->textfield);
- pathbar_resize(p->widget, p, NULL);
-}
-
-static void pathbar_pathinput(Widget w, PathBar *pb, XtPointer d)
-{
- char *newpath = XmTextFieldGetString(pb->textfield);
- if(newpath) {
- if(newpath[0] == '~') {
- char *p = newpath+1;
- char *cp = ConcatPath(GetHomeDir(), p);
- XtFree(newpath);
- newpath = cp;
- } else if(newpath[0] != '/') {
- char cwd[PATH_MAX];
- if(!getcwd(cwd, sizeof(cwd))) {
- cwd[0] = '/';
- cwd[1] = '\0';
- }
- char *cp = ConcatPath(cwd, newpath);
- XtFree(newpath);
- newpath = cp;
- }
-
- /* update path */
- if(pb->updateDir) {
- if(!pb->updateDir(pb->updateDirData, newpath)) {
- PathBarSetPath(pb, newpath);
- }
- } else {
- PathBarSetPath(pb, newpath);
- }
- XtFree(newpath);
-
- /* hide textfield and show path as buttons */
- XtUnmanageChild(pb->textfield);
- pathbar_resize(pb->widget, pb, NULL);
- }
-}
-
-static void pathbar_shift_left(Widget w, PathBar *p, XtPointer d) {
- p->shift--;
- pathbar_resize(p->widget, p, NULL);
-}
-
-static void pathbar_shift_right(Widget w, PathBar *p, XtPointer d) {
- if(p->shift < 0) {
- p->shift++;
- }
- pathbar_resize(p->widget, p, NULL);
-}
-
-static void pathbar_list_select(Widget w, PathBar *p, XmListCallbackStruct *cb) {
- char *value = NULL;
- XmStringGetLtoR(cb->item, XmSTRING_DEFAULT_CHARSET, &value);
- p->updateDir(p->updateDirData, value);
- PathBarSetPath(p, value);
- free(value);
-}
-
-static void pathbar_popup(Widget w, PathBar *p, XtPointer d) {
- Widget parent = XtParent(w);
- Display *dp = XtDisplay(parent);
- Window root = XDefaultRootWindow(dp);
-
- int x, y;
- Window child;
- XTranslateCoordinates(dp, XtWindow(parent), root, 0, 0, &x, &y, &child);
-
- XtManageChild(p->list);
- XtPopupSpringLoaded(p->popup);
- XtVaSetValues(p->popup, XmNx, x, XmNy, y + parent->core.height, XmNwidth, parent->core.width, XmNheight, 200, NULL);
-
- XmProcessTraversal(p->list, XmTRAVERSE_CURRENT);
-}
-
-static void popupEH(Widget widget, XtPointer data, XEvent *event, Boolean *dispatch) {
- PathBar *bar = data;
-
- Window w1 = bar->hs ? XtWindow(bar->hs) : 0;
- Window w2 = bar->vs ? XtWindow(bar->vs) : 0;
-
- if(event->type == ButtonPress) {
- if(event->xbutton.window != 0 && (event->xbutton.window == w1 || event->xbutton.window == w2)) {
- bar->popupScrollEvent = 1;
- } else {
- bar->popupScrollEvent = 0;
- }
- } else if(event->type == ButtonRelease) {
- if(bar->popupScrollEvent) {
- *dispatch = False;
- }
- bar->popupScrollEvent = 0;
- } else if(event->type == KeyReleaseMask) {
- int keycode = event->xkey.keycode;
- if(keycode == 36 || keycode == 9) {
- XtUnmapWidget(bar->popup);
- }
- }
-}
-
-static void pathTextEH(Widget widget, XtPointer data, XEvent *event, Boolean *dispatch) {
- PathBar *pb = data;
- if(event->type == KeyReleaseMask) {
- if(event->xkey.keycode == 9) {
- XtUnmanageChild(pb->textfield);
- pathbar_resize(pb->widget, pb, NULL);
- *dispatch = False;
- }
- }
-}
-
-
-PathBar* CreatePathBar(Widget parent, ArgList args, int n)
-{
- PathBar *bar = malloc(sizeof(PathBar));
- bar->path = NULL;
- bar->updateDir = NULL;
- bar->updateDirData = NULL;
- bar->disableResize = False;
-
- bar->shift = 0;
-
- XtSetArg(args[n], XmNmarginWidth, 0); n++;
- XtSetArg(args[n], XmNmarginHeight, 0); n++;
- bar->widget = XmCreateDrawingArea(parent, "pathbar", args, n);
- XtAddCallback(
- bar->widget,
- XmNresizeCallback,
- (XtCallbackProc)pathbar_resize,
- bar);
- XtAddCallback(
- bar->widget,
- XmNinputCallback,
- (XtCallbackProc)pathbar_input,
- bar);
-
- n = 0;
- XtSetArg(args[n], XmNownerEvents, True), n++;
- XtSetArg(args[n], XmNgrabStyle, GrabModeSync), n++;
- bar->popup = XmCreateGrabShell(bar->widget, "pbpopup", args, n);
- bar->list = XmCreateScrolledList(bar->popup, "pblist", NULL, 0);
- XtAddEventHandler(bar->popup, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask, FALSE, popupEH, bar);
- bar->popupScrollEvent = 0;
-
- XtAddCallback(
- bar->list,
- XmNdefaultActionCallback,
- (XtCallbackProc)pathbar_list_select,
- bar);
- XtAddCallback(
- bar->list,
- XmNbrowseSelectionCallback,
- (XtCallbackProc)pathbar_list_select,
- bar);
-
- bar->vs = NULL;
- bar->hs = NULL;
- XtVaGetValues(XtParent(bar->list), XmNhorizontalScrollBar, &bar->hs, XmNverticalScrollBar, &bar->vs, NULL);
-
- Arg a[4];
- XtSetArg(a[0], XmNshadowThickness, 0);
- XtSetArg(a[1], XmNx, 0);
- XtSetArg(a[2], XmNy, 0);
- bar->textfield = XmCreateTextField(bar->widget, "pbtext", a, 3);
- bar->input = 0;
- XtAddCallback(
- bar->textfield,
- XmNlosingFocusCallback,
- (XtCallbackProc)pathbar_losingfocus,
- bar);
- XtAddCallback(bar->textfield, XmNactivateCallback,
- (XtCallbackProc)pathbar_pathinput, bar);
- XtAddEventHandler(bar->textfield, KeyPressMask | KeyReleaseMask, FALSE, pathTextEH, bar);
-
- XtSetArg(a[0], XmNarrowDirection, XmARROW_DOWN);
- bar->down = XmCreateArrowButton(bar->widget, "pbbutton", a, 1);
- XtManageChild(bar->down);
- XtSetArg(a[0], XmNarrowDirection, XmARROW_LEFT);
- bar->left = XmCreateArrowButton(bar->widget, "pbbutton", a, 1);
- XtSetArg(a[0], XmNarrowDirection, XmARROW_RIGHT);
- bar->right = XmCreateArrowButton(bar->widget, "pbbutton", a, 1);
- XtAddCallback(
- bar->down,
- XmNactivateCallback,
- (XtCallbackProc)pathbar_popup,
- bar);
- XtAddCallback(
- bar->left,
- XmNactivateCallback,
- (XtCallbackProc)pathbar_shift_left,
- bar);
- XtAddCallback(
- bar->right,
- XmNactivateCallback,
- (XtCallbackProc)pathbar_shift_right,
- bar);
-
- Pixel bg;
- XtVaGetValues(bar->textfield, XmNbackground, &bg, NULL);
- XtVaSetValues(bar->widget, XmNbackground, bg, NULL);
-
- //XtManageChild(bar->left);
- //XtManageChild(bar->right);
-
- XtVaGetValues(bar->left, XmNwidth, &bar->lw, NULL);
- XtVaGetValues(bar->right, XmNwidth, &bar->rw, NULL);
-
- bar->segmentAlloc = 16;
- bar->numSegments = 0;
- bar->pathSegments = calloc(16, sizeof(Widget));
-
- bar->selection = 0;
-
- return bar;
-}
-
-static void PathBarChangeDir(Widget w, PathBar *bar, XtPointer unused) {
- XmToggleButtonSetState(bar->pathSegments[bar->selection], False, False);
-
- for(int i=0;i<bar->numSegments;i++) {
- if(bar->pathSegments[i] == w) {
- bar->selection = i;
- XmToggleButtonSetState(w, True, False);
- break;
- }
- }
-
- int plen = strlen(bar->path);
- int countSeg = 0;
- for(int i=0;i<=plen;i++) {
- char c = bar->path[i];
- if(c == '/' || c == '\0') {
- if(countSeg == bar->selection) {
- char *dir = malloc(i+2);
- memcpy(dir, bar->path, i+1);
- dir[i+1] = '\0';
- if(bar->updateDir) {
- bar->updateDir(bar->updateDirData, dir);
- }
- free(dir);
- }
- countSeg++;
- }
- }
-}
-
-void PathBarSetPath(PathBar *bar, const char *path) {
- if(bar->path) {
- free(bar->path);
- }
- bar->path = strdup(path);
-
- for(int i=0;i<bar->numSegments;i++) {
- XtDestroyWidget(bar->pathSegments[i]);
- }
- XtUnmanageChild(bar->textfield);
- //XtManageChild(bar->left);
- //XtManageChild(bar->right);
- bar->input = False;
-
- Arg args[4];
- XmString str;
-
- bar->numSegments = 0;
-
- int i=0;
- if(path[0] == '/') {
- str = XmStringCreateLocalized("/");
- XtSetArg(args[0], XmNlabelString, str);
- XtSetArg(args[1], XmNfillOnSelect, True);
- XtSetArg(args[2], XmNindicatorOn, False);
- bar->pathSegments[0] = XmCreateToggleButton(
- bar->widget, "pbbutton", args, 3);
- XtAddCallback(
- bar->pathSegments[0],
- XmNvalueChangedCallback,
- (XtCallbackProc)PathBarChangeDir,
- bar);
- XmStringFree(str);
- bar->numSegments++;
- i++;
- }
-
- int len = strlen(path);
- int begin = i;
- for(;i<=len;i++) {
- char c = path[i];
- if((c == '/' || c == '\0') && i > begin) {
- char *segStr = malloc(i - begin + 1);
- memcpy(segStr, path+begin, i-begin);
- segStr[i-begin] = '\0';
- begin = i+1;
-
- str = XmStringCreateLocalized(segStr);
- free(segStr);
- XtSetArg(args[0], XmNlabelString, str);
- XtSetArg(args[1], XmNfillOnSelect, True);
- XtSetArg(args[2], XmNindicatorOn, False);
- Widget button = XmCreateToggleButton(bar->widget, "pbbutton", args, 3);
- XtAddCallback(
- button,
- XmNvalueChangedCallback,
- (XtCallbackProc)PathBarChangeDir,
- bar);
- XmStringFree(str);
-
- if(bar->numSegments >= bar->segmentAlloc) {
- bar->segmentAlloc += 8;
- bar->pathSegments = realloc(bar->pathSegments, bar->segmentAlloc * sizeof(Widget));
- }
-
- bar->pathSegments[bar->numSegments++] = button;
- }
- }
-
- bar->selection = bar->numSegments-1;
- XmToggleButtonSetState(bar->pathSegments[bar->selection], True, False);
-
- XmTextFieldSetString(bar->textfield, (char*)path);
- XmTextFieldSetInsertionPosition(bar->textfield, XmTextFieldGetLastPosition(bar->textfield));
-
- pathbar_resize(bar->widget, bar, NULL);
-}
-
-void PathBarSetDirList(PathBar *bar, const char **dirlist, size_t nelm) {
- XmStringTable items = calloc(nelm, sizeof(XmString));
- for(int i=0;i<nelm;i++) {
- items[i] = XmStringCreateLocalized((char*)dirlist[i]);
- }
- XmListDeleteAllItems(bar->list);
- XmListAddItems(bar->list, items, nelm, 0);
- XmListSelectPos(bar->list, 1, False);
- for(int i=0;i<nelm;i++) {
- XmStringFree(items[i]);
- }
- free(items);
-}
-
-void PathBarDestroy(PathBar *bar) {
- if(bar->path) {
- free(bar->path);
- }
- free(bar->pathSegments);
- free(bar);
-}
/* ------------------------------ public API ------------------------------ */
f->fsb.view[f->fsb.numviews++] = view;
}
+/*
void XnFileSelectionBoxSetDirList(Widget fsb, const char **dirlist, size_t nelm) {
XnFileSelectionBox f = (XnFileSelectionBox)fsb;
PathBarSetDirList(f->fsb.pathBar, dirlist, nelm);
}
+*/
Widget XnFileSelectionBoxWorkArea(Widget fsb) {
XnFileSelectionBox f = (XnFileSelectionBox)fsb;
/*
* int FSBFilterFunc(const char *pattern, const char *string)
*
- * Checks checks whether the string matches the pattern
+ * Checks whether the string matches the pattern
*
* Return
* zero if the string matches the pattern
*/
typedef int(*FSBFilterFunc)(const char*, const char*);
-typedef int(*updatedir_callback)(void*,char*);
-
-typedef struct PathBar {
- Widget widget;
- Widget textfield;
-
- Widget down;
- Widget left;
- Widget right;
- Dimension lw;
- Dimension rw;
-
- Widget popup;
- Widget list;
-
- int shift;
-
- Widget *pathSegments;
- size_t numSegments;
- size_t segmentAlloc;
-
- char *path;
- int selection;
- Boolean input;
-
- Widget hs;
- Widget vs;
- int popupScrollEvent;
-
- updatedir_callback updateDir;
- void *updateDirData;
-
- Boolean disableResize;
-} PathBar;
typedef struct FileElm FileElm;
struct FileElm {
typedef void(*FSBViewCleanupProc)(Widget fsb, Widget view, void *userData);
typedef void(*FSBViewDestroyProc)(Widget fsb, Widget view, void *userData);
-PathBar* CreatePathBar(Widget parent, ArgList args, int n);
-void PathBarSetPath(PathBar *bar, const char *path);
-void PathBarSetDirList(PathBar *bar, const char **dirlist, size_t nelm);
-void PathBarDestroy(PathBar *bar);
-
Widget XnCreateFileSelectionDialog(
Widget parent,
String name,
Boolean useDirList,
void *userData);
-void XnFileSelectionBoxSetDirList(Widget fsb, const char **dirlist, size_t nelm);
+//void XnFileSelectionBoxSetDirList(Widget fsb, const char **dirlist, size_t nelm);
Widget XnFileSelectionBoxWorkArea(Widget fsb);
#include <Xm/FormP.h>
#include "Fsb.h"
+#include "pathbar.h"
#ifdef __cplusplus
extern "C" {
MOTIFOBJ += button.o
MOTIFOBJ += label.o
MOTIFOBJ += text.o
+MOTIFOBJ += pathbar.o
MOTIFOBJ += list.o
MOTIFOBJ += graphics.o
MOTIFOBJ += range.o
MOTIFOBJ += image.o
MOTIFOBJ += Grid.o
MOTIFOBJ += entry.o
+MOTIFOBJ += Fsb.o
TOOLKITOBJS += $(MOTIFOBJ:%=$(MOTIF_OBJPRE)%)
TOOLKITSOURCE += $(MOTIFOBJ:%.o=motif/%.c)
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "pathbar.h"
+
+#include <unistd.h>
+#include <cx/string.h>
+
+
+
+void pathbar_resize(Widget w, PathBar *p, XtPointer d)
+{
+ Dimension width, height;
+ XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL);
+
+ Dimension *segW = (void*)XtCalloc(p->numSegments, sizeof(Dimension));
+
+ Dimension maxHeight = 0;
+
+ /* get width/height from all widgets */
+ Dimension pathWidth = 0;
+ for(int i=0;i<p->numSegments;i++) {
+ Dimension segWidth;
+ Dimension segHeight;
+ XtVaGetValues(p->pathSegments[i], XmNwidth, &segWidth, XmNheight, &segHeight, NULL);
+ segW[i] = segWidth;
+ pathWidth += segWidth;
+ if(segHeight > maxHeight) {
+ maxHeight = segHeight;
+ }
+ }
+ Dimension tfHeight;
+ XtVaGetValues(p->textfield, XmNheight, &tfHeight, NULL);
+ if(tfHeight > maxHeight) {
+ maxHeight = tfHeight;
+ }
+
+ Boolean arrows = False;
+ if(pathWidth + 10 > width) {
+ arrows = True;
+ pathWidth += p->lw + p->rw;
+ }
+
+ /* calc max visible widgets */
+ int start = 0;
+ if(arrows) {
+ Dimension vis = p->lw+p->rw;
+ for(int i=p->numSegments;i>0;i--) {
+ Dimension segWidth = segW[i-1];
+ if(vis + segWidth + 10 > width) {
+ start = i;
+ arrows = True;
+ break;
+ }
+ vis += segWidth;
+ }
+ } else {
+ p->shift = 0;
+ }
+
+ int leftShift = 0;
+ if(p->shift < 0) {
+ if(start + p->shift < 0) {
+ leftShift = start;
+ start = 0;
+ p->shift = -leftShift;
+ } else {
+ leftShift = -p->shift; /* negative shift */
+ start += p->shift;
+ }
+ }
+
+ int x = 0;
+ if(arrows) {
+ XtManageChild(p->left);
+ XtManageChild(p->right);
+ x = p->lw;
+ } else {
+ XtUnmanageChild(p->left);
+ XtUnmanageChild(p->right);
+ }
+
+ for(int i=0;i<p->numSegments;i++) {
+ if(i >= start && i < p->numSegments - leftShift && !p->input) {
+ XtVaSetValues(p->pathSegments[i], XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL);
+ x += segW[i];
+ XtManageChild(p->pathSegments[i]);
+ } else {
+ XtUnmanageChild(p->pathSegments[i]);
+ }
+ }
+
+ if(arrows) {
+ XtVaSetValues(p->left, XmNx, 0, XmNy, 0, XmNheight, maxHeight, NULL);
+ XtVaSetValues(p->right, XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL);
+ }
+
+ free(segW);
+
+ Dimension rw, rh;
+ XtMakeResizeRequest(w, width, maxHeight, &rw, &rh);
+
+ XtVaSetValues(p->textfield, XmNwidth, rw, XmNheight, rh, NULL);
+}
+
+static void pathbarActivateTF(PathBar *p)
+{
+ XtUnmanageChild(p->left);
+ XtUnmanageChild(p->right);
+ XNETextSetSelection(p->textfield, 0, XNETextGetLastPosition(p->textfield), 0);
+ XtManageChild(p->textfield);
+ p->input = 1;
+
+ XmProcessTraversal(p->textfield, XmTRAVERSE_CURRENT);
+
+ pathbar_resize(p->widget, p, NULL);
+}
+
+void PathBarActivateTextfield(PathBar *p)
+{
+ p->focus = 1;
+ pathbarActivateTF(p);
+}
+
+void pathbar_input(Widget w, PathBar *p, XtPointer c)
+{
+ XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct*)c;
+ XEvent *xevent = cbs->event;
+
+ if (cbs->reason == XmCR_INPUT) {
+ if (xevent->xany.type == ButtonPress) {
+ p->focus = 0;
+ pathbarActivateTF(p);
+ }
+ }
+}
+
+void pathbar_losingfocus(Widget w, PathBar *p, XtPointer c)
+{
+ if(--p->focus < 0) {
+ p->input = False;
+ XtUnmanageChild(p->textfield);
+ }
+}
+
+static cxmutstr concat_path_s(cxstring base, cxstring path) {
+ if(!path.ptr) {
+ path = CX_STR("");
+ }
+
+ int add_separator = 0;
+ if(base.length != 0 && base.ptr[base.length-1] == '/') {
+ if(path.ptr[0] == '/') {
+ base.length--;
+ }
+ } else {
+ if(path.length == 0 || path.ptr[0] != '/') {
+ add_separator = 1;
+ }
+ }
+
+ cxmutstr url;
+ if(add_separator) {
+ url = cx_strcat(3, base, CX_STR("/"), path);
+ } else {
+ url = cx_strcat(2, base, path);
+ }
+
+ return url;
+}
+
+char* pathbar_concat_path(const char *path1, const char *path2) {
+ return concat_path_s(cx_str(path1), cx_str(path2)).ptr;
+}
+
+void pathbar_pathinput(Widget w, PathBar *p, XtPointer d)
+{
+ char *newpath = XNETextGetString(p->textfield);
+ if(newpath) {
+ if(newpath[0] == '~') {
+ char *p = newpath+1;
+ char *home = getenv("HOME");
+ char *cp = pathbar_concat_path(home, p);
+ XtFree(newpath);
+ newpath = cp;
+ } else if(newpath[0] != '/') {
+ char curdir[2048];
+ curdir[0] = 0;
+ getcwd(curdir, 2048);
+ char *cp = pathbar_concat_path(curdir, newpath);
+ XtFree(newpath);
+ newpath = cp;
+ }
+
+ /* update path */
+ PathBarSetPath(p, newpath);
+ if(p->updateDir) {
+ p->updateDir(p->updateDirData, newpath, -1);
+ }
+ XtFree(newpath);
+
+ /* hide textfield and show path as buttons */
+ XtUnmanageChild(p->textfield);
+ pathbar_resize(p->widget, p, NULL);
+
+ if(p->focus_widget) {
+ XmProcessTraversal(p->focus_widget, XmTRAVERSE_CURRENT);
+ }
+ }
+}
+
+void pathbar_shift_left(Widget w, PathBar *p, XtPointer d)
+{
+ p->shift--;
+ pathbar_resize(p->widget, p, NULL);
+}
+
+void pathbar_shift_right(Widget w, PathBar *p, XtPointer d)
+{
+ if(p->shift < 0) {
+ p->shift++;
+ }
+ pathbar_resize(p->widget, p, NULL);
+}
+
+static void pathTextEH(Widget widget, XtPointer data, XEvent *event, Boolean *dispatch) {
+ PathBar *pb = data;
+ if(event->type == KeyReleaseMask) {
+ if(event->xkey.keycode == 9) {
+ XtUnmanageChild(pb->textfield);
+ pathbar_resize(pb->widget, pb, NULL);
+ *dispatch = False;
+ } else if(event->xkey.keycode == 36) {
+ pathbar_pathinput(pb->textfield, pb, NULL);
+ *dispatch = False;
+ }
+ }
+}
+
+PathBar* CreatePathBar(Widget parent, ArgList args, int n)
+{
+ PathBar *bar = (PathBar*)XtMalloc(sizeof(PathBar));
+ bar->path = NULL;
+ bar->updateDir = NULL;
+ bar->updateDirData = NULL;
+
+ bar->focus_widget = NULL;
+
+ bar->getpathelm = NULL;
+ bar->getpathelmdata = NULL;
+ bar->current_pathelms = NULL;
+
+ bar->shift = 0;
+
+ XtSetArg(args[n], XmNmarginWidth, 0); n++;
+ XtSetArg(args[n], XmNmarginHeight, 0); n++;
+ bar->widget = XmCreateDrawingArea(parent, "pathbar", args, n);
+ XtAddCallback(
+ bar->widget,
+ XmNresizeCallback,
+ (XtCallbackProc)pathbar_resize,
+ bar);
+ XtAddCallback(
+ bar->widget,
+ XmNinputCallback,
+ (XtCallbackProc)pathbar_input,
+ bar);
+
+ Arg a[4];
+ XtSetArg(a[0], XmNshadowThickness, 0);
+ XtSetArg(a[1], XmNx, 0);
+ XtSetArg(a[2], XmNy, 0);
+ bar->textfield = XNECreateText(bar->widget, "pbtext", a, 3);
+ bar->input = 0;
+ XtAddCallback(
+ bar->textfield,
+ XmNlosingFocusCallback,
+ (XtCallbackProc)pathbar_losingfocus,
+ bar);
+ XtAddCallback(bar->textfield, XmNactivateCallback,
+ (XtCallbackProc)pathbar_pathinput, bar);
+ XtAddEventHandler(bar->textfield, KeyPressMask | KeyReleaseMask, FALSE, pathTextEH, bar);
+
+ XtSetArg(a[0], XmNarrowDirection, XmARROW_LEFT);
+ bar->left = XmCreateArrowButton(bar->widget, "pbbutton", a, 1);
+ XtSetArg(a[0], XmNarrowDirection, XmARROW_RIGHT);
+ bar->right = XmCreateArrowButton(bar->widget, "pbbutton", a, 1);
+ XtAddCallback(
+ bar->left,
+ XmNactivateCallback,
+ (XtCallbackProc)pathbar_shift_left,
+ bar);
+ XtAddCallback(
+ bar->right,
+ XmNactivateCallback,
+ (XtCallbackProc)pathbar_shift_right,
+ bar);
+
+ Pixel bg;
+ XtVaGetValues(bar->textfield, XmNbackground, &bg, NULL);
+ XtVaSetValues(bar->widget, XmNbackground, bg, NULL);
+
+ XtManageChild(bar->left);
+ XtManageChild(bar->right);
+
+ XtVaGetValues(bar->left, XmNwidth, &bar->lw, NULL);
+ XtVaGetValues(bar->right, XmNwidth, &bar->rw, NULL);
+
+ bar->segmentAlloc = 16;
+ bar->numSegments = 0;
+ bar->pathSegments = (Widget*)XtCalloc(16, sizeof(Widget));
+
+ bar->selection = 0;
+
+ return bar;
+}
+
+void PathBarChangeDir(Widget w, PathBar *bar, XtPointer c)
+{
+ XmToggleButtonSetState(bar->pathSegments[bar->selection], False, False);
+
+ int i;
+ for(i=0;i<bar->numSegments;i++) {
+ if(bar->pathSegments[i] == w) {
+ bar->selection = i;
+ XmToggleButtonSetState(w, True, False);
+ break;
+ }
+ }
+
+ UiPathElm elm = bar->current_pathelms[i];
+ cxmutstr path = cx_strdup(cx_strn(elm.path, elm.path_len));
+ if(bar->updateDir) {
+ XNETextSetString(bar->textfield, path.ptr);
+ bar->updateDir(bar->updateDirData, path.ptr, i);
+ }
+ free(path.ptr);
+}
+
+static void ui_pathelm_destroy(UiPathElm *elms, size_t nelm) {
+ for(int i=0;i<nelm;i++) {
+ free(elms[i].name);
+ free(elms[i].path);
+ }
+ free(elms);
+}
+
+void PathBarSetPath(PathBar *bar, const char *path)
+{
+ if(bar->path) {
+ free(bar->path);
+ }
+ bar->path = strdup(path);
+
+ for(int i=0;i<bar->numSegments;i++) {
+ XtDestroyWidget(bar->pathSegments[i]);
+ }
+ XtUnmanageChild(bar->textfield);
+ XtManageChild(bar->left);
+ XtManageChild(bar->right);
+ bar->input = False;
+
+ Arg args[4];
+ XmString str;
+
+ bar->numSegments = 0;
+
+ ui_pathelm_destroy(bar->current_pathelms, bar->numSegments);
+ size_t nelm = 0;
+ UiPathElm* path_elm = bar->getpathelm(bar->path, strlen(bar->path), &nelm, bar->getpathelmdata);
+ if (!path_elm) {
+ return;
+ }
+ bar->current_pathelms = path_elm;
+ bar->numSegments = nelm;
+ bar->pathSegments = realloc(bar->pathSegments, nelm * sizeof(Widget*));
+
+ for(int i=0;i<nelm;i++) {
+ UiPathElm elm = path_elm[i];
+
+ cxmutstr name = cx_strdup(cx_strn(elm.name, elm.name_len));
+ str = XmStringCreateLocalized(elm.name);
+ free(name.ptr);
+
+ XtSetArg(args[0], XmNlabelString, str);
+ XtSetArg(args[1], XmNfillOnSelect, True);
+ XtSetArg(args[2], XmNindicatorOn, False);
+ Widget button = XmCreateToggleButton(bar->widget, "pbbutton", args, 3);
+ XtAddCallback(
+ button,
+ XmNvalueChangedCallback,
+ (XtCallbackProc)PathBarChangeDir,
+ bar);
+ XmStringFree(str);
+
+ bar->pathSegments[i] = button;
+ }
+
+ bar->selection = bar->numSegments-1;
+ XmToggleButtonSetState(bar->pathSegments[bar->selection], True, False);
+
+ XNETextSetString(bar->textfield, (char*)path);
+ XNETextSetInsertionPosition(bar->textfield, XNETextGetLastPosition(bar->textfield));
+
+ pathbar_resize(bar->widget, bar, NULL);
+}
+
+void PathBarDestroy(PathBar *pathbar) {
+ if(pathbar->path) {
+ XtFree(pathbar->path);
+ }
+ XtFree((void*)pathbar->pathSegments);
+ XtFree((void*)pathbar);
+}
--- /dev/null
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2025 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PATHBAR_H
+#define PATHBAR_H
+
+#include <Xm/XmAll.h>
+
+#include "../ui/text.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define XNECreateText(parent,name,args,count) XmCreateTextField(parent,name,args,count)
+#define XNETextSetString(widget,value) XmTextFieldSetString(widget,value)
+#define XNETextGetString(widget) XmTextFieldGetString(widget)
+#define XNETextGetLastPosition(widget) XmTextFieldGetLastPosition(widget)
+#define XNETextSetInsertionPosition(widget, i) XmTextFieldSetInsertionPosition(widget, i)
+#define XNETextSetSelection(w, f, l, t) XmTextFieldSetSelection(w, f, l, t)
+
+typedef void(*updatedir_callback)(void*,char*,int);
+
+typedef struct PathBar {
+ Widget widget;
+ Widget textfield;
+
+ Widget focus_widget;
+
+ Widget left;
+ Widget right;
+ Dimension lw;
+ Dimension rw;
+
+ int shift;
+
+ UiPathElm *current_pathelms;
+ Widget *pathSegments;
+ size_t numSegments;
+ size_t segmentAlloc;
+
+ char *path;
+ int selection;
+ Boolean input;
+
+ int focus;
+
+ Boolean disableResize;
+
+ updatedir_callback updateDir;
+ void *updateDirData;
+
+ ui_pathelm_func getpathelm;
+ void *getpathelmdata;
+} PathBar;
+
+PathBar* CreatePathBar(Widget parent, ArgList args, int n);
+void PathBarSetPath(PathBar *bar, const char *path);
+void PathBarDestroy(PathBar *bar);
+
+void pathbar_resize(Widget w, PathBar *p, XtPointer d);
+
+char* pathbar_concat_path(const char *path1, const char *path2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PATHBAR_H */
+
#include "text.h"
#include "container.h"
+#include "pathbar.h"
+
+#include "../common/utils.h"
#include <cx/string.h>
}
-
-
-
-/* -------------------- path bar -------------------- */
-
-#define XNECreateText(parent,name,args,count) XmCreateTextField(parent,name,args,count)
-#define XNETextSetString(widget,value) XmTextFieldSetString(widget,value)
-#define XNETextGetString(widget) XmTextFieldGetString(widget)
-#define XNETextGetLastPosition(widget) XmTextFieldGetLastPosition(widget)
-#define XNETextSetInsertionPosition(widget, i) XmTextFieldSetInsertionPosition(widget, i)
-#define XNETextSetSelection(w, f, l, t) XmTextFieldSetSelection(w, f, l, t)
-
-typedef void(*updatedir_callback)(void*,char*,int);
-
-typedef struct PathBar {
- Widget widget;
- Widget textfield;
-
- Widget focus_widget;
-
- Widget left;
- Widget right;
- Dimension lw;
- Dimension rw;
-
- int shift;
-
- UiPathElm *current_pathelms;
- Widget *pathSegments;
- size_t numSegments;
- size_t segmentAlloc;
-
- char *path;
- int selection;
- Boolean input;
-
- int focus;
-
- updatedir_callback updateDir;
- void *updateDirData;
-
- ui_pathelm_func getpathelm;
- void *getpathelmdata;
-} PathBar;
-
-void PathBarSetPath(PathBar *bar, const char *path);
-
-void pathbar_resize(Widget w, PathBar *p, XtPointer d)
-{
- Dimension width, height;
- XtVaGetValues(w, XmNwidth, &width, XmNheight, &height, NULL);
-
- Dimension *segW = (void*)XtCalloc(p->numSegments, sizeof(Dimension));
-
- Dimension maxHeight = 0;
-
- /* get width/height from all widgets */
- Dimension pathWidth = 0;
- for(int i=0;i<p->numSegments;i++) {
- Dimension segWidth;
- Dimension segHeight;
- XtVaGetValues(p->pathSegments[i], XmNwidth, &segWidth, XmNheight, &segHeight, NULL);
- segW[i] = segWidth;
- pathWidth += segWidth;
- if(segHeight > maxHeight) {
- maxHeight = segHeight;
- }
- }
- Dimension tfHeight;
- XtVaGetValues(p->textfield, XmNheight, &tfHeight, NULL);
- if(tfHeight > maxHeight) {
- maxHeight = tfHeight;
- }
-
- Boolean arrows = False;
- if(pathWidth + 10 > width) {
- arrows = True;
- pathWidth += p->lw + p->rw;
- }
-
- /* calc max visible widgets */
- int start = 0;
- if(arrows) {
- Dimension vis = p->lw+p->rw;
- for(int i=p->numSegments;i>0;i--) {
- Dimension segWidth = segW[i-1];
- if(vis + segWidth + 10 > width) {
- start = i;
- arrows = True;
- break;
- }
- vis += segWidth;
- }
- } else {
- p->shift = 0;
- }
-
- int leftShift = 0;
- if(p->shift < 0) {
- if(start + p->shift < 0) {
- leftShift = start;
- start = 0;
- p->shift = -leftShift;
- } else {
- leftShift = -p->shift; /* negative shift */
- start += p->shift;
- }
- }
-
- int x = 0;
- if(arrows) {
- XtManageChild(p->left);
- XtManageChild(p->right);
- x = p->lw;
- } else {
- XtUnmanageChild(p->left);
- XtUnmanageChild(p->right);
- }
-
- for(int i=0;i<p->numSegments;i++) {
- if(i >= start && i < p->numSegments - leftShift && !p->input) {
- XtVaSetValues(p->pathSegments[i], XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL);
- x += segW[i];
- XtManageChild(p->pathSegments[i]);
- } else {
- XtUnmanageChild(p->pathSegments[i]);
- }
- }
-
- if(arrows) {
- XtVaSetValues(p->left, XmNx, 0, XmNy, 0, XmNheight, maxHeight, NULL);
- XtVaSetValues(p->right, XmNx, x, XmNy, 0, XmNheight, maxHeight, NULL);
- }
-
- free(segW);
-
- Dimension rw, rh;
- XtMakeResizeRequest(w, width, maxHeight, &rw, &rh);
-
- XtVaSetValues(p->textfield, XmNwidth, rw, XmNheight, rh, NULL);
-}
-
-static void pathbarActivateTF(PathBar *p)
-{
- XtUnmanageChild(p->left);
- XtUnmanageChild(p->right);
- XNETextSetSelection(p->textfield, 0, XNETextGetLastPosition(p->textfield), 0);
- XtManageChild(p->textfield);
- p->input = 1;
-
- XmProcessTraversal(p->textfield, XmTRAVERSE_CURRENT);
-
- pathbar_resize(p->widget, p, NULL);
-}
-
-void PathBarActivateTextfield(PathBar *p)
-{
- p->focus = 1;
- pathbarActivateTF(p);
-}
-
-void pathbar_input(Widget w, PathBar *p, XtPointer c)
-{
- XmDrawingAreaCallbackStruct *cbs = (XmDrawingAreaCallbackStruct*)c;
- XEvent *xevent = cbs->event;
-
- if (cbs->reason == XmCR_INPUT) {
- if (xevent->xany.type == ButtonPress) {
- p->focus = 0;
- pathbarActivateTF(p);
- }
- }
-}
-
-void pathbar_losingfocus(Widget w, PathBar *p, XtPointer c)
-{
- if(--p->focus < 0) {
- p->input = False;
- XtUnmanageChild(p->textfield);
- }
-}
-
-static cxmutstr concat_path_s(cxstring base, cxstring path) {
- if(!path.ptr) {
- path = CX_STR("");
- }
-
- int add_separator = 0;
- if(base.length != 0 && base.ptr[base.length-1] == '/') {
- if(path.ptr[0] == '/') {
- base.length--;
- }
- } else {
- if(path.length == 0 || path.ptr[0] != '/') {
- add_separator = 1;
- }
- }
-
- cxmutstr url;
- if(add_separator) {
- url = cx_strcat(3, base, CX_STR("/"), path);
- } else {
- url = cx_strcat(2, base, path);
- }
-
- return url;
-}
-
-static char* ConcatPath(const char *path1, const char *path2) {
- return concat_path_s(cx_str(path1), cx_str(path2)).ptr;
-}
-
-void pathbar_pathinput(Widget w, PathBar *p, XtPointer d)
-{
- char *newpath = XNETextGetString(p->textfield);
- if(newpath) {
- if(newpath[0] == '~') {
- char *p = newpath+1;
- char *home = getenv("HOME");
- char *cp = ConcatPath(home, p);
- XtFree(newpath);
- newpath = cp;
- } else if(newpath[0] != '/') {
- char curdir[2048];
- curdir[0] = 0;
- getcwd(curdir, 2048);
- char *cp = ConcatPath(curdir, newpath);
- XtFree(newpath);
- newpath = cp;
- }
-
- /* update path */
- PathBarSetPath(p, newpath);
- if(p->updateDir) {
- p->updateDir(p->updateDirData, newpath, -1);
- }
- XtFree(newpath);
-
- /* hide textfield and show path as buttons */
- XtUnmanageChild(p->textfield);
- pathbar_resize(p->widget, p, NULL);
-
- if(p->focus_widget) {
- XmProcessTraversal(p->focus_widget, XmTRAVERSE_CURRENT);
- }
- }
-}
-
-void pathbar_shift_left(Widget w, PathBar *p, XtPointer d)
-{
- p->shift--;
- pathbar_resize(p->widget, p, NULL);
-}
-
-void pathbar_shift_right(Widget w, PathBar *p, XtPointer d)
-{
- if(p->shift < 0) {
- p->shift++;
- }
- pathbar_resize(p->widget, p, NULL);
-}
-
-static void pathTextEH(Widget widget, XtPointer data, XEvent *event, Boolean *dispatch) {
- PathBar *pb = data;
- if(event->type == KeyReleaseMask) {
- if(event->xkey.keycode == 9) {
- XtUnmanageChild(pb->textfield);
- pathbar_resize(pb->widget, pb, NULL);
- *dispatch = False;
- } else if(event->xkey.keycode == 36) {
- pathbar_pathinput(pb->textfield, pb, NULL);
- *dispatch = False;
- }
- }
-}
-
-PathBar* CreatePathBar(Widget parent, ArgList args, int n)
-{
- PathBar *bar = (PathBar*)XtMalloc(sizeof(PathBar));
- bar->path = NULL;
- bar->updateDir = NULL;
- bar->updateDirData = NULL;
-
- bar->focus_widget = NULL;
-
- bar->getpathelm = NULL;
- bar->getpathelmdata = NULL;
- bar->current_pathelms = NULL;
-
- bar->shift = 0;
-
- XtSetArg(args[n], XmNmarginWidth, 0); n++;
- XtSetArg(args[n], XmNmarginHeight, 0); n++;
- bar->widget = XmCreateDrawingArea(parent, "pathbar", args, n);
- XtAddCallback(
- bar->widget,
- XmNresizeCallback,
- (XtCallbackProc)pathbar_resize,
- bar);
- XtAddCallback(
- bar->widget,
- XmNinputCallback,
- (XtCallbackProc)pathbar_input,
- bar);
-
- Arg a[4];
- XtSetArg(a[0], XmNshadowThickness, 0);
- XtSetArg(a[1], XmNx, 0);
- XtSetArg(a[2], XmNy, 0);
- bar->textfield = XNECreateText(bar->widget, "pbtext", a, 3);
- bar->input = 0;
- XtAddCallback(
- bar->textfield,
- XmNlosingFocusCallback,
- (XtCallbackProc)pathbar_losingfocus,
- bar);
- XtAddCallback(bar->textfield, XmNactivateCallback,
- (XtCallbackProc)pathbar_pathinput, bar);
- XtAddEventHandler(bar->textfield, KeyPressMask | KeyReleaseMask, FALSE, pathTextEH, bar);
-
- XtSetArg(a[0], XmNarrowDirection, XmARROW_LEFT);
- bar->left = XmCreateArrowButton(bar->widget, "pbbutton", a, 1);
- XtSetArg(a[0], XmNarrowDirection, XmARROW_RIGHT);
- bar->right = XmCreateArrowButton(bar->widget, "pbbutton", a, 1);
- XtAddCallback(
- bar->left,
- XmNactivateCallback,
- (XtCallbackProc)pathbar_shift_left,
- bar);
- XtAddCallback(
- bar->right,
- XmNactivateCallback,
- (XtCallbackProc)pathbar_shift_right,
- bar);
-
- Pixel bg;
- XtVaGetValues(bar->textfield, XmNbackground, &bg, NULL);
- XtVaSetValues(bar->widget, XmNbackground, bg, NULL);
-
- XtManageChild(bar->left);
- XtManageChild(bar->right);
-
- XtVaGetValues(bar->left, XmNwidth, &bar->lw, NULL);
- XtVaGetValues(bar->right, XmNwidth, &bar->rw, NULL);
-
- bar->segmentAlloc = 16;
- bar->numSegments = 0;
- bar->pathSegments = (Widget*)XtCalloc(16, sizeof(Widget));
-
- bar->selection = 0;
-
- return bar;
-}
-
-void PathBarChangeDir(Widget w, PathBar *bar, XtPointer c)
-{
- XmToggleButtonSetState(bar->pathSegments[bar->selection], False, False);
-
- int i;
- for(i=0;i<bar->numSegments;i++) {
- if(bar->pathSegments[i] == w) {
- bar->selection = i;
- XmToggleButtonSetState(w, True, False);
- break;
- }
- }
-
- UiPathElm elm = bar->current_pathelms[i];
- cxmutstr path = cx_strdup(cx_strn(elm.path, elm.path_len));
- if(bar->updateDir) {
- XNETextSetString(bar->textfield, path.ptr);
- bar->updateDir(bar->updateDirData, path.ptr, i);
- }
- free(path.ptr);
-}
-
-static void ui_pathelm_destroy(UiPathElm *elms, size_t nelm) {
- for(int i=0;i<nelm;i++) {
- free(elms[i].name);
- free(elms[i].path);
- }
- free(elms);
-}
-
-void PathBarSetPath(PathBar *bar, const char *path)
-{
- if(bar->path) {
- free(bar->path);
- }
- bar->path = strdup(path);
-
- for(int i=0;i<bar->numSegments;i++) {
- XtDestroyWidget(bar->pathSegments[i]);
- }
- XtUnmanageChild(bar->textfield);
- XtManageChild(bar->left);
- XtManageChild(bar->right);
- bar->input = False;
-
- Arg args[4];
- XmString str;
-
- bar->numSegments = 0;
-
- ui_pathelm_destroy(bar->current_pathelms, bar->numSegments);
- size_t nelm = 0;
- UiPathElm* path_elm = bar->getpathelm(bar->path, strlen(bar->path), &nelm, bar->getpathelmdata);
- if (!path_elm) {
- return;
- }
- bar->current_pathelms = path_elm;
- bar->numSegments = nelm;
- bar->pathSegments = realloc(bar->pathSegments, nelm * sizeof(Widget*));
-
- for(int i=0;i<nelm;i++) {
- UiPathElm elm = path_elm[i];
-
- cxmutstr name = cx_strdup(cx_strn(elm.name, elm.name_len));
- str = XmStringCreateLocalized(elm.name);
- free(name.ptr);
-
- XtSetArg(args[0], XmNlabelString, str);
- XtSetArg(args[1], XmNfillOnSelect, True);
- XtSetArg(args[2], XmNindicatorOn, False);
- Widget button = XmCreateToggleButton(bar->widget, "pbbutton", args, 3);
- XtAddCallback(
- button,
- XmNvalueChangedCallback,
- (XtCallbackProc)PathBarChangeDir,
- bar);
- XmStringFree(str);
-
- bar->pathSegments[i] = button;
- }
-
- bar->selection = bar->numSegments-1;
- XmToggleButtonSetState(bar->pathSegments[bar->selection], True, False);
-
- XNETextSetString(bar->textfield, (char*)path);
- XNETextSetInsertionPosition(bar->textfield, XNETextGetLastPosition(bar->textfield));
-
- pathbar_resize(bar->widget, bar, NULL);
-}
-
-void PathBarDestroy(PathBar *pathbar) {
- if(pathbar->path) {
- XtFree(pathbar->path);
- }
- XtFree((void*)pathbar->pathSegments);
- XtFree((void*)pathbar);
-}
-
-
/* ---------------------------- Path Text Field ---------------------------- */
static void destroy_pathbar(Widget w, XtPointer *data, XtPointer d) {
XtFree((void*)pathbar);
}
-// TODO: move to common
-static UiPathElm* default_pathelm_func(const char* full_path, size_t len, size_t* ret_nelm, void* data) {
- cxstring *pathelms;
- size_t nelm = cx_strsplit_a(cxDefaultAllocator, cx_strn(full_path, len), CX_STR("/"), 4096, &pathelms);
-
- if (nelm == 0) {
- *ret_nelm = 0;
- return NULL;
- }
-
- UiPathElm* elms = (UiPathElm*)calloc(nelm, sizeof(UiPathElm));
- size_t n = nelm;
- int j = 0;
- for (int i = 0; i < nelm; i++) {
- cxstring c = pathelms[i];
- if (c.length == 0) {
- if (i == 0) {
- c.length = 1;
- }
- else {
- n--;
- continue;
- }
- }
-
- cxmutstr m = cx_strdup(c);
- elms[j].name = m.ptr;
- elms[j].name_len = m.length;
-
- size_t elm_path_len = c.ptr + c.length - full_path;
- cxmutstr elm_path = cx_strdup(cx_strn(full_path, elm_path_len));
- elms[j].path = elm_path.ptr;
- elms[j].path_len = elm_path.length;
-
- j++;
- }
- *ret_nelm = n;
-
- return elms;
-}
-
static void pathbar_activate(void *data, char *path, int index) {
UiEventData *event = data;
UiEvent evt;
PathBar *pathbar = CreatePathBar(parent, xargs, n);
if(!args->getpathelm) {
- pathbar->getpathelm= default_pathelm_func;
+ pathbar->getpathelm= ui_default_pathelm_func;
} else {
pathbar->getpathelm = args->getpathelm;
pathbar->getpathelmdata = args->getpathelmdata;
typedef enum UiOrientation UiOrientation;
enum UiOrientation { UI_HORIZONTAL = 0, UI_VERTICAL };
-void ui_exit_mainloop();
-
XtAppContext ui_motif_get_app(void);
Display* ui_motif_get_display(void);
#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
#include "toolkit.h"
#include "menu.h"
#include "toolbar.h"
#include "container.h"
+#include "pathbar.h"
#include "../ui/window.h"
#include "../common/context.h"
#include "Grid.h"
+#include "Fsb.h"
#include <cx/mempool.h>
UiObject* ui_simple_window(const char *title, void *window_data) {
return create_window(title, window_data, TRUE);
}
+
+static void filedialog_event(UiEventData *event, int result, UiFileList flist) {
+ UiEvent evt;
+ evt.obj = event->obj;
+ evt.document = evt.obj->ctx->document;
+ evt.window = evt.obj->window;
+ evt.intval = result;
+
+ evt.eventdata = &flist;
+ evt.eventdatatype = UI_EVENT_DATA_FILE_LIST;
+
+ if(event->callback) {
+ event->callback(&evt, event->userdata);
+ }
+}
+
+static void filedialog_select(
+ Widget widget,
+ UiEventData *data,
+ XmFileSelectionBoxCallbackStruct *selection)
+{
+ UiFileList flist;
+
+ char *value = NULL;
+ XmStringGetLtoR(selection->value, XmSTRING_DEFAULT_CHARSET, &value);
+ flist.files = &value;
+ flist.nfiles = 1;
+
+ filedialog_event(data, 1, flist);
+
+ XtFree(value);
+
+ XtUnmanageChild(widget);
+ XtDestroyWidget(widget);
+}
+
+static void filedialog_cancel(
+ Widget widget,
+ UiEventData *data,
+ XmFileSelectionBoxCallbackStruct *selection)
+{
+ UiFileList flist;
+ flist.files = NULL;
+ flist.nfiles = 0;
+ filedialog_event(data, 0, flist);
+
+ XtUnmanageChild(widget);
+ XtDestroyWidget(widget);
+}
+
+void ui_openfiledialog(UiObject *obj, unsigned int mode, ui_callback file_selected_callback, void *cbdata) {
+ Widget dialog = XnCreateFileSelectionDialog(obj->widget, "dialog", NULL, 0);
+
+ UiEventData *data = malloc(sizeof(UiEventData));
+ memset(data, 0, sizeof(UiEventData));
+ data->obj = obj;
+ data->callback = file_selected_callback;
+ data->userdata = cbdata;
+
+ XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)filedialog_select, data);
+ XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)filedialog_cancel, data);
+ //XtAddCallback(dialog, XmNhelpCallback, (XtCallbackProc)filedialog_help, wd);
+
+ XtManageChild(dialog);
+}
+
+void ui_savefiledialog(UiObject *obj, const char *name, ui_callback file_selected_callback, void *cbdata) {
+ Arg args[16];
+ int n = 0;
+
+ // Save File Dialog needs this parameter
+ XtSetArg(args[n], XnNfsbType, FILEDIALOG_SAVE); n++;
+ char *selectedpath = (char*)name;
+ if(name) {
+ if(name[0] != '/') {
+ char cwd[PATH_MAX];
+ if(getcwd(cwd, PATH_MAX)) {
+ pathbar_concat_path(cwd, name);
+ } else {
+ fprintf(stderr, "Error: getcwd failed: %s\n", strerror(errno));
+ selectedpath = NULL;
+ }
+ }
+ if(selectedpath) {
+ XtSetArg(args[n], XnNselectedPath, selectedpath); n++;
+ }
+ }
+ Widget dialog = XnCreateFileSelectionDialog(obj->widget, "dialog", args, n);
+
+ UiEventData *data = malloc(sizeof(UiEventData));
+ memset(data, 0, sizeof(UiEventData));
+ data->obj = obj;
+ data->callback = file_selected_callback;
+ data->userdata = cbdata;
+
+ XtAddCallback(dialog, XmNokCallback, (XtCallbackProc)filedialog_select, data);
+ XtAddCallback(dialog, XmNcancelCallback, (XtCallbackProc)filedialog_cancel, data);
+ //XtAddCallback(dialog, XmNhelpCallback, (XtCallbackProc)filedialog_help, wd);
+
+ XtManageChild(dialog);
+
+ if(selectedpath != name) {
+ free(selectedpath);
+ }
+}