New skin tag: %if(<tag>, <operator>, <operand> [,option count]) which lets you do very simple logical comparissons on other tags.

<tag> is the tag to check against
<operator> is the comparisson to do, any one of... =, !=, >, >=, <, <=    (when comparring against a string tag like %ia only = and != work, and it is done NOT case sensitive)
<operand> is either another tag, a number, or text.
[option count] is an optinal number to use for the few tags which scale to the amount of options when used as a conditional (i.e %?pv<a|b|c|d> would have 4 options)

example: %?if(%pv, >=, 0)<Warning.. volume clipping|coool...>
That says "If the value from %pv (volume) is greater than or equal to 0 then display the warning line, otherwise the cool line."
%?if(%ia, =, %Ia)<same artist>   <= this artist and next artist are the same.

some tags might need a touch of tweaking to work better with this. experiment and have fun

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@27846 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Jonathan Gordon 2010-08-19 13:49:32 +00:00
parent b73d15e9c6
commit 74ec011bb8
6 changed files with 150 additions and 14 deletions

View file

@ -502,7 +502,39 @@ static int parse_setting_and_lang(struct skin_element *element,
token->value.i = i;
return 0;
}
static int parse_logical_if(struct skin_element *element,
struct wps_token *token,
struct wps_data *wps_data)
{
(void)wps_data;
char *op = element->params[1].data.text;
struct logical_if *lif = skin_buffer_alloc(sizeof(struct logical_if));
if (!lif)
return -1;
token->value.data = lif;
lif->token = element->params[0].data.code->data;
if (!strcmp(op, "="))
lif->op = IF_EQUALS;
if (!strcmp(op, "!="))
lif->op = IF_NOTEQUALS;
if (!strcmp(op, "<"))
lif->op = IF_LESSTHAN;
if (!strcmp(op, "<="))
lif->op = IF_LESSTHAN_EQ;
if (!strcmp(op, ">"))
lif->op = IF_GREATERTHAN;
if (!strcmp(op, ">="))
lif->op = IF_GREATERTHAN_EQ;
memcpy(&lif->operand, &element->params[2], sizeof(lif->operand));
if (element->params_count > 3)
lif->num_options = element->params[3].data.number;
else
lif->num_options = TOKEN_VALUE_ONLY;
return 0;
}
static int parse_timeout_tag(struct skin_element *element,
struct wps_token *token,
struct wps_data *wps_data)
@ -1298,6 +1330,9 @@ static int skin_element_callback(struct skin_element* element, void* data)
case SKIN_TOKEN_ALIGN_LANGDIRECTION:
follow_lang_direction = 2;
break;
case SKIN_TOKEN_LOGICAL_IF:
function = parse_logical_if;
break;
case SKIN_TOKEN_PROGRESSBAR:
case SKIN_TOKEN_VOLUME:
case SKIN_TOKEN_BATTERY_PERCENT:

View file

