/* * Copyright (c) 2002-2007 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 "combo.h" #include "primitive.h" AG_Combo * AG_ComboNew(void *parent, Uint flags, const char *label) { AG_Combo *com; com = Malloc(sizeof(AG_Combo)); AG_ObjectInit(com, &agComboClass); com->flags |= flags; if (label != NULL) { AG_TextboxSetLabel(com->tbox, "%s", label); } if (flags & AG_COMBO_ANY_TEXT) { AG_WidgetDisable(com->tbox); } if (flags & AG_COMBO_TREE) { com->list->flags |= AG_TLIST_TREE; } if (flags & AG_COMBO_POLL) { com->list->flags |= AG_TLIST_POLL; } if (flags & AG_COMBO_SCROLLTOSEL) { com->list->flags |= AG_TLIST_SCROLLTOSEL; } if (flags & AG_COMBO_HFILL) { AG_ExpandHoriz(com); } if (flags & AG_COMBO_VFILL) { AG_ExpandVert(com); } AG_ObjectAttach(parent, com); return (com); } static void Collapse(AG_Combo *com) { if (com->panel == NULL) { return; } com->wSaved = WIDTH(com->panel); com->hSaved = HEIGHT(com->panel); AG_WindowHide(com->panel); AG_ObjectDetach(com->list); AG_ViewDetach(com->panel); com->panel = NULL; AG_SetInt(com->button, "state", 0); } static void ModalClose(AG_Event *event) { AG_Combo *com = AG_PTR(1); if (com->panel != NULL) Collapse(com); } static void Expand(AG_Event *event) { AG_Combo *com = AG_PTR(1); int expand = AG_INT(2); AG_SizeReq rList; int x, y, w, h; if (expand) { /* Expand */ com->panel = AG_WindowNew(AG_WINDOW_MODAL|AG_WINDOW_NOTITLE); AG_WindowSetPadding(com->panel, 0, 0, 0, 0); AG_ObjectAttach(com->panel, com->list); if (com->wSaved > 0) { w = com->wSaved; h = com->hSaved; } else { if (com->wPreList != -1 && com->hPreList != -1) { AG_TlistSizeHintPixels(com->list, com->wPreList, com->hPreList); } AG_WidgetSizeReq(com->list, &rList); w = rList.w + com->panel->wBorderSide*2; h = rList.h + com->panel->wBorderBot; } x = WIDGET(com)->rView.x2 - w; y = WIDGET(com)->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(com); return; } AG_SetEvent(com->panel, "window-modal-close", ModalClose, "%p", com); AG_WindowSetGeometry(com->panel, x, y, w, h); AG_WindowShow(com->panel); } else { Collapse(com); } } /* Select a combo item based on its pointer. */ AG_TlistItem * AG_ComboSelectPointer(AG_Combo *com, void *p) { AG_TlistItem *it; AG_ObjectLock(com->list); if ((it = AG_TlistSelectPtr(com->list, p)) != NULL) { AG_TextboxSetString(com->tbox, it->text); } AG_ObjectUnlock(com->list); return (it); } /* Select a combo item based on its text. */ AG_TlistItem * AG_ComboSelectText(AG_Combo *com, const char *text) { AG_TlistItem *it; AG_ObjectLock(com->list); if ((it = AG_TlistSelectText(com->list, text)) != NULL) { AG_TextboxSetString(com->tbox, it->text); } AG_ObjectUnlock(com->list); return (it); } void AG_ComboSelect(AG_Combo *com, AG_TlistItem *it) { AG_ObjectLock(com->list); AG_TextboxSetString(com->tbox, it->text); AG_TlistSelect(com->list, it); AG_ObjectUnlock(com->list); } static void SelectedItem(AG_Event *event) { AG_Tlist *tl = AG_SELF(); AG_Combo *com = AG_PTR(1); AG_TlistItem *ti; AG_ObjectLock(tl); if ((ti = AG_TlistSelectedItem(tl)) != NULL) { AG_TextboxSetString(com->tbox, ti->text); AG_PostEvent(NULL, com, "combo-selected", "%p", ti); } AG_ObjectUnlock(tl); Collapse(com); } static void Return(AG_Event *event) { char text[AG_TEXTBOX_STRING_MAX]; AG_Textbox *tbox = AG_SELF(); AG_Combo *com = AG_PTR(1); AG_ObjectLock(com->list); AG_TextboxCopyString(tbox, text, sizeof(text)); if ((com->flags & AG_COMBO_ANY_TEXT) == 0) { AG_TlistItem *it; if (text[0] != '\0' && (it = AG_TlistSelectText(com->list, text)) != NULL) { AG_TextboxSetString(com->tbox, it->text); AG_PostEvent(NULL, com, "combo-selected", "%p", it); } else { AG_TlistDeselectAll(com->list); AG_TextboxSetString(com->tbox, ""); AG_PostEvent(NULL, com, "combo-text-unknown", "%s", text); } } else { AG_TlistDeselectAll(com->list); AG_PostEvent(NULL, com, "combo-text-entry", "%s", text); } AG_ObjectUnlock(com->list); } static void Init(void *obj) { AG_Combo *com = obj; com->flags = 0; com->panel = NULL; com->wSaved = 0; com->hSaved = 0; com->wPreList = -1; com->hPreList = -1; com->tbox = AG_TextboxNew(com, AG_TEXTBOX_COMBO, NULL); com->button = AG_ButtonNew(com, AG_BUTTON_STICKY, _(" ... ")); AG_ButtonSetPadding(com->button, 1,1,1,1); AG_WidgetSetFocusable(com->button, 0); com->list = Malloc(sizeof(AG_Tlist)); AG_ObjectInit(com->list, &agTlistClass); AG_Expand(com->list); AG_SetEvent(com->button, "button-pushed", Expand, "%p", com); AG_SetEvent(com->list, "tlist-changed", SelectedItem, "%p", com); AG_SetEvent(com->tbox, "textbox-return", Return, "%p", com); AG_WidgetForwardFocus(com, com->tbox); } void AG_ComboSizeHint(AG_Combo *com, const char *text, int h) { AG_TextSize(text, &com->wPreList, NULL); com->hPreList = h; } void AG_ComboSizeHintPixels(AG_Combo *com, int w, int h) { com->wPreList = w; com->hPreList = h; } void AG_ComboSetButtonText(AG_Combo *com, const char *text) { AG_ButtonText(com->button, "%s", text); } void AG_ComboSetButtonSurface(AG_Combo *com, AG_Surface *su) { AG_ButtonSurface(com->button, su); } void AG_ComboSetButtonSurfaceNODUP(AG_Combo *com, AG_Surface *su) { AG_ButtonSurfaceNODUP(com->button, su); } static void Destroy(void *p) { AG_Combo *com = p; if (com->panel != NULL) { AG_WindowHide(com->panel); AG_ObjectDetach(com->list); AG_ViewDetach(com->panel); } AG_ObjectDestroy(com->list); } static void Draw(void *obj) { AG_Combo *com = obj; AG_WidgetDraw(com->tbox); AG_WidgetDraw(com->button); } static void SizeRequest(void *obj, AG_SizeReq *r) { AG_Combo *com = obj; AG_SizeReq rChld; AG_WidgetSizeReq(com->tbox, &rChld); r->w = rChld.w; r->h = rChld.h; AG_WidgetSizeReq(com->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_Combo *com = obj; AG_SizeReq rBtn; AG_SizeAlloc aChld; AG_WidgetSizeReq(com->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(com->tbox, &aChld); aChld.x = aChld.w + 1; aChld.w = rBtn.w; AG_WidgetSizeAlloc(com->button, &aChld); return (0); } AG_WidgetClass agComboClass = { { "Agar(Widget:Combo)", sizeof(AG_Combo), { 0,0 }, Init, NULL, /* free */ Destroy, NULL, /* load */ NULL, /* save */ NULL /* edit */ }, Draw, SizeRequest, SizeAllocate };