This commit is contained in:
Mark Qvist 2014-04-03 22:21:37 +02:00
commit c898b090dd
1049 changed files with 288572 additions and 0 deletions

105
bertos/gui/levelbar.c Normal file
View file

@ -0,0 +1,105 @@
/**
* \file
* Copyright 2004, 2006 Develer S.r.l. (http://www.develer.com/)
*
*
* \brief Graphics user interface element to display a level bar.
*
* \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);
}

39
bertos/gui/levelbar.h Normal file
View file

@ -0,0 +1,39 @@
/**
* \file
* Copyright 2004, 2006 Develer S.r.l. (http://www.develer.com/)
*
*
* \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 */

321
bertos/gui/leveledit.c Normal file
View file

@ -0,0 +1,321 @@
/**
* \file
* <!--
* This file is part of BeRTOS.
*
* Bertos is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2004, 2006 Develer S.r.l. (http://www.develer.com/)
*
* -->
*
* \brief Generic editor for (volume/gain/contrast/...) setting.
*
* \author Stefano Fedrigo <aleph@develer.com>
*/
#include "leveledit.h"
#include "cfg/cfg_menu.h"
#include <cfg/macros.h> /* MAX() */
#include <drv/kbd.h>
#include <drv/timer.h>
#include <gui/levelbar.h>
#include <cpu/pgm.h>
#include <gfx/text.h>
#include <gfx/font.h>
#if CONFIG_MENU_MENUBAR
#include <gui/menubar.h>
#endif
#warning FIXME: Revise me!
#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
}
while (!(keys = kbd_peek()));
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;
}

87
bertos/gui/leveledit.h Normal file
View file

@ -0,0 +1,87 @@
/**
* \file
* <!--
* This file is part of BeRTOS.
*
* Bertos is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2004, 2006 Develer S.r.l. (http://www.develer.com/)
*
* -->
*
* \brief Generic editor for (volume/gain/contrast/...) setting.
*
* \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 number 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 */

582
bertos/gui/menu.c Normal file
View file

