/* * Copyright (c) 2004-2020 Julien Nadeau Carriere * 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. */ /* * Toolbar widget. This is a simple subclass of AG_Box(3) which packs a set * of AG_Button(3) in one or more rows. It can connect to an AG_Menu(3). */ #include #ifdef AG_WIDGETS #include #include #include #include AG_Toolbar * AG_ToolbarNew(void *parent, enum ag_toolbar_type type, int nRows, Uint flags) { AG_Toolbar *bar; int i; bar = Malloc(sizeof(AG_Toolbar)); AG_ObjectInit(bar, &agToolbarClass); bar->flags |= flags; bar->type = type; for (i = 0; i < nRows && i < AG_TOOLBAR_MAX_ROWS; i++) { AG_Box *row; Uint bflags = 0; if (flags & AG_TOOLBAR_HOMOGENOUS) { bflags = AG_BOX_HOMOGENOUS; } switch (type) { case AG_TOOLBAR_HORIZ: row = bar->rows[i] = AG_BoxNew(bar, AG_BOX_HORIZ, bflags); break; case AG_TOOLBAR_VERT: row = bar->rows[i] = AG_BoxNew(bar, AG_BOX_VERT, bflags); break; default: AG_FatalError("Bad type"); } if (flags & AG_TOOLBAR_HFILL) { WIDGET(row)->flags |= AG_WIDGET_HFILL; } if (flags & AG_TOOLBAR_VFILL) { WIDGET(row)->flags |= AG_WIDGET_VFILL; } AG_SetPadding(row, "1"); AG_SetSpacing(row, "1"); bar->nRows++; } AG_ObjectAttach(parent, bar); return (bar); } static void Init(void *_Nonnull obj) { AG_Toolbar *bar = obj; bar->flags = 0; bar->type = AG_TOOLBAR_HORIZ; bar->nRows = 0; bar->curRow = 0; bar->nButtons = 0; } static void StickyUpdate(AG_Event *_Nonnull event) { const AG_Button *selBtn = AG_BUTTON_SELF(); AG_Toolbar *bar = AG_TOOLBAR_PTR(1); AG_Variable *stateb; AG_Button *oBtn; int i; AG_ObjectLock(bar); for (i = 0; i < bar->nRows; i++) { OBJECT_FOREACH_CHILD(oBtn, bar->rows[i], ag_button) { int *state; stateb = AG_GetVariable(oBtn, "state", (void *)&state); if (bar->flags & AG_TOOLBAR_MULTI_STICKY) { *state = !(*state); } else { *state = (oBtn == selBtn); } AG_UnlockVariable(stateb); } } AG_ObjectUnlock(bar); } /* * Select the active row for subsequent AG_ToolbarButton*() calls * and AG_ToolbarSeparator() calls. */ void AG_ToolbarRow(AG_Toolbar *bar, int row) { AG_OBJECT_ISA(bar, "AG_Widget:AG_Box:AG_Toolbar:*"); AG_ObjectLock(bar); #ifdef AG_DEBUG if (row < 0 || row >= bar->nRows) AG_FatalError("Bad row"); #endif bar->curRow = row; AG_ObjectUnlock(bar); } /* Create a new Button (with icon) and attach to the Toolbar. */ AG_Button * AG_ToolbarButtonIcon(AG_Toolbar *bar, const AG_Surface *icon, int def, void (*handler)(AG_Event *), const char *fmt, ...) { AG_Button *bu; AG_Event *ev; AG_OBJECT_ISA(bar, "AG_Widget:AG_Box:AG_Toolbar:*"); AG_ObjectLock(bar); bu = AG_ButtonNewS(bar->rows[bar->curRow], AG_BUTTON_NO_FOCUS, NULL); AG_ButtonSurface(bu, icon); AG_ButtonSetSticky(bu, bar->flags & AG_TOOLBAR_STICKY); AG_SetInt(bu, "state", def); bar->nButtons++; ev = AG_SetEvent(bu, "button-pushed", handler, NULL); if (fmt) { va_list ap; va_start(ap, fmt); AG_EventGetArgs(ev, fmt, ap); va_end(ap); } if (bar->flags & (AG_TOOLBAR_STICKY | AG_TOOLBAR_MULTI_STICKY)) AG_AddEvent(bu, "button-pushed", StickyUpdate, "%p", bar); AG_Redraw(bar); AG_ObjectUnlock(bar); return (bu); } /* Create a new Button (no icon) and attach to the Toolbar. */ AG_Button * AG_ToolbarButton(AG_Toolbar *bar, const char *text, int def, void (*handler)(AG_Event *), const char *fmt, ...) { AG_Button *bu; AG_Event *ev; AG_OBJECT_ISA(bar, "AG_Widget:AG_Box:AG_Toolbar:*"); AG_ObjectLock(bar); bu = AG_ButtonNewS(bar->rows[bar->curRow], AG_BUTTON_NO_FOCUS, text); AG_ButtonSetSticky(bu, bar->flags & AG_TOOLBAR_STICKY); AG_SetInt(bu, "state", def); bar->nButtons++; ev = AG_SetEvent(bu, "button-pushed", handler, NULL); if (fmt) { va_list ap; va_start(ap, fmt); AG_EventGetArgs(ev, fmt, ap); va_end(ap); } if (bar->flags & (AG_TOOLBAR_STICKY | AG_TOOLBAR_MULTI_STICKY)) AG_AddEvent(bu, "button-pushed", StickyUpdate, "%p", bar); AG_Redraw(bar); AG_ObjectUnlock(bar); return (bu); } /* Create a new separator. */ void AG_ToolbarSeparator(AG_Toolbar *bar) { AG_OBJECT_ISA(bar, "AG_Widget:AG_Box:AG_Toolbar:*"); AG_ObjectLock(bar); AG_SeparatorNew(bar->rows[bar->curRow], (bar->type == AG_TOOLBAR_HORIZ) ? AG_SEPARATOR_VERT : AG_SEPARATOR_HORIZ); AG_Redraw(bar); AG_ObjectUnlock(bar); } /* Set the boolean state of a Button to 1. */ void AG_ToolbarSelect(AG_Toolbar *bar, AG_Button *bSel) { AG_SetInt(bSel, "state", 1); AG_Redraw(bar); } /* Set the boolean state of a Button to 0. */ void AG_ToolbarDeselect(AG_Toolbar *bar, AG_Button *bSel) { AG_SetInt(bSel, "state", 0); AG_Redraw(bar); } /* Set the boolean state of a Button to 1 and reset all others to 0. */ void AG_ToolbarSelectOnly(AG_Toolbar *bar, AG_Button *bSel) { AG_Variable *stateb; AG_Button *b; int i, *state; AG_OBJECT_ISA(bar, "AG_Widget:AG_Box:AG_Toolbar:*"); AG_ObjectLock(bar); for (i = 0; i < bar->nRows; i++) { OBJECT_FOREACH_CHILD(b, bar->rows[i], ag_button) { stateb = AG_GetVariable(b, "state", (void *)&state); *state = (b == bSel); AG_UnlockVariable(stateb); } } AG_Redraw(bar); AG_ObjectUnlock(bar); } /* Set the boolean state of all buttons to 1. */ void AG_ToolbarSelectAll(AG_Toolbar *bar) { AG_Variable *stateb; AG_Button *b; int i, *state; AG_OBJECT_ISA(bar, "AG_Widget:AG_Box:AG_Toolbar:*"); AG_ObjectLock(bar); for (i = 0; i < bar->nRows; i++) { OBJECT_FOREACH_CHILD(b, bar->rows[i], ag_button) { stateb = AG_GetVariable(b, "state", (void *)&state); *state = 1; AG_UnlockVariable(stateb); } } AG_Redraw(bar); AG_ObjectUnlock(bar); } /* Set the boolean state of all buttons to 0. */ void AG_ToolbarDeselectAll(AG_Toolbar *bar) { AG_Variable *stateb; AG_Button *b; int i, *state; AG_OBJECT_ISA(bar, "AG_Widget:AG_Box:AG_Toolbar:*"); AG_ObjectLock(bar); for (i = 0; i < bar->nRows; i++) { OBJECT_FOREACH_CHILD(b, bar->rows[i], ag_button) { stateb = AG_GetVariable(b, "state", (void *)&state); *state = 0; AG_UnlockVariable(stateb); } } AG_Redraw(bar); AG_ObjectUnlock(bar); } static void SizeRequest(void *_Nonnull p, AG_SizeReq *_Nonnull r) { AG_Toolbar *tbar = p; AG_SizeReq rBar; int i; WIDGET_SUPER_OPS(tbar)->size_request(tbar, r); rBar = *r; rBar.h = (tbar->type == AG_TOOLBAR_HORIZ) ? r->h/tbar->nRows : r->w/tbar->nRows; for (i = 0; i < tbar->nRows; i++) WIDGET_SUPER_OPS(tbar)->size_request(tbar->rows[i], &rBar); } AG_WidgetClass agToolbarClass = { { "Agar(Widget:Box:Toolbar)", sizeof(AG_Toolbar), { 1,0, AGC_TOOLBAR, 0 }, Init, NULL, /* reset */ NULL, /* destroy */ NULL, /* load */ NULL, /* save */ NULL /* edit */ }, NULL, /* draw */ SizeRequest, NULL, /* size_allocate */ NULL, /* mouse_button_down */ NULL, /* mouse_button_up */ NULL, /* mouse_motion */ NULL, /* key_down */ NULL, /* key_up */ NULL, /* touch */ NULL, /* ctrl */ NULL /* joy */ }; #endif /* AG_WIDGETS */