/* * Copyright (c) 2008 Hypertriton, Inc. * 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 AUTHOR 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 #include "file_selector.h" AG_FileSelector * AG_FileSelectorNew(void *parent, Uint flags, const char *label) { AG_FileSelector *fs; fs = Malloc(sizeof(AG_FileSelector)); AG_ObjectInit(fs, &agFileSelectorClass); fs->flags |= flags; if (label != NULL) { AG_TextboxSetLabel(fs->tbox, "%s", label); } if (flags & AG_FILE_SELECTOR_HFILL) { AG_ExpandHoriz(fs); } if (flags & AG_FILE_SELECTOR_VFILL) { AG_ExpandVert(fs); } AG_ObjectAttach(parent, fs); return (fs); } static void Collapse(AG_FileSelector *fs) { if (fs->panel == NULL) { return; } fs->wSaved = WIDTH(fs->panel); fs->hSaved = HEIGHT(fs->panel); AG_WindowHide(fs->panel); AG_ObjectDetach(fs->filedlg); AG_ViewDetach(fs->panel); fs->panel = NULL; AG_SetInt(fs->button, "state", 0); } static void ModalClose(AG_Event *event) { AG_FileSelector *fs = AG_PTR(1); if (fs->panel != NULL) Collapse(fs); } static void Expand(AG_Event *event) { AG_FileSelector *fs = AG_PTR(1); int expand = AG_INT(2); AG_SizeReq rFileDlg; int x, y, w, h; if (expand) { /* Expand */ fs->panel = AG_WindowNew(AG_WINDOW_MODAL|AG_WINDOW_NOTITLE); AG_WindowSetPadding(fs->panel, 0, 0, 0, 0); AG_ObjectAttach(fs->panel, fs->filedlg); if (fs->wSaved > 0) { w = fs->wSaved; h = fs->hSaved; } else { AG_WidgetSizeReq(fs->filedlg, &rFileDlg); w = rFileDlg.w + fs->panel->wBorderSide*2; h = rFileDlg.h + fs->panel->wBorderBot; } x = WIDGET(fs)->rView.x2 - w; y = WIDGET(fs)->rView.y1; if (x+w > agView->w) { w = agView->w - x; } if (y+h > agView->h) { h = agView->h - y; } if (w < 4 || h < 4) { Collapse(fs); return; } AG_SetEvent(fs->panel, "window-modal-close", ModalClose, "%p", fs); AG_WindowSetGeometry(fs->panel, x, y, w, h); AG_WindowShow(fs->panel); } else { Collapse(fs); } } static void SetDirectoryAndFile(AG_FileSelector *fs, const char *pPath) { char path[AG_FILENAME_MAX], *file; Strlcpy(path, pPath, sizeof(path)); if ((file = strrchr(path, AG_PATHSEPCHAR)) != NULL) { AG_FileDlgSetFilename(fs->filedlg, file); *file = '\0'; AG_FileDlgSetDirectory(fs->filedlg, path); } } static void SetDirectory(AG_FileSelector *fs, const char *pPath) { char path[AG_FILENAME_MAX]; Strlcpy(path, pPath, sizeof(path)); AG_FileDlgSetDirectory(fs->filedlg, path); } void AG_FileSelectorSetFile(AG_FileSelector *fs, const char *path) { AG_ObjectLock(fs->filedlg); SetDirectoryAndFile(fs, path); AG_TextboxSetString(fs->tbox, path); AG_ObjectUnlock(fs->filedlg); } void AG_FileSelectorSetDirectory(AG_FileSelector *fs, const char *path) { char dir[AG_PATHNAME_MAX]; Strlcpy(dir, path, sizeof(dir)); if (dir[0] != '\0' && dir[strlen(dir)-1] != AG_PATHSEPCHAR) { dir[strlen(dir)-1] = AG_PATHSEPCHAR; } AG_ObjectLock(fs->filedlg); SetDirectory(fs, dir); AG_TextboxSetString(fs->tbox, dir); AG_ObjectUnlock(fs->filedlg); } static void FileChosen(AG_Event *event) { AG_FileSelector *fs = AG_PTR(1); char *path = AG_STRING(2); AG_TextboxSetString(fs->tbox, path); AG_PostEvent(NULL, fs, "file-chosen", "%s", path); Collapse(fs); } static void Return(AG_Event *event) { char path[AG_TEXTBOX_STRING_MAX]; AG_Textbox *tbox = AG_SELF(); AG_FileSelector *fs = AG_PTR(1); AG_ObjectLock(fs->filedlg); AG_TextboxCopyString(tbox, path, sizeof(path)); /* XXX TODO: Check access, AG_FILE_SELECTOR_ANY_FILE */ SetDirectoryAndFile(fs, path); AG_PostEvent(NULL, fs, "file-chosen", "%s", path); AG_ObjectUnlock(fs->filedlg); } static void Init(void *obj) { AG_FileSelector *fs = obj; fs->flags = 0; fs->panel = NULL; fs->wSaved = 0; fs->hSaved = 0; fs->tbox = AG_TextboxNew(fs, AG_TEXTBOX_COMBO, NULL); fs->button = AG_ButtonNew(fs, AG_BUTTON_STICKY, _("Browse...")); AG_ButtonSetPadding(fs->button, 1,1,1,1); AG_WidgetSetFocusable(fs->button, 0); fs->filedlg = Malloc(sizeof(AG_FileDlg)); AG_ObjectInit(fs->filedlg, &agFileDlgClass); AG_Expand(fs->filedlg); AG_SetEvent(fs->button, "button-pushed", Expand, "%p", fs); AG_SetEvent(fs->filedlg, "file-chosen", FileChosen, "%p", fs); AG_SetEvent(fs->tbox, "textbox-return", Return, "%p", fs); } static void Destroy(void *p) { AG_FileSelector *fs = p; if (fs ->panel != NULL) { AG_WindowHide(fs->panel); AG_ObjectDetach(fs->filedlg); AG_ViewDetach(fs->panel); } AG_ObjectDestroy(fs->filedlg); } static void Draw(void *obj) { AG_Widget *chld; WIDGET_FOREACH_CHILD(chld, obj) AG_WidgetDraw(chld); } static void SizeRequest(void *obj, AG_SizeReq *r) { AG_FileSelector *fs = obj; AG_SizeReq rChld; AG_WidgetSizeReq(fs->tbox, &rChld); r->w = rChld.w; r->h = rChld.h; AG_WidgetSizeReq(fs->button, &rChld); r->w += rChld.w; if (r->h < rChld.h) { r->h = rChld.h; } } static int SizeAllocate(void *obj, const AG_SizeAlloc *a) { AG_FileSelector *fs = obj; AG_SizeReq rBtn; AG_SizeAlloc aChld; AG_WidgetSizeReq(fs->button, &rBtn); if (a->w < rBtn.w) { return (-1); } aChld.x = 0; aChld.y = 0; aChld.w = a->w - rBtn.w - 1; aChld.h = a->h; AG_WidgetSizeAlloc(fs->tbox, &aChld); aChld.x = aChld.w + 1; aChld.w = rBtn.w; AG_WidgetSizeAlloc(fs->button, &aChld); return (0); } AG_WidgetClass agFileSelectorClass = { { "Agar(Widget:FileSelector)", sizeof(AG_FileSelector), { 0,0 }, Init, NULL, /* free */ Destroy, NULL, /* load */ NULL, /* save */ NULL /* edit */ }, Draw, SizeRequest, SizeAllocate };