@ -0,0 +1,582 @@
/**
* \file
* <!--
* This file is part of BeRTOS.
*
* Bertos is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2003, 2004, 2006, 2010 Develer S.r.l. (http://www.develer.com/)
* Copyright 2000 Bernie Innocenti <bernie@codewiz.org>
*
* -->
*
* \author Bernie Innocenti <bernie@codewiz.org>
* \author Stefano Fedrigo <aleph@develer.com>
*
* \brief General pourpose menu handling functions
*/
#include "menu.h"
#include "cfg/cfg_menu.h"
#include "cfg/cfg_arch.h"
#include <cfg/compiler.h>
#include <cfg/debug.h>
#include <gfx/gfx.h>
#include <gfx/font.h>
#include <gfx/text.h>
#include <cpu/power.h>
#include <drv/kbd.h>
#include <string.h> /* strcpy() */
#if CPU_HARVARD
#include <avr/pgmspace.h> /* strncpy_P() */
#endif
#if (CONFIG_MENU_TIMEOUT != 0)
#include <drv/timer.h>
#endif
#if CONFIG_MENU_MENUBAR
#include "menubar.h"
#endif
#if defined(CONFIG_LOCALE) && (CONFIG_LOCALE == 1)
#include "msg.h"
#else
#define PTRMSG(x) ((const char *)x)
#endif
/* Temporary fake defines for ABORT stuff... */
#define abort_top 0
#define PUSH_ABORT false
#define POP_ABORT do {} while(0)
#define DO_ABORT do {} while(0)
/**
* Return the total number of items in in a menu.
*/
static int menu_count(const struct Menu *menu)
{
int cnt = 0;
for (cnt = 0; /*NOP*/; ++cnt)
{
const MenuItem *item = &menu->items[cnt];
#if CPU_HARVARD
MenuItem ram_item;
if (menu->flags & MF_ROMITEMS)
{
memcpy_P(&ram_item, item, sizeof(ram_item));
item = &ram_item;
}
#endif
if (!(item->label || item->hook))
break;
}
return cnt;
}
#if CONFIG_MENU_MENUBAR
/**
* Update the menu bar according to the selected item and redraw it.
*/
static void menu_update_menubar(
const struct Menu *menu,
struct MenuBar *mb,
int selected)
{
int item_flags;
#if CPU_HARVARD
if (menu->flags & MF_ROMITEMS)
{
ASSERT(sizeof(menu->items[selected].flags) == sizeof(int));
item_flags = pgm_read_int(&menu->items[selected].flags);
}
else
#endif
item_flags = menu->items[selected].flags;
const_iptr_t newlabel = (const_iptr_t)LABEL_OK;
if (item_flags & MIF_DISABLED)
newlabel = (const_iptr_t)LABEL_EMPTY;
else if (item_flags & MIF_TOGGLE)
newlabel = (const_iptr_t)LABEL_SEL;
else if (item_flags & MIF_CHECKIT)
{
newlabel = (item_flags & MIF_CHECKED) ?
(const_iptr_t)LABEL_EMPTY : (const_iptr_t)LABEL_SEL;
}
mb->labels[3] = newlabel;
mbar_draw(mb);
}
#endif /* CONFIG_MENU_MENUBAR */
static void menu_defaultRenderHook(struct Bitmap *bm, int ypos, bool selected, const struct MenuItem *item)
{
if (item->flags & MIF_CHECKIT)
{
gfx_rectClear(bm, 0, ypos,
bm->font->height, ypos + bm->font->height);
if (item->flags & MIF_TOGGLE)
gfx_rectDraw(bm, 2, ypos + 2,
bm->font->height - 2, ypos + bm->font->height - 2);
if (item->flags & MIF_CHECKED)
{
gfx_line(bm,
3, ypos + 3,
bm->font->height - 3, ypos + bm->font->height - 3);
gfx_line(bm,
bm->font->height - 3, ypos + 3,
3, ypos + bm->font->height - 3);
}
}
#if CPU_HARVARD
((item->flags & MIF_RAMLABEL) ? text_xyprintf : text_xyprintf_P)
#else
text_xyprintf
#endif
(
bm, (item->flags & MIF_CHECKIT) ? bm->font->height : 0, ypos,
selected ? (STYLEF_INVERT | TEXT_FILL) : TEXT_FILL,
PTRMSG(item->label)
);
}
/**
* Show a menu on the display.
*/
static void menu_layout(
const struct Menu *menu,
int first_item,
int selected,
bool redraw)
{
coord_t ypos;
int i;
const char * PROGMEM title = PTRMSG(menu->title);
Bitmap *bm = menu->bitmap;
ypos = bm->cr.ymin;
if (redraw)
{
/* Clear screen */
text_clear(menu->bitmap);
}
if (title)
{
if (redraw)
text_xyprintf(bm, 0, ypos, STYLEF_UNDERLINE | STYLEF_BOLD | TEXT_CENTER | TEXT_FILL, title);
ypos += bm->font->height;
}
#if CONFIG_MENU_SMOOTH
static coord_t yoffset = 0;
static int old_first_item = 0;
static int speed;
coord_t old_ymin = bm->cr.ymin;
/* Clip drawing inside menu items area */
gfx_setClipRect(bm,
bm->cr.xmin, bm->cr.ymin + ypos,
bm->cr.xmax, bm->cr.ymax);
if (old_first_item != first_item)
{
/* Speed proportional to distance */
speed = ABS(old_first_item - first_item) * 3;
if (old_first_item > first_item)
{
yoffset += speed;
if (yoffset > bm->font->height)
{
yoffset = 0;
--old_first_item;
}
}
else
{
yoffset -= speed;
if (yoffset < -bm->font->height)
{
yoffset = 0;
++old_first_item;
}
}
first_item = MIN(old_first_item, menu_count(menu));
ypos += yoffset;
redraw = true;
}
#endif /* CONFIG_MENU_SMOOTH */
if (redraw) for (i = first_item; /**/; ++i)
{
const MenuItem *item = &menu->items[i];
#if CPU_HARVARD
MenuItem ram_item;
if (menu->flags & MF_ROMITEMS)
{
memcpy_P(&ram_item, item, sizeof(ram_item));
item = &ram_item;
}
#endif /* CPU_HARVARD */
/* Check for end of room */
if (ypos > bm->cr.ymax)
break;
/* Check for end of menu */
if (!(item->label || item->hook))
break;
/* Only print visible items */
if (!(item->flags & MIF_HIDDEN))
{
#warning __FILTER_NEXT_WARNING__
RenderHook renderhook = (item->flags & MIF_RENDERHOOK) ? (RenderHook)item->label : menu_defaultRenderHook;
/* Render menuitem */
renderhook(menu->bitmap, ypos++, (i == selected), item);
ypos += bm->font->height;
}
}
#if CONFIG_MENU_SMOOTH
if (redraw)
{
/* Clear rest of area */
gfx_rectClear(bm, bm->cr.xmin, ypos, bm->cr.xmax, bm->cr.ymax);
menu->lcd_blitBitmap(bm);
}
/* Restore old cliprect */
gfx_setClipRect(bm,
bm->cr.xmin, old_ymin,
bm->cr.xmax, bm->cr.ymax);
#endif /* CONFIG_MENU_SMOOTH */
}
/**
* Handle menu item selection
*/
static iptr_t menu_doselect(const struct Menu *menu, struct MenuItem *item)
{
iptr_t result = 0;
/* Exclude other items */
int mask, i;
for (mask = item->flags & MIF_EXCLUDE_MASK, i = 0; mask; mask >>= 1, ++i)
{
if (mask & 1)
menu->items[i].flags &= ~MIF_CHECKED;
}
if (item->flags & MIF_DISABLED)
return MENU_DISABLED;
/* Handle checkable items */
if (item->flags & MIF_TOGGLE)
item->flags ^= MIF_CHECKED;
else if (item->flags & MIF_CHECKIT)
item->flags |= MIF_CHECKED;
/* Handle items with callback hooks */
if (item->hook)
{
/* Push a jmp buffer to abort the operation with the STOP/CANCEL key */
if (!PUSH_ABORT)
{
result = item->hook(item->userdata);
POP_ABORT;
}
}
else
result = item->userdata;
return result;
}
/**
* Return the next visible item (rolls back to the first item)
*/
static int menu_next_visible_item(const struct Menu *menu, int index)
{
int total = menu_count(menu);
int item_flags;
do
{
if (++index >= total)
index = 0;
#if CPU_HARVARD
if (menu->flags & MF_ROMITEMS)
{
ASSERT(sizeof(menu->items[index].flags) == sizeof(int));
item_flags = pgm_read_int(&menu->items[index].flags);
}
else
#endif
item_flags = menu->items[index].flags;
}
while (item_flags & MIF_HIDDEN);
return index;
}
/**
* Return the previous visible item (rolls back to the last item)
*/
static int menu_prev_visible_item(const struct Menu *menu, int index)
{
int total = menu_count(menu);
int item_flags;
do
{
if (--index < 0)
index = total - 1;
#if CPU_HARVARD
if (menu->flags & MF_ROMITEMS)
{
ASSERT(sizeof(menu->items[index].flags) == sizeof(int));
item_flags = pgm_read_int(&menu->items[index].flags);
}
else
#endif
item_flags = menu->items[index].flags;
}
while (item_flags & MIF_HIDDEN);
return index;
}
/**
* Handle a menu and invoke hook functions for the selected menu items.
*/
iptr_t menu_handle(const struct Menu *menu)
{
uint8_t items_per_page;
uint8_t first_item = 0;
uint8_t selected;
iptr_t result = 0;
bool redraw = true;
#if (CONFIG_MENU_TIMEOUT != 0)
ticks_t now, menu_idle_time = timer_clock();
#endif
#if CONFIG_MENU_MENUBAR
struct MenuBar mb;
const_iptr_t labels[] =
{
(const_iptr_t)LABEL_BACK,
(const_iptr_t)LABEL_UPARROW,
(const_iptr_t)LABEL_DOWNARROW,
(const_iptr_t)0
};
/*
* Initialize menu bar
*/
if (menu->flags & MF_TOPLEVEL)
labels[0] = (const_iptr_t)LABEL_EMPTY;
mbar_init(&mb, menu->bitmap, labels, countof(labels));
#endif /* CONFIG_MENU_MENUBAR */
items_per_page =
(menu->bitmap->height / menu->bitmap->font->height - 1)
#if CONFIG_MENU_MENUBAR
- 1 /* menu bar labels */
#endif
- (menu->title ? 1 : 0);
/* Selected item should be a visible entry */
//first_item = selected = menu_next_visible_item(menu, menu->selected - 1);
selected = menu->selected;
first_item = 0;
for(;;)
{
keymask_t key;
/*
* Keep selected item visible
*/
while (selected < first_item)
first_item = menu_prev_visible_item(menu, first_item);
while (selected >= first_item + items_per_page)
first_item = menu_next_visible_item(menu, first_item);
menu_layout(menu, first_item, selected, redraw);
redraw = false;
#if CONFIG_MENU_MENUBAR
menu_update_menubar(menu, &mb, selected);
#endif
#if CONFIG_MENU_SMOOTH || (CONFIG_MENU_TIMEOUT != 0)
key = kbd_peek();
cpu_relax();
#else
key = kbd_get();
#endif
#if (CONFIG_MENU_TIMEOUT != 0)
/* Reset idle timer on key press. */
now = timer_clock();
if (key)
menu_idle_time = now;
#endif
if (key & K_OK)
{
struct MenuItem *item = &(menu->items[selected]);
#if CPU_HARVARD
MenuItem ram_item;
if (menu->flags & MF_ROMITEMS)
{
memcpy_P(&ram_item, item, sizeof(ram_item));
item = &ram_item;
}
#endif
result = menu_doselect(menu, item);
redraw = true;
/* Return immediately */
if (!(menu->flags & MF_STICKY))
break;
#if (CONFIG_MENU_TIMEOUT != 0)
/* Chain timeout */
if ((result == MENU_TIMEOUT) && !(menu->flags & MF_TOPLEVEL))
break;
/* Reset timeout */
menu_idle_time = timer_clock();
#endif
}
else if (key & K_UP)
{
selected = menu_prev_visible_item(menu, selected);
redraw = true;
}
else if (key & K_DOWN)
{
selected = menu_next_visible_item(menu, selected);
redraw = true;
}
else if (!(menu->flags & MF_TOPLEVEL))
{
if (key & K_CANCEL)
{
result = MENU_CANCEL;
break;
}
#if CONFIG_MENU_TIMEOUT != 0
if (now - menu_idle_time > ms_to_ticks(CONFIG_MENU_TIMEOUT))
{
result = MENU_TIMEOUT;
break;
}
#endif
}
}
/* Store currently selected item before leaving. */
if (menu->flags & MF_SAVESEL)
#warning __FILTER_NEXT_WARNING__
CONST_CAST(struct Menu *, menu)->selected = selected;
return result;
}
/**
* Set flags on a menuitem.
*
* \param menu Menu owner of the item to change.
* \param idx Index of the menu item.
* \param flags Bit mask of the flags to set.
*
* \return Old flags.
*/
int menu_setFlags(struct Menu *menu, int idx, int flags)
{
ASSERT(idx < menu_count(menu));
ASSERT(!(menu->flags & MF_ROMITEMS));
int old = menu->items[idx].flags;
menu->items[idx].flags |= flags;
return old;
}
/**
* Clear flags on a menuitem.
*
* \param menu Menu owner of the item to change.
* \param idx Index of the menu item.
* \param flags Bit mask of the flags to clear.
*
* \return Old flags.
*/
int menu_clearFlags(struct Menu *menu, int idx, int flags)
{
ASSERT(idx < menu_count(menu));
ASSERT(!(menu->flags & MF_ROMITEMS));
int old = menu->items[idx].flags;
menu->items[idx].flags &= ~flags;
return old;
}

