2009-08-04 02:01:55 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* __________ __ ___.
|
|
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
|
|
* \/ \/ \/ \/ \/
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
* Copyright (C) 2009 Wincent Balin
|
|
|
|
*
|
|
|
|
* This program 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
|
|
* KIND, either express or implied.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "plugin.h"
|
|
|
|
#include "pdbox.h"
|
|
|
|
|
|
|
|
#include "lib/xlcd.h"
|
|
|
|
|
|
|
|
/* Button colors. */
|
|
|
|
#define BTNCOLOR_DARK (LCD_DARKGRAY)
|
|
|
|
#define BTNCOLOR_LIGHT (LCD_LIGHTGRAY)
|
|
|
|
|
|
|
|
/* Variables in the main code. */
|
|
|
|
extern char* filename;
|
|
|
|
extern bool quit;
|
|
|
|
|
|
|
|
/* Screen multiplier. */
|
|
|
|
static float screen_multiplier;
|
|
|
|
|
2009-08-17 15:30:02 +00:00
|
|
|
/* Back- and foreground colors. */
|
|
|
|
static unsigned bgcolor;
|
|
|
|
static unsigned fgcolor;
|
|
|
|
|
2009-08-04 02:01:55 +00:00
|
|
|
/* Displacement of the slanted corner in the contour of the number widget. */
|
|
|
|
static int number_corner;
|
|
|
|
|
|
|
|
/* Button flags. */
|
|
|
|
static bool play_on;
|
|
|
|
static bool previous_on;
|
|
|
|
static bool next_on;
|
|
|
|
static bool menu_on;
|
|
|
|
static bool action_on;
|
|
|
|
|
|
|
|
/* Pause flag. */
|
|
|
|
static bool paused;
|
|
|
|
|
|
|
|
|
|
|
|
/* Draw circle using midpoint circle algorithm.
|
|
|
|
Adapted from http://en.wikipedia.org/wiki/Midpoint_circle_algorithm. */
|
|
|
|
void drawcircle(int x, int y, int r)
|
|
|
|
{
|
|
|
|
int f = 1 - r;
|
|
|
|
int ddfx = 1;
|
|
|
|
int ddfy = -2 * r;
|
|
|
|
int xp = 0;
|
|
|
|
int yp = r;
|
|
|
|
|
|
|
|
/* Draw outer points. */
|
|
|
|
rb->lcd_drawpixel(x, y + r);
|
|
|
|
rb->lcd_drawpixel(x, y + r);
|
|
|
|
rb->lcd_drawpixel(x + r, y);
|
|
|
|
rb->lcd_drawpixel(x - r, y);
|
|
|
|
|
|
|
|
/* Calculate coordinates of points in one octant. */
|
|
|
|
while(xp < yp)
|
|
|
|
{
|
|
|
|
/* ddfx == 2 * xp + 1;
|
|
|
|
ddfy == -2 * yp;
|
|
|
|
f == xp*xp + yp*yp - r*r + 2*xp - yp + 1; */
|
|
|
|
if(f >= 0)
|
|
|
|
{
|
|
|
|
yp--;
|
|
|
|
ddfy += 2;
|
|
|
|
f += ddfy;
|
|
|
|
}
|
|
|
|
|
|
|
|
xp++;
|
|
|
|
ddfx += 2;
|
|
|
|
f += ddfx;
|
|
|
|
|
|
|
|
/* Draw pixels in all octants. */
|
|
|
|
rb->lcd_drawpixel(x + xp, y + yp);
|
|
|
|
rb->lcd_drawpixel(x + xp, y - yp);
|
|
|
|
rb->lcd_drawpixel(x - xp, y + yp);
|
|
|
|
rb->lcd_drawpixel(x - xp, y - yp);
|
|
|
|
rb->lcd_drawpixel(x + yp, y + xp);
|
|
|
|
rb->lcd_drawpixel(x + yp, y - xp);
|
|
|
|
rb->lcd_drawpixel(x - yp, y + xp);
|
|
|
|
rb->lcd_drawpixel(x - yp, y - xp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fill circle. */
|
|
|
|
void fillcircle(int x, int y, int r)
|
|
|
|
{
|
|
|
|
int f = 1 - r;
|
|
|
|
int ddfx = 1;
|
|
|
|
int ddfy = -2 * r;
|
|
|
|
int xp = 0;
|
|
|
|
int yp = r;
|
|
|
|
|
|
|
|
/* Draw outer points. */
|
|
|
|
rb->lcd_drawpixel(x, y + r);
|
|
|
|
rb->lcd_drawpixel(x, y + r);
|
|
|
|
rb->lcd_drawpixel(x + r, y);
|
|
|
|
rb->lcd_drawpixel(x - r, y);
|
|
|
|
|
|
|
|
/* Calculate coordinates of points in one octant. */
|
|
|
|
while(xp < yp)
|
|
|
|
{
|
|
|
|
/* ddfx == 2 * xp + 1;
|
|
|
|
ddfy == -2 * yp;
|
|
|
|
f == xp*xp + yp*yp - r*r + 2*xp - yp + 1; */
|
|
|
|
if(f >= 0)
|
|
|
|
{
|
|
|
|
yp--;
|
|
|
|
ddfy += 2;
|
|
|
|
f += ddfy;
|
|
|
|
}
|
|
|
|
|
|
|
|
xp++;
|
|
|
|
ddfx += 2;
|
|
|
|
f += ddfx;
|
|
|
|
|
|
|
|
/* Fill circle with horizontal lines. */
|
|
|
|
rb->lcd_hline(x - xp, x + xp, y - yp);
|
|
|
|
rb->lcd_hline(x - xp, x + xp, y + yp);
|
|
|
|
rb->lcd_hline(x - yp, x + yp, y - xp);
|
|
|
|
rb->lcd_hline(x - yp, x + yp, y + xp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Draw last horizontal line (central one). */
|
|
|
|
rb->lcd_hline(x - r, x + r, y);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize GUI. */
|
|
|
|
void pd_gui_init(void)
|
|
|
|
{
|
|
|
|
/* Reset button flags. */
|
|
|
|
play_on = false;
|
|
|
|
previous_on = false;
|
|
|
|
next_on = false;
|
|
|
|
menu_on = false;
|
|
|
|
action_on = false;
|
|
|
|
|
|
|
|
/* Unpause Pure Data. */
|
|
|
|
paused = false;
|
|
|
|
|
|
|
|
/* Calculate dimension factors. */
|
|
|
|
screen_multiplier = ((float) LCD_WIDTH) / 160.0f;
|
|
|
|
number_corner = 5 * screen_multiplier;
|
|
|
|
|
2009-08-17 15:30:02 +00:00
|
|
|
/* Get back- and foreground colors. */
|
|
|
|
bgcolor = rb->lcd_get_background();
|
|
|
|
fgcolor = rb->lcd_get_foreground();
|
2009-08-04 02:01:55 +00:00
|
|
|
|
|
|
|
/* Clear background. */
|
|
|
|
rb->lcd_clear_display();
|
|
|
|
|
2009-08-17 15:30:02 +00:00
|
|
|
/* Draw background of appropriate color. */
|
|
|
|
rb->lcd_set_foreground(bgcolor);
|
|
|
|
rb->lcd_fillrect(0, 0, LCD_WIDTH, LCD_HEIGHT);
|
|
|
|
rb->lcd_set_foreground(fgcolor);
|
|
|
|
|
2009-08-04 02:01:55 +00:00
|
|
|
/* Update display. */
|
|
|
|
rb->lcd_update();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Load PD patch. */
|
|
|
|
unsigned int pd_gui_load_patch(struct pd_widget* wg, unsigned int max_widgets)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
char line[100];
|
|
|
|
char* saveptr;
|
|
|
|
unsigned int widgets = 0;
|
|
|
|
|
|
|
|
/* Open PD patch. */
|
|
|
|
fd = open(filename, O_RDONLY);
|
|
|
|
|
|
|
|
/* Check for I/O error. */
|
|
|
|
if(!fd)
|
|
|
|
{
|
|
|
|
/* Show error message and make plug-in quit. */
|
|
|
|
rb->splash(HZ, "Error opening .pd file!");
|
|
|
|
quit = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read lines from PD file. */
|
|
|
|
while(rb->read_line(fd, line, sizeof(line)) > 0)
|
|
|
|
{
|
|
|
|
/* Check whether we got too many widgets. */
|
|
|
|
if(widgets >= max_widgets)
|
|
|
|
{
|
|
|
|
rb->splash(HZ, "Too many widgets!");
|
|
|
|
quit = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Search for key strings in the line. */
|
|
|
|
if((strstr(line, "floatatom") != NULL) &&
|
|
|
|
(strstr(line, "pod_") != NULL))
|
|
|
|
{
|
|
|
|
wg->id = PD_NUMBER;
|
|
|
|
|
|
|
|
strtok_r(line, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->x = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->y = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->w = 7 * atoi(strtok_r(NULL, " ", &saveptr)) *
|
|
|
|
screen_multiplier;
|
|
|
|
wg->h = 16 * screen_multiplier;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strncpy(wg->name, strtok_r(NULL, " ", &saveptr), sizeof(wg->name));
|
|
|
|
|
2010-06-04 18:05:59 +00:00
|
|
|
/* Reset value. */
|
|
|
|
wg->value = 0;
|
|
|
|
|
2009-08-04 02:01:55 +00:00
|
|
|
/* We got one more widget. */
|
|
|
|
wg++;
|
|
|
|
widgets++;
|
|
|
|
}
|
|
|
|
else if((strstr(line, "symbolatom") != NULL) &&
|
|
|
|
(strstr(line, "pod_") != NULL))
|
|
|
|
{
|
|
|
|
wg->id = PD_SYMBOL;
|
|
|
|
|
|
|
|
strtok_r(line, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->x = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->y = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->w = 7 * atoi(strtok_r(NULL, " ", &saveptr)) *
|
|
|
|
screen_multiplier;
|
|
|
|
wg->h = 16 * screen_multiplier;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strncpy(wg->name, strtok_r(NULL, " ", &saveptr), sizeof(wg->name));
|
|
|
|
|
2010-06-04 18:05:59 +00:00
|
|
|
/* Reset value. */
|
|
|
|
wg->value = 0;
|
|
|
|
|
2009-08-04 02:01:55 +00:00
|
|
|
/* We got one more widget. */
|
|
|
|
wg++;
|
|
|
|
widgets++;
|
|
|
|
}
|
|
|
|
else if((strstr(line, "vsl") != NULL) &&
|
|
|
|
(strstr(line, "pod_") != NULL))
|
|
|
|
{
|
|
|
|
wg->id = PD_VSLIDER;
|
|
|
|
|
|
|
|
strtok_r(line, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->x = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->y = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->w = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->h = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->min = atoi(strtok_r(NULL, " ", &saveptr));
|
|
|
|
wg->max = atoi(strtok_r(NULL, " ", &saveptr));
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strncpy(wg->name, strtok_r(NULL, " ", &saveptr), sizeof(wg->name));
|
|
|
|
|
2010-06-04 18:05:59 +00:00
|
|
|
/* Reset value. */
|
|
|
|
wg->value = 0;
|
|
|
|
|
2009-08-04 02:01:55 +00:00
|
|
|
/* We got one more widget. */
|
|
|
|
wg++;
|
|
|
|
widgets++;
|
|
|
|
}
|
|
|
|
else if((strstr(line, "hsl") != NULL) &&
|
|
|
|
(strstr(line, "pod_") != NULL))
|
|
|
|
{
|
|
|
|
wg->id = PD_HSLIDER;
|
|
|
|
|
|
|
|
strtok_r(line, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->x = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->y = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->w = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->h = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->min = atoi(strtok_r(NULL, " ", &saveptr));
|
|
|
|
wg->max = atoi(strtok_r(NULL, " ", &saveptr));
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strncpy(wg->name, strtok_r(NULL, " ", &saveptr), sizeof(wg->name));
|
|
|
|
|
2010-06-04 18:05:59 +00:00
|
|
|
/* Reset value. */
|
|
|
|
wg->value = 0;
|
|
|
|
|
2009-08-04 02:01:55 +00:00
|
|
|
/* We got one more widget. */
|
|
|
|
wg++;
|
|
|
|
widgets++;
|
|
|
|
}
|
|
|
|
else if((strstr(line, "vradio") != NULL) &&
|
|
|
|
(strstr(line, "pod_") != NULL))
|
|
|
|
{
|
|
|
|
wg->id = PD_VRADIO;
|
|
|
|
|
|
|
|
strtok_r(line, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->x = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->y = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->w = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->min = 0;
|
|
|
|
wg->max = atoi(strtok_r(NULL, " ", &saveptr));
|
|
|
|
wg->h = wg->w * wg->max;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strncpy(wg->name, strtok_r(NULL, " ", &saveptr), sizeof(wg->name));
|
|
|
|
wg->max--;
|
|
|
|
|
2010-06-04 18:05:59 +00:00
|
|
|
/* Reset value. */
|
|
|
|
wg->value = 0;
|
|
|
|
|
2009-08-04 02:01:55 +00:00
|
|
|
/* We got one more widget. */
|
|
|
|
wg++;
|
|
|
|
widgets++;
|
|
|
|
}
|
|
|
|
else if((strstr(line, "hradio") != NULL) &&
|
|
|
|
(strstr(line, "pod_") != NULL))
|
|
|
|
{
|
|
|
|
wg->id = PD_HRADIO;
|
|
|
|
|
|
|
|
strtok_r(line, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->x = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->y = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->h = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->min = 0;
|
|
|
|
wg->max = atoi(strtok_r(NULL, " ", &saveptr));
|
|
|
|
wg->w = wg->h * wg->max;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strncpy(wg->name, strtok_r(NULL, " ", &saveptr), sizeof(wg->name));
|
|
|
|
wg->max--;
|
|
|
|
|
2010-06-04 18:05:59 +00:00
|
|
|
/* Reset value. */
|
|
|
|
wg->value = 0;
|
|
|
|
|
2009-08-04 02:01:55 +00:00
|
|
|
/* We got one more widget. */
|
|
|
|
wg++;
|
|
|
|
widgets++;
|
|
|
|
}
|
|
|
|
else if((strstr(line, "bng") != NULL) &&
|
|
|
|
(strstr(line, "pod_") != NULL))
|
|
|
|
{
|
|
|
|
wg->id = PD_BANG;
|
|
|
|
|
|
|
|
strtok_r(line, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->x = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->y = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->w = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->h = wg->w;
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
strncpy(wg->name, strtok_r(NULL, " ", &saveptr), sizeof(wg->name));
|
|
|
|
wg->min = 0;
|
|
|
|
wg->max = 1;
|
|
|
|
|
2010-06-04 18:05:59 +00:00
|
|
|
/* Reset value. */
|
|
|
|
wg->value = 0;
|
|
|
|
|
2009-08-04 02:01:55 +00:00
|
|
|
/* Clear timeout flag. */
|
|
|
|
wg->timeout = 0;
|
|
|
|
|
|
|
|
/* We got one more widget. */
|
|
|
|
wg++;
|
|
|
|
widgets++;
|
|
|
|
}
|
|
|
|
else if(strstr(line, "text") != NULL)
|
|
|
|
{
|
|
|
|
wg->id = PD_TEXT;
|
|
|
|
|
|
|
|
strtok_r(line, " ", &saveptr);
|
|
|
|
strtok_r(NULL, " ", &saveptr);
|
|
|
|
wg->x = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
wg->y = atoi(strtok_r(NULL, " ", &saveptr)) * screen_multiplier;
|
|
|
|
strncpy(wg->name, strtok_r(NULL, " ", &saveptr), sizeof(wg->name));
|
|
|
|
char* w = strtok_r(NULL, " ", &saveptr);
|
|
|
|
while(w != NULL)
|
|
|
|
{
|
|
|
|
strcat(wg->name, w);
|
|
|
|
strcat(wg->name, " ");
|
|
|
|
w = strtok_r(NULL, " ", &saveptr);
|
|
|
|
}
|
|
|
|
/* Cut off unneeded characters (';' and '\n'). */
|
|
|
|
int namelen = strlen(wg->name);
|
|
|
|
if(namelen > 1)
|
|
|
|
{
|
|
|
|
/* Cut off '\n'. */
|
|
|
|
wg->name[namelen-1] = '\0';
|
|
|
|
namelen--;
|
|
|
|
/* Cut the last semi-colon, if there is one. */
|
|
|
|
if(wg->name[namelen-1] == ';')
|
|
|
|
wg->name[namelen-1] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* We got one more widget. */
|
|
|
|
wg++;
|
|
|
|
widgets++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Close PD patch. */
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
/* Return amount of loaded widgets. */
|
|
|
|
return widgets;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Draw standard user interface. */
|
|
|
|
void pd_gui_draw_standard(void)
|
|
|
|
{
|
|
|
|
/* Draw main circle. */
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(fgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
fillcircle(LCD_WIDTH / 2,
|
|
|
|
LCD_HEIGHT / 2,
|
|
|
|
2 * MIN(LCD_WIDTH, LCD_HEIGHT) / 5);
|
|
|
|
|
|
|
|
/* Draw center circle. */
|
|
|
|
rb->lcd_set_foreground(action_on ? BTNCOLOR_DARK : BTNCOLOR_LIGHT);
|
|
|
|
fillcircle(LCD_WIDTH / 2,
|
|
|
|
LCD_HEIGHT / 2,
|
|
|
|
MIN(LCD_WIDTH, LCD_HEIGHT) / 8);
|
|
|
|
|
|
|
|
/* Draw pressed buttons. */
|
|
|
|
if(play_on)
|
|
|
|
fillcircle(LCD_WIDTH / 2,
|
|
|
|
3 * LCD_HEIGHT / 4,
|
|
|
|
MIN(LCD_WIDTH, LCD_HEIGHT) / 8);
|
|
|
|
|
|
|
|
if(previous_on)
|
|
|
|
fillcircle(LCD_WIDTH / 3,
|
|
|
|
LCD_HEIGHT / 2,
|
|
|
|
MIN(LCD_WIDTH, LCD_HEIGHT) / 8);
|
|
|
|
|
|
|
|
if(next_on)
|
|
|
|
fillcircle(2 * LCD_WIDTH / 3 + 1,
|
|
|
|
LCD_HEIGHT / 2,
|
|
|
|
MIN(LCD_WIDTH, LCD_HEIGHT) / 8);
|
|
|
|
|
|
|
|
if(menu_on)
|
|
|
|
fillcircle(LCD_WIDTH / 2,
|
|
|
|
LCD_HEIGHT / 4,
|
|
|
|
MIN(LCD_WIDTH, LCD_HEIGHT) / 8);
|
|
|
|
|
|
|
|
/* Restore foreground color. */
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(fgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Draw custom user interface. */
|
|
|
|
void pd_gui_draw_custom(struct pd_widget* wg, unsigned int widgets)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
int j;
|
|
|
|
int v;
|
|
|
|
|
|
|
|
for(i = 0; i < widgets; wg++, i++)
|
|
|
|
{
|
|
|
|
switch(wg->id)
|
|
|
|
{
|
|
|
|
case PD_BANG:
|
|
|
|
/* Clear area to (re-)draw. */
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(bgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
rb->lcd_fillrect(wg->x, wg->y, wg->w, wg->h);
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(fgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
/* Draw border (rectangle). */
|
|
|
|
rb->lcd_drawrect(wg->x, wg->y, wg->w, wg->h);
|
|
|
|
/* Draw button (circle), being filled depending on value. */
|
|
|
|
if(((int) wg->value) == 0) /* Button not pressed. */
|
|
|
|
drawcircle(wg->x + wg->w/2,
|
|
|
|
wg->y + wg->w/2,
|
|
|
|
wg->w/2 - 1);
|
|
|
|
else /* Button pressed. */
|
|
|
|
fillcircle(wg->x + wg->w/2,
|
|
|
|
wg->y + wg->w/2,
|
|
|
|
wg->w/2 - 1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PD_VSLIDER:
|
|
|
|
/* Clear area to (re-)draw. */
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(bgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
rb->lcd_fillrect(wg->x, wg->y, wg->w, wg->h);
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(fgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
/* Draw border. */
|
|
|
|
rb->lcd_drawrect(wg->x, wg->y, wg->w, wg->h);
|
|
|
|
/* Draw slider. */
|
|
|
|
v = ((float) wg->h / (wg->max - wg->min)) *
|
|
|
|
(wg->max - wg->value);
|
|
|
|
rb->lcd_fillrect(wg->x, wg->y + v, wg->w, 2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PD_HSLIDER:
|
|
|
|
/* Clear area to (re-)draw. */
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(bgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
rb->lcd_fillrect(wg->x, wg->y, wg->w, wg->h);
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(fgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
/* Draw border. */
|
|
|
|
rb->lcd_drawrect(wg->x, wg->y, wg->w, wg->h);
|
|
|
|
/* Draw slider. */
|
|
|
|
v = ((float) wg->w / (wg->max - wg->min)) *
|
|
|
|
(wg->max - wg->value);
|
|
|
|
rb->lcd_fillrect(wg->x + wg->w - v, wg->y, 2, wg->h);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PD_HRADIO:
|
|
|
|
/* Clear area to (re-)draw. */
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(bgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
rb->lcd_fillrect(wg->x, wg->y, wg->w, wg->h);
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(fgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
for(j = 0; j < wg->w / wg->h; j++)
|
|
|
|
{
|
|
|
|
/* Draw border. */
|
|
|
|
rb->lcd_drawrect(wg->x + wg->h * j, wg->y, wg->h, wg->h);
|
|
|
|
/* If marked, draw button. */
|
|
|
|
if(((int) wg->value) == j)
|
|
|
|
rb->lcd_fillrect(wg->x + wg->h * j + 2, wg->y + 2,
|
|
|
|
wg->h - 4, wg->h - 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PD_VRADIO:
|
|
|
|
/* Clear area to (re-)draw. */
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(bgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
rb->lcd_fillrect(wg->x, wg->y, wg->w, wg->h);
|
2009-08-17 15:30:02 +00:00
|
|
|
rb->lcd_set_foreground(fgcolor);
|
2009-08-04 02:01:55 +00:00
|
|
|
for(j = 0; j < wg->h / wg->w; j++)
|
|
|
|
{
|
|
|
|
/* Draw border. */
|
|
|
|
rb->lcd_drawrect(wg->x, wg->y + wg->w * j, wg->w, wg->w);
|
|
|
|
/* If marked, draw button. */
|
|
|
|
if(((int) wg->value) == j)
|
|
|
|
rb->lcd_fillrect(wg->x + 2, wg->y + wg->w * j + 2,
|
|
|
|
wg->w - 4, wg->w - 4);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PD_NUMBER:
|
|
|
|
rb->lcd_hline(wg->x,
|
|
|
|
wg->x + wg->w - number_corner,
|
|
|
|
wg->y);
|
|
|
|
rb->lcd_drawline(wg->x + wg->w - number_corner,
|
|
|
|
wg->y,
|
|
|
|
wg->x + wg->w,
|
|
|
|
wg->y + number_corner);
|
|
|
|
rb->lcd_vline(wg->x + wg->w,
|
|
|
|
wg->y + number_corner,
|
|
|
|
wg->y + wg->h);
|
|
|
|
rb->lcd_hline(wg->x,
|
|
|
|
wg->x + wg->w,
|
|
|
|
wg->y + wg->h);
|
|
|
|
rb->lcd_vline(wg->x,
|
|
|
|
wg->y,
|
|
|
|
wg->y + wg->h);
|
2010-06-04 18:07:01 +00:00
|
|
|
char sbuf[8];
|
|
|
|
ftoan(wg->value, sbuf, 8);
|
2009-08-04 02:01:55 +00:00
|
|
|
rb->lcd_putsxy(wg->x + 2, wg->y + 2, sbuf);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PD_TEXT:
|
|
|
|
rb->lcd_putsxy(wg->x + 2, wg->y, wg->name);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PD_SYMBOL:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Draw the GUI. */
|
|
|
|
void pd_gui_draw(struct pd_widget* wg, unsigned int widgets)
|
|
|
|
{
|
|
|
|
/* Draw GUI. */
|
|
|
|
if(widgets == 0)
|
|
|
|
pd_gui_draw_standard();
|
|
|
|
else
|
|
|
|
pd_gui_draw_custom(wg, widgets);
|
|
|
|
|
|
|
|
/* Update display. */
|
|
|
|
rb->lcd_update();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse buttons, if needed, send messages to the Pure Data code. */
|
|
|
|
bool pd_gui_parse_buttons(unsigned int widgets)
|
|
|
|
{
|
|
|
|
static long last_bv = 0;
|
|
|
|
long bv = rb->button_get(false);
|
|
|
|
|
|
|
|
/* Extract differences between current and previous button values. */
|
|
|
|
long diff_bv = bv ^ last_bv;
|
|
|
|
|
|
|
|
/* If no difference since the last button value, return here. */
|
|
|
|
if(diff_bv == 0)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* Query whether we have to quit. */
|
|
|
|
if(bv == PDPOD_QUIT)
|
|
|
|
{
|
|
|
|
/* No need to send the quitting message to Pure Data core,
|
|
|
|
as setting the quit flag ends threads and jumps
|
|
|
|
to the cleanup code. */
|
|
|
|
quit = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check the action (shift, mode) button. */
|
|
|
|
if(diff_bv & PDPOD_ACTION)
|
|
|
|
{
|
|
|
|
if(bv & PDPOD_ACTION)
|
|
|
|
{
|
|
|
|
SEND_TO_CORE("b;\n");
|
|
|
|
|
|
|
|
if(widgets == 0)
|
|
|
|
action_on = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(widgets == 0)
|
|
|
|
action_on = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check play button. */
|
|
|
|
if(diff_bv & PDPOD_PLAY)
|
|
|
|
{
|
|
|
|
if(bv & PDPOD_PLAY)
|
|
|
|
{
|
|
|
|
/* Action + play = pause. */
|
|
|
|
if(action_on)
|
|
|
|
{
|
|
|
|
/* Switch paused state. */
|
|
|
|
paused = !paused;
|
|
|
|
SEND_TO_CORE(paused ? "p 1;\n" : "p 0;\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!action_on && !paused)
|
|
|
|
SEND_TO_CORE("d 1;\n");
|
|
|
|
|
|
|
|
if(widgets == 0)
|
|
|
|
play_on = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(!action_on && !paused)
|
|
|
|
SEND_TO_CORE("d 0;\n");
|
|
|
|
|
|
|
|
if(widgets == 0)
|
|
|
|
play_on = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check rewind (previous) button. */
|
|
|
|
if(diff_bv & PDPOD_PREVIOUS)
|
|
|
|
{
|
|
|
|
if(bv & PDPOD_PREVIOUS)
|
|
|
|
{
|
|
|
|
if(!paused)
|
|
|
|
SEND_TO_CORE("w 1;\n");
|
|
|
|
|
|
|
|
if(widgets == 0)
|
|
|
|
previous_on = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(!paused)
|
|
|
|
SEND_TO_CORE("w 0;\n");
|
|
|
|
|
|
|
|
if(widgets == 0)
|
|
|
|
previous_on = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check forward (next) button. */
|
|
|
|
if(diff_bv & PDPOD_NEXT)
|
|
|
|
{
|
|
|
|
if(bv & PDPOD_NEXT)
|
|
|
|
{
|
|
|
|
if(!paused)
|
|
|
|
SEND_TO_CORE("f 1;\n");
|
|
|
|
|
|
|
|
if(widgets == 0)
|
|
|
|
next_on = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(!paused)
|
|
|
|
SEND_TO_CORE("f 0;\n");
|
|
|
|
|
|
|
|
if(widgets == 0)
|
|
|
|
next_on = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check menu (select) button. */
|
|
|
|
if(diff_bv & PDPOD_MENU)
|
|
|
|
{
|
|
|
|
if(bv & PDPOD_MENU)
|
|
|
|
{
|
|
|
|
if(!action_on && !paused)
|
|
|
|
SEND_TO_CORE("m 1;\n");
|
|
|
|
|
|
|
|
if(widgets == 0)
|
|
|
|
menu_on = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(!action_on && !paused)
|
|
|
|
SEND_TO_CORE("m 0;\n");
|
|
|
|
|
|
|
|
if(widgets == 0)
|
|
|
|
menu_on = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check scroll right (or up) button. */
|
|
|
|
if(diff_bv & PDPOD_WHEELRIGHT)
|
|
|
|
{
|
|
|
|
if(bv & PDPOD_WHEELRIGHT)
|
|
|
|
{
|
|
|
|
SEND_TO_CORE(action_on ? "r 10;\n" : "r 1;\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check scroll left (or down) button. */
|
|
|
|
if(diff_bv & PDPOD_WHEELLEFT)
|
|
|
|
{
|
|
|
|
if(bv & PDPOD_WHEELLEFT)
|
|
|
|
{
|
|
|
|
SEND_TO_CORE(action_on ? "l 10;\n" : "l 1;\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Backup button value. */
|
|
|
|
last_bv = bv;
|
|
|
|
|
|
|
|
/* GUI has to be updated. */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Emulate timer for widgets which use time-out. */
|
|
|
|
bool pd_gui_apply_timeouts(struct pd_widget* wg, unsigned int widgets)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
bool result = false;
|
|
|
|
|
|
|
|
for(i = 0; i < widgets; wg++, i++)
|
|
|
|
{
|
|
|
|
if(wg->id == PD_BANG)
|
|
|
|
{
|
|
|
|
if(wg->timeout > 0)
|
|
|
|
{
|
|
|
|
/* Decrement timeout value. */
|
|
|
|
wg->timeout--;
|
|
|
|
|
|
|
|
/* If zero reached, clear value. */
|
|
|
|
if(wg->timeout == 0)
|
|
|
|
{
|
|
|
|
wg->value = 0;
|
|
|
|
result = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parse and apply message from the Pure Data core. */
|
|
|
|
void pd_gui_parse_message(struct datagram* dg,
|
|
|
|
struct pd_widget* wg,
|
|
|
|
unsigned int widgets)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
char* saveptr;
|
|
|
|
char* object = NULL;
|
|
|
|
char* argument = NULL;
|
|
|
|
float argvalue = 0;
|
|
|
|
|
|
|
|
object = strtok_r(dg->data, " ", &saveptr);
|
|
|
|
argument = strtok_r(NULL, " ;\n", &saveptr);
|
|
|
|
|
|
|
|
if(argument != NULL)
|
|
|
|
argvalue = atof(argument);
|
|
|
|
|
|
|
|
for(i = 0; i < widgets; wg++, i++)
|
|
|
|
{
|
|
|
|
if(strncmp(object, wg->name, strlen(wg->name)) == 0)
|
|
|
|
{
|
|
|
|
/* If object not a number, set boundaries. */
|
|
|
|
if(wg->id != PD_NUMBER)
|
|
|
|
{
|
|
|
|
if(argvalue > wg->max)
|
|
|
|
argvalue = wg->max;
|
|
|
|
else if(argvalue < wg->min)
|
|
|
|
argvalue = wg->min;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set value. */
|
|
|
|
if(wg->id == PD_BANG)
|
|
|
|
{
|
|
|
|
wg->value = 1;
|
|
|
|
wg->timeout = HZ / 10;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wg->value = argvalue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|