Rockbox Ports are now being developed for various digital audio players!
/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2017 William Wilgus * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/#include "plugin.h"#include "lib/pluginlib_actions.h"#define settings_filename PLUGIN_APPS_DIR "/fade2sleep_settings.f2s"#define MSTR_CT(x) (sizeof(x)/sizeof(0[x]))#define MFMT_PLAYLIST "%s %s %s;"#define MFMT_TIME "%s %s;"#define MFMT_VOL "%s %d %s;"#define MFMT_STR "%s;"#define MFMT_SEPARATOR " ;"#define MENU_SETTINGS_BEGIN "",#define MENUSETTING_VOLUME(item) setting_strings[item],settings->table[item],\ rb->sound_unit(SOUND_VOLUME)#define MENUSETTING_TRIGGER(item) setting_strings[item],\ trigger_strings[settings->table[item]]#define MENUSETTING_ACTION(item) action_strings[settings->table[item]]#define MENUSETTING_PLAY(item) setting_strings[item],\ play_strings[settings->table[item]],\ (settings->table[item])? settings->play : "\0"#define WATCHED_EV(flag) ((watched_events & flag) == flag) ? flag : 0 #define THREAD_STACK_SIZE DEFAULT_STACK_SIZE/* use long for aligning */static unsigned long thread_stack[THREAD_STACK_SIZE/sizeof(long)];#define EV_EXIT MAKE_SYS_EVENT(SYS_EVENT_CLS_PRIVATE, 1)#define TIMEOUT_VOL_CHANGE HZ/2static unsigned int thread_id;static struct event_queue thread_q SHAREDBSS_ATTR;const struct button_mapping *plugin_contexts[] = { pla_main_ctx };//#define MAX_MENU_ENTRIES 10 /* menu string pointers statically allocated *///const char* menu_strings[MAX_MENU_ENTRIES];// * sizeof(const char*)static unsigned int triggered_events = 0;static unsigned int watched_events = 0;static bool quit = false, in_usb_mode = false;/*Time setting formatting (NOT RTC)*/#define MS_IN_TICK (1000U/HZ)enum e_fmt_time_auto_idx{ UNIT_IDX_HR = 0, UNIT_IDX_MIN, UNIT_IDX_SEC, UNIT_IDX_MS, UNIT_IDX_TIME_COUNT,};/* format_time_auto */#define UNIT_IDX_MASK 0x01FFU /*Return only Unit_IDX*/#define UNIT_TRIM_ZERO 0x0200U /*Don't show leading zero on max_idx*/#define UNIT_LOCK_HR 0x0400U /*Don't Auto Range below this field*/#define UNIT_LOCK_MIN 0x0800U /*Don't Auto Range below this field*/#define UNIT_LOCK_SEC 0x1000U /*Don't Auto Range below this field*/static const char *unit_strings[] ={ [UNIT_INT] = "", [UNIT_MS] = "ms", [UNIT_SEC] = "s", [UNIT_MIN] = "min", [UNIT_HOUR]= "hr", [UNIT_KHZ] = "kHz", [UNIT_DB] = "dB", [UNIT_PERCENT] = "%", [UNIT_MAH] = "mAh", [UNIT_PIXEL] = "px", [UNIT_PER_SEC] = "per sec", [UNIT_HERTZ] = "Hz", [UNIT_MB] = "MB", [UNIT_KBIT] = "kb/s", [UNIT_PM_TICK] = "units/10ms",};enum e_self_triggered_events{ /* TRIGGERED WITHIN THIS PLUGIN */ SELF_EVENT_CHECK_TRIGGERED = 0, SELF_EVENT_TIMEOUT_REACHED = 1, SELF_EVENT_FINALVOL_REACHED = 2,};enum e_triggered_events{ //TRIG_EVENT_=0x0001, TRIG_EVENT_START_PLAYBACK = 0x0002, TRIG_EVENT_TRACK_SKIP = 0x0004, TRIG_EVENT_TRACK_CHANGE = 0x0008, TRIG_EVENT_TRACK_FINISH = 0x0010, TRIG_EVENT_VOL_CHANGED = 0x0020, TRIG_EVENT_SCREEN_CHANGED = 0x0040, TRIG_EVENT_SCREEN_ON = 0x0080, TRIG_EVENT_VOL_FINAL = 0x0100, TRIG_EVENT_PAUSE = 0x0200, TRIG_EVENT_RESUME = 0x0400, TRIG_EVENT_PLAY = 0x0800, TRIG_EVENT_STOP = 0x1000, TRIG_EVENT_TIMEOUT = 0x2000, //TRIG_EVENT_=0x4000, //TRIG_EVENT_=0x8000,};enum e_play_str{ PLAY_USECURRENT = 0, PLAY_LOAD,};static const char * play_strings[] ={ [PLAY_USECURRENT]"Use Current", [PLAY_LOAD] "Load",};enum e_save_str{ SAV_SAVE = 0, SAV_SAVED,};static const char * saved_strings[] ={ [SAV_SAVE] "Save", [SAV_SAVED]"Saved",};enum e_trigger_str{ TRIG_NONE = 0, TRIG_TIMEOUT, TRIG_FINALVOL, TRIG_PAUSE, TRIG_VOLCHANGE, TRIG_TRACKCHANGE, TRIG_ANY,};static const char * trigger_strings[] ={ [TRIG_NONE] "None", [TRIG_TIMEOUT] "Timeout", [TRIG_FINALVOL] "Final Volume", [TRIG_PAUSE] "Pause", [TRIG_VOLCHANGE] "Volume Change", [TRIG_TRACKCHANGE]"Track Change", [TRIG_ANY] "Any Action",};enum e_delay_str{ DLY_NONE = 0, DLY_TIMEOUT, DLY_TRACKCHANGE, DLY_PAUSERESUME, DLY_PLAYSTOP,};static const char * delay_strings[] ={ [DLY_NONE] "None", [DLY_TIMEOUT] "Timeout", [DLY_TRACKCHANGE]"Track Change", [DLY_PAUSERESUME]"Pause/Resume", [DLY_PLAYSTOP] "Play/Stop",};enum e_curvol_str{ CURVOL_NONE = 0, CURVOL_START, CURVOL_END,};static const char * cur_vol_strings[] ={ [CURVOL_NONE] "None", [CURVOL_START]"Start", [CURVOL_END] "End",};enum e_action_str{ ACT_NONE = 0, ACT_SLEEP, ACT_STARTOVER, ACT_INVERTFADE, ACT_EXIT,};static const char * action_strings[] ={ [ACT_NONE] "None", [ACT_SLEEP] "Sleep", [ACT_STARTOVER] "Start Over", [ACT_INVERTFADE]"Invert Fade", [ACT_EXIT] "Exit",};enum e_ny_str{ NY_NO = 0, NY_YES,};static const char * ny_strings[] ={ [NY_NO] "No", [NY_YES]"Yes",};enum enum_menu{ /*same order as they will be displayed in the menu*/ M_PLAY = 0, M_DELAY, M_ACTDELAY, M_USECURVOL, M_STARTVOL, M_ENDVOL, M_TIMEOUT, M_TRIG1, M_ACT1, M_TRIG2, M_ACT2, M_TRIG3, M_ACT3, M_TSR, M_SEP, M_SAVE, M_RUN, M_EXIT, M_ITEM_COUNT,};static const char * setting_strings[M_ITEM_COUNT] ={//[]"", [M_PLAY] "Play", [M_DELAY] "Delay", [M_ACTDELAY] "After", [M_USECURVOL] "Use Cur Volume", [M_STARTVOL] "Fade from :", [M_ENDVOL] "to :", [M_TIMEOUT] "Timeout", [M_TRIG1] "After", [M_ACT1] "Action1", [M_TRIG2] "After", [M_ACT2] "Action2", [M_TRIG3] "After", [M_ACT3] "Action3", [M_TSR] "In Background", /*[M_SEP]*/ [M_SAVE] "Save", [M_RUN] "Run", [M_EXIT] "Exit",};static const int setting_icons[M_ITEM_COUNT] ={//Icon_NOICON[M_DELAY]Icon_Menu_setting,[M_ACTDELAY]Icon_Playback_menu,[M_USECURVOL]Icon_Questionmark,[M_STARTVOL]Icon_EQ,[M_ENDVOL]Icon_Audio,[M_TIMEOUT]Icon_Config,[M_TRIG1]Icon_Menu_setting,[M_ACT1]Icon_Menu_functioncall,[M_TRIG2]Icon_NOICON,[M_ACT2]Icon_NOICON,[M_TRIG3]Icon_NOICON,[M_ACT3]Icon_NOICON,[M_SEP]Icon_NOICON,[M_SAVE]Icon_Submenu,[M_EXIT]Icon_Reverse_Cursor,};//static int setting_table[M_ITEM_COUNT]={0};static struct viewport viewport[NB_SCREENS];static struct fade_settings{ int vol_orig; int vol_min; int vol_max; int vol_step; int vol_cur; bool fade_out; long timeout_ticks; long ticks_remaining; int audio_status; int duration; int delay_duration; int vol_init; bool init_use_cur; int vol_final; bool final_use_cur; int actions; int sleep; bool tsr;} fade_set;static struct settings{ uint32_t crc; char play[MAX_PATH]; int table[M_ITEM_COUNT];} settings;static const char * dyn_menu_get_entry(int selected_item, void * data, char * buffer, size_t buffer_len){ //(void)data; (void)buffer; (void)buffer_len; char * menustr = ((char**) data)[selected_item]; return menustr;}static enum themable_icons menu_get_icon(int selected_item, void * data){ (void)data; if ((unsigned) selected_item >= M_ITEM_COUNT) return Icon_NOICON; return setting_icons[selected_item];//data[selected_item];// : Icon_NOICON;}static int do_dyn_menu(const char* title, char* strentry, const char ** entrylist, int entries, int *cur_selection, int *list_start, list_get_icon *icon_callback, struct viewport parent[NB_SCREENS], bool hide_theme){/* Creates a menu, can use non constant strings by supplying a comma separated list of menu items via strentry ex. "item1;item2;item3;item4" strentry may be a buffer filled by any means (sprintf) or a string literal but NOT const since every separator ';' will be replaced by a '\0' ALTERNATIVELY can use a list of const strings via entrylist ex. static const char * menu_str[] ={"item1", "item2", "item3"};do_dyn_menu(titlestr, menustr, entrylist, entries, start, hidetheme)titlestr - title for the menumenustr - comma separated list of menu entriesentrylist - ALTERNATIVE to menustr pointer to const string listentries - number of entries in menustr if > MAX_MENU_ENTRIES will be truncated.cur_sel - sets menu item selected, returns users selectionlist_start - sets menu entry at top of list, keeps position between callshide_theme - hides theme elements such as the status bar and backgroundreturns selected item index, -2 if canceled, <0 on other error*/ enum{MAX_DYN_MENU_ENTRIES=M_ITEM_COUNT +1 }; static const char* menu_strings[MAX_DYN_MENU_ENTRIES]; char *remain, *token = NULL; const char * const sep= ";"; struct gui_synclist list; int result = 0; int action; entries = MIN(MAX_DYN_MENU_ENTRIES, entries); if(menu_strings != NULL && entrylist == NULL) { for(int i=0; i < entries; i++) { token = rb->strtok_r(strentry, sep, &remain); strentry = NULL; /*strtok will continue with sequence*/ menu_strings[i] = (token != NULL)? token : "???"; } entrylist = menu_strings; } rb->gui_synclist_init(&list, dyn_menu_get_entry, entrylist, true, 1, parent); rb->gui_synclist_set_title(&list, (unsigned char*) title, Icon_Rockbox); if (icon_callback) rb->gui_synclist_set_icon_callback(&list, *icon_callback); rb->gui_synclist_set_nb_items(&list, entries); rb->gui_synclist_select_item(&list, (cur_selection) ? *cur_selection : 0); FOR_NB_SCREENS(i) { if (list_start) list.start_item[i] = *list_start; rb->viewportmanager_theme_enable(i, !hide_theme, parent); } rb->gui_synclist_draw(&list); while (result == 0) { action = rb->get_action(CONTEXT_LIST, TIMEOUT_BLOCK); if (rb->gui_synclist_do_button(&list, &action, LIST_WRAP_UNLESS_HELD)) continue; switch (action) { case ACTION_STD_OK: { result = 1; break; } case ACTION_STD_CANCEL: { result = -1; break; } } } if (cur_selection) *cur_selection = rb->gui_synclist_get_sel_pos(&list); FOR_NB_SCREENS(i) { rb->viewportmanager_theme_undo(i, false); if (list_start) { if (i == 0) *list_start = 0; *list_start |= list.start_item[i]; } }return result;}/*unsigned int ms_to_ticks(unsigned int ms){ return ms/MS_IN_TICK;}unsigned int ticks_to_ms(unsigned int ticks){ return ticks * MS_IN_TICK;}*//* time_split_units() split time values depending on base unit unit_idx: UNIT_HOUR, UNIT_MIN, UNIT_SEC, UNIT_MS abs_value: absolute time value units_in: array of unsigned ints with UNIT_IDX_TIME_COUNT fields*/static unsigned int time_split_units(int unit_idx, unsigned long abs_val, unsigned int (*units_in)[UNIT_IDX_TIME_COUNT]){ unsigned int base_idx = UNIT_IDX_HR; int hours; int minutes = 0; int seconds = 0; int millisec = 0; switch (unit_idx & UNIT_IDX_MASK) /*Mask off upper bits*/ { case UNIT_MS: base_idx = UNIT_IDX_MS; millisec = abs_val; abs_val = abs_val / 1000U; millisec = millisec - (1000U * abs_val); /* fallthrough and calculate the rest of the units */ case UNIT_SEC: if (base_idx == UNIT_IDX_HR) base_idx = UNIT_IDX_SEC; seconds = abs_val; abs_val = abs_val / 60U; seconds = seconds - (60U * abs_val); /* fallthrough and calculate the rest of the units */ case UNIT_MIN: if (base_idx == UNIT_IDX_HR) base_idx = UNIT_IDX_MIN; minutes = abs_val; abs_val = abs_val / 60U; minutes = minutes -(60U * abs_val); /* fallthrough and calculate the rest of the units */ case UNIT_HOUR: default: hours = abs_val; break; } (*units_in)[UNIT_IDX_HR] = hours; (*units_in)[UNIT_IDX_MIN] = minutes; (*units_in)[UNIT_IDX_SEC] = seconds; (*units_in)[UNIT_IDX_MS] = millisec; return base_idx;}/* format_time_auto - return an auto ranged time string; buffer: needs to be at least 64 characters unit_idx: specifies lowest or base index of the value add | UNIT_LOCK_ to prevent autorange below this index add | UNIT_TRIM_ZERO to supress leading zero on the largest unit value: should be passed in the same form as unit_idx supress_unit: if true unit string is NOT printed idx_pos[2]: (if !NULL) [0] specifies an index of interest, the offset and width for that index will be returned. In field [0] offset, field [1] length Ex: given 12:34:56.78 if you pass the idx_pos UNIT_IDX_MIN idx_pos returns -> {3,2}.. offset(3) and length(2) = '34'*/static const char *format_time_auto(char *buffer, int buf_len, const long value, int unit_idx, bool supress_unit, unsigned char (*idx_pos)[2]){ const char * const sign = &"-"[value < 0 ? 0 : 1]; bool is_rtl = rb->lang_is_rtl(); unsigned int timebuf_len = 30; /* -2147483648:00:00.00\0 */ char *timebuf;/*timebuf[24]; shared with buffer instead*/ int len, left_offset; unsigned char base_idx, max_idx; unsigned int units_in[UNIT_IDX_TIME_COUNT]; char fwidth[UNIT_IDX_TIME_COUNT] = { [UNIT_IDX_HR] = 0, /* hr is variable length */ [UNIT_IDX_MIN] = 2, [UNIT_IDX_SEC] = 2, [UNIT_IDX_MS] = 3, }; /* {0,2,2,3}; Field Widths*/ unsigned char offsets[UNIT_IDX_TIME_COUNT] = { [UNIT_IDX_HR] = 10,/* ?:59:59.999 Std offsets */ [UNIT_IDX_MIN] = 7, /*0?:+1:+4.+7 need calculated */ [UNIT_IDX_SEC] = 4,/* 999.59:59:0 RTL offsets */ [UNIT_IDX_MS] = 0,/* 0 .4 :7 :10 won't change */ }; /* {10,7,4,0}; Offsets*/ static const int unitlock[UNIT_IDX_TIME_COUNT] = { [UNIT_IDX_HR] = UNIT_LOCK_HR, [UNIT_IDX_MIN] = UNIT_LOCK_MIN, [UNIT_IDX_SEC] = UNIT_LOCK_SEC, [UNIT_IDX_MS] = 0, }; /* unitlock*/ static const int units[UNIT_IDX_TIME_COUNT] = { [UNIT_IDX_HR] = UNIT_HOUR, [UNIT_IDX_MIN] = UNIT_MIN, [UNIT_IDX_SEC] = UNIT_SEC, [UNIT_IDX_MS] = UNIT_MS, }; /* units*/ buf_len = buf_len - (timebuf_len + 2); timebuf = &buffer[buf_len + 1]; /* use part of the supplied buffer */ if (buf_len < 32) return buffer; if (idx_pos != NULL) { (*idx_pos)[0] = MIN((*idx_pos)[0], UNIT_IDX_TIME_COUNT - 1); unit_idx |= unitlock[(*idx_pos)[0]]; } base_idx = time_split_units(unit_idx, abs(value), &units_in); if (units_in[UNIT_IDX_HR] || (unit_idx & unitlock[UNIT_IDX_HR])) max_idx = UNIT_IDX_HR; else if (units_in[UNIT_IDX_MIN] || (unit_idx & unitlock[UNIT_IDX_MIN])) max_idx = UNIT_IDX_MIN; else if (units_in[UNIT_IDX_SEC] || (unit_idx & unitlock[UNIT_IDX_SEC])) max_idx = UNIT_IDX_SEC; else if (units_in[UNIT_IDX_MS]) max_idx = UNIT_IDX_MS; else /* value is 0*/ max_idx = base_idx; if (!is_rtl) { len = snprintf(timebuf, timebuf_len, "%02d:%02d:%02d.%03d", units_in[UNIT_IDX_HR], units_in[UNIT_IDX_MIN], units_in[UNIT_IDX_SEC], units_in[UNIT_IDX_MS]); fwidth[UNIT_IDX_HR] = len - offsets[UNIT_IDX_HR]; offsets[UNIT_IDX_MS] = fwidth[UNIT_IDX_HR] + offsets[UNIT_IDX_MIN]; offsets[UNIT_IDX_SEC] = fwidth[UNIT_IDX_HR] + offsets[UNIT_IDX_SEC]; offsets[UNIT_IDX_MIN] = fwidth[UNIT_IDX_HR] + 1; offsets[UNIT_IDX_HR] = 0; timebuf[offsets[base_idx] + fwidth[base_idx]] = '\0'; left_offset = -(offsets[max_idx]); left_offset += rb->strlcpy(buffer, sign, buf_len); /* trim leading zero on the max_idx */ if ((unit_idx & UNIT_TRIM_ZERO) == UNIT_TRIM_ZERO && timebuf[offsets[max_idx]] == '0') { offsets[max_idx]++; } rb->strlcat(buffer, &timebuf[offsets[max_idx]], buf_len); if (!supress_unit) { rb->strlcat(buffer, " ", buf_len); rb->strlcat(buffer, unit_strings[units[max_idx]], buf_len); } } else /*RTL Languages*/ { len = snprintf(timebuf, timebuf_len, "%03d.%02d:%02d:%02d", units_in[UNIT_IDX_MS], units_in[UNIT_IDX_SEC], units_in[UNIT_IDX_MIN], units_in[UNIT_IDX_HR]); fwidth[UNIT_IDX_HR] = len - offsets[UNIT_IDX_HR]; left_offset = -(offsets[base_idx]); /* trim leading zero on the max_idx */ if ((unit_idx & UNIT_TRIM_ZERO) == UNIT_TRIM_ZERO && timebuf[offsets[max_idx]] == '0') { timebuf[offsets[max_idx]] = timebuf[offsets[max_idx]+1]; fwidth[max_idx]--; } timebuf[offsets[max_idx] + fwidth[max_idx]] = '\0'; if (!supress_unit) { rb->strlcpy(buffer, unit_strings[units[max_idx]], buf_len); left_offset += rb->strlcat(buffer, " ", buf_len); rb->strlcat(buffer, &timebuf[offsets[base_idx]], buf_len); } else rb->strlcpy(buffer, &timebuf[offsets[base_idx]], buf_len); rb->strlcat(buffer, sign, buf_len); } if (idx_pos != NULL) { (*idx_pos)[1]= fwidth[*(idx_pos)[0]]; (*idx_pos)[0]= left_offset + offsets[(*idx_pos)[0]]; } return buffer;}static void draw_horiz_scrollbar(struct screen * display, int top, int height, int cur_pct){ rb->gui_scrollbar_draw(display, /* screen */ 5, /* x */ top, /* y */ LCD_WIDTH-10, /* width */ height , /* height */ 100, /* items */ 0, /* min_shown */ cur_pct, /* max_shown */ HORIZONTAL); /* flags */}static inline int get_button(void){ return pluginlib_getaction(HZ/10, plugin_contexts, ARRAYLEN(plugin_contexts));}static bool can_play(void){ int audio_status = rb->audio_status(); if ((!audio_status && rb->global_status->resume_index != -1) && (rb->playlist_resume() != -1)) { return true; } else if (audio_status & AUDIO_STATUS_PLAY) return true; return false;}static void resume_audio(bool from_stop){ int audio_status = rb->audio_status(); //rb->playlist_resume() if (from_stop && !audio_status && rb->global_status->resume_index != -1) { if (rb->playlist_resume() != -1) { rb->playlist_resume_track(rb->global_status->resume_index, rb->global_status->resume_crc32, rb->global_status->resume_elapsed, rb->global_status->resume_offset); } } else if (audio_status & AUDIO_STATUS_PLAY) rb->audio_resume();}static void pause_audio(void){ if (rb->audio_status() & AUDIO_STATUS_PLAY) rb->audio_pause();}int value_to_pct(int value, int min, int max){ int pct = 0; pct = ((value * 100 - min *100)/(abs(max-min))); return pct;}static int clamp_int(int value, int min, int max){ int tmp = 0; if (min > max) { /* Swap max and min if needed */ tmp = max; max = min; min = tmp; } if (value < min) value = min; else if (value > max) value = max; return value;}static int do_select_clamped(int v1, int v2, bool use_v2, int v_min, int v_max){ /* selects val1 or val2 by bool use_v2 false = val1, true = val2 0 = val1 1 = val2 returns selected clamped to v_min/v_max */ int value; if (use_v2) value = v2; else value = v1; return clamp_int(value, v_min, v_max);}static int clamp_int_rollover(int value, int min, int max){ int tmp = 0; if (min > max) { /* Swap max and min if needed */ tmp = max; max = min; min = tmp; } if (value < min) value = max; else if (value > max) value = min; return value;}static int do_volume_change(int vol_step, int vol_min, int vol_max){ /* Negative numbers lower volume Positive numbers raise volume clamps to vol_min/volmax returns current volume */ rb->button_clear_queue(); //clear any pending buttons int vol = rb->sound_get_current(SOUND_VOLUME); vol = clamp_int(vol + vol_step, vol_min, vol_max); rb->sound_set_current(SOUND_VOLUME, vol); return vol;}static void do_set_fade(struct fade_settings * fade_set){ int duration = fade_set->duration; int vol_min = rb->sound_min(SOUND_VOLUME); int vol_max = rb->sound_max(SOUND_VOLUME); int vol_orig = rb->sound_get_current(SOUND_VOLUME); /* get current volume */ int vol_cur; /*vol_orig is the global volume not necessarily current volume*/ int vol_init; int vol_final; int vol_step; int vol_range; bool fade_out; long ticks_remaining; long timeout_ticks; vol_init = do_select_clamped(vol_orig, fade_set->vol_init, !fade_set->init_use_cur, vol_min, vol_max); fade_set->vol_init = vol_init; vol_cur = vol_init; vol_final = do_select_clamped(vol_orig, fade_set->vol_final, !fade_set->final_use_cur, vol_min, vol_max); fade_set->vol_final = vol_final; if (vol_init > vol_final) { fade_out = true; vol_range = vol_init - vol_final; //abs() vol_step = -1; } else { fade_out = false; vol_range = vol_final - vol_init;//abs() vol_step = 1; } fade_set->fade_out = fade_out; fade_set->vol_step = vol_step; ticks_remaining = HZ * duration; if (ticks_remaining < HZ) ticks_remaining = HZ; fade_set->ticks_remaining = ticks_remaining; timeout_ticks = (ticks_remaining / vol_range); if (timeout_ticks < HZ/10) timeout_ticks = HZ/10; fade_set->timeout_ticks = timeout_ticks; fade_set->vol_min = vol_min; fade_set->vol_max = vol_max; fade_set->vol_cur = vol_cur; fade_set->vol_orig = vol_orig;}static bool do_fade(struct fade_settings * fade_set){ int vol_min = fade_set->vol_init; int vol_max = fade_set->vol_final; int vol_step = fade_set->vol_step; int vol_cur = fade_set->vol_cur; int ret = true; vol_cur = do_volume_change(vol_step, vol_min, vol_max); if (fade_set->vol_cur == vol_cur) { rb->splashf(HZ, "usr = %d", vol_cur); } if (vol_cur == vol_max) { ret = false; rb->splashf(HZ, "v = %d", vol_cur); } fade_set->vol_cur = vol_cur; return ret;}static int get_button_dpad(int *value, int *h_pos, int * v_pos, unsigned int multiplier){/* Allow user to use left,right, up, down, and (scroll) buttons to set a value single button press increments/decrements value by 1 * multiplier repeat button press accelerates inc/dec by multiplier * 2 if h_pos is not NULL then left decrements h_pos, right increments if v_pos is not NULL then down decrements v_pos, up increments h_pos/v_pos being defined blocks actions for respective single press inc/dec of value Returns 0 if no button matched, -1 if canceled, 1 if value selected*/ int button; int exit_val = 0; button = get_button(); switch (button) { case PLA_RIGHT: if (h_pos) { *h_pos += 1; break; } case PLA_UP: if (v_pos) { *v_pos += 1; break; } *value+=1 * multiplier; break; case PLA_RIGHT_REPEAT: case PLA_UP_REPEAT: *value+=2 * multiplier; break;#ifdef HAVE_SCROLLWHEEL case PLA_SCROLL_FWD: *value+=1 * multiplier; break; case PLA_SCROLL_FWD_REPEAT: *value+=2 * multiplier; break;#endif case PLA_LEFT: if (h_pos) { *h_pos -= 1; break; } case PLA_DOWN: if (v_pos) { *v_pos -= 1; break; } *value-=1 * multiplier; break; case PLA_LEFT_REPEAT: case PLA_DOWN_REPEAT: *value-=2 * multiplier; break;#ifdef HAVE_SCROLLWHEEL case PLA_SCROLL_BACK: *value-=1 * multiplier; break; case PLA_SCROLL_BACK_REPEAT: *value -=2 * multiplier; break;#endif case PLA_SELECT: case PLA_SELECT_REPEAT: exit_val = 1; break; case PLA_EXIT: case PLA_CANCEL: exit_val = -1; break; default: exit_val = 0; break; } return exit_val;}void pop_up_frame(struct screen * display, int x, int y, int width, int height){/*|___________|| || ||___________|*/ //int title_height = display->getcharheight() + 5; //display->puts_scroll(1, 0, title_buf);//void (*lcd_fillrect)(int x, int y, int width, int height); display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID); display->fillrect(x, y, width, height); display->set_drawmode(DRMODE_SOLID); display->hline(0, width, height/3); display->hline(1, width-1, height); display->vline(x, 0, height-1); display->vline(width-x, 0, height-1); }int do_set_value(const char * title, int val, int val_min, int val_max, const char * val_lbl){ struct screen * display = rb->screens[SCREEN_MAIN]; int title_height = display->getcharheight() + 5; char title_buf[48]= "\0"; int initial_val = val; int ret = 0; FOR_NB_SCREENS(i) rb->viewportmanager_theme_enable(i, false, NULL); //rb->lcd_clear_display(); pop_up_frame(display, 0, 0, LCD_WIDTH-1, title_height * 3); while(ret == 0) { ret = get_button_dpad(&val, NULL, NULL, 1); /* allow user to set value*/ val = clamp_int_rollover(val, val_min, val_max); draw_horiz_scrollbar(display, title_height * 2, title_height/2, value_to_pct(val, val_min, val_max)); rb->snprintf(title_buf, sizeof(title_buf), "%s %d %s ", title, val, val_lbl); display->puts_scroll(1, 0, title_buf); display->update(); rb->sleep(HZ/100); } if (ret == -1) { val = initial_val; rb->splash(HZ/2, "Canceled"); } display->clear_display(); FOR_NB_SCREENS(i) rb->viewportmanager_theme_undo(i, true); //display->update(); return val;}int do_set_time(const char * title, int sec, int sec_min, int sec_max){ char time_buf[64]= "\0"; const int time_buf_sz = sizeof(time_buf); struct screen *display = rb->screens[SCREEN_MAIN]; int title_height = display->getcharheight() + 5; int is_rtl = rb->lang_is_rtl(); const int initial_sec = sec; /* on cancel original time returned*/ int ret = 0; enum {FIELD_ST = 0, FIELD_CT = 3}; unsigned char idx_pos[2]; int field_pos = (is_rtl? FIELD_ST : FIELD_CT - 1); int rel_field; /* If lang is RTL then fields/cols are reversed */ static const unsigned char field_cols[FIELD_CT] = {UNIT_IDX_HR, UNIT_IDX_MIN, UNIT_IDX_SEC}; static const unsigned int multiplier_cols[FIELD_CT] = {3600, 60, 1}; int offset = 1; const int lcd_chr_width = (LCD_WIDTH/rb->lcd_getstringsize("W", NULL, NULL)); //rb->lcd_clear_display(); pop_up_frame(display, 0, 0, LCD_WIDTH-1, title_height * 3); while(ret == 0) { field_pos = clamp_int_rollover(field_pos, FIELD_ST, FIELD_CT - 1); /* if lang is RTL then columns flip */ rel_field = (is_rtl? FIELD_CT - field_pos - 1 : field_pos); idx_pos[0] = field_cols[rel_field]; ret = get_button_dpad(&sec, &field_pos, NULL, multiplier_cols[rel_field]); /* allow user to set value*/ sec = clamp_int_rollover(sec, sec_min, sec_max); rb->lcd_puts_scroll(offset, 2, " "); format_time_auto(time_buf, time_buf_sz, sec, UNIT_SEC, false, &idx_pos); offset = (lcd_chr_width - rb->strlen(time_buf))/2; rb->lcd_puts_scroll(offset, 2, time_buf); rb->lcd_set_drawmode(DRMODE_SOLID | DRMODE_INVERSEVID); time_buf[idx_pos[0] + idx_pos[1]] = '\0'; /*draw selected position inverse*/ rb->lcd_puts_scroll(offset + idx_pos[0], 2, &time_buf[idx_pos[0]]); rb->lcd_set_drawmode(DRMODE_SOLID); rb->lcd_puts_scroll(1,0,title); rb->lcd_update(); rb->sleep(HZ/100); } if (ret == -1) { sec = initial_sec; rb->splash(HZ/2, "Canceled"); } rb->lcd_clear_display(); rb->lcd_update(); return sec;}uint32_t crc_settings(struct settings * set){ //struct settings set_tmp /* some fields are ignored in crc calculation */ uint32_t current_crc = set->crc; set->crc = 0; int vol_start = set->table[M_STARTVOL]; int vol_end = set->table[M_ENDVOL]; if (set->table[M_USECURVOL] == CURVOL_START) set->table[M_STARTVOL] = 0; if (set->table[M_USECURVOL] == CURVOL_END) set->table[M_ENDVOL] = 0; set->table[M_SAVE] = 0; uint32_t crc = rb->crc_32(set, sizeof(*set), 0xffffffff); /* put back ignored fields */ set->crc = current_crc; set->table[M_STARTVOL] = vol_start; set->table[M_ENDVOL] = vol_end; return crc;}void load_settings(struct settings * settings, char* filename){ int fh = rb->open(filename, O_RDONLY); struct settings settings_load; /* defaults */ settings->play[0] = '\0'; if(fh >= 0) { /* does file exist? */ /* basic consistency check */ if(rb->filesize(fh) == sizeof(*settings)) { rb->read(fh, &settings_load, sizeof(struct settings)); if (settings_load.crc == crc_settings(&settings_load)) { rb->memcpy(settings, &settings_load, sizeof(struct settings)); } else rb->splashf(HZ * 5, "CRC Check Failed %s", filename); } else rb->splashf(HZ * 5, "Incorrect File Size %s", filename); rb->close(fh); }}void save_settings(struct settings * settings, char* filename){ int fd = rb->creat(filename, 0666); settings->crc = crc_settings(settings); if(fd >= 0) { /* does file exist? */ rb->write (fd, settings, sizeof(*settings)); rb->close(fd); }}void scroll_table_rollover(int * p_sel, int entries, int direction){ int sel = *p_sel; if (direction < 0) (sel)--; else (sel)++; *p_sel = clamp_int_rollover(sel, 0, entries - 1);}static bool play_load(const char* filename){ struct browse_context browse; if (rb->file_exists(filename)) { rb->browse_context_init(&browse, 0, BROWSE_RUNFILE, "", 0, filename, ""); rb->rockbox_browse(&browse); return true; } else rb->splashf(HZ * 2, "Error: %s Does Not Exist", filename); return false;}static bool play_picker(struct settings *settings){ bool ret = false; struct browse_context browse; rb->browse_context_init(&browse, SHOW_PLAYLIST, BROWSE_SELECTONLY|BROWSE_NO_CONTEXT_MENU, "Play", Icon_Menu_setting, "/", ""); browse.buf = settings->play; browse.bufsize = sizeof(settings->play); rb->rockbox_browse(&browse); if (browse.flags & BROWSE_SELECTED) { rb->splashf(HZ * 2, "%s", settings->play); if (rb->file_exists(settings->play)) ret = true; //play_load("/test.txt"); } return ret;}static void do_set_volume_table_values(struct settings *set){/* user can elect to use the current volume level as the start or end volume */ int vol = rb->sound_get_current(SOUND_VOLUME); int vol_min = rb->sound_min(SOUND_VOLUME); int vol_max = rb->sound_max(SOUND_VOLUME); set->table[M_STARTVOL] = do_select_clamped(set->table[M_STARTVOL], vol, set->table[M_USECURVOL] == CURVOL_START, vol_min, vol_max); set->table[M_ENDVOL] = do_select_clamped(set->table[M_ENDVOL], vol, set->table[M_USECURVOL] == CURVOL_END, vol_min, vol_max);}static void do_set_action_table_values(struct settings *set){ if (set->table[M_TRIG1] == TRIG_NONE) set->table[M_ACT1] = ACT_NONE; if (set->table[M_TRIG2] == TRIG_NONE) set->table[M_ACT2] = ACT_NONE; if (set->table[M_TRIG3] == TRIG_NONE) set->table[M_ACT3] = ACT_NONE;}static void init_table_settings(struct settings *set){ do_set_volume_table_values(set); do_set_action_table_values(set); set->table[M_SAVE] = (set->crc == crc_settings(set))? SAV_SAVED : SAV_SAVE;}static void event_callback(unsigned short id, void *param){ static int last_audio = AUDIO_STATUS_ERROR; static int last_screen = 0; static bool backlight_on = true; int audio_status; int screen; int last_vol_change; if (((struct track_event *)param)->flags & TEF_REWIND)//TEF_AUTO_SKIP return; /* Not a true track end */ switch(id) { case PLAYBACK_EVENT_START_PLAYBACK: triggered_events |= WATCHED_EV(TRIG_EVENT_START_PLAYBACK); break; case PLAYBACK_EVENT_TRACK_SKIP: if (!(((struct track_event *)param)->flags & TEF_AUTO_SKIP)) triggered_events |= WATCHED_EV(TRIG_EVENT_TRACK_SKIP); break; case PLAYBACK_EVENT_TRACK_CHANGE: triggered_events |= WATCHED_EV(TRIG_EVENT_TRACK_CHANGE); break; case PLAYBACK_EVENT_TRACK_FINISH: if (!(((struct track_event *)param)->flags & TEF_REWIND))//TEF_AUTO_SKIP triggered_events |= WATCHED_EV(TRIG_EVENT_TRACK_FINISH); break; case SELF_EVENT_FINALVOL_REACHED: triggered_events |= WATCHED_EV(TRIG_EVENT_VOL_FINAL); break; case SELF_EVENT_TIMEOUT_REACHED: triggered_events |= WATCHED_EV(TRIG_EVENT_TIMEOUT); break; case SELF_EVENT_CHECK_TRIGGERED: last_vol_change = rb->global_status->last_volume_change; if (last_vol_change + TIMEOUT_VOL_CHANGE < *rb->current_tick) triggered_events |= WATCHED_EV(TRIG_EVENT_VOL_CHANGED
I don't think lua scripts work through shortcuts you might try adding the lua_scripts.lua script to shortcuts and see if that works
Page created in 0.057 seconds with 21 queries.