135
bertos/gui/menu.h Normal file
View file

@ -0,0 +1,135 @@
/**
* \file
* <!--
* This file is part of BeRTOS.
*
* Bertos is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2003, 2004, 2006, 2010 Develer S.r.l. (http://www.develer.com/)
* Copyright 2000 Bernie Innocenti <bernie@codewiz.org>
* All Rights Reserved.
* -->
*
* \defgroup menu Menu handling module
* \ingroup gui
* \{
* \author Bernie Innocenti <bernie@codewiz.org>
* \author Stefano Fedrigo <aleph@develer.com>
*
* \brief Common menu handling API
*
* $WIZ$ module_name = "menu"
* $WIZ$ module_depends = "text", "gfx", "timer", "kbd"
*/
#ifndef GUI_MENU_H
#define GUI_MENU_H
#include <cfg/compiler.h>
#include <gfx/gfx.h>
/** Menu callback function */
typedef iptr_t (*MenuHook)(iptr_t userdata);
typedef void (*BlitBitmap)(const Bitmap *bm);
/**
* Menu item description.
*/
typedef struct MenuItem
{
const_iptr_t label; /**< Item label (ID or ptr to string, 0 to disable) */
int flags; /**< See MIF_#? definitions below */
MenuHook hook; /**< Callback function (NULL to terminate item list) */
iptr_t userdata; /**< User data to be passed back to the hook */
} MenuItem;
/** Render hook callback function prototype */
typedef void (*RenderHook)(struct Bitmap *bitmap, int ypos, bool selected, const struct MenuItem *item);
/**
* \name Flags for MenuItem.flags.
* \{
*/
#define MIF_EXCLUDE_MASK 0x00FF /**< Mask for mutual exclusion map (shared with priority). */
#define MIF_PRI_MASK 0x00FF /**< Mask for priority value (shared with mutual exclusion). */
#define MIF_PRI(x) ((x) & MIF_PRI_MASK) /**< Set menu item priority. */
#define MIF_EXCLUDE_0 BV(0) /**< Exclude item 0 when this item is checked */
#define MIF_EXCLUDE_1 BV(1) /**< Exclude item 1 when this item is checked */
#define MIF_EXCLUDE_2 BV(2) /**< Exclude item 2 when this item is checked */
#define MIF_EXCLUDE_3 BV(3) /**< Exclude item 3 when this item is checked */
#define MIF_EXCLUDE_4 BV(4) /**< Exclude item 4 when this item is checked */
#define MIF_EXCLUDE_5 BV(5) /**< Exclude item 5 when this item is checked */
#define MIF_EXCLUDE_6 BV(6) /**< Exclude item 6 when this item is checked */
#define MIF_EXCLUDE_7 BV(7) /**< Exclude item 7 when this item is checked */
#define MIF_CHECKED BV(8) /**< Item is currently checked */
#define MIF_CHECKIT BV(9) /**< Automatically check this item when selected */
#define MIF_TOGGLE BV(10) /**< Toggle MIF_CHECKED when item is selected */
#define MIF_HIDDEN BV(11) /**< This menu item is not visible */
#define MIF_DISABLED BV(12) /**< This menu item is not visible */
#define MIF_RAMLABEL BV(13) /**< Item label is stored in RAM, not in program memory */
#define MIF_RENDERHOOK BV(14) /**< Menu render function is passed in label field */
/* \} */
/**
* Menu description.
*/
typedef struct Menu
{
MenuItem *items; /**< Array of items (end with a NULL hook) */
const_iptr_t title; /**< Menu title (ID or ptr to string, 0 to disable) */
int flags; /**< See MF_#? definitions below */
struct Bitmap *bitmap; /**< Bitmap where the menu is rendered */
int selected; /**< Initial selection (written to if MF_SAVESEL is set). */
BlitBitmap lcd_blitBitmap; /**< Callback to call to do smooth the display */
} Menu;
/**
* \name Flags for Menu.flags.
* \{
*/
#define MF_STICKY BV(0) /**< Stay in the menu when the items called return */
#define MF_TOPLEVEL BV(1) /**< Top-level menu (do not display "back" label) */
#define MF_ROMITEMS BV(2) /**< Menu items are stored in ROM (default is RAM) */
#define MF_SAVESEL BV(3) /**< Remember the selected item across invocations. */
/* \} */
/**
* \name Special result codes for menu_handle().
* \{
*/
#define MENU_OK ((iptr_t)0)
#define MENU_CANCEL ((iptr_t)-1)
#define MENU_TIMEOUT ((iptr_t)-2)
#define MENU_ABORT ((iptr_t)-3)
#define MENU_DISABLED ((iptr_t)-4)
/* \} */
/* Function prototypes */
iptr_t menu_handle(const struct Menu *menu);
int menu_setFlags(struct Menu *menu, int idx, int flags);
int menu_clearFlags(struct Menu *menu, int idx, int flags);
/** \} */ //defgroup menu
#endif /* GUI_MENU_H */