@ -315,6 +315,8 @@ const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
if (intval)
{
if (limit == TOKEN_VALUE_ONLY)
limit = 100; /* make it a percentage */
*intval = limit * elapsed / length + 1;
}
snprintf(buf, buf_size, "%lu", 100 * elapsed / length);
@ -619,6 +621,72 @@ const char *get_token_value(struct gui_wps *gwps,
switch (token->type)
{
case SKIN_TOKEN_LOGICAL_IF:
{
struct logical_if *lif = token->value.data;
int a = lif->num_options;
int b;
out_text = get_token_value(gwps, lif->token, offset, buf, buf_size, &a);
if (a == -1 && lif->token->type != SKIN_TOKEN_VOLUME)
a = (out_text && *out_text) ? 1 : 0;
switch (lif->operand.type)
{
case STRING:
if (lif->op == IF_EQUALS)
return strcmp(out_text, lif->operand.data.text) == 0 ?
"eq" : NULL;
else
return NULL;
break;
case INTEGER:
case DECIMAL:
b = lif->operand.data.number;
break;
case CODE:
{
char temp_buf[MAX_PATH];
const char *outb;
struct wps_token *token = lif->operand.data.code->data;
b = lif->num_options;
outb = get_token_value(gwps, token, offset, temp_buf,
sizeof(temp_buf), &b);
if (b == -1 && lif->token->type != SKIN_TOKEN_VOLUME)
{
if (!out_text || !outb)
return (lif->op == IF_EQUALS) ? NULL : "neq";
bool equal = strcmp(out_text, outb) == 0;
if (lif->op == IF_EQUALS)
return equal ? "eq" : NULL;
else if (lif->op == IF_NOTEQUALS)
return !equal ? "neq" : NULL;
else
b = (outb && *outb) ? 1 : 0;
}
}
break;
case DEFAULT:
break;
}
switch (lif->op)
{
case IF_EQUALS:
return a == b ? "eq" : NULL;
case IF_NOTEQUALS:
return a != b ? "neq" : NULL;
case IF_LESSTHAN:
return a < b ? "lt" : NULL;
case IF_LESSTHAN_EQ:
return a <= b ? "lte" : NULL;
case IF_GREATERTHAN:
return a > b ? "gt" : NULL;
case IF_GREATERTHAN_EQ:
return a >= b ? "gte" : NULL;
}
return NULL;
}
break;
case SKIN_TOKEN_CHARACTER:
if (token->value.c == '\n')
return NULL;
@ -632,6 +700,8 @@ const char *get_token_value(struct gui_wps *gwps,
case SKIN_TOKEN_PLAYLIST_ENTRIES:
snprintf(buf, buf_size, "%d", playlist_amount());
if (intval)
*intval = playlist_amount();
return buf;
case SKIN_TOKEN_LIST_TITLE_TEXT:
@ -647,6 +717,8 @@ const char *get_token_value(struct gui_wps *gwps,
case SKIN_TOKEN_PLAYLIST_POSITION:
snprintf(buf, buf_size, "%d", playlist_get_display_index()+offset);
if (intval)
*intval = playlist_get_display_index()+offset;
return buf;
case SKIN_TOKEN_PLAYLIST_SHUFFLE:
@ -661,7 +733,11 @@ const char *get_token_value(struct gui_wps *gwps,
if (intval)
{
int minvol = sound_min(SOUND_VOLUME);
if (global_settings.volume == minvol)
if (limit == TOKEN_VALUE_ONLY)
{
*intval = global_settings.volume;
}
else if (global_settings.volume == minvol)
{
*intval = 1;
}
@ -705,14 +781,21 @@ const char *get_token_value(struct gui_wps *gwps,
if (intval)
{
limit = MAX(limit, 3);
if (l > -1) {
/* First enum is used for "unknown level",
* last enum is used for 100%.
*/
*intval = (limit - 2) * l / 100 + 2;
} else {
*intval = 1;
if (limit == TOKEN_VALUE_ONLY)
{
*intval = l;
}
else
{
limit = MAX(limit, 3);
if (l > -1) {
/* First enum is used for "unknown level",
* last enum is used for 100%.
*/
*intval = (limit - 2) * l / 100 + 2;
} else {
*intval = 1;
}
}
}

View file

@ -50,7 +50,7 @@
#define WPS_ALIGN_LEFT 128
#define TOKEN_VALUE_ONLY 0xDEADD0D0
#define TOKEN_VALUE_ONLY 0x0DEADC0D
#ifdef HAVE_ALBUMART
@ -223,7 +223,7 @@ struct skin_albumart {
int draw_handle;
};
#endif
struct line {
int timeout; /* if inside a line alternator */
@ -240,6 +240,19 @@ struct conditional {
struct wps_token *token;
};
struct logical_if {
struct wps_token *token;
enum {
IF_EQUALS, /* == */
IF_NOTEQUALS, /* != */
IF_LESSTHAN, /* < */
IF_LESSTHAN_EQ, /* <= */
IF_GREATERTHAN, /* > */
IF_GREATERTHAN_EQ /* >= */
} op;
struct skin_tag_parameter operand;
int num_options;
};
/* wps_data
this struct holds all necessary data which describes the

View file

@ -621,11 +621,13 @@ static int skin_parse_tag(struct skin_element* element, const char** document)
}
temp_params[j] = '\0';
j = 0;
while (cursor[j] != ',' && cursor[j] != ')')
while (cursor[j] && cursor[j] != ',' && cursor[j] != ')')
{
haspercent = haspercent || (cursor[j] == '%');
hasdecimal = hasdecimal || (cursor[j] == '.');
number = number && (isdigit(cursor[j]) || (cursor[j] == '.'));
number = number && (isdigit(cursor[j]) ||
(cursor[j] == '.') ||
(cursor[j] == '-'));
j++;
}
type_code = '*';

View file

@ -33,6 +33,8 @@ static const struct tag_info legal_tags[] =
{ SKIN_TOKEN_ALIGN_RIGHT_RTL, "aR", "", 0 },
{ SKIN_TOKEN_ALIGN_LANGDIRECTION, "ax", "", 0 },
{ SKIN_TOKEN_LOGICAL_IF, "if", "TS[ITS]|D", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_BATTERY_PERCENT, "bl" , BAR_PARAMS, SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_BATTERY_VOLTS, "bv", "", SKIN_REFRESH_DYNAMIC },
{ SKIN_TOKEN_BATTERY_TIME, "bt", "", SKIN_REFRESH_DYNAMIC },

View file

@ -73,6 +73,7 @@ enum skin_token_type {
SKIN_TOKEN_SUBLINE_SCROLL,
/* Conditional */
SKIN_TOKEN_LOGICAL_IF,
SKIN_TOKEN_CONDITIONAL,
SKIN_TOKEN_CONDITIONAL_START,
SKIN_TOKEN_CONDITIONAL_OPTION,