summaryrefslogtreecommitdiff
path: root/apps/gui/mask_select.c
diff options
context:
space:
mode:
authorWilliam Wilgus <me.theuser@yahoo.com>2016-11-22 06:21:31 +0100
committerWilliam Wilgus <me.theuser@yahoo.com>2017-01-17 23:06:17 +0100
commitdc87e9e9f3c383b63c3cb3713886a6c93b6a79d1 (patch)
tree47a6c0d49e7741f91fa74d7230b1267f60617902 /apps/gui/mask_select.c
parent16a9f84571276a13f4cfd5c66db8cd63ce4e2e7f (diff)
downloadrockbox-dc87e9e9f3c383b63c3cb3713886a6c93b6a79d1.tar.gz
rockbox-dc87e9e9f3c383b63c3cb3713886a6c93b6a79d1.zip
Selective Backlight/Advanced Softlock - Selective actions based on context
Selective backlight allows the user to choose actions that will not enable the backlight when pressed. Advanced softlock allows user to choose actions that will not be blocked by screenlock on devices without a hold button. Both only occur in FM and WPS Contexts. Update: Back from the dead -Cleaned up code, removed unnecessary calls, re-arranged last filter action timeout conditional to work in case last_filtered_action_tick was never set -Added entries to the manual -Fixed back button on some menus not activating backlight -Made menus more intuitive, no actions selected now changes menu item to off. -Added talk fuctionality. -Added option to disable selective backlight while on external power. -Rewrote backlight and softlock handling code to fix issue with scrollwheels -Menu changed to have toggle(yes/no) and settings -Optimized selective actions lookup -Added option to disable notification of 'buttons locked' while softlocked -Removed uneeded code, consolidated action lookup to single function -Fixed incorrect name on selective softlock menu -Added option to disable touch on touchscreen devices -Fixed backlight on original screenlock without selective screenlock active -Added text selection in mask_select for when show_icons is off -Fixed voice in mask_select to speak if voice is defined instead of spelling -Added more lang defines (play skip seek) -Added option to disable unknown keys turning on backlight -Fixed Conditional argument In wrong place causing players without backlight to fail to build -Fixed Disable Unknown blocking detection of context change -Fixed canceling menu didn't update new settings -Added Autolock on backlight off -Removed backlight_on_force from backlight.c, Now sets ignore next to false and uses backlight_on -Cleaned up autolock code added strings to lang file -Fixed issue where rapid presses would bypass softlock -Removed old softlock code, Cleaned selective actions code -Changed menu to match existing RB menus -Fixed Backlight_on_Hold blocked by backlight_ignore_next -Fixed ignore_next for ipod -Fixed bug allowing context with softlock to bypass selective backlight -Changed mask_select to no longer prompt for changes to be saved -Changed menu names -Added ignore timeout to allow ipod scroll wheel to work properly and other players to still work properly, removed some previous code including ignore_event -Increased ignore timeout to prevent sd card accesses from interrupting action code and turning on backlight -Changed Unknown action to unmapped action in menu, changed handling code -Removed unneeded logic and variables for handling unfiltered actions -Reverted unmapped action code to previous functionality -Added manual entries (thanks JohnB) -Removed elusive unhandled unicode character from manual, changed formatting slightly Actions: Volume,Play,Seek,Skip Extras: Disable unmapped actions Disable selective backlight on external power Disable touch during softlock on touchscreen devices Disable softlock notifications (power button still notifies) Autolock on backlight off Method: Adds a function to ignore backlight on next call If selected action occurs backlight is forced on, Filter_first_keypress stays intact. Selective softlock allows selected actions through, bypasses the normal softlock routine. ToDo: DONE previous commit (#1) has attribution for folder_select.c which mask_select is based from. Change-Id: I08132ddcfd64c81751ef23b720f3ec6d68695fe4
Diffstat (limited to 'apps/gui/mask_select.c')
-rw-r--r--apps/gui/mask_select.c287
1 files changed, 287 insertions, 0 deletions
diff --git a/apps/gui/mask_select.c b/apps/gui/mask_select.c
new file mode 100644
index 0000000000..e22ba7dd03
--- /dev/null
+++ b/apps/gui/mask_select.c
@@ -0,0 +1,287 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * Copyright (C) 2016 William Wilgus
9 * Derivative of folder_select.c by:
10 * Copyright (C) 2012 Jonathan Gordon
11 * Copyright (C) 2012 Thomas Martitz
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22/* TODO add language defines */
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include "lang.h"
28#include "language.h"
29#include "list.h"
30#include "plugin.h"
31#include "mask_select.h"
32#include "talk.h"
33
34/*
35 * Order for changing child states:
36 * 1) expand folder
37 * 2) collapse and select
38 * 3) deselect (skip to 1)
39 */
40
41enum child_state {
42 EXPANDED,
43 SELECTED,
44 COLLAPSED,
45 DESELECTED,
46};
47
48/* Children of main categories */
49struct child {
50 const char* name;
51 struct category *category;
52 enum child_state state;
53 int key_value;
54};
55
56/* Main Categories in root */
57struct category {
58 const char *name;
59 struct child *children;
60 int children_count;
61 int depth;
62 struct category* previous;
63 int key_value; /*values of all children OR|D*/
64};
65
66/* empty category for children of root only one level needed */
67static struct category empty = {
68 .name = "",
69 .children = NULL,
70 .children_count = 0,
71 .depth = 1,
72 .previous = NULL,
73};
74
75/* Or | all keyvalues that user selected */
76static int calculate_mask_r(struct category *root, int mask)
77{
78 int i = 0;
79 while (i < root->children_count)
80 {
81 struct child *this = &root->children[i];
82 if (this->state == SELECTED)
83 mask |= this->key_value;
84
85 else if (this->state == EXPANDED)
86 mask = calculate_mask_r(this->category, mask);
87 i++;
88 }
89return mask;
90}
91
92static int count_items(struct category *start)
93{
94 int count = 0;
95 int i;
96
97 for (i=0; i<start->children_count; i++)
98 {
99 struct child *foo = &start->children[i];
100 if (foo->state == EXPANDED)
101 count += count_items(foo->category);
102 count++;
103 }
104 return count;
105}
106
107static struct child* find_index(struct category *start,
108 int index,struct category **parent)
109{
110 int i = 0;
111
112 *parent = NULL;
113
114 while (i < start->children_count)
115 {
116 struct child *foo = &start->children[i];
117 if (i == index)
118 {
119 *parent = start;
120 return foo;
121 }
122 i++;
123 if (foo->state == EXPANDED)
124 {
125 struct child *bar = find_index(foo->category, index - i, parent);
126 if (bar)
127 {
128 return bar;
129 }
130 index -= count_items(foo->category);
131 }
132 }
133 return NULL;
134}
135
136/* simplelist uses this callback to change
137 the states of the categories/children */
138static int item_action_callback(int action, struct gui_synclist *list)
139{
140 struct category *root = (struct category*)list->data;
141 struct category *parent;
142 struct child *this = find_index(root, list->selected_item, &parent);
143
144 if (action == ACTION_STD_OK)
145 {
146 switch (this->state)
147 {
148 case EXPANDED:
149 this->state = SELECTED;
150 if (global_settings.talk_menu)
151 talk_id(LANG_ON, false);
152 break;
153 case SELECTED:
154 this->state = this->category->children_count == 0 ?
155 DESELECTED : COLLAPSED;
156 if (global_settings.talk_menu && this->category->children_count == 0)
157 talk_id(LANG_OFF, false);
158 break;
159 case COLLAPSED:
160 if (this->category == NULL)
161 this->category = root;
162 this->state = this->category->children_count == 0 ?
163 SELECTED : EXPANDED;
164 if (global_settings.talk_menu && this->category->children_count == 0)
165 talk_id(LANG_ON, false);
166 break;
167 case DESELECTED:
168 this->state = SELECTED;
169 if (global_settings.talk_menu)
170 talk_id(LANG_ON, false);
171 break;
172
173 default:
174 /* do nothing */
175 return action;
176 }
177 list->nb_items = count_items(root);
178 return ACTION_REDRAW;
179 }
180
181 return action;
182}
183
184static const char * item_get_name(int selected_item, void * data,
185 char * buffer, size_t buffer_len)
186{
187 struct category *root = (struct category*)data;
188 struct category *parent;
189 struct child *this = find_index(root, selected_item , &parent);
190
191 buffer[0] = '\0';
192
193 if (parent->depth >= 0)
194 for(int i = 0; i <= parent->depth; i++)
195 strcat(buffer, "\t\0");
196
197 /* state of selection needs icons so if icons are disabled use text*/
198 if (!global_settings.show_icons)
199 {
200 if (this->state == SELECTED)
201 strcat(buffer, "+\0");
202 else
203 strcat(buffer," \0");
204 }
205 strlcat(buffer, P2STR((const unsigned char *)this->name), buffer_len);
206
207 return buffer;
208}
209
210static int item_get_talk(int selected_item, void *data)
211{
212 struct category *root = (struct category*)data;
213 struct category *parent;
214 struct child *this = find_index(root, selected_item , &parent);
215 if (global_settings.talk_menu)
216 {
217 long id = P2ID((const unsigned char *)(this->name));
218 if(id>=0)
219 talk_id(id, true);
220 else
221 talk_spell(this->name, true);
222 talk_id(VOICE_PAUSE,true);
223 if (this->state == SELECTED)
224 talk_id(LANG_ON, true);
225 else if (this->state == DESELECTED)
226 talk_id(LANG_OFF, true);
227 }
228 return 0;
229}
230
231static enum themable_icons item_get_icon(int selected_item, void * data)
232{
233 struct category *root = (struct category*)data;
234 struct category *parent;
235 struct child *this = find_index(root, selected_item, &parent);
236
237 switch (this->state)
238 {
239 case SELECTED:
240 return Icon_Submenu;
241 case COLLAPSED:
242 return Icon_NOICON;
243 case EXPANDED:
244 return Icon_Submenu_Entered;
245 default:
246 return Icon_NOICON;
247 }
248 return Icon_NOICON;
249}
250
251/* supply your original mask,the page header (ie. User do this..), mask items
252 and count, they will be selected automatically if the mask includes
253 them. If user selects new items and chooses to save settings
254 new mask returned otherwise, original is returned
255*/
256int mask_select(int mask, const unsigned char* headermsg,
257 struct s_mask_items *mask_items, size_t items)
258{
259 struct simplelist_info info;
260
261 struct child action_child[items];
262 for (unsigned i = 0; i < items; i++)
263 {
264 action_child[i].name = mask_items[i].name;
265 action_child[i].category = &empty;
266 action_child[i].key_value = mask_items[i].bit_value;
267 action_child[i].state = mask_items[i].bit_value & mask ?
268 SELECTED : DESELECTED;
269 }
270
271 struct category root = {
272 .name = "",
273 .children = (struct child*) &action_child,
274 .children_count = items,
275 .depth = -1,
276 .previous = NULL,
277 };
278
279 simplelist_info_init(&info, P2STR(headermsg), count_items(&root), &root);
280 info.get_name = item_get_name;
281 info.action_callback = item_action_callback;
282 info.get_icon = item_get_icon;
283 info.get_talk = item_get_talk;
284 simplelist_show_list(&info);
285
286 return calculate_mask_r(&root,0);
287}