summaryrefslogtreecommitdiffstats
path: root/apps/gui
diff options
context:
space:
mode:
Diffstat (limited to 'apps/gui')
-rw-r--r--apps/gui/bitmap/list.c206
-rw-r--r--apps/gui/folder_select.c429
-rw-r--r--apps/gui/list.c9
-rw-r--r--apps/gui/list.h30
-rw-r--r--apps/gui/option_select.c62
-rw-r--r--apps/gui/option_select.h9
-rw-r--r--apps/gui/pitchscreen.c1055
-rw-r--r--apps/gui/quickscreen.c52
-rw-r--r--apps/gui/skin_engine/skin_engine.c3
-rw-r--r--apps/gui/skin_engine/skin_parser.c4
-rw-r--r--apps/gui/skin_engine/skin_tokens.c4
-rw-r--r--apps/gui/statusbar.c12
-rw-r--r--apps/gui/statusbar.h3
-rw-r--r--apps/gui/wps.c4
14 files changed, 544 insertions, 1338 deletions
diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c
index ff0f5a29c1..1b051cd800 100644
--- a/apps/gui/bitmap/list.c
+++ b/apps/gui/bitmap/list.c
@@ -90,11 +90,57 @@ static int list_icon_width(enum screen_type screen)
return get_icon_width(screen) + ICON_PADDING * 2;
}
-static bool draw_title(struct screen *display, struct gui_synclist *list)
+static void _default_listdraw_fn(struct list_putlineinfo_t *list_info)
+{
+ struct screen *display = list_info->display;
+ int x = list_info->x;
+ int y = list_info->y;
+ int item_indent = list_info->item_indent;
+ int item_offset = list_info->item_offset;
+ int icon = list_info->icon;
+ bool is_selected = list_info->is_selected;
+ bool is_title = list_info->is_title;
+ bool show_cursor = list_info->show_cursor;
+ bool have_icons = list_info->have_icons;
+ struct line_desc *linedes = list_info->linedes;
+ char *dsp_text = list_info->dsp_text;
+
+ if (is_title)
+ {
+ if (have_icons)
+ display->put_line(x, y, linedes, "$"ICON_PADDING_S"I$t",
+ icon, dsp_text);
+ else
+ display->put_line(x, y, linedes, "$t", dsp_text);
+ }
+ else if (show_cursor && have_icons)
+ {
+ /* the list can have both, one of or neither of cursor and item icons,
+ * if both don't apply icon padding twice between the icons */
+ display->put_line(x, y,
+ linedes, "$*s$"ICON_PADDING_S"I$i$"ICON_PADDING_S"s$*t",
+ item_indent, is_selected ? Icon_Cursor : Icon_NOICON,
+ icon, item_offset, dsp_text);
+ }
+ else if (show_cursor || have_icons)
+ {
+ display->put_line(x, y, linedes, "$*s$"ICON_PADDING_S"I$*t", item_indent,
+ show_cursor ? (is_selected ? Icon_Cursor:Icon_NOICON):icon,
+ item_offset, dsp_text);
+ }
+ else
+ {
+ display->put_line(x, y, linedes, "$*s$*t", item_indent, item_offset, dsp_text);
+ }
+}
+
+static bool draw_title(struct screen *display,
+ struct gui_synclist *list,
+ list_draw_item *callback_draw_item)
{
const int screen = display->screen_type;
struct viewport *title_text_vp = &title_text[screen];
- struct line_desc line = LINE_DESC_DEFINIT;
+ struct line_desc linedes = LINE_DESC_DEFINIT;
if (sb_set_title_text(list->title, list->title_icon, screen))
return false; /* the sbs is handling the title */
@@ -102,29 +148,39 @@ static bool draw_title(struct screen *display, struct gui_synclist *list)
if (!list_display_title(list, screen))
return false;
*title_text_vp = *(list->parent[screen]);
- line.height = list->line_height[screen];
- title_text_vp->height = line.height;
+ linedes.height = list->line_height[screen];
+ title_text_vp->height = linedes.height;
#if LCD_DEPTH > 1
/* XXX: Do we want to support the separator on remote displays? */
if (display->screen_type == SCREEN_MAIN && global_settings.list_separator_height != 0)
- line.separator_height = abs(global_settings.list_separator_height)
+ linedes.separator_height = abs(global_settings.list_separator_height)
+ (lcd_get_dpi() > 200 ? 2 : 1);
#endif
#ifdef HAVE_LCD_COLOR
if (list->title_color >= 0)
- line.style |= (STYLE_COLORED|list->title_color);
+ linedes.style |= (STYLE_COLORED|list->title_color);
#endif
- line.scroll = true;
+ linedes.scroll = true;
display->set_viewport(title_text_vp);
+ int icon = list->title_icon;
+ int icon_w = list_icon_width(display->screen_type);
+ bool have_icons = false;
+ if (icon != Icon_NOICON && global_settings.show_icons)
+ have_icons = true;
- if (list->title_icon != Icon_NOICON && global_settings.show_icons)
- put_line(display, 0, 0, &line, "$"ICON_PADDING_S"I$t",
- list->title_icon, list->title);
- else
- put_line(display, 0, 0, &line, "$t", list->title);
+ struct list_putlineinfo_t list_info =
+ {
+ .x = 0, .y = 0, .item_indent = 0, .item_offset = 0,
+ .line = -1, .icon = icon, .icon_width = icon_w,
+ .display = display, .vp = title_text_vp, .linedes = &linedes, .list = list,
+ .dsp_text = list->title,
+ .is_selected = false, .is_title = true, .show_cursor = false,
+ .have_icons = have_icons
+ };
+ callback_draw_item(&list_info);
return true;
}
@@ -133,6 +189,8 @@ void list_draw(struct screen *display, struct gui_synclist *list)
{
int start, end, item_offset, i;
const int screen = display->screen_type;
+ list_draw_item *callback_draw_item;
+
const int list_start_item = list->start_item[screen];
const bool scrollbar_in_left = (global_settings.scrollbar == SCROLLBAR_LEFT);
const bool scrollbar_in_right = (global_settings.scrollbar == SCROLLBAR_RIGHT);
@@ -145,11 +203,16 @@ void list_draw(struct screen *display, struct gui_synclist *list)
struct viewport *list_text_vp = &list_text[screen];
int indent = 0;
+ if (list->callback_draw_item != NULL)
+ callback_draw_item = list->callback_draw_item;
+ else
+ callback_draw_item = _default_listdraw_fn;
+
struct viewport * last_vp = display->set_viewport(parent);
display->clear_viewport();
display->scroll_stop_viewport(list_text_vp);
*list_text_vp = *parent;
- if ((show_title = draw_title(display, list)))
+ if ((show_title = draw_title(display, list, callback_draw_item)))
{
int title_height = title_text[screen].height;
list_text_vp->y += title_height;
@@ -169,6 +232,12 @@ void list_draw(struct screen *display, struct gui_synclist *list)
end = start + nb_lines;
#ifdef HAVE_TOUCHSCREEN
+ /* y_pos needs to be clamped now since it can overflow the maximum
+ * in some cases, and we have no easy way to prevent this beforehand */
+ int max_y_pos = list->nb_items * linedes.height - list_text[screen].height;
+ if (max_y_pos > 0 && list->y_pos > max_y_pos)
+ list->y_pos = max_y_pos;
+
int draw_offset = list_start_item * linedes.height - list->y_pos;
/* draw some extra items to not have empty lines at the top and bottom */
if (draw_offset > 0)
@@ -179,8 +248,17 @@ void list_draw(struct screen *display, struct gui_synclist *list)
if (start > 0)
start--;
}
- else if (draw_offset < 0)
- end++;
+ else if (draw_offset < 0) {
+ if(end < list->nb_items)
+ end++;
+ }
+
+ /* If the viewport is not an exact multiple of the line height, then
+ * there will be space for one more partial line. */
+ int spare_space = list_text_vp->height - linedes.height * nb_lines;
+ if(nb_lines < list->nb_items && spare_space > 0 && end < list->nb_items)
+ if(end < list->nb_items)
+ end++;
#else
#define draw_offset 0
#endif
@@ -193,17 +271,32 @@ void list_draw(struct screen *display, struct gui_synclist *list)
{
struct viewport vp = *list_text_vp;
vp.width = SCROLLBAR_WIDTH;
+#ifndef HAVE_TOUCHSCREEN
+ /* touchscreens must use full viewport height
+ * due to pixelwise rendering */
vp.height = linedes.height * nb_lines;
+#endif
list_text_vp->width -= SCROLLBAR_WIDTH;
if (scrollbar_in_right)
vp.x += list_text_vp->width;
else /* left */
list_text_vp->x += SCROLLBAR_WIDTH;
struct viewport *last = display->set_viewport(&vp);
+
+#ifndef HAVE_TOUCHSCREEN
+ /* button targets go itemwise */
+ int scrollbar_items = list->nb_items;
+ int scrollbar_min = list_start_item;
+ int scrollbar_max = list_start_item + nb_lines;
+#else
+ /* touchscreens use pixelwise scrolling */
+ int scrollbar_items = list->nb_items * linedes.height;
+ int scrollbar_min = list->y_pos;
+ int scrollbar_max = list->y_pos + list_text_vp->height;
+#endif
gui_scrollbar_draw(display,
(scrollbar_in_left? 0: 1), 0, SCROLLBAR_WIDTH-1, vp.height,
- list->nb_items, list_start_item, list_start_item + nb_lines,
- VERTICAL);
+ scrollbar_items, scrollbar_min, scrollbar_max, VERTICAL);
display->set_viewport(last);
}
/* shift everything a bit in relation to the title */
@@ -214,6 +307,16 @@ void list_draw(struct screen *display, struct gui_synclist *list)
}
display->set_viewport(list_text_vp);
+ int icon_w = list_icon_width(screen);
+ int character_width = display->getcharwidth();
+
+ struct list_putlineinfo_t list_info =
+ {
+ .x = 0, .y = 0, .vp = list_text_vp, .list = list,
+ .icon_width = icon_w, .is_title = false, .show_cursor = show_cursor,
+ .have_icons = have_icons, .linedes = &linedes, .display = display
+ };
+
for (i=start; i<end && i<list->nb_items; i++)
{
/* do the text */
@@ -221,7 +324,7 @@ void list_draw(struct screen *display, struct gui_synclist *list)
unsigned const char *s;
char entry_buffer[MAX_PATH];
unsigned char *entry_name;
- int text_pos = 0;
+ const int text_pos = 0; /* UNUSED */
int line = i - start;
int line_indent = 0;
int style = STYLE_DEFAULT;
@@ -238,9 +341,9 @@ void list_draw(struct screen *display, struct gui_synclist *list)
if (line_indent)
{
if (global_settings.show_icons)
- line_indent *= list_icon_width(screen);
+ line_indent *= icon_w;
else
- line_indent *= display->getcharwidth();
+ line_indent *= character_width;
}
line_indent += indent;
@@ -315,27 +418,22 @@ void list_draw(struct screen *display, struct gui_synclist *list)
}
}
#endif
-
linedes.style = style;
linedes.scroll = is_selected ? true : list->scroll_all;
linedes.line = i % list->selected_size;
icon = list->callback_get_item_icon ?
list->callback_get_item_icon(i, list->data) : Icon_NOICON;
- /* the list can have both, one of or neither of cursor and item icons,
- * if both don't apply icon padding twice between the icons */
- if (show_cursor && have_icons)
- put_line(display, 0, line * linedes.height + draw_offset,
- &linedes, "$*s$"ICON_PADDING_S"I$i$"ICON_PADDING_S"s$*t",
- line_indent, is_selected ? Icon_Cursor : Icon_NOICON,
- icon, item_offset, entry_name);
- else if (show_cursor || have_icons)
- put_line(display, 0, line * linedes.height + draw_offset,
- &linedes, "$*s$"ICON_PADDING_S"I$*t", line_indent,
- show_cursor ? (is_selected ? Icon_Cursor:Icon_NOICON):icon,
- item_offset, entry_name);
- else
- put_line(display, 0, line * linedes.height + draw_offset,
- &linedes, "$*s$*t", line_indent, item_offset, entry_name);
+
+
+ list_info.y = line * linedes.height + draw_offset;
+ list_info.is_selected = is_selected;
+ list_info.item_indent = line_indent;
+ list_info.line = i;
+ list_info.icon = icon;
+ list_info.dsp_text = entry_name;
+ list_info.item_offset = item_offset;
+
+ callback_draw_item(&list_info);
}
display->set_viewport(parent);
display->update_viewport();
@@ -360,21 +458,28 @@ static int scrollbar_scroll(struct gui_synclist * gui_list, int y)
const int screen = screens[SCREEN_MAIN].screen_type;
const int nb_lines = list_get_nb_lines(gui_list, screen);
- if (nb_lines < gui_list->nb_items)
+ if (nb_lines < gui_list->nb_items)
{
- /* scrollbar scrolling is still line based */
- int scrollbar_size = nb_lines * gui_list->line_height[screen];
- int actual_y = y - list_text[screen].y;
- int new_selection = (actual_y * gui_list->nb_items) / scrollbar_size;
+ const int line_height = gui_list->line_height[screen];
- int start_item = new_selection - nb_lines/2;
- if(start_item < 0)
- start_item = 0;
- else if(start_item > gui_list->nb_items - nb_lines)
- start_item = gui_list->nb_items - nb_lines;
+ /* try to position the center of the scrollbar at the touch point */
+ int scrollbar_size = list_text[screen].height;
+ int actual_y = y - list_text[screen].y;
+ int new_y_pos = (actual_y * gui_list->nb_items * line_height) / scrollbar_size;
+ int new_start = (actual_y * gui_list->nb_items) / scrollbar_size;
+
+ new_start -= nb_lines / 2;
+ new_y_pos -= (nb_lines * line_height) / 2;
+ if(new_start < 0) {
+ new_start = 0;
+ new_y_pos = 0;
+ } else if(new_start > gui_list->nb_items - nb_lines) {
+ new_start = gui_list->nb_items - nb_lines;
+ new_y_pos = new_start * line_height;
+ }
- gui_list->start_item[screen] = start_item;
- gui_list->y_pos = start_item * gui_list->line_height[screen];
+ gui_list->start_item[screen] = new_start;
+ gui_list->y_pos = new_y_pos;
return ACTION_REDRAW;
}
@@ -509,6 +614,7 @@ static bool swipe_scroll(struct gui_synclist * gui_list, int difference)
const int old_start = gui_list->start_item[screen];
int new_start_item = -1;
int line_diff = 0;
+ int max_y_pos = gui_list->nb_items * line_height - list_text[screen].height;
/* Track whether we hit the end of the list for sake of kinetic scroll */
bool hit_end = true;
@@ -517,8 +623,8 @@ static bool swipe_scroll(struct gui_synclist * gui_list, int difference)
gui_list->y_pos -= difference;
if(gui_list->y_pos < 0)
gui_list->y_pos = 0;
- else if(gui_list->y_pos > (gui_list->nb_items - nb_lines) * line_height)
- gui_list->y_pos = (gui_list->nb_items - nb_lines) * line_height;
+ else if(gui_list->y_pos > max_y_pos)
+ gui_list->y_pos = max_y_pos;
else
hit_end = false;
diff --git a/apps/gui/folder_select.c b/apps/gui/folder_select.c
index 706b166941..e324e8649a 100644
--- a/apps/gui/folder_select.c
+++ b/apps/gui/folder_select.c
@@ -8,6 +8,7 @@
*
* Copyright (C) 2012 Jonathan Gordon
* Copyright (C) 2012 Thomas Martitz
+* * Copyright (C) 2021 William Wilgus
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -30,7 +31,11 @@
#include "language.h"
#include "list.h"
#include "plugin.h"
+#include "splash.h"
+/* Define LOGF_ENABLE to enable logf output in this file */
+//#define LOGF_ENABLE
+#include "logf.h"
/*
* Order for changing child states:
@@ -56,18 +61,31 @@ struct child {
struct folder {
char *name;
struct child *children;
- int children_count;
- int depth;
-
struct folder* previous;
+ uint16_t children_count;
+ uint16_t depth;
};
static char *buffer_front, *buffer_end;
+
+static struct
+{
+ int32_t len; /* keeps count versus maxlen to give buffer full notification */
+ uint32_t val; /* hash of all selected items */
+ char buf[3];/* address used as identifier -- only \0 written to it */
+ char maxlen_exceeded; /*0,1*/
+} hashed;
+
+static inline void get_hash(const char *key, uint32_t *hash, int len)
+{
+ *hash = crc_32(key, len, *hash);
+}
+
static char* folder_alloc(size_t size)
{
char* retval;
/* 32-bit aligned */
- size = (size + 3) & ~3;
+ size = ALIGN_UP(size, 4);
if (buffer_front + size > buffer_end)
{
return NULL;
@@ -86,32 +104,57 @@ static char* folder_alloc_from_end(size_t size)
buffer_end -= size;
return buffer_end;
}
-
-static void get_full_path_r(struct folder *start, char* dst)
+#if 0
+/* returns the buffer size required to store the path + \0 */
+static int get_full_pathsz(struct folder *start)
{
- if (start->previous)
- get_full_path_r(start->previous, dst);
-
- if (start->name && start->name[0] && strcmp(start->name, "/"))
+ int reql = 0;
+ struct folder *next = start;
+ do
{
- strlcat(dst, "/", MAX_PATH);
- strlcat(dst, start->name, MAX_PATH);
- }
+ reql += strlen(next->name) + 1;
+ } while ((next = next->previous));
+
+ if (start->name[0] != '/') reql--;
+ if (--reql < 0) reql = 0;
+ return reql;
}
+#endif
-static char* get_full_path(struct folder *start)
+static size_t get_full_path(struct folder *start, char *dst, size_t dst_sz)
{
- static char buffer[MAX_PATH];
-
- if (strcmp(start->name, "/"))
+ size_t pos = 0;
+ struct folder *prev, *cur = NULL, *next = start;
+ dst[0] = '\0'; /* for strlcat to do its thing */
+ /* First traversal R->L mutate nodes->previous to point at child */
+ while (next->previous != NULL) /* stop at the root */
{
- buffer[0] = 0;
- get_full_path_r(start, buffer);
+#define PATHMUTATE() \
+ ({ \
+ prev = cur; \
+ cur = next; \
+ next = cur->previous;\
+ cur->previous = prev; \
+ })
+ PATHMUTATE();
}
- else /* get_full_path_r() does the wrong thing for / */
- return "/";
-
- return buffer;
+ /*swap the next and cur nodes to reverse direction */
+ prev = next;
+ next = cur;
+ cur = prev;
+ /* Second traversal L->R mutate nodes->previous to point back at parent
+ * copy strings to buf as they go by */
+ while (next != NULL)
+ {
+ PATHMUTATE();
+ pos = strlcat(dst, cur->name, dst_sz);
+ /* do not append slash to paths starting with slash */
+ if (cur->name[0] != '/')
+ pos = strlcat(dst, "/", dst_sz);
+ }
+ logf("get_full_path: (%d)[%s]", (int)pos, dst);
+ return pos;
+#undef PATHMUTATE
}
/* support function for qsort() */
@@ -125,49 +168,52 @@ static int compare(const void* p1, const void* p2)
static struct folder* load_folder(struct folder* parent, char *folder)
{
DIR *dir;
- char* path = get_full_path(parent);
char fullpath[MAX_PATH];
+
struct dirent *entry;
- struct folder* this = (struct folder*)folder_alloc(sizeof(struct folder));
int child_count = 0;
char *first_child = NULL;
+ size_t len = 0;
- if (!strcmp(folder,"/"))
- strlcpy(fullpath, folder, 2);
- else
- snprintf(fullpath, MAX_PATH, "%s/%s", parent ? path : "", folder);
+ struct folder* this = (struct folder*)folder_alloc(sizeof(struct folder));
+ if (this == NULL)
+ goto fail;
+
+ if (parent)
+ {
+ len = get_full_path(parent, fullpath, sizeof(fullpath));
+ if (len >= sizeof(fullpath))
+ goto fail;
+ }
+ strlcpy(&fullpath[len], folder, sizeof(fullpath) - len);
+ logf("load_folder: [%s]", fullpath);
- if (!this)
- return NULL;
dir = opendir(fullpath);
- if (!dir)
- return NULL;
+ if (dir == NULL)
+ goto fail;
this->previous = parent;
this->name = folder;
this->children = NULL;
this->children_count = 0;
- this->depth = parent ? parent->depth + 1 : 0;
+ if (parent)
+ this->depth = parent->depth + 1;
while ((entry = readdir(dir))) {
- int len = strlen((char *)entry->d_name);
- struct dirinfo info;
-
- info = dir_get_info(dir, entry);
-
/* skip anything not a directory */
- if ((info.attribute & ATTR_DIRECTORY) == 0) {
+ if ((dir_get_info(dir, entry).attribute & ATTR_DIRECTORY) == 0) {
continue;
}
- /* skip directories . and .. */
- if ((!strcmp((char *)entry->d_name, ".")) ||
- (!strcmp((char *)entry->d_name, ".."))) {
+ /* skip . and .. */
+ char *dn = entry->d_name;
+ if ((dn[0] == '.') && (dn[1] == '\0' || (dn[1] == '.' && dn[2] == '\0')))
continue;
- }
- char *name = folder_alloc_from_end(len+1);
- if (!name)
+ /* copy entry name to end of buffer, save pointer */
+ int len = strlen((char *)entry->d_name);
+ char *name = folder_alloc_from_end(len+1); /*for NULL*/
+ if (name == NULL)
{
closedir(dir);
- return NULL;
+ goto fail;
}
memcpy(name, (char *)entry->d_name, len+1);
child_count++;
@@ -177,26 +223,29 @@ static struct folder* load_folder(struct folder* parent, char *folder)
/* now put the names in the array */
this->children = (struct child*)folder_alloc(sizeof(struct child) * child_count);
- if (!this->children)
- return NULL;
+ if (this->children == NULL)
+ goto fail;
+
while (child_count)
{
- this->children[this->children_count].name = first_child;
- this->children[this->children_count].folder = NULL;
- this->children[this->children_count].state = COLLAPSED;
- this->children_count++;
- first_child += strlen(first_child) + 1;
+ struct child *child = &this->children[this->children_count++];
+ child->name = first_child;
+ child->folder = NULL;
+ child->state = COLLAPSED;
+ while(*first_child++ != '\0'){};/* move to next name entry */
child_count--;
}
qsort(this->children, this->children_count, sizeof(struct child), compare);
return this;
+fail:
+ return NULL;
}
struct folder* load_root(void)
{
static struct child root_child;
-
+ /* reset the root for each call */
root_child.name = "/";
root_child.folder = NULL;
root_child.state = COLLAPSED;
@@ -205,7 +254,7 @@ struct folder* load_root(void)
.name = "",
.children = &root_child,
.children_count = 1,
- .depth = -1,
+ .depth = 0,
.previous = NULL,
};
@@ -230,7 +279,6 @@ static int count_items(struct folder *start)
static struct child* find_index(struct folder *start, int index, struct folder **parent)
{
int i = 0;
-
*parent = NULL;
while (i < start->children_count)
@@ -262,22 +310,22 @@ static const char * folder_get_name(int selected_item, void * data,
struct folder *parent;
struct child *this = find_index(root, selected_item , &parent);
- buffer[0] = '\0';
-
- if (parent->depth >= 0)
- for(int i = 0; i <= parent->depth; i++)
- strcat(buffer, "\t");
-
+ char *buf = buffer;
+ if ((int)buffer_len > parent->depth)
+ {
+ int i = parent->depth;
+ while(--i > 0) /* don't indent the parent /folders */
+ *buf++ = '\t';
+ }
+ *buf = '\0';
strlcat(buffer, this->name, buffer_len);
if (this->state == EACCESS)
{ /* append error message to the entry if unaccessible */
- size_t len = strlcat(buffer, " (", buffer_len);
+ size_t len = strlcat(buffer, " ( ", buffer_len);
if (buffer_len > len)
{
- snprintf(&buffer[len], buffer_len - len, str(LANG_READ_FAILED),
- this->name);
- strlcat(buffer, ")", buffer_len);
+ snprintf(&buffer[len], buffer_len - len, str(LANG_READ_FAILED), ")");
}
}
@@ -304,6 +352,23 @@ static enum themable_icons folder_get_icon(int selected_item, void * data)
return Icon_NOICON;
}
+static int child_set_state_expand(struct child *this, struct folder *parent)
+{
+ int newstate = EACCESS;
+ if (this->folder == NULL)
+ this->folder = load_folder(parent, this->name);
+
+ if (this->folder != NULL)
+ {
+ if(this->folder->children_count == 0)
+ newstate = SELECTED;
+ else
+ newstate = EXPANDED;
+ }
+ this->state = newstate;
+ return newstate;
+}
+
static int folder_action_callback(int action, struct gui_synclist *list)
{
struct folder *root = (struct folder*)list->data;
@@ -322,17 +387,13 @@ static int folder_action_callback(int action, struct gui_synclist *list)
this->state = COLLAPSED;
break;
case COLLAPSED:
- if (this->folder == NULL)
- this->folder = load_folder(parent, this->name);
- this->state = this->folder ? (this->folder->children_count == 0 ?
- SELECTED : EXPANDED) : EACCESS;
+ child_set_state_expand(this, parent);
break;
case EACCESS:
/* cannot open, do nothing */
return action;
}
- list->nb_items = count_items(root);
- return ACTION_REDRAW;
+ action = ACTION_REDRAW;
}
else if (action == ACTION_STD_CONTEXT)
{
@@ -342,140 +403,198 @@ static int folder_action_callback(int action, struct gui_synclist *list)
for (i = 0; i < this->folder->children_count; i++)
{
child = &this->folder->children[i];
- if (child->state == SELECTED ||
- child->state == EXPANDED)
- child->state = COLLAPSED;
- else if (child->state == COLLAPSED)
- child->state = SELECTED;
+ switch (child->state)
+ {
+ case SELECTED:
+ case EXPANDED:
+ child->state = COLLAPSED;
+ break;
+ case COLLAPSED:
+ child->state = SELECTED;
+ break;
+ case EACCESS:
+ break;
+ }
}
break;
case SELECTED:
case COLLAPSED:
- if (this->folder == NULL)
- this->folder = load_folder(parent, this->name);
- this->state = this->folder ? (this->folder->children_count == 0 ?
- SELECTED : EXPANDED) : EACCESS;
- if (this->state == EACCESS)
- break;
- for (i = 0; i < this->folder->children_count; i++)
+ if (child_set_state_expand(this, parent) != EACCESS)
{
- child = &this->folder->children[i];
- child->state = SELECTED;
+ for (i = 0; i < (this->folder->children_count); i++)
+ {
+ child = &this->folder->children[i];
+ child->state = SELECTED;
+ }
}
break;
case EACCESS:
/* cannot open, do nothing */
return action;
}
- list->nb_items = count_items(root);
- return ACTION_REDRAW;
+ action = ACTION_REDRAW;
}
-
-
+ if (action == ACTION_REDRAW)
+ list->nb_items = count_items(root);
return action;
}
-static struct child* find_from_filename(char* filename, struct folder *root)
+static struct child* find_from_filename(const char* filename, struct folder *root)
{
- char *slash = strchr(filename, '/');
- int i = 0;
- if (slash)
- *slash = '\0';
if (!root)
return NULL;
-
+ const char *slash = strchr(filename, '/');
struct child *this;
/* filenames beginning with a / are specially treated as the
* loop below can't handle them. they can only occur on the first,
* and not recursive, calls to this function.*/
- if (slash == filename)
+ if (filename[0] == '/') /* in the loop nothing starts with '/' */
{
+ logf("find_from_filename [%s]", filename);
/* filename begins with /. in this case root must be the
* top level folder */
this = &root->children[0];
- if (!slash[1])
+ if (filename[1] == '\0')
{ /* filename == "/" */
return this;
}
- else
- {
- /* filename == "/XXX/YYY". cascade down */
- if (!this->folder)
- this->folder = load_folder(root, this->name);
- this->state = EXPANDED;
- /* recurse with XXX/YYY */
- return find_from_filename(slash+1, this->folder);
- }
+ else /* filename == "/XXX/YYY". cascade down */
+ goto cascade;
}
- while (i < root->children_count)
+ for (int i = 0; i < root->children_count; i++)
{
this = &root->children[i];
- if (!strcasecmp(this->name, filename))
+ /* when slash == NULL n will be really large but \0 stops the compare */
+ if (strncasecmp(this->name, filename, slash - filename) == 0)
{
- if (!slash)
+ if (slash == NULL)
{ /* filename == XXX */
return this;
}
else
- {
- /* filename == XXX/YYY. cascade down */
- if (!this->folder)
- this->folder = load_folder(root, this->name);
- this->state = EXPANDED;
- return find_from_filename(slash+1, this->folder);
- }
+ goto cascade;
}
- i++;
}
return NULL;
+
+cascade:
+ /* filename == XXX/YYY. cascade down */
+ child_set_state_expand(this, root);
+ while (slash[0] == '/') slash++; /* eat slashes */
+ return find_from_filename(slash, this->folder);
}
-/* _modifies_ buf */
-int select_paths(struct folder* root, char* buf)
+static int select_paths(struct folder* root, const char* filenames)
{
- struct child *item = find_from_filename(buf, root);
- if (item)
- item->state = SELECTED;
+ /* Takes a list of filenames in a ':' delimited string
+ splits filenames at the ':' character loads each into buffer
+ selects each file in the folder list
+
+ if last item or only item the rest of the string is copied to the buffer
+ *End the last item WITHOUT the ':' character /.rockbox/eqs:/.rockbox/wps\0*
+ */
+ char buf[MAX_PATH];
+ const int buflen = sizeof(buf);
+
+ const char *fnp = filenames;
+ const char *lastfnp = fnp;
+ const char *sstr;
+ off_t len;
+
+ while (fnp)
+ {
+ fnp = strchr(fnp, ':');
+ if (fnp)
+ {
+ len = fnp - lastfnp;
+ fnp++;
+ }
+ else /* no ':' get the rest of the string */
+ len = strlen(lastfnp);
+
+ sstr = lastfnp;
+ lastfnp = fnp;
+ if (len <= 0 || len > buflen)
+ continue;
+ strlcpy(buf, sstr, len + 1);
+ struct child *item = find_from_filename(buf, root);
+ if (item)
+ item->state = SELECTED;
+ }
+
return 0;
}
-static void save_folders_r(struct folder *root, char* dst, size_t maxlen)
+static void save_folders_r(struct folder *root, char* dst, size_t maxlen, size_t buflen)
{
- int i = 0;
+ size_t len;
+ struct folder *curfolder;
+ char* name;
- while (i < root->children_count)
+ for (int i = 0; i < root->children_count; i++)
{
struct child *this = &root->children[i];
if (this->state == SELECTED)
{
- if (this->folder)
- snprintf(buffer_front, buffer_end - buffer_front,
- "%s:", get_full_path(this->folder));
+ if (this->folder == NULL)
+ {
+ curfolder = root;
+ name = this->name;
+ logf("save_folders_r: this->name[%s]", name);
+ }
+ else
+ {
+ curfolder = this->folder->previous;
+ name = this->folder->name;
+ logf("save_folders_r: this->folder->name[%s]", name);
+ }
+
+ len = get_full_path(curfolder, buffer_front, buflen);
+
+ if (len + 2 >= buflen)
+ continue;
+
+ len += snprintf(&buffer_front[len], buflen - len, "%s:", name);
+ logf("save_folders_r: [%s]", buffer_front);
+ if (dst != hashed.buf)
+ {
+ int dlen = strlen(dst);
+ if (dlen + len >= maxlen)
+ continue;
+ strlcpy(&dst[dlen], buffer_front, maxlen - dlen);
+ }
else
{
- char *p = get_full_path(root);
- snprintf(buffer_front, buffer_end - buffer_front,
- "%s/%s:", strcmp(p, "/") ? p : "",
- strcmp(this->name, "/") ? this->name : "");
+ if (hashed.len + len >= maxlen)
+ {
+ hashed.maxlen_exceeded = 1;
+ continue;
+ }
+ get_hash(buffer_front, &hashed.val, len);
+ hashed.len += len;
}
- strlcat(dst, buffer_front, maxlen);
}
else if (this->state == EXPANDED)
- save_folders_r(this->folder, dst, maxlen);
- i++;
+ save_folders_r(this->folder, dst, maxlen, buflen);
}
}
-static void save_folders(struct folder *root, char* dst, size_t maxlen)
+static uint32_t save_folders(struct folder *root, char* dst, size_t maxlen)
{
- int len;
+ hashed.len = 0;
+ hashed.val = 0;
+ hashed.maxlen_exceeded = 0;
+ size_t len = buffer_end - buffer_front;
dst[0] = '\0';
- save_folders_r(root, dst, maxlen);
+ save_folders_r(root, dst, maxlen, len);
len = strlen(dst);
/* fix trailing ':' */
if (len > 1) dst[len-1] = '\0';
+ /*Notify - user will probably not see save dialog if nothing new got added*/
+ if (hashed.maxlen_exceeded > 0) splash(HZ *2, ID2P(LANG_SHOWDIR_BUFFER_FULL));
+ return hashed.val;
}
bool folder_select(char* setting, int setting_len)
@@ -483,40 +602,32 @@ bool folder_select(char* setting, int setting_len)
struct folder *root;
struct simplelist_info info;
size_t buf_size;
- /* 32 separate folders should be Enough For Everybody(TM) */
- char *vect[32];
- char copy[setting_len];
- int nb_items;
-
- /* copy onto stack as split_string() modifies it */
- strlcpy(copy, setting, setting_len);
- nb_items = split_string(copy, ':', vect, ARRAYLEN(vect));
buffer_front = plugin_get_buffer(&buf_size);
buffer_end = buffer_front + buf_size;
+ logf("%d bytes free", (int)(buffer_end - buffer_front));
root = load_root();
- if (nb_items > 0)
- {
- for(int i = 0; i < nb_items; i++)
- select_paths(root, vect[i]);
- }
-
+ logf("folders in: %s", setting);
+ /* Load previous selection(s) */
+ select_paths(root, setting);
+ /* get current hash to check for changes later */
+ uint32_t hash = save_folders(root, hashed.buf, setting_len);
simplelist_info_init(&info, str(LANG_SELECT_FOLDER),
count_items(root), root);
info.get_name = folder_get_name;
info.action_callback = folder_action_callback;
info.get_icon = folder_get_icon;
simplelist_show_list(&info);
-
+ logf("%d bytes free", (int)(buffer_end - buffer_front));
/* done editing. check for changes */
- save_folders(root, copy, setting_len);
- if (strcmp(copy, setting))
- { /* prompt for saving changes and commit if yes */
+ if (hash != save_folders(root, hashed.buf, setting_len))
+ { /* prompt for saving changes and commit if yes */
if (yesno_pop(ID2P(LANG_SAVE_CHANGES)))
{
- strcpy(setting, copy);
+ save_folders(root, setting, setting_len);
settings_save();
+ logf("folders out: %s", setting);
return true;
}
}
diff --git a/apps/gui/list.c b/apps/gui/list.c
index 13a850bd7b..a8055c4581 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -150,6 +150,7 @@ void gui_synclist_init(struct gui_synclist * gui_list,
gui_list->callback_get_item_icon = NULL;
gui_list->callback_get_item_name = callback_get_item_name;
gui_list->callback_speak_item = NULL;
+ gui_list->callback_draw_item = NULL;
gui_list->nb_items = 0;
gui_list->selected_item = 0;
#ifdef HAVE_TOUCHSCREEN
@@ -686,7 +687,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
switch (wrap)
{
case LIST_WRAP_ON:
- gui_synclist_limit_scroll(lists, false);
+ gui_synclist_limit_scroll(lists, !global_settings.list_wraparound);
break;
case LIST_WRAP_OFF:
gui_synclist_limit_scroll(lists, true);
@@ -697,7 +698,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
action == ACTION_LISTTREE_PGUP ||
action == ACTION_LISTTREE_PGDOWN)
gui_synclist_limit_scroll(lists, true);
- else gui_synclist_limit_scroll(lists, false);
+ else gui_synclist_limit_scroll(lists, !global_settings.list_wraparound);
break;
};
@@ -754,7 +755,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
if (lists->offset_position[0] == 0)
{
pgleft_allow_cancel = true;
- *actionptr = ACTION_STD_CANCEL;
+ *actionptr = ACTION_STD_MENU;
return true;
}
*actionptr = ACTION_TREE_PGLEFT;
@@ -911,7 +912,7 @@ bool simplelist_show_list(struct simplelist_info *info)
struct gui_synclist lists;
int action, old_line_count = simplelist_line_count;
list_get_name *getname;
- int wrap = LIST_WRAP_UNLESS_HELD;
+ int wrap = global_settings.list_wraparound ? LIST_WRAP_UNLESS_HELD : LIST_WRAP_OFF;
if (info->get_name)
getname = info->get_name;
else
diff --git a/apps/gui/list.h b/apps/gui/list.h
index 64ff3e3fdd..1f910577a1 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -69,6 +69,35 @@ typedef enum themable_icons list_get_icon(int selected_item, void * data);
typedef const char * list_get_name(int selected_item, void * data,
char * buffer, size_t buffer_len);
/*
+ * Draw callback
+ * - display : functions supplied depends on the screen call originated from (typ: MAIN)
+ * - list_info : a pointer to an internal struct containing item display information
+ */
+/* owner drawn lists need to know this info */
+struct list_putlineinfo_t {
+ int x;
+ int y;
+ int item_indent;
+ int item_offset;
+ int line;
+
+ int icon;
+ int icon_width;
+
+ struct screen *display;
+ struct viewport *vp;
+ struct line_desc *linedes;
+ struct gui_synclist * list;
+ char *dsp_text;
+
+ bool is_selected;
+ bool is_title;
+ bool show_cursor;
+ bool have_icons;
+};
+
+typedef void list_draw_item(struct list_putlineinfo_t *list_info);
+/*
* Voice callback
* - selected_item : an integer that tells the number of the item to speak
* - data : a void pointer to the data you gave to the list when you
@@ -133,6 +162,7 @@ struct gui_synclist
list_get_icon *callback_get_item_icon;
list_get_name *callback_get_item_name;
list_speak_item *callback_speak_item;
+ list_draw_item *callback_draw_item;
/* The data that will be passed to the callback function YOU implement */
void * data;
diff --git a/apps/gui/option_select.c b/apps/gui/option_select.c
index 9f1f0a64e3..7068fee510 100644
--- a/apps/gui/option_select.c
+++ b/apps/gui/option_select.c
@@ -334,29 +334,35 @@ static int selection_to_val(const struct settings_list *setting, int selection)
else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
{
int setting_id = setting->sound_setting->setting;
-#ifndef ASCENDING_INT_SETTINGS
- step = sound_steps(setting_id);
- max = (setting_id == SOUND_VOLUME) ?
- global_settings.volume_limit : sound_max(setting_id);
- /* min = sound_min(setting_id); */
-#else
- step = -sound_steps(setting_id);
- /* min = sound_max(setting_id); */
- max = sound_min(setting_id);
-#endif
+ if(global_settings.list_order == LIST_ORDER_DESCENDING)
+ {
+ step = sound_steps(setting_id);
+ max = (setting_id == SOUND_VOLUME) ?
+ global_settings.volume_limit : sound_max(setting_id);
+ /* min = sound_min(setting_id); */
+ }
+ else
+ {
+ step = -sound_steps(setting_id);
+ /* min = sound_max(setting_id); */
+ max = sound_min(setting_id);
+ }
}
else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
{
const struct int_setting *info = setting->int_setting;
-#ifndef ASCENDING_INT_SETTINGS
- /* min = info->min; */
- max = info->max;
- step = info->step;
-#else
- max = info->min;
- /* min = info->max; */
- step = -info->step;
-#endif
+ if(global_settings.list_order == LIST_ORDER_DESCENDING)
+ {
+ /* min = info->min; */
+ max = info->max;
+ step = info->step;
+ }
+ else
+ {
+ max = info->min;
+ /* min = info->max; */
+ step = -info->step;
+ }
}
return max- (selection * step);
}
@@ -424,11 +430,10 @@ static void val_to_selection(const struct settings_list *setting, int oldvalue,
int max = (setting_id == SOUND_VOLUME) ?
global_settings.volume_limit : sound_max(setting_id);
*nb_items = (max-min)/steps + 1;
-#ifndef ASCENDING_INT_SETTINGS
- *selected = (max - oldvalue) / steps;
-#else
- *selected = (oldvalue - min) / steps;
-#endif
+ if (global_settings.list_order == LIST_ORDER_DESCENDING)
+ *selected = (max - oldvalue) / steps;
+ else
+ *selected = (oldvalue - min) / steps;
*function = sound_get_fn(setting_id);
}
else
@@ -439,11 +444,10 @@ static void val_to_selection(const struct settings_list *setting, int oldvalue,
min = info->min;
step = info->step;
*nb_items = (max-min)/step + 1;
-#ifndef ASCENDING_INT_SETTINGS
- *selected = (max - oldvalue) / step;
-#else
- *selected = (oldvalue - min) / step;
-#endif
+ if(global_settings.list_order == LIST_ORDER_DESCENDING)
+ *selected = (max - oldvalue) / step;
+ else
+ *selected = (oldvalue - min) / step;
*function = info->option_callback;
}
}
diff --git a/apps/gui/option_select.h b/apps/gui/option_select.h
index 476e7b81bd..104e86f64d 100644
--- a/apps/gui/option_select.h
+++ b/apps/gui/option_select.h
@@ -25,11 +25,10 @@
#include "screen_access.h"
#include "settings.h"
-#if defined (HAVE_SCROLLWHEEL) && !defined(FIIO_M3K)
-/* Define this if your target makes sense to have
- smaller values at the top of the list increasing down the list */
-#define ASCENDING_INT_SETTINGS
-#endif
+enum {
+ LIST_ORDER_DESCENDING = 0,
+ LIST_ORDER_ASCENDING = 1,
+};
bool option_screen(const struct settings_list *setting,
struct viewport parent[NB_SCREENS],
diff --git a/apps/gui/pitchscreen.c b/apps/gui/pitchscreen.c
index 871921a10f..9f42aedb5d 100644
--- a/apps/gui/pitchscreen.c
+++ b/apps/gui/pitchscreen.c
@@ -18,1059 +18,8 @@
* KIND, either express or implied.
*
****************************************************************************/
-
-#include <stdbool.h>
-#include <string.h>
-#include <stdio.h>
-#include <math.h>
-#include <stdlib.h> /* for abs() */
-#include "config.h"
-#include "action.h"
-#include "sound.h"
-#include "pcmbuf.h"
-#include "lang.h"
-#include "icons.h"
-#include "screens.h"
-#include "talk.h"
-#include "viewport.h"
-#include "font.h"
-#include "system.h"
-#include "misc.h"
-#include "pitchscreen.h"
-#include "settings.h"
-#include "tdspeed.h"
-
-#define ICON_BORDER 12 /* icons are currently 7x8, so add ~2 pixels */
- /* on both sides when drawing */
-
-#define PITCH_MAX (200 * PITCH_SPEED_PRECISION)
-#define PITCH_MIN (50 * PITCH_SPEED_PRECISION)
-#define PITCH_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* .1% */
-#define PITCH_BIG_DELTA (PITCH_SPEED_PRECISION) /* 1% */
-#define PITCH_NUDGE_DELTA (2 * PITCH_SPEED_PRECISION) /* 2% */
-
-#define SPEED_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* .1% */
-#define SPEED_BIG_DELTA (PITCH_SPEED_PRECISION) /* 1% */
-
-#define SEMITONE_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* 10 cents */
-#define SEMITONE_BIG_DELTA PITCH_SPEED_PRECISION /* 1 semitone */
-
-enum
-{
- PITCH_TOP = 0,
- PITCH_MID,
- PITCH_BOTTOM,
- PITCH_ITEM_COUNT,
-};
-
-
-/* This is a table of semitone percentage values of the appropriate
- precision (based on PITCH_SPEED_PRECISION). Note that these are
- all constant expressions, which will be evaluated at compile time,
- so no need to worry about how complex the expressions look.
- That's just to get the precision right.
-
- I calculated these values, starting from 50, as
-
- x(n) = 50 * 2^(n/12)
-
- All that math in each entry simply converts the float constant
- to an integer equal to PITCH_SPEED_PRECISION times the float value,
- with as little precision loss as possible (i.e. correctly rounding
- the last digit).
-*/
-#define TO_INT_WITH_PRECISION(x) \
- ( (unsigned short)(((x) * PITCH_SPEED_PRECISION * 10 + 5) / 10) )
-
-static const unsigned short semitone_table[] =
-{
- TO_INT_WITH_PRECISION(50.00000000), /* Octave lower */
- TO_INT_WITH_PRECISION(52.97315472),
- TO_INT_WITH_PRECISION(56.12310242),
- TO_INT_WITH_PRECISION(59.46035575),
- TO_INT_WITH_PRECISION(62.99605249),
- TO_INT_WITH_PRECISION(66.74199271),
- TO_INT_WITH_PRECISION(70.71067812),
- TO_INT_WITH_PRECISION(74.91535384),
- TO_INT_WITH_PRECISION(79.37005260),
- TO_INT_WITH_PRECISION(84.08964153),
- TO_INT_WITH_PRECISION(89.08987181),
- TO_INT_WITH_PRECISION(94.38743127),
- TO_INT_WITH_PRECISION(100.0000000), /* Normal sound */
- TO_INT_WITH_PRECISION(105.9463094),
- TO_INT_WITH_PRECISION(112.2462048),
- TO_INT_WITH_PRECISION(118.9207115),
- TO_INT_WITH_PRECISION(125.9921049),
- TO_INT_WITH_PRECISION(133.4839854),
- TO_INT_WITH_PRECISION(141.4213562),
- TO_INT_WITH_PRECISION(149.8307077),
- TO_INT_WITH_PRECISION(158.7401052),
- TO_INT_WITH_PRECISION(168.1792831),
- TO_INT_WITH_PRECISION(178.1797436),
- TO_INT_WITH_PRECISION(188.7748625),
- TO_INT_WITH_PRECISION(200.0000000) /* Octave higher */
-};
-
-#define NUM_SEMITONES ((int)(sizeof(semitone_table)/sizeof(semitone_table[0])))
-#define SEMITONE_END (NUM_SEMITONES/2)
-#define SEMITONE_START (-SEMITONE_END)
-
-/* A table of values for approximating the cent curve with
- linear interpolation. Multipy the next lowest semitone
- by this much to find the corresponding cent percentage.
-
- These values were calculated as
- x(n) = 100 * 2^(n * 20/1200)
-*/
-
-static const unsigned short cent_interp[] =
-{
- TO_INT_WITH_PRECISION(100.0000000),
- TO_INT_WITH_PRECISION(101.1619440),
- TO_INT_WITH_PRECISION(102.3373892),
- TO_INT_WITH_PRECISION(103.5264924),
- TO_INT_WITH_PRECISION(104.7294123),
- /* this one's the next semitone but we have it here for convenience */
- TO_INT_WITH_PRECISION(105.9463094),
-};
-
-/* Number of cents between entries in the cent_interp table */
-#define CENT_INTERP_INTERVAL 20
-#define CENT_INTERP_NUM ((int)(sizeof(cent_interp)/sizeof(cent_interp[0])))
-
-/* This stores whether the pitch and speed are at their own limits */
-/* or that of the timestretching algorithm */
-static bool at_limit = false;
-
-/*
- *
- * The pitchscreen is divided into 3 viewports (each row is a viewport)
- * Then each viewport is again divided into 3 colums, each showsing some infos
- * Additionally, on touchscreen, each cell represents a button
- *
- * Below a sketch describing what each cell will show (what's drawn on it)
- * --------------------------
- * | | | | <-- pitch up in the middle (text and button)
- * | | | | <-- arrows for mode toggling on the sides for touchscreen
- * |------------------------|
- * | | | | <-- semitone/speed up/down on the sides
- * | | | | <-- reset pitch&speed in the middle
- * |------------------------|
- * | | | | <-- pitch down in the middle
- * | | | | <-- Two "OK" for exit on the sides for touchscreen
- * |------------------------|
- *
- *
- */
-
-static void speak_pitch_mode(bool enqueue)
-{
- bool timestretch_mode = global_settings.pitch_mode_timestretch && dsp_timestretch_available();
- if (timestretch_mode)
- talk_id(VOICE_PITCH_TIMESTRETCH_MODE, enqueue);
- if (global_settings.pitch_mode_semitone)
- talk_id(VOICE_PITCH_SEMITONE_MODE, timestretch_mode ? true : enqueue);
- else
- talk_id(VOICE_PITCH_ABSOLUTE_MODE, timestretch_mode ? true : enqueue);
- return;
-}
-
-/*
- * Fixes the viewports so they represent the 3 rows, and adds a little margin
- * on all sides for the icons (which are drawn outside of the grid
- *
- * The modified viewports need to be passed to the touchscreen handling function
- **/
-static void pitchscreen_fix_viewports(struct viewport *parent,
- struct viewport pitch_viewports[PITCH_ITEM_COUNT])
-{
- int i, font_height;
- font_height = font_get(parent->font)->height;
- for (i = 0; i < PITCH_ITEM_COUNT; i++)
- {
- pitch_viewports[i] = *parent;
- pitch_viewports[i].height = parent->height / PITCH_ITEM_COUNT;
- pitch_viewports[i].x += ICON_BORDER;
- pitch_viewports[i].width -= 2*ICON_BORDER;
- }
- pitch_viewports[PITCH_TOP].y += ICON_BORDER;
- pitch_viewports[PITCH_TOP].height -= ICON_BORDER;
-
- if(pitch_viewports[PITCH_MID].height < font_height * 2)
- pitch_viewports[PITCH_MID].height = font_height * 2;
-
- pitch_viewports[PITCH_MID].y = pitch_viewports[PITCH_TOP].y
- + pitch_viewports[PITCH_TOP].height;
-
- pitch_viewports[PITCH_BOTTOM].y = pitch_viewports[PITCH_MID].y
- + pitch_viewports[PITCH_MID].height;
-
- pitch_viewports[PITCH_BOTTOM].height -= ICON_BORDER;
-}
-
-/* must be called before pitchscreen_draw, or within
- * since it neither clears nor updates the display */
-static void pitchscreen_draw_icons(struct screen *display,
- struct viewport *parent)
-{
- display->set_viewport(parent);
- display->mono_bitmap(bitmap_icons_7x8[Icon_UpArrow],
- parent->width/2 - 3,
- 2, 7, 8);
- display->mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
- parent->width /2 - 3,
- parent->height - 10, 7, 8);
- display->mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
- parent->width - 10,
- parent->height /2 - 4, 7, 8);
- display->mono_bitmap(bitmap_icons_7x8[Icon_FastBackward],
- 2,
- parent->height /2 - 4, 7, 8);
- display->update_viewport();
-}
-
-static void pitchscreen_draw(struct screen *display, int max_lines,
- struct viewport pitch_viewports[PITCH_ITEM_COUNT],
- int32_t pitch, int32_t semitone
- ,int32_t speed
- )
-{
- const char* ptr;
- char buf[32];
- int w, h;
- bool show_lang_pitch;
- struct viewport *last_vp = NULL;
-
- /* "Pitch up/Pitch down" - hide for a small screen,
- * the text is drawn centered automatically
- *
- * note: this assumes 5 lines always fit on a touchscreen (should be
- * reasonable) */
- if (max_lines >= 5)
- {
- int w, h;
- struct viewport *vp = &pitch_viewports[PITCH_TOP];
- last_vp = display->set_viewport(vp);
- display->clear_viewport();
-#ifdef HAVE_TOUCHSCREEN
- /* two arrows in the top row, left and right column */
- char *arrows[] = { "<", ">"};
- display->getstringsize(arrows[0], &w, &h);
- display->putsxy(0, vp->height/2 - h/2, arrows[0]);
- display->putsxy(vp->width - w, vp->height/2 - h/2, arrows[1]);
-#endif
- /* UP: Pitch Up */
- if (global_settings.pitch_mode_semitone)
- ptr = str(LANG_PITCH_UP_SEMITONE);
- else
- ptr = str(LANG_PITCH_UP);
-
- display->getstringsize(ptr, &w, NULL);
- /* draw text */
- display->putsxy(vp->width/2 - w/2, 0, ptr);
- display->update_viewport();
-
- /* DOWN: Pitch Down */
- vp = &pitch_viewports[PITCH_BOTTOM];
- display->set_viewport(vp);
- display->clear_viewport();
-
-#ifdef HAVE_TOUCHSCREEN
- ptr = str(LANG_KBD_OK);
- display->getstringsize(ptr, &w, &h);
- /* one OK in the middle first column of the vp (at half height) */
- display->putsxy(vp->width/6 - w/2, vp->height/2 - h/2, ptr);
- /* one OK in the middle of the last column of the vp (at half height) */
- display->putsxy(5*vp->width/6 - w/2, vp->height/2 - h/2, ptr);
-#endif
- if (global_settings.pitch_mode_semitone)
- ptr = str(LANG_PITCH_DOWN_SEMITONE);
- else
- ptr = str(LANG_PITCH_DOWN);
- display->getstringsize(ptr, &w, &h);
- /* draw text */
- display->putsxy(vp->width/2 - w/2, vp->height - h, ptr);
- display->update_viewport();
- }
-
- /* Middle section */
- display->set_viewport(&pitch_viewports[PITCH_MID]);
- display->clear_viewport();
- int width_used = 0;
-
- /* Middle section upper line - hide for a small screen */
- if ((show_lang_pitch = (max_lines >= 3)))
- {
- if(global_settings.pitch_mode_timestretch)
- {
- /* Pitch:XXX.X% */
- if(global_settings.pitch_mode_semitone)
- {
- snprintf(buf, sizeof(buf), "%s: %s%d.%02d", str(LANG_PITCH),
- semitone >= 0 ? "+" : "-",
- abs(semitone / PITCH_SPEED_PRECISION),
- abs((semitone % PITCH_SPEED_PRECISION) /
- (PITCH_SPEED_PRECISION / 100))
- );
- }
- else
- {
- snprintf(buf, sizeof(buf), "%s: %ld.%ld%%", str(LANG_PITCH),
- pitch / PITCH_SPEED_PRECISION,
- (pitch % PITCH_SPEED_PRECISION) /
- (PITCH_SPEED_PRECISION / 10));
- }
- }
- else
- {
- /* Rate */
- snprintf(buf, sizeof(buf), "%s:", str(LANG_PLAYBACK_RATE));
- }
- display->getstringsize(buf, &w, &h);
- display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2),
- (pitch_viewports[PITCH_MID].height / 2) - h, buf);
- if (w > width_used)
- width_used = w;
- }
-
- /* Middle section lower line */
- /* "Speed:XXX%" */
- if(global_settings.pitch_mode_timestretch)
- {
- snprintf(buf, sizeof(buf), "%s: %ld.%ld%%", str(LANG_SPEED),
- speed / PITCH_SPEED_PRECISION,
- (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
- }
- else
- {
- if(global_settings.pitch_mode_semitone)
- {
- snprintf(buf, sizeof(buf), "%s%d.%02d",
- semitone >= 0 ? "+" : "-",
- abs(semitone / PITCH_SPEED_PRECISION),
- abs((semitone % PITCH_SPEED_PRECISION) /
- (PITCH_SPEED_PRECISION / 100))
- );
- }
- else
- {
- snprintf(buf, sizeof(buf), "%ld.%ld%%",
- pitch / PITCH_SPEED_PRECISION,
- (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
- }
- }
-
- display->getstringsize(buf, &w, &h);
- display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2),
- show_lang_pitch ? (pitch_viewports[PITCH_MID].height / 2) :
- (pitch_viewports[PITCH_MID].height / 2) - (h / 2),
- buf);
- if (w > width_used)
- width_used = w;
-
- /* "limit" and "timestretch" labels */
- if (max_lines >= 7)
- {
- if(at_limit)
- {
- const char * const p = str(LANG_STRETCH_LIMIT);
- display->getstringsize(p, &w, &h);
- display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2),
- (pitch_viewports[PITCH_MID].height / 2) + h, p);
- if (w > width_used)
- width_used = w;
- }
- }
-
- /* Middle section left/right labels */
- const char *leftlabel = "-2%";
- const char *rightlabel = "+2%";
- if (global_settings.pitch_mode_timestretch)
- {
- leftlabel = "<<";
- rightlabel = ">>";
- }
-
- /* Only display if they fit */
- display->getstringsize(leftlabel, &w, &h);
- width_used += w;
- display->getstringsize(rightlabel, &w, &h);
- width_used += w;
-
- if (width_used <= pitch_viewports[PITCH_MID].width)
- {
- display->putsxy(0, (pitch_viewports[PITCH_MID].height / 2) - (h / 2),
- leftlabel);
- display->putsxy((pitch_viewports[PITCH_MID].width - w),
- (pitch_viewports[PITCH_MID].height / 2) - (h / 2),
- rightlabel);
- }
- display->update_viewport();
- display->set_viewport(last_vp);
-}
-
-static int32_t pitch_increase(int32_t pitch, int32_t pitch_delta, bool allow_cutoff
- /* need this to maintain correct pitch/speed caps */
- , int32_t speed
- )
-{
- int32_t new_pitch;
- int32_t new_stretch;
- at_limit = false;
-
- if (pitch_delta < 0)
- {
- /* for large jumps, snap up to whole numbers */
- if(allow_cutoff && pitch_delta <= -PITCH_SPEED_PRECISION &&
- (pitch + pitch_delta) % PITCH_SPEED_PRECISION != 0)
- {
- pitch_delta += PITCH_SPEED_PRECISION - ((pitch + pitch_delta) % PITCH_SPEED_PRECISION);
- }
-
- new_pitch = pitch + pitch_delta;
-
- if (new_pitch < PITCH_MIN)
- {
- if (!allow_cutoff)
- {
- return pitch;
- }
- new_pitch = PITCH_MIN;
- at_limit = true;
- }
- }
- else if (pitch_delta > 0)
- {
- /* for large jumps, snap down to whole numbers */
- if(allow_cutoff && pitch_delta >= PITCH_SPEED_PRECISION &&
- (pitch + pitch_delta) % PITCH_SPEED_PRECISION != 0)
- {
- pitch_delta -= (pitch + pitch_delta) % PITCH_SPEED_PRECISION;
- }
-
- new_pitch = pitch + pitch_delta;
-
- if (new_pitch > PITCH_MAX)
- {
- if (!allow_cutoff)
- return pitch;
- new_pitch = PITCH_MAX;
- at_limit = true;
- }
- }
- else
- {
- /* pitch_delta == 0 -> no real change */
- return pitch;
- }
- if (dsp_timestretch_available())
- {
- /* increase the multiple to increase precision of this calculation */
- new_stretch = GET_STRETCH(new_pitch, speed);
- if(new_stretch < STRETCH_MIN)
- {
- /* we have to ignore allow_cutoff, because we can't have the */
- /* stretch go higher than STRETCH_MAX */
- new_pitch = GET_PITCH(speed, STRETCH_MIN);
- }
- else if(new_stretch > STRETCH_MAX)
- {
- /* we have to ignore allow_cutoff, because we can't have the */
- /* stretch go higher than STRETCH_MAX */
- new_pitch = GET_PITCH(speed, STRETCH_MAX);
- }
-
- if(new_stretch >= STRETCH_MAX ||
- new_stretch <= STRETCH_MIN)
- {
- at_limit = true;
- }
- }
-
- sound_set_pitch(new_pitch);
-
- return new_pitch;
-}
-
-static int32_t get_semitone_from_pitch(int32_t pitch)
-{
- int semitone = 0;
- int32_t fractional_index = 0;
-
- while(semitone < NUM_SEMITONES - 1 &&
- pitch >= semitone_table[semitone + 1])
- {
- semitone++;
- }
-
-
- /* now find the fractional part */
- while(pitch > (cent_interp[fractional_index + 1] *
- semitone_table[semitone] / PITCH_SPEED_100))
- {
- /* Check to make sure fractional_index isn't too big */
- /* This should never happen. */
- if(fractional_index >= CENT_INTERP_NUM - 1)
- {
- break;
- }
- fractional_index++;
- }
-
- int32_t semitone_pitch_a = cent_interp[fractional_index] *
- semitone_table[semitone] /
- PITCH_SPEED_100;
- int32_t semitone_pitch_b = cent_interp[fractional_index + 1] *
- semitone_table[semitone] /
- PITCH_SPEED_100;
- /* this will be the integer offset from the cent_interp entry */
- int32_t semitone_frac_ofs = (pitch - semitone_pitch_a) * CENT_INTERP_INTERVAL /
- (semitone_pitch_b - semitone_pitch_a);
- semitone = (semitone + SEMITONE_START) * PITCH_SPEED_PRECISION +
- fractional_index * CENT_INTERP_INTERVAL +
- semitone_frac_ofs;
-
- return semitone;
-}
-
-static int32_t get_pitch_from_semitone(int32_t semitone)
-{
- int32_t adjusted_semitone = semitone - SEMITONE_START * PITCH_SPEED_PRECISION;
-
- /* Find the index into the semitone table */
- int32_t semitone_index = (adjusted_semitone / PITCH_SPEED_PRECISION);
-
- /* set pitch to the semitone's integer part value */
- int32_t pitch = semitone_table[semitone_index];
- /* get the range of the cent modification for future calculation */
- int32_t pitch_mod_a =
- cent_interp[(adjusted_semitone % PITCH_SPEED_PRECISION) /
- CENT_INTERP_INTERVAL];
- int32_t pitch_mod_b =
- cent_interp[(adjusted_semitone % PITCH_SPEED_PRECISION) /
- CENT_INTERP_INTERVAL + 1];
- /* figure out the cent mod amount based on the semitone fractional value */
- int32_t pitch_mod = pitch_mod_a + (pitch_mod_b - pitch_mod_a) *
- (adjusted_semitone % CENT_INTERP_INTERVAL) / CENT_INTERP_INTERVAL;
-
- /* modify pitch based on the mod amount we just calculated */
- return (pitch * pitch_mod + PITCH_SPEED_100 / 2) / PITCH_SPEED_100;
-}
-
-static int32_t pitch_increase_semitone(int32_t pitch,
- int32_t current_semitone,
- int32_t semitone_delta
- , int32_t speed
- )
-{
- int32_t new_semitone = current_semitone;
-
- /* snap to the delta interval */
- if(current_semitone % semitone_delta != 0)
- {
- if(current_semitone > 0 && semitone_delta > 0)
- new_semitone += semitone_delta;
- else if(current_semitone < 0 && semitone_delta < 0)
- new_semitone += semitone_delta;
-
- new_semitone -= new_semitone % semitone_delta;
- }
- else
- new_semitone += semitone_delta;
-
- /* clamp the pitch so it doesn't go beyond the pitch limits */
- if(new_semitone < (SEMITONE_START * PITCH_SPEED_PRECISION))
- {
- new_semitone = SEMITONE_START * PITCH_SPEED_PRECISION;
- at_limit = true;
- }
- else if(new_semitone > (SEMITONE_END * PITCH_SPEED_PRECISION))
- {
- new_semitone = SEMITONE_END * PITCH_SPEED_PRECISION;
- at_limit = true;
- }
-
- int32_t new_pitch = get_pitch_from_semitone(new_semitone);
-
- int32_t new_stretch = GET_STRETCH(new_pitch, speed);
-
- /* clamp the pitch so it doesn't go beyond the stretch limits */
- if( new_stretch > STRETCH_MAX)
- {
- new_pitch = GET_PITCH(speed, STRETCH_MAX);
- new_semitone = get_semitone_from_pitch(new_pitch);
- at_limit = true;
- }
- else if (new_stretch < STRETCH_MIN)
- {
- new_pitch = GET_PITCH(speed, STRETCH_MIN);
- new_semitone = get_semitone_from_pitch(new_pitch);
- at_limit = true;
- }
-
- pitch_increase(pitch, new_pitch - pitch, false
- , speed
- );
-
- return new_semitone;
-}
-
-#ifdef HAVE_TOUCHSCREEN
-/*
- * Check for touchscreen presses as per sketch above in this file
- *
- * goes through each row of the, checks whether the touchscreen
- * was pressed in it. Then it looks the columns of each row for specific actions
- */
-static int pitchscreen_do_touchscreen(struct viewport vps[])
-{
- short x, y;
- struct viewport *this_vp = &vps[PITCH_TOP];
- int ret;
- static bool wait_for_release = false;
- ret = action_get_touchscreen_press_in_vp(&x, &y, this_vp);
-
- /* top row */
- if (ret > ACTION_UNKNOWN)
- { /* press on top row, left or right column
- * only toggle mode if released */
- int column = this_vp->width / 3;
- if ((x < column || x > (2*column)) && (ret == BUTTON_REL))
- return ACTION_PS_TOGGLE_MODE;
-
-
- else if (x >= column && x <= (2*column))
- { /* center column pressed */
- if (ret == BUTTON_REPEAT)
- return ACTION_PS_INC_BIG;
- else if (ret & BUTTON_REL)
- return ACTION_PS_INC_SMALL;
- }
- return ACTION_NONE;
- }
-
- /* now the center row */
- this_vp = &vps[PITCH_MID];
- ret = action_get_touchscreen_press_in_vp(&x, &y, this_vp);
-
- if (ret > ACTION_UNKNOWN)
- {
- int column = this_vp->width / 3;
-
- if (x < column)
- { /* left column */
- if (ret & BUTTON_REL)
- {
- wait_for_release = false;
- return ACTION_PS_NUDGE_LEFTOFF;
- }
- else if (ret & BUTTON_REPEAT)
- return ACTION_PS_SLOWER;
- if (!wait_for_release)
- {
- wait_for_release = true;
- return ACTION_PS_NUDGE_LEFT;
- }
- }
- else if (x > (2*column))
- { /* right column */
- if (ret & BUTTON_REL)
- {
- wait_for_release = false;
- return ACTION_PS_NUDGE_RIGHTOFF;
- }
- else if (ret & BUTTON_REPEAT)
- return ACTION_PS_FASTER;
- if (!wait_for_release)
- {
- wait_for_release = true;
- return ACTION_PS_NUDGE_RIGHT;
- }
- }
- else
- /* center column was pressed */
- return ACTION_PS_RESET;
- }
-
- /* now the bottom row */
- this_vp = &vps[PITCH_BOTTOM];
- ret = action_get_touchscreen_press_in_vp(&x, &y, this_vp);
-
- if (ret > ACTION_UNKNOWN)
- {
- int column = this_vp->width / 3;
-
- /* left or right column is exit */
- if ((x < column || x > (2*column)) && (ret == BUTTON_REL))
- return ACTION_PS_EXIT;
- else if (x >= column && x <= (2*column))
- { /* center column was pressed */
- if (ret & BUTTON_REPEAT)
- return ACTION_PS_DEC_BIG;
- else if (ret & BUTTON_REL)
- return ACTION_PS_DEC_SMALL;
- }
- return ACTION_NONE;
- }
- return ACTION_NONE;
-}
-
-#endif
-/*
- returns:
- 0 on exit
- 1 if USB was connected
-*/
-
+#include "plugin.h"
int gui_syncpitchscreen_run(void)
{
- int button;
- int32_t pitch = sound_get_pitch();
- int32_t semitone;
-
- int32_t new_pitch;
- int32_t pitch_delta;
- bool nudged = false;
- int i, updated = 4, decimals = 0;
- bool exit = false;
- /* should maybe be passed per parameter later, not needed for now */
- struct viewport parent[NB_SCREENS];
- struct viewport pitch_viewports[NB_SCREENS][PITCH_ITEM_COUNT];
- int max_lines[NB_SCREENS];
-
- push_current_activity(ACTIVITY_PITCHSCREEN);
-
- int32_t new_speed = 0, new_stretch;
-
- /* the speed variable holds the apparent speed of the playback */
- int32_t speed;
- if (dsp_timestretch_available())
- {
- speed = GET_SPEED(pitch, dsp_get_timestretch());
- }
- else
- {
- speed = pitch;
- }
-
- /* Figure out whether to be in timestretch mode */
- if (global_settings.pitch_mode_timestretch && !dsp_timestretch_available())
- {
- global_settings.pitch_mode_timestretch = false;
- settings_save();
- }
-
- /* Count decimals for speaking */
- for (i = PITCH_SPEED_PRECISION; i >= 10; i /= 10)
- decimals++;
-
- /* set the semitone index based on the current pitch */
- semitone = get_semitone_from_pitch(pitch);
-
- /* initialize pitchscreen vps */
- FOR_NB_SCREENS(i)
- {
- viewport_set_defaults(&parent[i], i);
- max_lines[i] = viewport_get_nb_lines(&parent[i]);
- pitchscreen_fix_viewports(&parent[i], pitch_viewports[i]);
- screens[i].set_viewport(&parent[i]);
- screens[i].clear_viewport();
-
- /* also, draw the icons now, it's only needed once */
- pitchscreen_draw_icons(&screens[i], &parent[i]);
- }
- pcmbuf_set_low_latency(true);
-
- while (!exit)
- {
- FOR_NB_SCREENS(i)
- pitchscreen_draw(&screens[i], max_lines[i],
- pitch_viewports[i], pitch, semitone
- , speed
- );
- pitch_delta = 0;
- new_speed = 0;
-
- if (global_settings.talk_menu && updated)
- {
- talk_shutup();
- switch (updated)
- {
- case 1:
- if (global_settings.pitch_mode_semitone)
- talk_value_decimal(semitone, UNIT_SIGNED, decimals, false);
- else
- talk_value_decimal(pitch, UNIT_PERCENT, decimals, false);
- break;
- case 2:
- talk_value_decimal(speed, UNIT_PERCENT, decimals, false);
- break;
- case 3:
- speak_pitch_mode(false);
- break;
- case 4:
- if (global_settings.pitch_mode_timestretch && dsp_timestretch_available())
- talk_id(LANG_PITCH, false);
- else
- talk_id(LANG_PLAYBACK_RATE, false);
- talk_value_decimal(pitch, UNIT_PERCENT, decimals, true);
- if (global_settings.pitch_mode_timestretch && dsp_timestretch_available())
- {
- talk_id(LANG_SPEED, true);
- talk_value_decimal(speed, UNIT_PERCENT, decimals, true);
- }
- speak_pitch_mode(true);
- break;
- default:
- break;
- }
- }
- updated = 0;
-
- button = get_action(CONTEXT_PITCHSCREEN, HZ);
-
-#ifdef HAVE_TOUCHSCREEN
- if (button == ACTION_TOUCHSCREEN)
- {
- FOR_NB_SCREENS(i)
- button = pitchscreen_do_touchscreen(pitch_viewports[i]);
- }
-#endif
- switch (button)
- {
- case ACTION_PS_INC_SMALL:
- if(global_settings.pitch_mode_semitone)
- pitch_delta = SEMITONE_SMALL_DELTA;
- else
- pitch_delta = PITCH_SMALL_DELTA;
- updated = 1;
- break;
-
- case ACTION_PS_INC_BIG:
- if(global_settings.pitch_mode_semitone)
- pitch_delta = SEMITONE_BIG_DELTA;
- else
- pitch_delta = PITCH_BIG_DELTA;
- updated = 1;
- break;
-
- case ACTION_PS_DEC_SMALL:
- if(global_settings.pitch_mode_semitone)
- pitch_delta = -SEMITONE_SMALL_DELTA;
- else
- pitch_delta = -PITCH_SMALL_DELTA;
- updated = 1;
- break;
-
- case ACTION_PS_DEC_BIG:
- if(global_settings.pitch_mode_semitone)
- pitch_delta = -SEMITONE_BIG_DELTA;
- else
- pitch_delta = -PITCH_BIG_DELTA;
- updated = 1;
- break;
-
- case ACTION_PS_NUDGE_RIGHT:
- if (!global_settings.pitch_mode_timestretch)
- {
- new_pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false
- , speed
- );
- nudged = (new_pitch != pitch);
- pitch = new_pitch;
- semitone = get_semitone_from_pitch(pitch);
- speed = pitch;
- updated = nudged ? 1 : 0;
- break;
- }
- else
- {
- new_speed = speed + SPEED_SMALL_DELTA;
- at_limit = false;
- updated = 2;
- }
- break;
-
- case ACTION_PS_FASTER:
- if (global_settings.pitch_mode_timestretch)
- {
- new_speed = speed + SPEED_BIG_DELTA;
- /* snap to whole numbers */
- if(new_speed % PITCH_SPEED_PRECISION != 0)
- new_speed -= new_speed % PITCH_SPEED_PRECISION;
- at_limit = false;
- updated = 2;
- }
- break;
-
- case ACTION_PS_NUDGE_RIGHTOFF:
- if (nudged)
- {
- pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false
- , speed
- );
- speed = pitch;
- semitone = get_semitone_from_pitch(pitch);
- nudged = false;
- updated = 1;
- }
- break;
-
- case ACTION_PS_NUDGE_LEFT:
- if (!global_settings.pitch_mode_timestretch)
- {
- new_pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false
- , speed
- );
- nudged = (new_pitch != pitch);
- pitch = new_pitch;
- semitone = get_semitone_from_pitch(pitch);
- speed = pitch;
- updated = nudged ? 1 : 0;
- break;
- }
- else
- {
- new_speed = speed - SPEED_SMALL_DELTA;
- at_limit = false;
- updated = 2;
- }
- break;
-
- case ACTION_PS_SLOWER:
- if (global_settings.pitch_mode_timestretch)
- {
- new_speed = speed - SPEED_BIG_DELTA;
- /* snap to whole numbers */
- if(new_speed % PITCH_SPEED_PRECISION != 0)
- new_speed += PITCH_SPEED_PRECISION - speed % PITCH_SPEED_PRECISION;
- at_limit = false;
- updated = 2;
- }
- break;
-
- case ACTION_PS_NUDGE_LEFTOFF:
- if (nudged)
- {
- pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false
- , speed
- );
- speed = pitch;
- semitone = get_semitone_from_pitch(pitch);
- nudged = false;
- updated = 1;
- }
- break;
-
- case ACTION_PS_RESET:
- pitch = PITCH_SPEED_100;
- sound_set_pitch(pitch);
- speed = PITCH_SPEED_100;
- if (dsp_timestretch_available())
- {
- dsp_set_timestretch(PITCH_SPEED_100);
- at_limit = false;
- }
- semitone = get_semitone_from_pitch(pitch);
- updated = 4;
- break;
-
- case ACTION_PS_TOGGLE_MODE:
- global_settings.pitch_mode_semitone = !global_settings.pitch_mode_semitone;
-
- if (dsp_timestretch_available() && !global_settings.pitch_mode_semitone)
- {
- global_settings.pitch_mode_timestretch = !global_settings.pitch_mode_timestretch;
- if(!global_settings.pitch_mode_timestretch)
- {
- /* no longer in timestretch mode. Reset speed */
- speed = pitch;
- dsp_set_timestretch(PITCH_SPEED_100);
- }
- }
- settings_save();
- updated = 3;
- break;
-
- case ACTION_PS_EXIT:
- exit = true;
- break;
-
- default:
- if (default_event_handler(button) == SYS_USB_CONNECTED)
- return 1;
- break;
- }
- if (pitch_delta)
- {
- if (global_settings.pitch_mode_semitone)
- {
- semitone = pitch_increase_semitone(pitch, semitone, pitch_delta
- , speed
- );
- pitch = get_pitch_from_semitone(semitone);
- }
- else
- {
- pitch = pitch_increase(pitch, pitch_delta, true
- , speed
- );
- semitone = get_semitone_from_pitch(pitch);
- }
- if (global_settings.pitch_mode_timestretch)
- {
- /* do this to make sure we properly obey the stretch limits */
- new_speed = speed;
- }
- else
- {
- speed = pitch;
- }
- }
-
- if(new_speed)
- {
- new_stretch = GET_STRETCH(pitch, new_speed);
-
- /* limit the amount of stretch */
- if(new_stretch > STRETCH_MAX)
- {
- new_stretch = STRETCH_MAX;
- new_speed = GET_SPEED(pitch, new_stretch);
- }
- else if(new_stretch < STRETCH_MIN)
- {
- new_stretch = STRETCH_MIN;
- new_speed = GET_SPEED(pitch, new_stretch);
- }
-
- new_stretch = GET_STRETCH(pitch, new_speed);
- if(new_stretch >= STRETCH_MAX ||
- new_stretch <= STRETCH_MIN)
- {
- at_limit = true;
- }
-
- /* set the amount of stretch */
- dsp_set_timestretch(new_stretch);
-
- /* update the speed variable with the new speed */
- speed = new_speed;
-
- /* Reset new_speed so we only call dsp_set_timestretch */
- /* when needed */
- new_speed = 0;
- }
- }
-
- pcmbuf_set_low_latency(false);
- pop_current_activity();
-
- /* Clean up */
- FOR_NB_SCREENS(i)
- {
- screens[i].set_viewport(NULL);
- }
-
- return 0;
+ return (plugin_load(VIEWERS_DIR"/pitch_screen.rock", NULL) == PLUGIN_USB_CONNECTED);
}
diff --git a/apps/gui/quickscreen.c b/apps/gui/quickscreen.c
index f8bf98d4ee..a7d07f4e33 100644
--- a/apps/gui/quickscreen.c
+++ b/apps/gui/quickscreen.c
@@ -39,6 +39,9 @@
#include "option_select.h"
#include "debug.h"
#include "shortcuts.h"
+#ifdef HAVE_ALBUMART
+#include "playback.h"
+#endif
/* 1 top, 1 bottom, 2 on either side, 1 for the icons
* if enough space, top and bottom have 2 lines */
@@ -248,20 +251,21 @@ static void talk_qs_option(const struct settings_list *opt, bool enqueue)
static bool gui_quickscreen_do_button(struct gui_quickscreen * qs, int button)
{
int item;
- bool invert = false;
+ bool previous = false;
switch(button)
{
case ACTION_QS_TOP:
- invert = true;
item = QUICKSCREEN_TOP;
break;
+
case ACTION_QS_LEFT:
- invert = true;
item = QUICKSCREEN_LEFT;
+ previous = true;
break;
case ACTION_QS_DOWN:
item = QUICKSCREEN_BOTTOM;
+ previous = true;
break;
case ACTION_QS_RIGHT:
@@ -271,37 +275,40 @@ static bool gui_quickscreen_do_button(struct gui_quickscreen * qs, int button)
default:
return false;
}
+
if (qs->items[item] == NULL)
return false;
-#ifdef ASCENDING_INT_SETTINGS
- if (((qs->items[item]->flags & F_INT_SETTING) == F_INT_SETTING) &&
- ( button == ACTION_QS_DOWN || button == ACTION_QS_TOP))
- {
- invert = !invert;
- }
-#endif
- option_select_next_val(qs->items[item], invert, true);
+
+ option_select_next_val(qs->items[item], previous, true);
talk_qs_option(qs->items[item], false);
return true;
}
#ifdef HAVE_TOUCHSCREEN
-static int quickscreen_touchscreen_button(const struct viewport
- vps[QUICKSCREEN_ITEM_COUNT])
+static int quickscreen_touchscreen_button(void)
{
short x,y;
/* only hitting the text counts, everything else is exit */
if (action_get_touchscreen_press(&x, &y) != BUTTON_REL)
return ACTION_NONE;
- else if (viewport_point_within_vp(&vps[QUICKSCREEN_TOP], x, y))
+
+ enum { left=1, right=2, top=4, bottom=8 };
+
+ int bits = (x < LCD_WIDTH/3 ? left : (x > 2*LCD_WIDTH/3 ? 2 : right)) |
+ (y < LCD_WIDTH/3 ? top : (y > 2*LCD_WIDTH/3 ? 8 : bottom));
+
+ switch(bits) {
+ case top:
return ACTION_QS_TOP;
- else if (viewport_point_within_vp(&vps[QUICKSCREEN_BOTTOM], x, y))
+ case bottom:
return ACTION_QS_DOWN;
- else if (viewport_point_within_vp(&vps[QUICKSCREEN_LEFT], x, y))
+ case left:
return ACTION_QS_LEFT;
- else if (viewport_point_within_vp(&vps[QUICKSCREEN_RIGHT], x, y))
+ case right:
return ACTION_QS_RIGHT;
- return ACTION_STD_CANCEL;
+ default:
+ return ACTION_STD_CANCEL;
+ }
}
#endif
@@ -343,7 +350,7 @@ static bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_ente
button = get_action(CONTEXT_QUICKSCREEN, HZ/5);
#ifdef HAVE_TOUCHSCREEN
if (button == ACTION_TOUCHSCREEN)
- button = quickscreen_touchscreen_button(vps[SCREEN_MAIN]);
+ button = quickscreen_touchscreen_button();
#endif
if (default_event_handler(button) == SYS_USB_CONNECTED)
{
@@ -407,6 +414,9 @@ int quick_screen_quick(int button_enter)
struct gui_quickscreen qs;
bool oldshuffle = global_settings.playlist_shuffle;
int oldrepeat = global_settings.repeat_mode;
+#ifdef HAVE_ALBUMART
+ int old_album_art = global_settings.album_art;
+#endif
bool usb = false;
if (global_settings.shortcuts_replaces_qs)
@@ -442,6 +452,10 @@ int quick_screen_quick(int button_enter)
else
playlist_sort(NULL, true);
}
+#ifdef HAVE_ALBUMART
+ if (old_album_art != global_settings.album_art)
+ set_albumart_mode(global_settings.album_art);
+#endif
}
return (usb ? 1:0);
}
diff --git a/apps/gui/skin_engine/skin_engine.c b/apps/gui/skin_engine/skin_engine.c
index ce3401f41c..b3626b681d 100644
--- a/apps/gui/skin_engine/skin_engine.c
+++ b/apps/gui/skin_engine/skin_engine.c
@@ -155,6 +155,9 @@ void settings_apply_skins(void)
char filename[MAX_PATH];
static bool first_run = true;
+ if (audio_status() & AUDIO_STATUS_PLAY)
+ audio_stop();
+
skin_backdrop_init();
skins_initialised = true;
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c
index 4ebdcab722..b3840f689f 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -1187,7 +1187,7 @@ static int parse_progressbar_tag(struct skin_element* element,
region->reverse_bar = false;
region->allow_while_locked = false;
region->press_length = PRESS;
- region->last_press = 0xffff;
+ region->last_press = -1;
region->armed = false;
region->bar = PTRTOSKINOFFSET(skin_buffer, pb);
@@ -1602,7 +1602,7 @@ static int parse_touchregion(struct skin_element *element,
region->armed = false;
region->reverse_bar = false;
region->value = 0;
- region->last_press = 0xffff;
+ region->last_press = -1;
region->press_length = PRESS;
region->allow_while_locked = false;
region->bar = PTRTOSKINOFFSET(skin_buffer, NULL);
diff --git a/apps/gui/skin_engine/skin_tokens.c b/apps/gui/skin_engine/skin_tokens.c
index a4c9af7539..27022b87d1 100644
--- a/apps/gui/skin_engine/skin_tokens.c
+++ b/apps/gui/skin_engine/skin_tokens.c
@@ -1367,7 +1367,7 @@ const char *get_token_value(struct gui_wps *gwps,
case SKIN_TOKEN_LASTTOUCH:
{
#ifdef HAVE_TOUCHSCREEN
- unsigned int last_touch = touchscreen_last_touch();
+ long last_touch = touchscreen_last_touch();
char *skin_base = get_skin_buffer(data);
struct touchregion_lastpress *data = SKINOFFSETTOPTR(skin_base, token->value.data);
if (!data) return NULL;
@@ -1375,7 +1375,7 @@ const char *get_token_value(struct gui_wps *gwps,
if (region)
last_touch = region->last_press;
- if (last_touch != 0xffff &&
+ if (last_touch != -1 &&
TIME_BEFORE(current_tick, data->timeout + last_touch))
return "t";
#endif
diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c
index a961d191b2..74da14bd3f 100644
--- a/apps/gui/statusbar.c
+++ b/apps/gui/statusbar.c
@@ -725,18 +725,6 @@ void gui_syncstatusbar_init(struct gui_syncstatusbar * bars)
}
}
-void gui_syncstatusbar_draw(struct gui_syncstatusbar * bars,
- bool force_redraw)
-{
- if(!global_settings.statusbar)
- return;
- struct viewport viewport;
- FOR_NB_SCREENS(i) {
- GET_RECT(viewport,statusbar_position(i),&screens[i]);
- gui_statusbar_draw( &(bars->statusbars[i]), force_redraw, &viewport );
- }
-}
-
#ifdef HAVE_REMOTE_LCD
enum statusbar_values statusbar_position(int screen)
diff --git a/apps/gui/statusbar.h b/apps/gui/statusbar.h
index a676c7b143..c62434155d 100644
--- a/apps/gui/statusbar.h
+++ b/apps/gui/statusbar.h
@@ -99,8 +99,7 @@ struct gui_syncstatusbar
};
extern void gui_syncstatusbar_init(struct gui_syncstatusbar * bars) INIT_ATTR;
-extern void gui_syncstatusbar_draw(struct gui_syncstatusbar * bars,
- bool force_redraw);
+
#if !defined(HAVE_REMOTE_LCD) || defined(__PCTOOL__)
#include "settings.h"
#define statusbar_position(a) ((enum statusbar_values)global_settings.statusbar)
diff --git a/apps/gui/wps.c b/apps/gui/wps.c
index cdb34ab447..7554892451 100644
--- a/apps/gui/wps.c
+++ b/apps/gui/wps.c
@@ -903,7 +903,9 @@ long gui_wps_show(void)
case ACTION_WPS_ID3SCREEN:
{
gwps_leave_wps();
- if (browse_id3())
+ if (browse_id3(audio_current_track(),
+ playlist_get_display_index(),
+ playlist_amount()))
return GO_TO_ROOT;
restore = true;
}