--- /dev/null
+/**
+ * \file
+ * <!--
+ * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \version $Id$
+ * \author Massimiliano Corsini <chad@develer.com>
+ *
+ *
+ * \brief Low-level drawing routines.
+ *
+ * This file contains the implementation of the low-level drawing routines
+ * to draw fill rectangle, fill triangle and so on.
+ *
+ */
+
+/*#*
+ *#* $Log$
+ *#* Revision 1.1 2006/07/19 13:00:01 bernie
+ *#* Import into DevLib.
+ *#*
+ *#* Revision 1.10 2005/10/15 15:03:43 rasky
+ *#* Remove per-pixel clipping from line().
+ *#* Use clipLine() also for a-scope.
+ *#*
+ *#* Revision 1.9 2005/10/14 15:21:32 eldes
+ *#* Implement the cohen-sutherland clipping on the buffer
+ *#*
+ *#* Revision 1.8 2005/09/27 13:28:10 rasky
+ *#* Add clipping capabilities to line()
+ *#* Fix off-by-one computation of rectangles of drawing.
+ *#*
+ *#* Revision 1.7 2005/09/27 10:41:35 rasky
+ *#* Import line-drawing routine from Devlib
+ *#*
+ *#* Revision 1.6 2005/09/19 16:36:05 chad
+ *#* Fix doxygen autobrief
+ *#*
+ *#* Revision 1.5 2005/07/06 12:51:47 chad
+ *#* Make the fillRectangle() independent of the order of the points of the rectangle
+ *#*
+ *#* Revision 1.4 2005/06/17 15:06:36 chad
+ *#* Remove conversion warning
+ *#*
+ *#* Revision 1.3 2005/06/17 15:04:47 chad
+ *#* Add line clipping capability
+ *#*
+ *#* Revision 1.2 2005/06/15 14:04:43 chad
+ *#* Add line routine
+ *#*
+ *#* Revision 1.1 2005/06/15 13:34:34 chad
+ *#* Low-level drawing routines
+ *#*
+ *#*/
+
+// Qt-specific headers
+#include <qpoint.h>
+
+
+/**
+ * Low-level routine to draw a line.
+ *
+ * This routine is based on the Bresenham Line-Drawing Algorithm.
+ *
+ * The \a stride represents the width of the image buffer.
+ * (\a x1, \a y1) are the coordinates of the starting point.
+ * (\a x2, \a y2) are the coordinates of the ending point.
+ *
+ * The line has no anti-alias, and clipping is not performed. The line
+ * must be fully contained in the buffer (use clipLine() if you need
+ * to clip it).
+ */
+void line(unsigned char *buf,
+ unsigned long bufw, unsigned long bufh, unsigned long stride,
+ int x1, int y1, int x2, int y2, unsigned char color)
+{
+ int x, y, e, len, adx, ady, signx, signy;
+
+ if (x2 > x1)
+ {
+ /* left to right */
+ signx = +1;
+ adx = x2 - x1;
+ }
+ else
+ {
+ /* right to left */
+ signx = -1;
+ adx = x1 - x2;
+ }
+
+ if (y2 > y1)
+ {
+ /* top to bottom */
+ signy = +1;
+ ady = y2 - y1;
+ }
+ else
+ {
+ /* bottom to top */
+ signy = -1;
+ ady = y1 - y2;
+ }
+
+ x = x1;
+ y = y1;
+
+ if (adx > ady)
+ {
+ /* X-major line (octants 1/4/5/8) */
+ len = adx;
+ e = -adx;
+ while (len--)
+ {
+ /* Sanity check */
+ assert(y >= 0 && y < static_cast<int>(bufh) &&
+ x >= 0 && x < static_cast<int>(bufw));
+ buf[y * stride + x] = color;
+ x += signx;
+ e += ady;
+ if (e >= 0)
+ {
+ y += signy;
+ e -= adx;
+ }
+ }
+ }
+ else
+ {
+ /* Y-major line (octants 2/3/6/7) */
+ len = ady;
+ e = -ady;
+ while (len--)
+ {
+ /* Sanity check */
+ assert(y >= 0 && y < static_cast<int>(bufh) &&
+ x >= 0 && x < static_cast<int>(bufw));
+ buf[y * stride + x] = color;
+ y += signy;
+ e += adx;
+ if (e >= 0)
+ {
+ x += signx;
+ e -= ady;
+ }
+ }
+ }
+}
+
+/// Helper routine for clipLine().
+static int region(int x, int y, int w, int h)
+{
+ int code = 0;
+
+ if (y >= h)
+ code |= 1; // top
+ else if (y < 0)
+ code |= 2; // bottom
+
+ if (x >= w)
+ code |= 4; // right
+ else if (x < 0)
+ code |= 8; // left
+
+ return code;
+}
+
+/**
+ * Low-level routine to draw a line, clipped to the buffer extents.
+ *
+ * This routine executes the clipping, and then invokes line().
+ * Parameters are the same of line(). The clipping is performed
+ * using the Cohen-Sutherland algorithm, which is very fast.
+ */
+void clipLine(unsigned char *buf,
+ unsigned long w, unsigned long h, unsigned long stride,
+ int x1, int y1, int x2, int y2, unsigned char color)
+{
+ int code1 = region(x1, y1, w, h);
+ int code2 = region(x2, y2, w, h);
+
+ // Loop while there is at least one point outside
+ while (code1 | code2)
+ {
+ // Check for line totally outside
+ if (code1 & code2)
+ return;
+
+ int c = code1 ? code1 : code2;
+ int x, y;
+
+ if (c & 1) // top
+ {
+ x = x1 + (x2 - x1) * (h - y1) / (y2 - y1);
+ y = h - 1;
+ }
+ else if (c & 2) //bottom
+ {
+ x = x1 + (x2 - x1) * -y1 / (y2 - y1);
+ y = 0;
+ }
+ else if (c & 4) //right
+ {
+ y = y1 + (y2 - y1) * (w - x1) / (x2 - x1);
+ x = w - 1;
+ }
+ else //left
+ {
+ y = y1 + (y2 - y1) * -x1 / (x2 - x1);
+ x = 0;
+ }
+
+ if (c == code1) // first endpoint was clipped
+ {
+ x1 = x; y1 = y;
+ code1 = region(x1, y1, w, h);
+ }
+ else //second endpoint was clipped
+ {
+ x2 = x; y2 = y;
+ code2 = region(x2, y2, w, h);
+ }
+ }
+
+ line(buf, w, h, stride, x1, y1, x2, y2, color);
+}
+
+
+/**
+ * Low-level routine to draw a filled rectangle.
+ *
+ * The triangle is filled with the given color.
+ *
+ * The \a stride represents the width of the image buffer.
+ * The points \a p1 and \a p2 are two opposite corners of the
+ * rectangle.
+ */
+void fillRectangle(unsigned char *buf, unsigned long stride,
+ QPoint p1, QPoint p2, unsigned char color)
+{
+ QPoint ul; // upper-left corner
+ QPoint lr; // lower-right corner
+
+ if (p2.x() > p1.x())
+ {
+ ul.setX(p1.x());
+ lr.setX(p2.x());
+ }
+ else
+ {
+ ul.setX(p2.x());
+ lr.setX(p1.x());
+ }
+
+ if (p2.y() > p1.y())
+ {
+ ul.setY(p1.y());
+ lr.setY(p2.y());
+ }
+ else
+ {
+ ul.setY(p2.y());
+ lr.setY(p1.y());
+ }
+
+ int width = lr.x() - ul.x();
+ unsigned long offset = ul.x() + ul.y()*stride;
+
+ for (int h = ul.y(); h < lr.y(); h++)
+ {
+ memset(buf+offset, color, width);
+ offset += stride;
+ }
+}
+
+/**
+ * Low-level routines to draw a filled triangle.
+ *
+ * The triangle is filled with the given \a color.
+ * The \a stride represents the width of the image buffer (\a buf).
+ *
+ * The routine use fixed-point arithmetic.
+ */
+void fillTriangle(unsigned char* buf, unsigned long stride,
+ QPoint v1, QPoint v2, QPoint v3, unsigned char color)
+{
+ int altezza[3];
+
+ // Sort by vertical coordinate
+ if (v1.y() > v2.y())
+ std::swap(v1, v2);
+ if (v1.y() > v3.y())
+ std::swap(v1, v3);
+ if (v2.y() > v3.y())
+ std::swap(v2, v3);
+
+ altezza[0] = v3.y() - v1.y();
+ if (!altezza[0])
+ return;
+
+ int sezioni = 2;
+ int sezione = 1;
+
+ buf += v1.y() * stride;
+
+ altezza[1] = v2.y() - v1.y();
+ altezza[2] = v3.y() - v2.y();
+
+ int sinistra = v1.x();
+ int destra = sinistra;
+
+ if (v1.y() == v2.y())
+ {
+ if (v1.x() < v2.x())
+ destra = v2.x();
+ else
+ sinistra = v2.x();
+ }
+
+ sinistra <<= 16;
+ destra <<= 16;
+
+ int stmp1, stmp2, stmp3;
+
+ stmp1 = (altezza[1] << 16) / altezza[0];
+ int lunghezza = stmp1 * (v3.x() - v1.x()) + ((v1.x() - v2.x()) << 16);
+
+ if (!lunghezza )
+ return;
+
+ int delta_sinistra[2];
+ int delta_destra[2];
+
+ stmp1 = ((v3.x() - v1.x()) << 16) / altezza[0];
+
+ if (altezza[1])
+ stmp2 = ((v2.x() - v1.x()) << 16) / altezza[1];
+ if (altezza[2])
+ stmp3 = ((v3.x() - v2.x()) << 16) / altezza[2];
+
+ if (lunghezza < 0) // Il secondo vertice ~J a destra
+ {
+ delta_sinistra[0] = stmp1;
+ delta_sinistra[1] = stmp1;
+ delta_destra[0] = stmp2;
+ delta_destra[1] = stmp3;
+ }
+ else // Il secondo vertice ~J a sinistra
+ {
+ delta_sinistra[0] = stmp2;
+ delta_sinistra[1] = stmp3;
+ delta_destra[0] = stmp1;
+ delta_destra[1] = stmp1;
+ }
+
+ int len2 = lunghezza;
+
+ do
+ {
+ while (altezza [sezione])
+ {
+ unsigned char* curpos = buf + ((sinistra )>> 16);
+ lunghezza = ((destra ) >> 16) - ((sinistra ) >> 16);
+ assert(lunghezza >= 0);
+ if (lunghezza)
+ memset(curpos, color, lunghezza);
+ buf += stride;
+ destra += delta_destra[sezione - 1];
+ sinistra += delta_sinistra[sezione - 1];
+ altezza[sezione]--;
+ }
+ if (len2 < 0)
+ destra = v2.x() << 16;
+ else
+ sinistra = v2.x() << 16;
+ sezione++;
+ } while (--sezioni);
+}
--- /dev/null
+/**
+ * \file
+ * Copyright 2004, 2006 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ *
+ * \brief Graphics user interface element to display a level bar.
+ *
+ * \version $Id$
+ * \author Stefano Fedrigo <aleph@develer.com>
+ */
+
+#include "levelbar.h"
+
+
+/**
+ * Initialize the LevelBar widget with the bitmap associated,
+ * the value range and the coordinates in the bitmap.
+ * \note The levelbar should be at least 5 pixels wide and high
+ * for correct borders drawing. No check is done on this.
+ */
+void lbar_init(struct LevelBar *lb, struct Bitmap *bmp, int type, int min, int max, int pos,
+ coord_t x1, coord_t y1, coord_t x2, coord_t y2)
+{
+ lb->bitmap = bmp;
+ lb->type = type;
+ lb->min = min;
+ lb->max = max;
+ lb->pos = pos;
+ lb->x1 = x1;
+ lb->y1 = y1;
+ lb->x2 = x2;
+ lb->y2 = y2;
+}
+
+
+/**
+ * Set the level.
+ */
+void lbar_setLevel(struct LevelBar *lb, int level)
+{
+ if (level < lb->min)
+ level = lb->min;
+ if (level > lb->max)
+ level = lb->max;
+
+ lb->pos = level;
+}
+
+
+/**
+ * Get current level.
+ */
+int lbar_getLevel(struct LevelBar *lb)
+{
+ return lb->pos;
+}
+
+
+/**
+ * Change level with respect to previous value
+ * (delta can be negative).
+ */
+void lbar_changeLevel(struct LevelBar *lb, int delta)
+{
+ lbar_setLevel(lb, lb->pos + delta);
+}
+
+
+/**
+ * Change the top limit.
+ */
+void lbar_setMax(struct LevelBar *lb, int max)
+{
+ lb->max = max;
+}
+
+
+/**
+ * Render the LevelBar on the bitmap.
+ */
+void lbar_draw(struct LevelBar *lb)
+{
+#define BORDERW 1
+#define BORDERH 1
+
+ /* Compute filled bar length in pixels */
+ int totlen = (lb->type & LBAR_HORIZONTAL) ? lb->x2 - lb->x1 - BORDERW*4 : lb->y2 - lb->y1 - BORDERH*4;
+ int range = lb->max - lb->min;
+ int barlen = ((long)(lb->pos - lb->min) * (long)totlen + range - 1) / range;
+
+ // Draw border
+ gfx_rectDraw(lb->bitmap, lb->x1, lb->y1, lb->x2, lb->y2);
+
+ // Clear inside
+ gfx_rectClear(lb->bitmap, lb->x1 + BORDERW, lb->y1 + BORDERH, lb->x2 - BORDERW, lb->y2 - BORDERH);
+
+ // Draw bar
+ if (lb->type & LBAR_HORIZONTAL)
+ gfx_rectFill(lb->bitmap,
+ lb->x1 + BORDERW*2, lb->y1 + BORDERH*2,
+ lb->x1 + BORDERW*2 + barlen, lb->y2 - BORDERH*2);
+ else
+ gfx_rectFill(lb->bitmap,
+ lb->x1 + BORDERW*2, lb->y2 - BORDERH*2 - barlen,
+ lb->x2 - BORDERW*2, lb->y2 - BORDERH*2);
+}
--- /dev/null
+/**
+ * \file
+ * Copyright 2004, 2006 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ *
+ * \version $Id$
+ *
+ * \author Stefano Fedrigo <aleph@develer.com>
+ *
+ * \brief Graphics level bar widget
+ */
+
+#ifndef GUI_LEVELBAR_H
+#define GUI_LEVELBAR_H
+
+#include <gfx/gfx.h>
+
+
+/** Type of levelbar */
+#define LBAR_HORIZONTAL 1
+#define LBAR_VERTICAL 2
+
+typedef struct LevelBar
+{
+ struct Bitmap *bitmap;
+ int type;
+ int pos; ///< Current level
+ int min; ///< Minimum level
+ int max; ///< Maximum level
+ coord_t x1, y1, x2, y2; ///< Position of widget in the bitmap
+} LevelBar;
+
+void lbar_init(struct LevelBar *lb, struct Bitmap *bmp, int type, int min, int max, int pos,
+ coord_t x1, coord_t y1, coord_t x2, coord_t y2);
+void lbar_setLevel(struct LevelBar *lb, int level);
+int lbar_getLevel(struct LevelBar *lb);
+void lbar_changeLevel(struct LevelBar *lb, int delta);
+void lbar_setMax(struct LevelBar *lb, int max);
+void lbar_draw(struct LevelBar *lb);
+
+#endif /* GUI_LEVELBAR_H */
--- /dev/null
+/**
+ * \file
+ * <!--
+ * Copyright 2004, 2006 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \brief Generic editor for (volume/gain/contrast/...) setting.
+ *
+ * \version $Id$
+ * \author Stefano Fedrigo <aleph@develer.com>
+ */
+
+#include "leveledit.h"
+
+#include <cfg/macros.h> /* MAX() */
+#include <drv/kbd.h>
+#include <drv/timer.h>
+#include <gui/levelbar.h>
+#include <mware/pgm.h>
+#include <gfx/text.h>
+#include <gfx/font.h>
+#include <appconfig.h>
+
+#if CONFIG_MENU_MENUBAR
+#include <gui/menubar.h>
+#endif
+
+// BEGIN project_grl LOCAL
+#include <drv/lcd_gfx.h>
+#include <gui/guiman.h>
+// END project_grl LOCAL
+
+#define LBAR_HEIGHT 16
+
+/**
+ * Allow user to change level.
+ */
+void level_edit(struct LevelEdit *lev)
+{
+#if CONFIG_MENU_MENUBAR
+ /* Labels for menubars */
+ enum LabelId ch_labels[] = { LABEL_C1PLUS2, LABEL_CH_1, LABEL_CH_2 };
+ const_iptr_t labels[] =
+ {
+ (const_iptr_t)LABEL_BACK,
+ (const_iptr_t)LABEL_MINUS,
+ (const_iptr_t)LABEL_PLUS,
+ (const_iptr_t)LABEL_EMPTY
+ };
+ struct MenuBar mb;
+#endif /* CONFIG_MENU_MENUBAR */
+
+ struct LevelBar bar1, bar2;
+ keymask_t keys, old_rpt_mask;
+ int step, rep_step;
+
+ rep_step = MAX(lev->step, ((lev->max - lev->min) / 200));
+ step = lev->step;
+
+ // Allow keys repetition.
+ old_rpt_mask = kbd_setRepeatMask(K_UP | K_DOWN);
+
+ text_clear(lev->bitmap);
+ //text_style(STYLEF_UNDERLINE, STYLEF_UNDERLINE);
+ text_puts(lev->title, lev->bitmap);
+ //text_style(0, STYLEF_UNDERLINE);
+
+ if (lev->type & LEVELEDIT_DOUBLE)
+ {
+ int chn = 0; /* edit both channels */
+
+ /* Levelbars init */
+ lbar_init(&bar1, lev->bitmap, LBAR_HORIZONTAL,
+ lev->min, lev->max, *lev->ch1_val, 0, 16, lev->bitmap->width / 2 - 1, 23);
+ lbar_init(&bar2, lev->bitmap, LBAR_HORIZONTAL,
+ lev->min, lev->max, *lev->ch2_val, lev->bitmap->width / 2 + 1, 16, lev->bitmap->width, 23);
+
+ #if CONFIG_MENU_MENUBAR
+ labels[3] = (const_iptr_t)ch_labels[chn];
+ mbar_init(&mb, lev->bitmap, labels, countof(labels));
+ mbar_draw(&mb);
+ #endif /* CONFIG_MENU_MENUBAR */
+
+ /* Input loop for double level setting */
+ for (;;)
+ {
+ #if CONFIG_LEVELEDIT_TIMEOUT != 0
+ ticks_t idle_timeout = timer_clock();
+ #endif
+ do
+ {
+ if (lev->display_hook)
+ lev->display_hook(lev);
+ else
+ {
+ text_xprintf(lev->bitmap, 1, 0, TEXT_CENTER | TEXT_FILL, lev->unit);
+ PGM_FUNC(text_xprintf)(lev->bitmap, 1, 3, 0, PGM_STR("%d"), *lev->ch1_val);
+ PGM_FUNC(text_xprintf)(lev->bitmap, 1, 14, 0, PGM_STR("%d"), *lev->ch2_val);
+
+ lbar_setLevel(&bar1, *lev->ch1_val);
+ lbar_setLevel(&bar2, *lev->ch2_val);
+ lbar_draw(&bar1);
+ lbar_draw(&bar2);
+ }
+
+ #if CONFIG_LEVELEDIT_TIMEOUT != 0
+ if (timer_clock() - idle_timeout > ms_to_ticks(CONFIG_LEVELEDIT_TIMEOUT))
+ {
+ /* Accept input implicitly */
+ keys = K_OK;
+ break;
+ }
+ #endif
+ }
+ while (!(keys = kbd_peek()));
+
+ if (keys & K_CANCEL)
+ break;
+
+ if (keys & K_OK)
+ {
+ chn = (chn + 1) % 3;
+
+ #if CONFIG_MENU_MENUBAR
+ labels[3] = (const_iptr_t)ch_labels[chn];
+ mbar_draw(&mb);
+ #endif /* CONFIG_MENU_MENUBAR */
+ }
+
+ /* Increment step to achieve greater accelerations on larger values */
+ if (keys & K_REPEAT)
+ step = MIN(rep_step, step + 1);
+ else
+ step = lev->step;
+
+ if (keys & (K_UP | K_DOWN))
+ {
+ if (keys & K_UP)
+ {
+ /* If changing both channels (chn == 0), don't change
+ * level if one of two is at min or max */
+ if (chn != 0 ||
+ (*lev->ch1_val + step <= lev->max
+ && *lev->ch2_val + step <= lev->max))
+ {
+ /* If chn == 0 change both channels */
+ if (chn != 2)
+ {
+ *lev->ch1_val += step;
+ if (*lev->ch1_val > lev->max)
+ *lev->ch1_val = lev->max;
+ }
+ if (chn != 1)
+ {
+ *lev->ch2_val += step;
+ if (*lev->ch2_val > lev->max)
+ *lev->ch2_val = lev->max;
+ }
+ }
+ }
+ else
+ {
+ if (chn != 0 ||
+ (*lev->ch1_val - step >= lev->min
+ && *lev->ch2_val - step >= lev->min))
+ {
+ if (chn != 2)
+ {
+ *lev->ch1_val -= step;
+ if (*lev->ch1_val < lev->min)
+ *lev->ch1_val = lev->min;
+ }
+ if (chn != 1)
+ {
+ *lev->ch2_val -= step;
+ if (*lev->ch2_val < lev->min)
+ *lev->ch2_val = lev->min;
+ }
+ }
+ }
+
+ if (lev->set_hook)
+ lev->set_hook();
+ }
+ } // end for(;;)
+ }
+ else
+ {
+ const PGM_ATTR char *fmt = lev->unit ? PGM_STR("%d %s") : PGM_STR("%d");
+
+/*
+ const int textw = MAX(PGM_FUNC(text_widthf)(lev->bitmap, fmt, lev->max, lev->unit),
+ PGM_FUNC(text_widthf)(lev->bitmap, fmt, lev->min, lev->unit));
+
+ const coord_t barlen = lev->bitmap->width - 6 - textw;
+*/
+ const coord_t barlen = lev->bitmap->width;
+ const coord_t barvtop = lev->bitmap->height / 2 - LBAR_HEIGHT/2 + lev->bitmap->font->height;
+ lbar_init(&bar1, lev->bitmap, LBAR_HORIZONTAL,
+ lev->min, lev->max, *lev->ch1_val,
+ 0, barvtop, barlen, barvtop + LBAR_HEIGHT);
+
+ #if CONFIG_MENU_MENUBAR
+ mbar_init(&mb, lev->bitmap, labels, countof(labels));
+ mbar_draw(&mb);
+ #endif /* CONFIG_MENU_MENUBAR */
+
+ /* Input loop for single level setting */
+ for (;;)
+ {
+ #if CONFIG_LEVELEDIT_TIMEOUT != 0
+ ticks_t idle_timeout = timer_clock();
+ #endif
+ do
+ {
+ if (lev->display_hook)
+ lev->display_hook(lev);
+ else
+ {
+ if (lev->type != LEVELEDIT_NOBAR)
+ {
+ lbar_setLevel(&bar1, *lev->ch1_val);
+ lbar_draw(&bar1);
+ }
+ PGM_FUNC(text_xyprintf)(lev->bitmap, 0, bar1.y1 - lev->bitmap->font->height,
+ TEXT_CENTER | TEXT_FILL, fmt, *lev->ch1_val, lev->unit);
+ }
+
+ #if CONFIG_LEVELEDIT_TIMEOUT != 0
+ if (timer_clock() - idle_timeout > CONFIG_LEVELEDIT_TIMEOUT)
+ {
+ /* Accept input implicitly */
+ keys = K_CANCEL;
+ break;
+ }
+ #endif
+
+// BEGIN project_grl LOCAL
+#if 1
+ //FIXME: must to this only when needed
+ lcd_blitBitmap(&lcd_bitmap);
+ }
+ while (!(keys = GuiMan_KbdPeek()));
+#else
+ }
+ while (!(keys = kbd_peek()));
+#endif
+// END project_grl LOCAL
+
+ if (keys & K_CANCEL)
+ break;
+
+ /* Increment step to achieve greater accelerations on larger values */
+ if (keys & K_REPEAT)
+ step = MIN(rep_step, step + 1);
+ else
+ step = lev->step;
+
+ if (keys & K_UP)
+ {
+ *lev->ch1_val += step;
+ if (*lev->ch1_val > lev->max)
+ *lev->ch1_val = lev->max;
+ }
+
+ if (keys & K_DOWN)
+ {
+ *lev->ch1_val -= step;
+ if (*lev->ch1_val < lev->min)
+ *lev->ch1_val = lev->min;
+ }
+
+ if (lev->set_hook)
+ lev->set_hook();
+ }
+ }
+
+ kbd_setRepeatMask(old_rpt_mask);
+}
+
+/**
+ * LevelEdit structure initialization.
+ * Init data structure and init LevelEdit widgets.
+ */
+void level_init(struct LevelEdit *lev,
+ int type,
+ struct Bitmap *bmp, const char *title, const char *unit,
+ int min, int max, int step,
+ int *ch1_val, int *ch2_val,
+ level_set_callback *set_hook, display_callback *display_hook)
+{
+ lev->type = type;
+ lev->bitmap = bmp;
+ lev->title = title;
+ lev->unit = unit;
+ lev->min = min;
+ lev->max = max;
+ lev->step = step;
+
+ lev->ch1_val = ch1_val;
+ lev->ch2_val = ch2_val;
+ lev->set_hook = set_hook;
+ lev->display_hook = display_hook;
+}
--- /dev/null
+/**
+ * \file
+ * <!--
+ * Copyright 2004, 2006 Develer S.r.l. (http://www.develer.com/)
+ * This file is part of DevLib - See README.devlib for information.
+ * -->
+ *
+ * \brief Generic editor for (volume/gain/contrast/...) setting.
+ *
+ * \version $Id$
+ *
+ * \author Stefano Fedrigo <aleph@develer.com>
+ */
+#ifndef GUI_LEVELEDIT_H
+#define GUI_LEVELEDIT_H
+
+//#include <gui/levelbar.h>
+
+/* Type for level_init */
+#define LEVELEDIT_NOBAR 0 /**< Edit numeber only, without bar nor units */
+#define LEVELEDIT_SINGLE 1 /**< Single channel editing */
+#define LEVELEDIT_DOUBLE 2 /**< Double channel editing */
+
+
+
+/* Fwd decl */
+struct Bitmap;
+struct LevelEdit;
+
+/** Type for callback used to set meter levels */
+typedef void level_set_callback(void);
+
+/** Type for callback used to customize display of units */
+typedef void display_callback(struct LevelEdit *);
+
+/**
+ * State of a level meter
+ */
+typedef struct LevelEdit {
+ int type; /*<! Type of level edititing mode (see prev defines) */
+ const char *title; /*<! Title on top of screen */
+ const char *unit; /*<! Unit of quantity changed by this LevelEdit */
+ int min; /*<! Minimum level */
+ int max; /*<! Maximum level */
+ int step; /*<! Value of a single increment/decrement */
+
+ level_set_callback *set_hook; /*<! Callback called when a value is changed */
+ display_callback *display_hook; /*<! Callback for complex unit display */
+ int *ch1_val; /*<! (left) Value edited by this leveledit */
+ int *ch2_val; /*<! Right channel edited */
+
+ struct Bitmap *bitmap; /*<! Bitmap where the whole thing is rendered */
+} LevelEdit;
+
+
+void level_init(struct LevelEdit *lev,
+ int type,
+ struct Bitmap *bmp, const char *title, const char *unit,
+ int min, int max, int step,
+ int *ch1_val, int *ch2_val,
+ level_set_callback *change_hook, display_callback *display_hook);
+void level_edit(struct LevelEdit *lev);
+
+#endif /* GUI_LEVELEDIT_H */