177
bertos/gui/menubar.c Normal file
View file

@ -0,0 +1,177 @@
/**
* \file
* <!--
* This file is part of BeRTOS.
*
* Bertos is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2004, 2008 Develer S.r.l. (http://www.develer.com/)
* All Rights Reserved.
* -->
*
* \brief Graphics Menu bar widget
*
* \author Stefano Fedrigo <aleph@develer.com>
* \author Francesco Sacchi <batt@develer.com>
*
*/
#include "menubar.h"
#include <gfx/gfx.h>
#include <gfx/text.h>
#include <gfx/font.h>
#include <cfg/compiler.h>
#warning FIXME:This module is obsolete, you must refactor it!
#if 0
#if CPU_AVR
#include <avr/pgmspace.h> /* strlen_P() */
#else
#define strlen_P(s) strlen(s)
#define text_puts_P(s, b) text_puts(s, b)
#define pgm_read_uint16_t(addr) (*(addr))
#endif
#include <string.h> /* strlen, memcpy */
/** Predefined labels */
static const pgm_char lab_1[] = "";
static const pgm_char lab_2[] = "mute";
static const pgm_char lab_3[] = "menu";
static const pgm_char lab_4[] = "back";
static const pgm_char lab_5[] = " ok ";
static const pgm_char lab_6[] = "Ch 1";
static const pgm_char lab_7[] = "Ch 2";
static const pgm_char lab_8[] = "C1+2";
static const pgm_char lab_9[] = " "UP_ARROW" ";
static const pgm_char lab_10[] = " "DOWN_ARROW" ";
static const pgm_char lab_11[] = " - ";
static const pgm_char lab_12[] = " + ";
static const pgm_char lab_13[] = "sel ";
static const pgm_char lab_14[] = "lock";
static const pgm_char lab_15[] = "unlock";
static const pgm_char lab_16[] = "more";
static const pgm_char lab_17[] = "edit";
static const pgm_char lab_18[] = "fast";
static const pgm_char lab_19[] = LEFT_ARROW" ";
static const pgm_char lab_20[] = " "RIGHT_ARROW;
static const pgm_char lab_21[] = "slow";
static const pgm_char lab_22[] = "yes";
static const pgm_char lab_23[] = "no";
static const pgm_char * PROGMEM label_strings[LABEL_CNT] = {
lab_1, lab_2, lab_3, lab_4, lab_5, lab_6, lab_7, lab_8, lab_9,
lab_10, lab_11, lab_12, lab_13, lab_14, lab_15, lab_16, lab_17,
lab_18, lab_19, lab_20, lab_21, lab_22, lab_23
};
/**
* Macro to access a label iptr_t: if a char pointer get the string pointed to
* in program memory, otherwise return the corrispondent predefined string
* (see label_strings in menubar.c)
*/
#define PTRLBL(x) ((unsigned int)(x) < 256 ? \
(const pgm_char *)pgm_read_uint16_t(label_strings + (unsigned int)(x)) \
: (const pgm_char *)(x))
/**
* Initialize the MenuBar widget with the bitmap associated,
* the label names and the number of labels.
*/
void mbar_init(
struct MenuBar *mb,
struct Bitmap *bmp,
const_iptr_t labels[],
int num_labels)
{
mb->bitmap = bmp;
mb->labels = labels;
mb->num_labels = num_labels;
}
/**
* Render the MenuBar on the bitmap.
*/
void mbar_draw(const struct MenuBar *mb)
{
uint8_t oldstyle;
int i;
size_t maxlen = 0; /* Length of the longest label */
coord_t x1, x2, y1, y2, label_padding;
/* Maximum space available for a label */
coord_t slot_width = mb->bitmap->width / mb->num_labels;
/* Find longest label */
for (i = 0; i < mb->num_labels; i++)
if (strlen_P(PTRLBL(mb->labels[i])) > maxlen)
maxlen = strlen_P(PTRLBL(mb->labels[i]));
oldstyle = text_style(mb->bitmap, STYLEF_INVERT, STYLEF_MASK);
/* y coords for menubar: bottom of the bitmap */
y1 = mb->bitmap->height - FONT_HEIGHT;
y2 = mb->bitmap->height;
/* Clear menubar area */
gfx_rectClear(mb->bitmap, 0, y1, mb->bitmap->width, y2);
for (i = 0; i < mb->num_labels; i++)
{
size_t lablen = strlen_P(PTRLBL(mb->labels[i]));
/* Don't draw empty labels */
if (mb->labels[i] == (const_iptr_t)LABEL_EMPTY)
continue;
/* x coords: magic formula for equal distribution of the
* labels along bitmap
*/
label_padding = slot_width - (FONT_WIDTH * lablen + 2);
x1 = i * (slot_width + (label_padding / (mb->num_labels - 1)));
x2 = x1 + lablen * FONT_WIDTH + 1;
/* Draw vertical line before.
* Uncomment +1 for "rounded" menubars */
gfx_line(mb->bitmap, x1, y1 /* + 1 */, x1, y2);
/* Draw text */
text_setCoord(mb->bitmap, x1 + 1, y1);
text_puts_P(PTRLBL(mb->labels[i]), mb->bitmap);
/* Draw vertical line after
* Uncomment +1 for "rounded" menubars */
gfx_line(mb->bitmap, x2, y1 /* + 1 */, x2, y2);
}
text_style(mb->bitmap, oldstyle, STYLEF_MASK);
}
#endif

