diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c
index 87d7107..10d4a91 100644
--- a/apps/gui/bitmap/list.c
+++ b/apps/gui/bitmap/list.c
@@ -40,6 +40,7 @@
#include "misc.h"
#include "viewport.h"
#include "statusbar-skinned.h"
+#include "debug.h"

#define ICON_PADDING 1

@@ -230,8 +231,10 @@ void list_draw(struct screen *display, struct gui_synclist *list)
}
}
#endif
- if(i >= list->selected_item && i < list->selected_item
- + list->selected_size && list->show_selection_marker)
+ /* draw the selected line */
+ if(!list->hide_selection && i >= list->selected_item
+ && i < list->selected_item + list->selected_size
+ && list->show_selection_marker)
{/* The selected item must be displayed scrolling */
if (global_settings.cursor_style == 1
#ifdef HAVE_REMOTE_LCD
@@ -308,7 +311,16 @@ void list_draw(struct screen *display, struct gui_synclist *list)

#if defined(HAVE_TOUCHSCREEN)
/* This needs to be fixed if we ever get more than 1 touchscreen on a target. */
-static bool scrolling=false;
+static bool scrolling = false;
+static bool released = false;
+
+/* Used for kinetic scrolling as we need to know the last position to
+ * recognize the scroll direction.
+ * This gets reset to 0 at the end of scrolling
+ */
+static int last_position=0;
+static long scroll_cancel;
+

static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list,
int y)
@@ -319,7 +331,6 @@ static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list,
if (nb_lines < gui_list->nb_items)
{
scrolling = true;
-
int scrollbar_size = nb_lines*
font_get(gui_list->parent[screen]->font)->height;
int actual_y = y - list_text[screen].y;
@@ -334,7 +345,6 @@ static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list,
start_item = gui_list->nb_items - nb_lines;

gui_list->start_item[screen] = start_item;
- gui_synclist_select_item(gui_list, new_selection);

return ACTION_REDRAW;
}
@@ -342,16 +352,47 @@ static int gui_synclist_touchscreen_scrollbar(struct gui_synclist * gui_list,
return ACTION_NONE;
}

+#ifdef HAVE_TOUCHSCREEN
+static int gui_synclist_touchscreen_scrolling(struct gui_synclist * gui_list, int position)
+{
+ const int screen = screens[SCREEN_MAIN].screen_type;
+ const int difference = position - last_position;
+ const int nb_lines = viewport_get_nb_lines(&list_text[screen]);
+ if(nb_lines < gui_list->nb_items && difference != 0) // only scroll if needed
+ {
+ int new_start_item;
+ new_start_item = gui_list->start_item[screen] - difference;
+ // check if new_start_item is bigger than list item count
+ if(new_start_item > gui_list->nb_items - nb_lines)
+ new_start_item = gui_list->nb_items - nb_lines;
+ // set new_start_item to 0 if it's negative
+ if(new_start_item < 0)
+ new_start_item = 0;
+ gui_list->start_item[screen] = new_start_item;
+ }
+ return difference;
+}
+#endif
+
unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
{
short x, y;
- const int button = action_get_touchscreen_press(&x, &y);
+ int button = action_get_touchscreen_press(&x, &y);
int line;
const int screen = SCREEN_MAIN;
const int list_start_item = gui_list->start_item[screen];
const struct viewport *list_text_vp = &list_text[screen];
int list_width = list_text_vp->width;
+ bool old_released = released;
+
+ if (UNLIKELY(scroll_cancel == 0))
+ scroll_cancel = current_tick;
+
+ released = (button&BUTTON_REL) != 0;
+ gui_list->hide_selection = scrolling;

+
+
if (global_settings.scrollbar == SCROLLBAR_RIGHT)
list_width += SCROLLBAR_WIDTH;

@@ -385,9 +426,17 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
}
else
{
- if (x > list_text_vp->x + list_text_vp->width &&
- global_settings.scrollbar == SCROLLBAR_RIGHT)
- return gui_synclist_touchscreen_scrollbar(gui_list, y);
+ int line_height = font_get(gui_list->parent[screen]->font)->height;
+ if (global_settings.scrollbar == SCROLLBAR_RIGHT)
+ {
+ int x_end = list_text_vp->x+list_text_vp->width;
+ if (x > x_end)
+ return gui_synclist_touchscreen_scrollbar(gui_list, y);
+ /* empty margin to prevent accidental selection when using
+ * the scrollbar */
+ else if (x > (x_end - line_height))
+ return ACTION_NONE;
+ }

/* |--------------------------------------------------------|
* | Description of the touchscreen list interface: |
@@ -403,10 +452,9 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
*/
if (y > list_text_vp->y || button & BUTTON_REPEAT)
{
- int line_height, actual_y;
-
+ int actual_y;
+
actual_y = y - list_text_vp->y;
- line_height = font_get(gui_list->parent[screen]->font)->height;
line = actual_y / line_height;

/* Pressed below the list*/
@@ -416,30 +464,10 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
/* Pressed a border */
if(UNLIKELY(actual_y % line_height == 0))
return ACTION_NONE;
-
- if (line != (gui_list->selected_item - list_start_item)
- && button ^ BUTTON_REL)
- {
- if(button & BUTTON_REPEAT)
- scrolling = true;
-
- gui_synclist_select_item(gui_list, list_start_item + line);
-
- return ACTION_REDRAW;
- }
-
- /* This has the same effect as the icons do when the scrollbar
- is on the left (ie eliminate the chances an user enters/starts
- an item when he wanted to use the scrollbar, due to touchscreen
- dead zones)
- */
- if(global_settings.scrollbar == SCROLLBAR_RIGHT &&
- x > list_text_vp->x + list_text_vp->width -
- get_icon_width(SCREEN_MAIN))
- return ACTION_NONE;
-
+
if (button == (BUTTON_REPEAT|BUTTON_REL))
{
+ last_position = 0;
if(!scrolling)
{
/* Pen was hold on the same line as the
@@ -454,21 +482,55 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list)
* this one
* => do nothing
*/
- scrolling = false;
return ACTION_NONE;
}
}
- else if(button == BUTTON_REL &&
- line == gui_list->selected_item - list_start_item)
+ else if (button & BUTTON_REL)
{
/* Pen was released on either the same line as the previously
* selected one or an other one
* => simulate short press
*/
- return ACTION_STD_OK;
+ last_position = 0;
+ if (!scrolling)
+ {
+ gui_synclist_select_item(gui_list, list_start_item + line);
+ return ACTION_STD_OK;
+ }
+ else
+ return ACTION_NONE;
}
else
- return ACTION_NONE;
+ {
+ int result = 0;
+ bool redraw = false;
+
+ /* beginning of list interaction */
+ if (old_released)
+ {
+ scrolling = false;
+ scroll_cancel = current_tick;
+ redraw = true;
+ gui_list->hide_selection = false;
+ }
+
+
+ gui_synclist_select_item(gui_list, list_start_item+line);
+ if (last_position == 0)
+ last_position = line;
+ else
+ result = gui_synclist_touchscreen_scrolling(gui_list, line);
+
+ if (result)
+ {
+ redraw = true;
+ scrolling = true;
+ }
+
+ last_position = line;
+
+ return redraw ? ACTION_REDRAW:ACTION_NONE;
+ }
}
}
return ACTION_NONE;
diff --git a/apps/gui/list.h b/apps/gui/list.h
index 965a46b..57ca912 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -94,7 +94,10 @@ struct gui_synclist
/* wether the text of the whole items of the list have to be
* scrolled or only for the selected item */
bool scroll_all;
-
+ /*
+ * if true the selection bar will not be drawn
+ */
+ bool hide_selection;
int nb_items;
int selected_item;
int start_item[NB_SCREENS]; /* the item that is displayed at the top of the screen */
diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c
index 0d0d1cd..3d8a5a4 100644
--- a/firmware/drivers/button.c
+++ b/firmware/drivers/button.c
@@ -233,6 +233,13 @@ static void button_tick(void)
/* initial repeat */
count = REPEAT_INTERVAL_START;
}
+#ifdef HAVE_TOUCHSCREEN
+ else if (data != lastdata && btn == lastbtn)
+ { /* only coordinates changed, post anyway */
+ if (touchscreen_get_mode() == TOUCHSCREEN_POINT)
+ post = true;
+ }
+#endif
}
}
if ( post )