97
bertos/gui/menubar.h Normal file
View file

@ -0,0 +1,97 @@
/**
* \file
* <!--
* This file is part of BeRTOS.
*
* Bertos is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2004, 2005, 2008 Develer S.r.l. (http://www.develer.com/)
* All Rights Reserved.
* -->
*
* \brief Graphic menu bar widget.
*
* \author Stefano Fedrigo <aleph@develer.com>
*
*/
#ifndef GUI_MENUBAR_H
#define GUI_MENUBAR_H
#include <cfg/compiler.h>
/** Predefined labels ids */
enum LabelId
{
LABEL_EMPTY, /* empty label */
LABEL_MUTE,
LABEL_MENU,
LABEL_BACK,
LABEL_OK,
LABEL_CH_1,
LABEL_CH_2,
LABEL_C1PLUS2,
LABEL_UPARROW,
LABEL_DOWNARROW,
LABEL_MINUS,
LABEL_PLUS,
LABEL_SEL,
LABEL_LOCK,
LABEL_UNLOCK,
LABEL_MORE,
LABEL_EDIT,
LABEL_FAST,
LABEL_PREV,
LABEL_NEXT,
LABEL_SLOW,
LABEL_YES,
LABEL_NO,
LABEL_CNT
};
#define UP_ARROW "\x18"
#define DOWN_ARROW "\x19"
#define RIGHT_ARROW "\xC4\x1A"
#define LEFT_ARROW "\x10\xC4"
/* Forward decl */
struct Bitmap;
typedef struct MenuBar
{
struct Bitmap *bitmap;
const_iptr_t *labels;
int num_labels;
} MenuBar;
void mbar_init(
struct MenuBar *mb,
struct Bitmap *bmp,
const_iptr_t *labels,
int num_labels);
void mbar_draw(const struct MenuBar *mb);
#endif /* GUI_MENUBAR_H */