Compare commits

..

15 commits

Author SHA1 Message Date
Franklin Wei
d4d233c31a Correctly update game file download URLs.
Change-Id: I04a967a6a88d2e1440203401ca3022a8ca985177
2019-11-14 19:09:11 -05:00
Franklin Wei
45a9b54f24 rbutil: include nwztools source in release tarball
Change-Id: Ic6d998441fb532a914eea2838fdc0d196f930bb2
2019-11-10 23:09:35 -05:00
Franklin Wei
8d37673a78 rbutil: fix windows release build
This fixes two of them: not finding the lrelease binary and not
compiling for C++11 (which is required by some Qt headers now).

Change-Id: I3c0eb3c2002c3ce7a2eeea877db5fa6942c9b2ba
2019-11-10 23:09:35 -05:00
Franklin Wei
43c049b9ad rbutil: fix windows cross compile (via M cross environment)
This fixes a couple of issues when cross-compiling for windows:
 - lib builds (i.e. mks5lboot) were overriding the cross CC/CXX with the
   native CC, producing incompatible binaries.
 - Qt made the accessibility plugin part of the core library, so we no
   longer need to import it.

Change-Id: I9d884aee62dfa51d3624a3fa9b99c23b3b375f20
2019-11-10 23:09:35 -05:00
Franklin Wei
4d510ab628 Bump versions for 3.15.
Change-Id: Iecea72d420ded89023798e6d613cba1413adec73
2019-11-05 19:39:45 -05:00
Frank Gevaerts
32e9698dac Greek language update. Thanks to Constantine Mountantonakis (FS#13179)
Change-Id: Ie817df92dfbe896512b72f53921d4d682ea54a2f
2019-11-05 19:39:45 -05:00
Franklin Wei
22638ede8d solitaire: reword menu to "Quit without Saving" and "Quit"
Patch submitted by Michael Carr.

Change-Id: I3a1555fe4b6182211203dc8770137e868c76e245
2019-11-05 19:39:45 -05:00
Moshe Piekarski
5f17935ac4 Pacbox AI Improvements
-Make pacbox AI score agnostic.
 -Fix corner case of Game Over/reset with AI on.
 -AI can now start on level where pattern starts facing right.

Change-Id: Ibc5416a53ebc07506c31434051b6d47b276cf668
2019-11-05 19:39:45 -05:00
Franklin Wei
1b76c761d5 rbutil: update game data URLs to official download server
Do not merge until files are in place.

Change-Id: I8e0564f2cfdae0fecde1a56f98cb22f59a4bf9e2
2019-11-05 19:39:45 -05:00
Franklin Wei
c593ad5264 rbutil: extend game file installation
RbUtil will now install freely distributable data files for Duke Nukem 3D,
Quake, SGT-Puzzles (fonts), Wolfenstein 3-D, and Another World. Currently
the urls point to my personal server, pending upload to the main download
server.

Change-Id: I2806fd1ad7e9bb0fcb7aee5444840708e6e63032
2019-11-05 19:39:45 -05:00
Franklin Wei
4d633bb6b8 Add some scripts to automate target listing and generating build-info
This adds tools/list_targets.pl and tools/build-info.pl. list_targets does
exactly what it sounds like - it lists targets by target status. build-info
automates the generation of build-info.release for new releases.

Change-Id: I4c859fdeb54c8cc645832a7c4192f9d18590031e
2019-11-05 19:39:45 -05:00
Franklin Wei
1ea74dc42b wolf3d: change version to shareware
This makes wolf3d work with the shareware files available on the wiki. This
will make things work out-of-the-box with Rockbox Utility.

Change-Id: I9118ecf8715c688565982fc4feb29a8641d68b6a
2019-11-05 19:39:45 -05:00
Franklin Wei
72e00216e1 rbutil: enable ipod6g
Change-Id: Ice8f7fa682c75ccabb52f8d9ef27fa48af4c0689
2019-10-28 17:31:17 -04:00
Franklin Wei
280bbbfba7 Bump RockboxUtility version to 1.4.1
Needed to get ipod6g bootloader support in place for upcoming 3.15 release.

Change-Id: I22ab3f97224577b148baf7197fa57486ee015174
2019-10-28 01:14:10 -04:00
Franklin Wei
67a1465f57 Bump versions for 3.15.
Change-Id: Iecea72d420ded89023798e6d613cba1413adec73
2019-10-28 00:54:52 -04:00
3489 changed files with 206199 additions and 301984 deletions

95
.gitignore vendored
View file

@ -7,20 +7,6 @@
*.so
*.o
*.a
*~
__pycache__
# Intermediate language files
/apps/lang/*.update
/apps/lang/*.new
# checkwps
/tools/checkwps/output
/tools/checkwps/Makefile
/tools/checkwps/autoconf.h
/tools/checkwps/make.dep
/tools/checkwps/rockbox-info.txt
/tools/checkwps/checkwps.failures
# android: java build system
/android/bin
@ -60,48 +46,34 @@ __pycache__
/firmware/test/buflib/test_shrink_startchanged
/firmware/test/buflib/test_shrink_unaligned
# /utils/
/utils/Makefile
/utils/rbutil
# /rbutil/
/rbutil/Makefile
/rbutil/rbutil
# /utils/ipodpatcher/
/utils/ipodpatcher/ipodpatcher
# /rbutil/ipodpatcher/
/rbutil/ipodpatcher/ipodpatcher
# /utils/chinachippatcher/
/utils/chinachippatcher/chinachip
# /rbutil/chinachippatcher/
/rbutil/chinachippatcher/chinachip
# /utils/bspatch/
/utils/bspatch/bspatch
# /rbutil/rbutilqt/
/rbutil/rbutilqt/build
/rbutil/rbutilqt/RockboxUtility
/rbutil/rbutilqt/RockboxUtility.*
/rbutil/rbutilqt/Makefile
/rbutil/rbutilqt/*.qm
/rbutil/rbutilqt/release
/rbutil/rbutilqt/debug
/rbutil/rbutilqt/*.Debug
/rbutil/rbutilqt/*.Release
/rbutil/rbutilqt/tags
# /utils/rbutilqt/
/utils/rbutilqt/build
/utils/rbutilqt/RockboxUtility
/utils/rbutilqt/RockboxUtility.*
/utils/rbutilqt/Makefile
/utils/rbutilqt/*.qm
/utils/rbutilqt/release
/utils/rbutilqt/debug
/utils/rbutilqt/*.Debug
/utils/rbutilqt/*.Release
/utils/rbutilqt/tags
/utils/rbutilqt/.qmake.stash
# /utils/rbutilqt/lang/
/utils/rbutilqt/lang/*.qm
# More rbutil
/utils/*/buildposix
/utils/*/uninstall_script.[ch]
/utils/*/install_script.[ch]
/utils/mkimxboot/mkimxboot
/utils/mknwzboot/mknwzboot
/utils/mkzenboot/mkzenboot
/utils/sansapatcher/sansapatcher
/utils/jztool/jztool
/utils/tools/bin2c
# /rbutil/rbutilqt/lang/
/rbutil/rbutilqt/lang/*.qm
# /tools/
/tools/bdf2bmp
/tools/sh2d
/tools/scramble
/tools/generate_rocklatin
/tools/descramble
@ -110,6 +82,7 @@ __pycache__
/tools/codepages
/tools/rdf2binary
/tools/mkboot
/tools/player_unifont
/tools/uclpack
/tools/ipod_fw
/tools/wavtrim
@ -119,7 +92,6 @@ __pycache__
/tools/mknkboot
/tools/mktccboot
/tools/mkzenboot
/tools/mkspl-x1000
/tools/iaudio_bl_flash.c
/tools/iaudio_bl_flash.h
/tools/.vagrant
@ -129,7 +101,7 @@ __pycache__
/tools/database/database
# /tools/rbspeex/
/tools/rbspeex/build*
/tools/rbspeex/build
/tools/rbspeex/libspeex.a
/tools/rbspeex/librbspeex.a
/tools/rbspeex/dep-speex
@ -163,20 +135,6 @@ __pycache__
/utils/jz4740_tools/jz_xloader.*
/utils/jz4740_tools/bin2c
# /utils/jz4760_tools
/utils/jz4760_tools/packtools
/utils/jz4760_tools/usbboot
# /utils/ingenic_tools
/utils/ingenic_tools/usbboot
# /utils/nwztools
/utils/nwztools/scsitools/scsitool
/utils/nwztools/upgtools/upgtool
# utils/rk27utils
/utils/rk27utils/rkboottool/rkboottool
# /utils/themeeditor/
/utils/themeeditor/debug
/utils/themeeditor/release
@ -294,10 +252,3 @@ __pycache__
/utils/zenutils/source/zen_crypt/CMakeFiles
/utils/zenutils/source/zen_crypt/cmake_install.cmake
/utils/zenutils/source/zen_crypt/Makefile
# /utils/regtools/
/utils/regtools/headergen_v1
/utils/regtools/headergen_v2
/utils/regtools/regtool
/utils/regtools/swiss_knife
/utils/regtools/tester_v1

View file

@ -1,5 +0,0 @@
[gerrit]
host=gerrit.rockbox.org
port=29418
project=rockbox.git
defaultbranch=master

View file

@ -28,13 +28,11 @@ $(CPUFEAT_BUILD)/cpu-features.o: $(CPUFEAT)/cpu-features.c
.PHONY: apk classes clean dex dirs libs jar
# API version
#ANDROID_PLATFORM_VERSION=19 # Set by configure script
ANDROID_PLATFORM_VERSION=19
ANDROID_PLATFORM=$(ANDROID_SDK_PATH)/platforms/android-$(ANDROID_PLATFORM_VERSION)
# Use oldest version available..
BUILD_TOOLS_VERSION=$(notdir $(firstword $(wildcard $(ANDROID_SDK_PATH)/build-tools/*)))
# android tools
BUILD_TOOLS_VERSION=$(notdir $(firstword $(wildcard $(ANDROID_SDK_PATH)/build-tools/$(ANDROID_PLATFORM_VERSION).*)))
AAPT=$(ANDROID_SDK_PATH)/build-tools/$(BUILD_TOOLS_VERSION)/aapt
DX=$(ANDROID_SDK_PATH)/build-tools/$(BUILD_TOOLS_VERSION)/dx
ifneq ("$(wildcard $(ANDROID_SDK_PATH)/tools/zipalign)","")

View file

@ -7,7 +7,6 @@ alarm_menu.c
#endif
abrepeat.c
bookmark.c
core_keymap.c
debug_menu.c
filetypes.c
language.c
@ -20,6 +19,7 @@ menus/plugin_menu.c
#if CONFIG_TUNER
menus/radio_menu.c
#endif
#if CONFIG_CODEC == SWCODEC
#ifdef HAVE_WM8978
menus/audiohw_eq_menu.c
#endif
@ -27,6 +27,9 @@ menus/eq_menu.c
buffering.c
voice_thread.c
rbcodec_helpers.c
#else /* !SWCODEC */
mpeg.c
#endif
menus/main_menu.c
menus/playback_menu.c
menus/playlist_menu.c
@ -39,7 +42,6 @@ menus/sound_menu.c
menus/time_menu.c
#endif
misc.c
open_plugin.c
onplay.c
playlist.c
playlist_catalog.c
@ -58,6 +60,7 @@ tree.c
tagtree.c
#endif
filetree.c
scrobbler.c
#ifdef IPOD_ACCESSORY_PROTOCOL
iap/iap-core.c
iap/iap-lingo0.c
@ -67,16 +70,23 @@ iap/iap-lingo1.c
iap/iap-lingo2.c
iap/iap-lingo3.c
iap/iap-lingo4.c
#if CONFIG_TUNER
iap/iap-lingo7.c
#endif
#endif
screen_access.c
#ifdef HAVE_BUTTONBAR
gui/buttonbar.c
#endif
#ifdef HAVE_LCD_BITMAP
gui/icon.c
#endif
gui/list.c
gui/line.c
#ifdef HAVE_LCD_BITMAP
gui/bitmap/list.c
gui/bitmap/list-skinned.c
#else
gui/charcell/list.c
#endif
gui/option_select.c
#ifdef HAVE_PITCHCONTROL
gui/pitchscreen.c
@ -93,7 +103,9 @@ gui/wps.c
gui/scrollbar.c
gui/splash.c
gui/statusbar.c
#ifdef HAVE_LCD_BITMAP
gui/statusbar-skinned.c
#endif
#if (CONFIG_PLATFORM&PLATFORM_ANDROID)
hosted/android/yesno.c
hosted/android/notification.c
@ -116,6 +128,11 @@ gui/skin_engine/skin_touchsupport.c
gui/backdrop.c
#endif
#ifdef HAVE_LCD_CHARCELLS
player/icons.c
player/keyboard.c
#endif
#ifdef HAVE_LCD_BITMAP
recorder/bmp.c
recorder/icons.c
#if (CONFIG_PLATFORM&PLATFORM_ANDROID)
@ -139,7 +156,7 @@ recorder/albumart.c
#ifdef HAVE_LCD_COLOR
gui/color_picker.c
#endif
#endif
#ifdef HAVE_RECORDING
recorder/recording.c
#endif
@ -153,6 +170,7 @@ radio/radioart.c
#endif
#endif
#if CONFIG_CODEC == SWCODEC
#if INPUT_SRC_CAPS != 0
audio_path.c
#endif /* INPUT_SRC_CAPS != 0 */
@ -168,6 +186,7 @@ beep.c
enc_config.c
recorder/pcm_record.c
#endif
#endif
#ifdef USB_ENABLE_HID
usb_keymaps.c
#endif
@ -187,6 +206,12 @@ keymaps/keymap-h1x0_h3x0.c
|| (CONFIG_KEYPAD == IPOD_3G_PAD) \
|| (CONFIG_KEYPAD == IPOD_1G2G_PAD))
keymaps/keymap-ipod.c
#elif CONFIG_KEYPAD == RECORDER_PAD
keymaps/keymap-recorder.c
#elif CONFIG_KEYPAD == ONDIO_PAD
keymaps/keymap-ondio.c
#elif CONFIG_KEYPAD == PLAYER_PAD
keymaps/keymap-player.c
#elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
keymaps/keymap-x5.c
#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
@ -197,6 +222,8 @@ keymaps/keymap-gigabeat.c
keymaps/keymap-gigabeat-s.c
#elif CONFIG_KEYPAD == IRIVER_H10_PAD
keymaps/keymap-h10.c
#elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
keymaps/keymap-ifp7xx.c
#elif CONFIG_KEYPAD == SANSA_E200_PAD
keymaps/keymap-e200.c
#elif CONFIG_KEYPAD == SANSA_C200_PAD
@ -205,6 +232,8 @@ keymaps/keymap-c200.c
keymaps/keymap-m200.c
#elif CONFIG_KEYPAD == SANSA_CLIP_PAD
keymaps/keymap-clip.c
#elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
keymaps/keymap-av300.c
#elif CONFIG_KEYPAD == MROBE500_PAD
keymaps/keymap-mr500.c
#elif CONFIG_KEYPAD == MROBE100_PAD
@ -229,6 +258,12 @@ keymaps/keymap-sa9200.c
keymaps/keymap-hdd1630.c
#elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
keymaps/keymap-hdd6330.c
#elif CONFIG_KEYPAD == IAUDIO67_PAD
keymaps/keymap-iaudio67.c
#elif CONFIG_KEYPAD == SANSA_C100_PAD
keymaps/keymap-c100.c
#elif CONFIG_KEYPAD == LOGIK_DAX_PAD
keymaps/keymap-logikdax.c
#elif CONFIG_KEYPAD == SANSA_FUZE_PAD
keymaps/keymap-fuze.c
#elif CONFIG_KEYPAD == ONDAVX747_PAD
@ -272,6 +307,8 @@ keymaps/keymap-ma.c
keymaps/keymap-nwz.c
#elif CONFIG_KEYPAD == SONY_NWZA860_PAD
keymaps/keymap-nwza860.c
#elif CONFIG_KEYPAD == SAMSUNG_YPZ5_PAD
keymaps/keymap-ypz5.c
#elif CONFIG_KEYPAD == IHIFI_PAD
keymaps/keymap-ihifi.c
#elif CONFIG_KEYPAD == IHIFI_770_PAD
@ -286,16 +323,4 @@ keymaps/keymap-dx50.c
keymaps/keymap-agptekrocker.c
#elif CONFIG_KEYPAD == XDUOO_X3_PAD
keymaps/keymap-xduoox3.c
#elif CONFIG_KEYPAD == XDUOO_X3II_PAD
keymaps/keymap-xduoox3ii.c
#elif CONFIG_KEYPAD == XDUOO_X20_PAD
keymaps/keymap-xduoox20.c
#elif CONFIG_KEYPAD == FIIO_M3K_LINUX_PAD
keymaps/keymap-fiiom3klinux.c
#elif CONFIG_KEYPAD == FIIO_M3K_PAD
keymaps/keymap-fiiom3k.c
#elif CONFIG_KEYPAD == EROSQ_PAD
keymaps/keymap-erosq.c
#elif CONFIG_KEYPAD == SHANLING_Q1_PAD
keymaps/keymap-shanlingq1.c
#endif

View file

@ -39,6 +39,7 @@ static inline bool ab_B_marker_set(void)
}
#if (CONFIG_CODEC == SWCODEC)
void ab_end_of_track_report(void)
{
if ( ab_A_marker_set() && ! ab_B_marker_set() )
@ -46,6 +47,38 @@ void ab_end_of_track_report(void)
ab_jump_to_A_marker();
}
}
#else
static int ab_audio_event_handler(unsigned short event, unsigned long data)
{
int rc = AUDIO_EVENT_RC_IGNORED;
if ( ab_repeat_mode_enabled() )
{
switch(event)
{
case AUDIO_EVENT_POS_REPORT:
{
if ( ! (audio_status() & AUDIO_STATUS_PAUSE) &&
ab_reached_B_marker(data) )
{
ab_jump_to_A_marker();
rc = AUDIO_EVENT_RC_HANDLED;
}
break;
}
case AUDIO_EVENT_END_OF_TRACK:
{
if ( ab_A_marker_set() && ! ab_B_marker_set() )
{
ab_jump_to_A_marker();
rc = AUDIO_EVENT_RC_HANDLED;
}
break;
}
}
}
return rc;
}
#endif
void ab_repeat_init(void)
{
@ -53,6 +86,10 @@ void ab_repeat_init(void)
if ( ! ab_initialized )
{
ab_initialized = true;
#if (CONFIG_CODEC != SWCODEC)
audio_register_event_handler(ab_audio_event_handler,
AUDIO_EVENT_POS_REPORT | AUDIO_EVENT_END_OF_TRACK );
#endif
}
}
@ -79,7 +116,16 @@ reasonable amount of time for the typical user to react */
void ab_jump_to_A_marker(void)
{
#if (CONFIG_CODEC != SWCODEC)
bool paused = (audio_status() & AUDIO_STATUS_PAUSE) != 0;
if ( ! paused )
audio_pause();
#endif
audio_ff_rewind(ab_A_marker);
#if (CONFIG_CODEC != SWCODEC)
if ( ! paused )
audio_resume();
#endif
}
void ab_reset_markers(void)

View file

@ -20,38 +20,9 @@
****************************************************************************/
#ifndef _ABREPEAT_H_
#define _ABREPEAT_H_
#ifdef AB_REPEAT_ENABLE
#include <stdbool.h>
#ifndef AB_REPEAT_ENABLE /* Dummy functions */
static inline bool ab_repeat_mode_enabled(void)
{
return false;
}
static inline bool ab_bool_dummy_marker(unsigned int song_position)
{
(void) song_position;
return false;
}
static inline void ab_void_dummy_marker(unsigned int song_position)
{
(void) song_position;
}
static inline void ab_dummy_voidfn(void){}
#define ab_repeat_init ab_dummy_voidfn
#define ab_before_A_marker ab_bool_dummy_marker
#define ab_after_A_marker ab_bool_dummy_marker
#define ab_jump_to_A_marker ab_dummy_voidfn
#define ab_reset_markers ab_dummy_voidfn
#define ab_set_A_marker ab_void_dummy_marker
#define ab_set_B_marker ab_void_dummy_marker
#define ab_get_A_marker ab_bool_dummy_marker
#define ab_get_B_marker ab_bool_dummy_marker
#define ab_end_of_track_report ab_dummy_voidfn
#define ab_reached_B_marker ab_bool_dummy_marker
#define ab_position_report ab_void_dummy_marker
#else /*def AB_REPEAT_ENABLE*/
#include "audio.h"
#include "kernel.h" /* needed for HZ */
@ -70,7 +41,9 @@ void ab_set_B_marker(unsigned int song_position);
* The actual positions are returned via output parameter */
bool ab_get_A_marker(unsigned int *song_position);
bool ab_get_B_marker(unsigned int *song_position);
#if (CONFIG_CODEC == SWCODEC)
void ab_end_of_track_report(void);
#endif
/* These functions really need to be inlined for speed */
extern unsigned int ab_A_marker;
@ -86,9 +59,16 @@ static inline bool ab_reached_B_marker(unsigned int song_position)
/* following is the size of the window in which we'll detect that the B marker
was hit; it must be larger than the frequency (in milliseconds) at which this
function is called otherwise detection of the B marker will be unreliable */
#if (CONFIG_CODEC == SWCODEC)
/* On swcodec, the worst case seems to be 9600kHz with 1024 samples between
* calls, meaning ~9 calls per second, look within 1/5 of a second */
#define B_MARKER_DETECT_WINDOW 200
#else
/* we assume that this function will be called on each system tick and derive
the window size from this with a generous margin of error (note: the number
of ticks per second is given by HZ) */
#define B_MARKER_DETECT_WINDOW ((1000/HZ)*10)
#endif
if (ab_B_marker != AB_MARKER_NONE)
{
if ( (song_position >= ab_B_marker)
@ -98,6 +78,7 @@ function is called otherwise detection of the B marker will be unreliable */
return false;
}
#if (CONFIG_CODEC == SWCODEC)
static inline void ab_position_report(unsigned long position)
{
if (ab_repeat_mode_enabled())
@ -109,6 +90,7 @@ static inline void ab_position_report(unsigned long position)
}
}
}
#endif
#endif

View file

@ -26,7 +26,7 @@
#include "config.h"
#include "lang.h"
#if !defined(BOOTLOADER)
#if defined(HAVE_LCD_BITMAP) && !defined(BOOTLOADER)
#include "language.h"
#endif
@ -34,7 +34,6 @@
#include "button.h"
#include "action.h"
#include "kernel.h"
#include "core_alloc.h"
#include "splash.h"
#include "settings.h"
@ -70,10 +69,6 @@ static action_last_t action_last =
.tick = 0,
.wait_for_release = false,
#ifndef DISABLE_ACTION_REMAP
.key_remap = 0,
#endif
#ifdef HAVE_TOUCHSCREEN
.ts_data = 0,
.ts_short_press = false,
@ -125,7 +120,7 @@ static bool is_action_filtered(int action, unsigned int mask, int context)
{
case ACTION_NONE:
break;
/* Actions that are not mapped will not turn on the backlight */
/*Actions that are not mapped will not turn on the backlight option NOUNMAPPED*/
case ACTION_UNKNOWN:
match = has_flag(mask, SEL_ACTION_NOUNMAPPED);
break;
@ -133,25 +128,21 @@ static bool is_action_filtered(int action, unsigned int mask, int context)
case ACTION_FM_PLAY:
match = has_flag(mask, SEL_ACTION_PLAY);
break;
/* case ACTION_STD_PREVREPEAT:*/ /* seek not exempted outside of WPS */
/* case ACTION_STD_NEXTREPEAT: */
case ACTION_STD_PREVREPEAT:
case ACTION_STD_NEXTREPEAT:
case ACTION_WPS_SEEKBACK:
case ACTION_WPS_SEEKFWD:
case ACTION_WPS_STOPSEEK:
match = has_flag(mask, SEL_ACTION_SEEK);
break;
/* case ACTION_STD_PREV: */ /* skip/scrollwheel not */
/* case ACTION_STD_NEXT: */ /* exempted outside of WPS */
case ACTION_STD_PREV:
case ACTION_STD_NEXT:
case ACTION_WPS_SKIPNEXT:
case ACTION_WPS_SKIPPREV:
case ACTION_FM_NEXT_PRESET:
case ACTION_FM_PREV_PRESET:
match = has_flag(mask, SEL_ACTION_SKIP);
break;
#ifdef HAVE_VOLUME_IN_LIST
case ACTION_LIST_VOLUP: /* volume exempted outside of WPS */
case ACTION_LIST_VOLDOWN: /* ( if the device supports it )*/
#endif
case ACTION_WPS_VOLUP:
case ACTION_WPS_VOLDOWN:
match = has_flag(mask, SEL_ACTION_VOL);
@ -410,7 +401,6 @@ static inline bool get_action_touchscreen(action_last_t *last, action_cur_t *cur
}
last->button = cur->button;
last->tick = current_tick;
cur->action = ACTION_TOUCHSCREEN;
return true;
}
@ -431,7 +421,7 @@ static inline bool get_action_touchscreen(action_last_t *last, action_cur_t *cur
static inline void button_flip_horizontally(int context, int *button)
{
#if defined(BOOTLOADER)
#if !defined(HAVE_LCD_BITMAP) || defined(BOOTLOADER)
(void) context;
(void) *button;
return;
@ -444,7 +434,6 @@ static inline void button_flip_horizontally(int context, int *button)
return;
}
#if defined(BUTTON_LEFT) && defined(BUTTON_RIGHT)
newbutton &= ~(BUTTON_LEFT | BUTTON_RIGHT);
if (has_flag(*button, BUTTON_LEFT))
{
@ -455,10 +444,6 @@ static inline void button_flip_horizontally(int context, int *button)
{
newbutton |= BUTTON_LEFT;
}
#else
#warning "BUTTON_LEFT / BUTTON_RIGHT not defined!"
#endif
#ifndef SIMULATOR
#ifdef HAVE_SCROLLWHEEL
newbutton &= ~(BUTTON_SCROLL_BACK | BUTTON_SCROLL_FWD);
@ -488,7 +473,7 @@ static inline void button_flip_horizontally(int context, int *button)
#endif /* !SIMULATOR */
*button = newbutton;
#endif /* !BOOTLOADER */
#endif /* !HAVE_LCD_BITMAP | BOOTLOADER */
} /* button_flip_horizontally */
/**********************************************************************
@ -504,7 +489,7 @@ static inline int action_code_worker(action_last_t *last,
int *end )
{
int ret = ACTION_UNKNOWN;
int i = *end;
int i = 0;
unsigned int found = 0;
while (cur->items[i].button_code != BUTTON_NONE)
{
@ -588,52 +573,14 @@ static inline int get_next_context(const struct button_mapping *items, int i)
* for a more in-depth explanation
* places action into current_action
*/
static inline void action_code_lookup(action_last_t *last, action_cur_t *cur)
{
int action, i;
int action = ACTION_NONE;
int context = cur->context;
int i = 0;
cur->is_prebutton = false;
#if !defined(HAS_BUTTON_HOLD) && !defined(BOOTLOADER)
/* This only applies to the first context, to allow locked contexts to
* specify a fall through to their non-locked version */
if (is_keys_locked())
context |= CONTEXT_LOCKED;
#endif
#ifndef DISABLE_ACTION_REMAP
/* attempt to look up the button in user supplied remap */
if(last->key_remap && (context & CONTEXT_PLUGIN) == 0)
{
if ((cur->button & BUTTON_REMOTE) != 0)
{
context |= CONTEXT_REMOTE;
}
cur->items = core_get_data(last->key_remap);
i = 0;
action = ACTION_UNKNOWN;
/* check the lut at the beginning for the desired context */
while (cur->items[i].button_code != BUTTON_NONE)
{
if (cur->items[i].action_code == CORE_CONTEXT_REMAP(context))
{
i = cur->items[i].button_code;
action = action_code_worker(last, cur, &i);
if (action != ACTION_UNKNOWN)
{
cur->action = action;
return;
}
}
i++;
}
}
#endif
i = 0;
action = ACTION_NONE;
/* attempt to look up the button in the in-built keymaps */
for(;;)
{
/* logf("context = %x",context); */
@ -645,13 +592,9 @@ static inline void action_code_lookup(action_last_t *last, action_cur_t *cur)
#endif
if ((context & CONTEXT_PLUGIN) && cur->get_context_map)
{
cur->items = cur->get_context_map(context);
}
else
{
cur->items = get_context_mapping(context);
}
if (cur->items != NULL)
{
@ -724,60 +667,27 @@ static inline int do_auto_softlock(action_last_t *last, action_cur_t *cur)
if (is_timeout)
{
do_key_lock(true);
#if defined(HAVE_TOUCHPAD) || defined(HAVE_TOUCHSCREEN)
/* if the touchpad is supposed to be off and the current buttonpress
* is from the touchpad, nullify both button and action. */
if (!has_flag(action_last.softlock_mask, SEL_ACTION_ENABLED) ||
has_flag(action_last.softlock_mask, SEL_ACTION_NOTOUCH))
{
#if defined(HAVE_TOUCHPAD)
cur->button = touchpad_filter(cur->button);
#endif
#if defined(HAVE_TOUCHSCREEN)
const int touch_fakebuttons =
BUTTON_TOPLEFT | BUTTON_TOPMIDDLE | BUTTON_TOPRIGHT |
BUTTON_LEFT | BUTTON_CENTER | BUTTON_RIGHT |
BUTTON_BOTTOMLEFT | BUTTON_BOTTOMMIDDLE | BUTTON_BOTTOMRIGHT;
if (has_flag(cur->button, BUTTON_TOUCHSCREEN))
cur->button = BUTTON_NONE;
else
cur->button &= ~touch_fakebuttons;
#endif
if (cur->button == BUTTON_NONE)
{
action = ACTION_NONE;
}
}
#endif
}
else if (action == ACTION_STD_KEYLOCK)
{
if (!has_flag(last->softlock_mask, SEL_ACTION_ALWAYSAUTOLOCK)) // normal operation, clear/arm autolock
last->unlock_combo = cur->button;/* set unlock combo to allow unlock */
last->softlock_mask ^= SEL_ACTION_ALOCK_OK;
action_handle_backlight(true, false);
/* If we don't wait for a moment for the backlight queue
* to process, the user will never see the message */
if (!is_backlight_on(false))
{
last->unlock_combo = cur->button;/* set unlock combo to allow unlock */
last->softlock_mask ^= SEL_ACTION_ALOCK_OK;
action_handle_backlight(true, false);
/* If we don't wait for a moment for the backlight queue
* to process, the user will never see the message */
if (!is_backlight_on(false))
{
sleep(HZ/2);
}
sleep(HZ/2);
}
if (has_flag(last->softlock_mask, SEL_ACTION_ALOCK_OK))
{
splash(HZ/2, ID2P(LANG_ACTION_AUTOLOCK_ON));
action = ACTION_REDRAW;
}
else
{
splash(HZ/2, ID2P(LANG_ACTION_AUTOLOCK_OFF));
}
} else if (!has_flag(last->softlock_mask, SEL_ACTION_ALOCK_OK)) // always autolock, but not currently armed
if (has_flag(last->softlock_mask, SEL_ACTION_ALOCK_OK))
{
last->unlock_combo = cur->button;/* set unlock combo to allow unlock */
last->softlock_mask ^= SEL_ACTION_ALOCK_OK;
splash(HZ/2, ID2P(LANG_ACTION_AUTOLOCK_ON));
action = ACTION_REDRAW;
}
else
{
splash(HZ/2, ID2P(LANG_ACTION_AUTOLOCK_OFF));
}
}
@ -802,11 +712,8 @@ static inline void do_softlock(action_last_t *last, action_cur_t *cur)
#else
int action = cur->action;
/* check to make sure we don't get stuck without a way to unlock - if locked,
* we can still use unlock_combo to unlock */
if (!last->screen_has_lock && !last->keys_locked)
{
/* no need to check softlock return immediately */
if (!last->screen_has_lock)
{ /* no need to check softlock return immediately */
return;
}
@ -818,19 +725,10 @@ static inline void do_softlock(action_last_t *last, action_cur_t *cur)
{
action = do_auto_softlock(last, cur);
}
/* Lock/Unlock toggled by ACTION_STD_KEYLOCK presses*/
if ((action == ACTION_STD_KEYLOCK)
|| (last->keys_locked && last->unlock_combo == cur->button))
{
#ifdef HAVE_BACKLIGHT
// if backlight is off and keys are unlocked, do nothing and exit.
// The backlight should come on without locking keypad.
if ((!last->keys_locked) && (!is_backlight_on(false)))
{
return;
}
#endif
last->unlock_combo = cur->button;
do_key_lock(!last->keys_locked);
notify_user = true;
@ -885,16 +783,13 @@ static inline void do_softlock(action_last_t *last, action_cur_t *cur)
sleep(HZ/2);
}
#endif
if (!has_flag(last->softlock_mask, SEL_ACTION_ALLNONOTIFY))
if (last->keys_locked)
{
if (last->keys_locked)
{
splash(HZ/2, ID2P(LANG_KEYLOCK_ON));
}
else
{
splash(HZ/2, ID2P(LANG_KEYLOCK_OFF));
}
splash(HZ/2, ID2P(LANG_KEYLOCK_ON));
}
else
{
splash(HZ/2, ID2P(LANG_KEYLOCK_OFF));
}
action = ACTION_REDRAW;
@ -937,8 +832,10 @@ static inline int update_action_last(action_last_t *last, action_cur_t *cur)
last->data = button_get_data();
last->tick = current_tick;
#if CONFIG_CODEC == SWCODEC
/* Produce keyclick */
keyclick_click(false, action);
#endif
return action;
}
@ -1000,8 +897,7 @@ static inline int do_backlight(action_last_t *last, action_cur_t *cur, int actio
&& power_input_present());
#endif
/* skip if backlight on | incorrect context | SEL_ACTION_NOEXT + ext pwr */
if (bl_is_off && (cur->context == CONTEXT_FM || cur->context == CONTEXT_WPS ||
cur->context == CONTEXT_MAINMENU))
if ((cur->context == CONTEXT_FM || cur->context == CONTEXT_WPS) && bl_is_off)
{
filtered = is_action_filtered(action, last->backlight_mask, cur->context);
bl_activate = !is_action_discarded(cur, filtered, &last->bl_filter_tick);
@ -1062,7 +958,6 @@ static int get_action_worker(action_last_t *last, action_cur_t *cur)
if (get_action_touchscreen(last, cur))
{
do_softlock(last, cur);
return cur->action;
}
@ -1191,92 +1086,6 @@ int get_action(int context, int timeout)
return action;
}
int action_set_keymap(struct button_mapping* core_keymap, int count)
{
#ifdef DISABLE_ACTION_REMAP
(void)core_keymap;
(void)count;
return -1;
#else
if (count <= 0 || core_keymap == NULL)
return action_set_keymap_handle(0, 0);
size_t keyremap_buf_size = count * sizeof(struct button_mapping);
int handle = core_alloc(keyremap_buf_size);
if (handle < 0)
return -6;
memcpy(core_get_data(handle), core_keymap, keyremap_buf_size);
return action_set_keymap_handle(handle, count);
#endif
}
int action_set_keymap_handle(int handle, int count)
{
#ifdef DISABLE_ACTION_REMAP
(void)core_keymap;
(void)count;
return -1;
#else
/* free an existing remap */
action_last.key_remap = core_free(action_last.key_remap);
/* if clearing the remap, we're done */
if (count <= 0 || handle <= 0)
return 0;
/* validate the keymap */
struct button_mapping* core_keymap = core_get_data(handle);
struct button_mapping* entry = &core_keymap[count - 1];
if (entry->action_code != (int) CONTEXT_STOPSEARCHING ||
entry->button_code != BUTTON_NONE) /* check for sentinel at end*/
{
/* missing sentinel entry */
return -1;
}
/* check the lut at the beginning for invalid offsets */
for (int i = 0; i < count; ++i)
{
entry = &core_keymap[i];
if (entry->action_code == (int)CONTEXT_STOPSEARCHING)
break;
if ((entry->action_code & CONTEXT_REMAPPED) == CONTEXT_REMAPPED)
{
int firstbtn = entry->button_code;
int endpos = firstbtn + entry->pre_button_code;
if (firstbtn > count || firstbtn < i || endpos > count)
{
/* offset out of bounds */
return -2;
}
if (core_keymap[endpos].button_code != BUTTON_NONE)
{
/* stop sentinel is not at end of action lut */
return -3;
}
}
else
{
/* something other than a context remap in the lut */
return -4;
}
if (i+1 >= count)
{
/* no sentinel in the lut */
return -5;
}
}
/* success */
action_last.key_remap = handle;
return count;
#endif
}
int get_custom_action(int context,int timeout,
const struct button_mapping* (*get_context_map)(int))
{
@ -1338,7 +1147,7 @@ void set_selective_backlight_actions(bool selective, unsigned int mask,
#ifndef HAS_BUTTON_HOLD
bool is_keys_locked(void)
{
return (action_last.keys_locked);
return (action_last.screen_has_lock && action_last.keys_locked);
}
/* Enable selected actions to bypass a locked state */
@ -1354,60 +1163,7 @@ void set_selective_softlock_actions(bool selective, unsigned int mask)
action_last.softlock_mask = SEL_ACTION_NONE;
}
}
/* look for an action in the given context, return button which triggers it.
* (note: pre_button isn't taken into account here) */
static int find_button_for_action(int context, int action)
{
const struct button_mapping *items;
int i;
do
{
items = get_context_mapping(context);
if (items == NULL)
break;
for (i = 0; items[i].button_code != BUTTON_NONE; ++i)
{
if (items[i].action_code == action)
return items[i].button_code;
}
/* get chained context, if none it will be CONTEXT_STOPSEARCHING */
context = items[i].action_code;
} while (context != (int)CONTEXT_STOPSEARCHING);
return BUTTON_NONE;
}
void action_autosoftlock_init(void)
{
/* search in WPS and STD contexts for the keylock button combo */
static const int contexts[2] = { CONTEXT_WPS, CONTEXT_STD };
for (int i = 0; i < 2; ++i)
{
int button = find_button_for_action(contexts[i], ACTION_STD_KEYLOCK);
if (button != BUTTON_NONE)
{
action_last.unlock_combo = button;
break;
}
}
/* if we have autolock and alwaysautolock, go ahead and arm it */
if (has_flag(action_last.softlock_mask, SEL_ACTION_AUTOLOCK) &&
has_flag(action_last.softlock_mask, SEL_ACTION_ALWAYSAUTOLOCK) &&
(action_last.unlock_combo != BUTTON_NONE))
{
action_last.softlock_mask = action_last.softlock_mask | SEL_ACTION_ALOCK_OK;
}
return;
}
#endif /* !HAS_BUTTON_HOLD */
/*
*******************************************************************************
* END EXPORTED ACTION FUNCTIONS ***********************************************

View file

@ -28,15 +28,10 @@
#define TIMEOUT_NOBLOCK 0
#define CONTEXT_STOPSEARCHING 0xFFFFFFFF
#define CONTEXT_REMOTE 0x80000000 /* | this against another context to get remote buttons for that context */
#define CONTEXT_CUSTOM 0x40000000 /* | this against anything to get your context number */
#define CONTEXT_CUSTOM2 0x20000000 /* as above */
#define CONTEXT_PLUGIN 0x10000000 /* for plugins using get_custom_action */
#define CONTEXT_REMAPPED 0x08000000 /* marker for key remap context table */
#define CORE_CONTEXT_REMAP(context) (CONTEXT_REMAPPED | context)
#define CONTEXT_LOCKED 0x04000000 /* flag to use alternate keymap when screen is locked */
#define LAST_ITEM_IN_LIST { CONTEXT_STOPSEARCHING, BUTTON_NONE, BUTTON_NONE }
#define LAST_ITEM_IN_LIST__NEXTLIST(a) { a, BUTTON_NONE, BUTTON_NONE }
@ -55,8 +50,8 @@
#define SEL_ACTION_SEEK 0x004U
#define SEL_ACTION_SKIP 0x008U
#define SEL_ACTION_NOUNMAPPED 0x010U/* disable backlight on unmapped buttons */
#define SEL_ACTION_ALLNONOTIFY 0x020U/* disable switch for all softlock notifications */
#define SEL_ACTION_ALWAYSAUTOLOCK 0x040U/* always prime autolock, requires autolock enabled */
/* Available 0x020U*/
/* Available 0x040U*/
#define SEL_ACTION_NOTOUCH 0x080U/* disable touch screen/pad on screen lock */
#define SEL_ACTION_AUTOLOCK 0x100U/* autolock on backlight off */
#define SEL_ACTION_NOEXT 0x200U/* disable selective backlight while charge*/
@ -70,17 +65,10 @@
#if !defined(HAS_BUTTON_HOLD)
/* returns true if keys_locked and screen_has_lock */
bool is_keys_locked(void);
/* Enable selected actions to bypass a locked state
* mask is combination of Selective action selection flags */
void set_selective_softlock_actions(bool selective, unsigned int mask);
/* search the standard and wps contexts for ACTION_STD_KEYLOCK,
* load it into unlock_combo if we find it,
* also arm autolock if enabled. */
void action_autosoftlock_init(void);
#endif /* !defined(HAS_BUTTON_HOLD) */
#endif
#if defined(HAVE_BACKLIGHT)
/* Enable selected actions to leave the backlight off
@ -94,7 +82,7 @@ void set_selective_backlight_actions(bool selective, unsigned int mask,
enum {
CONTEXT_STD = 0,
/* These CONTEXT_ values were here before me,
their values may have significance, so dont touch! */
there values may have significance, so dont touch! */
CONTEXT_WPS = 1,
CONTEXT_TREE = 2,
CONTEXT_RECORD = 3,
@ -131,7 +119,6 @@ enum {
CONTEXT_USB_HID_MODE_PRESENTATION,
CONTEXT_USB_HID_MODE_BROWSER,
CONTEXT_USB_HID_MODE_MOUSE,
LAST_CONTEXT_PLACEHOLDER,
};
@ -159,6 +146,7 @@ enum {
ACTION_STD_REC,
ACTION_STD_HOTKEY,
ACTION_F3, /* just so everything works again, possibly change me */
/* code context actions */
/* WPS codes */
@ -247,6 +235,7 @@ enum {
ACTION_SETTINGS_DEC,
ACTION_SETTINGS_DECREPEAT,
ACTION_SETTINGS_DECBIGSTEP,
ACTION_SETTINGS_RESET,
ACTION_SETTINGS_SET, /* Used by touchscreen targets */
/* bookmark screen */
@ -257,8 +246,6 @@ enum {
ACTION_QS_RIGHT,
ACTION_QS_DOWN,
ACTION_QS_TOP,
ACTION_QS_VOLUP,
ACTION_QS_VOLDOWN,
/* pitchscreen */
/* obviously ignore if you dont have thise screen */
@ -417,10 +404,6 @@ typedef struct
bool repeated;
bool wait_for_release;
#ifndef DISABLE_ACTION_REMAP
int key_remap;
#endif
#ifdef HAVE_TOUCHSCREEN
bool ts_short_press;
int ts_data;
@ -447,11 +430,6 @@ bool action_userabort(int timeout);
/* no other code should need this apart from action.c */
const struct button_mapping* get_context_mapping(int context);
/* load a key map to allow buttons for actions to be remapped see: core_keymap */
int action_set_keymap(struct button_mapping* core_keymap, int count);
/* load keymap in a handle: takes ownership of the handle on success */
int action_set_keymap_handle(int handle, int count);
/* returns the status code variable from action.c for the button just pressed
If button != NULL it will be set to the actual button code */
#define ACTION_REMOTE 0x1 /* remote was pressed */

View file

@ -38,56 +38,160 @@
#include "splash.h"
#include "viewport.h"
static void speak_time(int hours, int minutes, bool speak_hours, bool enqueue)
{
if (global_settings.talk_menu){
if(speak_hours) {
talk_value(hours, UNIT_HOUR, enqueue);
talk_value(minutes, UNIT_MIN, true);
} else {
talk_value(minutes, UNIT_MIN, enqueue);
}
}
}
int alarm_screen(void)
{
bool usb, update;
struct tm *now = get_time();
struct tm atm;
memcpy(&atm, now, sizeof(struct tm));
rtc_get_alarm(&atm.tm_hour, &atm.tm_min);
int h, m;
bool done = false;
struct tm *tm;
int togo;
int button;
bool update = true;
bool hour_wrapped = false;
struct viewport vp[NB_SCREENS];
rtc_get_alarm(&h, &m);
/* After a battery change the RTC values are out of range */
if (!valid_time(&atm))
memcpy(&atm, now, sizeof(struct tm));
atm.tm_sec = 0;
usb = set_time_screen(str(LANG_ALARM_MOD_TIME), &atm, false);
update = valid_time(&atm); /* set_time returns invalid time if canceled */
if (!usb && update)
if (m > 60 || h > 24) {
m = 0;
h = 12;
} else {
m = m / 5 * 5; /* 5 min accuracy should be enough */
}
FOR_NB_SCREENS(i)
{
viewport_set_defaults(&vp[i], i);
}
now = get_time();
int nmins = now->tm_min + (now->tm_hour * 60);
int amins = atm.tm_min + (atm.tm_hour * 60);
int mins_togo = (amins - nmins + 1440) % 1440;
while(!done) {
if(update)
{
FOR_NB_SCREENS(i)
{
screens[i].set_viewport(&vp[i]);
screens[i].clear_viewport();
screens[i].puts(0, 4, str(LANG_ALARM_MOD_KEYS));
}
/* Talk when entering the wakeup screen */
speak_time(h, m, true, true);
update = false;
}
FOR_NB_SCREENS(i)
{
screens[i].set_viewport(&vp[i]);
screens[i].putsf(0, 1, str(LANG_ALARM_MOD_TIME));
screens[i].putsf(0, 2, "%02d:%02d", h, m);
screens[i].update_viewport();
screens[i].set_viewport(NULL);
}
button = get_action(CONTEXT_SETTINGS,HZ);
switch(button) {
case ACTION_STD_OK:
/* prevent that an alarm occurs in the shutdown procedure */
/* accept alarms only if they are in 2 minutes or more */
if (mins_togo > 1) {
tm = get_time();
togo = (m + h * 60 - tm->tm_min - tm->tm_hour * 60 + 1440) % 1440;
if (togo > 1) {
rtc_init();
rtc_set_alarm(atm.tm_hour,atm.tm_min);
rtc_set_alarm(h,m);
rtc_enable_alarm(true);
if (global_settings.talk_menu)
{
talk_id(LANG_ALARM_MOD_TIME_TO_GO, true);
talk_value(mins_togo / 60, UNIT_HOUR, true);
talk_value(mins_togo % 60, UNIT_MIN, true);
talk_value(togo / 60, UNIT_HOUR, true);
talk_value(togo % 60, UNIT_MIN, true);
talk_force_enqueue_next();
}
splashf(HZ*2, str(LANG_ALARM_MOD_TIME_TO_GO),
mins_togo / 60, mins_togo % 60);
togo / 60, togo % 60);
done = true;
} else {
splash(HZ, ID2P(LANG_ALARM_MOD_ERROR));
update = false;
update = true;
}
}
break;
if (usb || !update)
{
if (!usb)
/* inc(m) */
case ACTION_SETTINGS_INC:
case ACTION_SETTINGS_INCREPEAT:
m += 5;
if (m == 60) {
h += 1;
m = 0;
hour_wrapped = true;
}
if (h == 24)
h = 0;
speak_time(h, m, hour_wrapped, false);
break;
/* dec(m) */
case ACTION_SETTINGS_DEC:
case ACTION_SETTINGS_DECREPEAT:
m -= 5;
if (m == -5) {
h -= 1;
m = 55;
hour_wrapped = true;
}
if (h == -1)
h = 23;
speak_time(h, m, hour_wrapped, false);
break;
/* inc(h) */
case ACTION_STD_NEXT:
case ACTION_STD_NEXTREPEAT:
h = (h+1) % 24;
if (global_settings.talk_menu)
talk_value(h, UNIT_HOUR, false);
break;
/* dec(h) */
case ACTION_STD_PREV:
case ACTION_STD_PREVREPEAT:
h = (h+23) % 24;
if (global_settings.talk_menu)
talk_value(h, UNIT_HOUR, false);
break;
case ACTION_STD_CANCEL:
rtc_enable_alarm(false);
splash(HZ*2, ID2P(LANG_ALARM_MOD_DISABLE));
rtc_enable_alarm(false);
return 1;
done = true;
break;
case ACTION_NONE:
hour_wrapped = false;
break;
default:
if(default_event_handler(button) == SYS_USB_CONNECTED)
{
rtc_enable_alarm(false);
return 1;
}
break;
}
}
return 0;
}

View file

@ -24,7 +24,7 @@ $(BUILDDIR)/apps/features: $(APPSDIR)/features.txt $(BUILDDIR)/firmware/common/
$(call PRINTS,PP $(<F))
$(SILENT)$(CC) $(PPCFLAGS) \
-E -P -imacros "config.h" -imacros "button.h" -x c $< | \
grep -v "^#" | grep -v "^ *$$" > $(BUILDDIR)/apps/features; \
grep -v "^\#" | grep -v "^ *$$" > $(BUILDDIR)/apps/features; \
$(BUILDDIR)/apps/genlang-features: $(BUILDDIR)/apps/features
$(call PRINTS,GEN $(subst $(BUILDDIR)/,,$@))tr \\n : < $< > $@

View file

@ -46,7 +46,7 @@
#endif
#if ((CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1) \
|| (defined(SONY_NWZ_LINUX) && !defined(SIMULATOR)))
|| defined(SONY_NWZ_LINUX))
#ifdef AUDIO_CPU_BOOST
static void audio_cpu_boost(bool state)
@ -169,19 +169,10 @@ int audio_get_spdif_sample_rate(void)
#ifdef HAVE_SPEAKER
void audio_enable_speaker(int mode)
{
#if defined(HAVE_HEADPHONE_DETECTION) || defined(HAVE_LINEOUT_DETECTION)
#ifdef HAVE_HEADPHONE_DETECTION
/* if needed, query jack state */
if(mode == 2)
{
#ifdef HAVE_HEADPHONE_DETECTION
if (headphones_inserted())
mode = 0;
#endif
#ifdef HAVE_LINEOUT_DETECTION
if (lineout_inserted())
mode = 0;
#endif
}
mode = !headphones_inserted();
#endif
/* treat any nonzero value as enable */
audiohw_enable_speaker(mode);

View file

@ -1,4 +1,6 @@
#ifdef HAVE_LCD_BITMAP
default_icons.bmp
#endif
#if (CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(__APPLE__)
osx_dummy.bmp

View file

@ -1,3 +1,5 @@
#ifdef HAVE_LCD_BITMAP
/* Rockbox logo */
#if (LCD_DEPTH == 1)
#if (LCD_WIDTH == 160)
@ -38,7 +40,7 @@ rockboxlogo.640x198x16.bmp
#endif
/* The Sony NWZ linux bootloader needs icons to display a menu */
#if defined(BOOTLOADER)
#if defined(BOOTLOADER)
#if defined(SONY_NWZ_LINUX)
rockboxicon.130x130x16.bmp
toolsicon.130x130x16.bmp
@ -46,14 +48,6 @@ toolsicon.130x130x16.bmp
hibyicon.70x70x16.bmp
rockboxicon.70x70x16.bmp
toolsicon.70x70x16.bmp
#elif (defined(XDUOO_X3II) || defined(XDUOO_X20) || defined(EROS_Q))
hibyicon.130x130x16.bmp
rockboxicon.130x130x16.bmp
toolsicon.130x130x16.bmp
#elif defined(FIIO_M3K_LINUX)
fiioicon.130x130x16.bmp
rockboxicon.130x130x16.bmp
toolsicon.130x130x16.bmp
#endif
#endif
@ -83,3 +77,5 @@ usblogo.104x27x1.bmp
#endif
#endif /* BOOTLOADER */
#endif /* HAVE_LCD_BITMAP */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

View file

@ -1,4 +1,6 @@
#ifdef HAVE_LCD_BITMAP
remote_default_icons.bmp
#endif
#if (CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(__APPLE__)
osx_remote_dummy.bmp

File diff suppressed because it is too large Load diff

View file

@ -29,17 +29,11 @@ enum {
BOOKMARK_USB_CONNECTED = 1
};
enum {
BOOKMARK_CANCEL,
BOOKMARK_DONT_RESUME,
BOOKMARK_DO_RESUME
};
int bookmark_load_menu(void);
bool bookmark_autobookmark(bool prompt_ok);
bool bookmark_create_menu(void);
bool bookmark_mrb_load(void);
int bookmark_autoload(const char* file);
bool bookmark_autoload(const char* file);
bool bookmark_load(const char* file, bool autoload);
bool bookmark_exists(void);
bool bookmark_is_bookmarkable_state(void);

View file

@ -20,6 +20,7 @@
****************************************************************************/
#include "config.h"
#include <string.h>
#include "strlcpy.h"
#include "system.h"
#include "storage.h"
#include "thread.h"
@ -70,6 +71,8 @@
/* amount of data to read in one read() call */
#define BUFFERING_DEFAULT_FILECHUNK (1024*32)
#define BUF_HANDLE_MASK 0x7FFFFFFF
enum handle_flags
{
H_CANWRAP = 0x1, /* Handle data may wrap in buffer */
@ -292,11 +295,12 @@ static int next_handle_id(void)
{
static int cur_handle_id = 0;
int next_hid = cur_handle_id + 1;
if (next_hid == INT_MAX)
cur_handle_id = 0; /* next would overflow; reset the counter */
else
cur_handle_id = next_hid;
/* Wrap signed int is safe and 0 doesn't happen */
int next_hid = (cur_handle_id + 1) & BUF_HANDLE_MASK;
if (next_hid == 0)
next_hid = 1;
cur_handle_id = next_hid;
return next_hid;
}
@ -416,8 +420,7 @@ add_handle(unsigned int flags, size_t data_size, const char *path,
h->signaled = 0; /* Data can be waited for */
/* Save the provided path */
if (path)
memcpy(h->path, path, pathsize);
memcpy(h->path, path, pathsize);
/* Return the start of the data area */
*data_out = ringbuf_add(index, handlesize);
@ -848,9 +851,8 @@ static bool fill_buffer(void)
Return value is the total size (struct + data). */
static int load_image(int fd, const char *path,
struct bufopen_bitmap_data *data,
size_t bufidx, size_t max_size)
size_t bufidx)
{
(void)path;
int rc;
struct bitmap *bmp = ringbuf_ptr(bufidx);
struct dim *dim = data->dim;
@ -864,20 +866,25 @@ static int load_image(int fd, const char *path,
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
bmp->maskdata = NULL;
#endif
const int format = FORMAT_NATIVE | FORMAT_DITHER |
FORMAT_RESIZE | FORMAT_KEEP_ASPECT;
int free = (int)MIN(buffer_len - bytes_used(), buffer_len - bufidx)
- sizeof(struct bitmap);
#ifdef HAVE_JPEG
if (aa != NULL) {
lseek(fd, aa->pos, SEEK_SET);
rc = clip_jpeg_fd(fd, aa->size, bmp, (int)max_size, format, NULL);
rc = clip_jpeg_fd(fd, aa->size, bmp, free, FORMAT_NATIVE|FORMAT_DITHER|
FORMAT_RESIZE|FORMAT_KEEP_ASPECT, NULL);
}
else if (strcmp(path + strlen(path) - 4, ".bmp"))
rc = read_jpeg_fd(fd, bmp, (int)max_size, format, NULL);
rc = read_jpeg_fd(fd, bmp, free, FORMAT_NATIVE|FORMAT_DITHER|
FORMAT_RESIZE|FORMAT_KEEP_ASPECT, NULL);
else
#endif
rc = read_bmp_fd(fd, bmp, (int)max_size, format, NULL);
rc = read_bmp_fd(fd, bmp, free, FORMAT_NATIVE|FORMAT_DITHER|
FORMAT_RESIZE|FORMAT_KEEP_ASPECT, NULL);
return rc + (rc > 0 ? sizeof(struct bitmap) : 0);
(void)path;
}
#endif /* HAVE_ALBUMART */
@ -963,18 +970,11 @@ int bufopen(const char *file, off_t offset, enum data_type type,
size_t size = 0;
#ifdef HAVE_ALBUMART
if (type == TYPE_BITMAP) {
/* Bitmaps are resized to the requested dimensions when loaded,
* so the file size should not be used as it may be too large
* or too small */
/* If albumart is embedded, the complete file is not buffered,
* but only the jpeg part; filesize() would be wrong */
struct bufopen_bitmap_data *aa = user_data;
size = BM_SIZE(aa->dim->width, aa->dim->height, FORMAT_NATIVE, false);
size += sizeof(struct bitmap);
#ifdef HAVE_JPEG
/* JPEG loading requires extra memory
* TODO: don't add unncessary overhead for .bmp images! */
size += JPEG_DECODE_OVERHEAD;
#endif
if (aa->embedded_albumart)
size = aa->embedded_albumart->size;
}
#endif
@ -983,10 +983,7 @@ int bufopen(const char *file, off_t offset, enum data_type type,
unsigned int hflags = 0;
if (type == TYPE_PACKET_AUDIO || type == TYPE_CODEC)
hflags |= H_CANWRAP;
/* Bitmaps need their space allocated up front */
if (type == TYPE_BITMAP)
hflags |= H_ALLOCALL;
hflags = H_CANWRAP;
size_t adjusted_offset = offset;
if (adjusted_offset > size)
@ -1002,14 +999,7 @@ int bufopen(const char *file, off_t offset, enum data_type type,
DEBUGF("%s(): failed to add handle\n", __func__);
mutex_unlock(&llist_mutex);
close(fd);
/*warn playback.c if it is trying to buffer too large of an image*/
if(type == TYPE_BITMAP && padded_size >= buffer_len - 64*1024)
{
return ERR_BITMAP_TOO_LARGE;
}
return ERR_BUFFER_FULL;
}
handle_id = h->id;
@ -1037,7 +1027,7 @@ int bufopen(const char *file, off_t offset, enum data_type type,
#ifdef HAVE_ALBUMART
if (type == TYPE_BITMAP) {
/* Bitmap file: we load the data instead of the file */
int rc = load_image(fd, file, user_data, data, padded_size);
int rc = load_image(fd, file, user_data, data);
if (rc <= 0) {
handle_id = ERR_FILE_ERROR;
} else {
@ -1436,6 +1426,62 @@ ssize_t bufgetdata(int handle_id, size_t size, void **data)
return size;
}
ssize_t bufgettail(int handle_id, size_t size, void **data)
{
if (thread_self() != buffering_thread_id)
return ERR_WRONG_THREAD; /* only from buffering thread */
/* We don't support tail requests of > guardbuf_size, for simplicity */
if (size > GUARD_BUFSIZE)
return ERR_INVALID_VALUE;
const struct memory_handle *h = find_handle(handle_id);
if (!h)
return ERR_HANDLE_NOT_FOUND;
if (h->end >= h->filesize) {
size_t tidx = ringbuf_sub_empty(h->widx, size);
if (tidx + size > buffer_len) {
size_t copy_n = tidx + size - buffer_len;
memcpy(guard_buffer, ringbuf_ptr(0), copy_n);
}
*data = ringbuf_ptr(tidx);
}
else {
size = ERR_HANDLE_NOT_DONE;
}
return size;
}
ssize_t bufcuttail(int handle_id, size_t size)
{
if (thread_self() != buffering_thread_id)
return ERR_WRONG_THREAD; /* only from buffering thread */
struct memory_handle *h = find_handle(handle_id);
if (!h)
return ERR_HANDLE_NOT_FOUND;
if (h->end >= h->filesize) {
/* Cannot trim to before read position */
size_t available = h->end - MAX(h->start, h->pos);
if (available < size)
size = available;
h->widx = ringbuf_sub_empty(h->widx, size);
h->filesize -= size;
h->end -= size;
} else {
size = ERR_HANDLE_NOT_DONE;
}
return size;
}
/*
SECONDARY EXPORTED FUNCTIONS
============================

View file

@ -46,7 +46,7 @@ enum data_type {
#define ERR_FILE_ERROR -4
#define ERR_HANDLE_NOT_DONE -5
#define ERR_UNSUPPORTED_TYPE -6
#define ERR_BITMAP_TOO_LARGE -7
#define ERR_WRONG_THREAD -7
/* Initialise the buffering subsystem */
void buffering_init(void) INIT_ATTR;
@ -67,6 +67,8 @@ bool buffering_reset(char *buf, size_t buflen);
* bufftell : Return the handle's file read position
* bufread : Copy data from a handle to a buffer
* bufgetdata: Obtain a pointer for linear access to a "size" amount of data
* bufgettail: Out-of-band get the last size bytes of a handle.
* bufcuttail: Out-of-band remove the trailing 'size' bytes of a handle.
*
* NOTE: bufread and bufgetdata will block the caller until the requested
* amount of data is ready (unless EOF is reached).
@ -82,6 +84,8 @@ int bufadvance(int handle_id, off_t offset);
off_t bufftell(int handle_id);
ssize_t bufread(int handle_id, size_t size, void *dest);
ssize_t bufgetdata(int handle_id, size_t size, void **data);
ssize_t bufgettail(int handle_id, size_t size, void **data);
ssize_t bufcuttail(int handle_id, size_t size);
/***************************************************************************
* SECONDARY FUNCTIONS

View file

@ -183,16 +183,14 @@ const char * get_codec_filename(int cod_spec)
/* Can choose decoder or encoder if one available */
int type = cod_spec & CODEC_TYPE_MASK;
int afmt = cod_spec & CODEC_AFMT_MASK;
int tmp_fmt = afmt;
if ((unsigned)afmt >= AFMT_NUM_CODECS)
{
type = AFMT_UNKNOWN | (type & CODEC_TYPE_MASK);
tmp_fmt = AFMT_UNKNOWN;
}
fname = (type == CODEC_TYPE_ENCODER) ?
audio_formats[tmp_fmt].codec_enc_root_fn :
audio_formats[tmp_fmt].codec_root_fn;
audio_formats[afmt].codec_enc_root_fn :
audio_formats[afmt].codec_root_fn;
logf("%s: %d - %s",
(type == CODEC_TYPE_ENCODER) ? "Encoder" : "Decoder",
afmt, fname ? fname : "<unknown>");

View file

@ -40,6 +40,7 @@
#include "lang.h"
#include "keyboard.h"
#include "buffering.h"
#include "mp3_playback.h"
#include "backlight.h"
#include "storage.h"
#include "talk.h"
@ -203,9 +204,8 @@ static int codec_load_ram(struct codec_api *api)
return CODEC_ERROR;
}
if (hdr->api_version != CODEC_API_VERSION ||
c_hdr->api_size > sizeof(struct codec_api))
{
if (hdr->api_version > CODEC_API_VERSION
|| hdr->api_version < CODEC_MIN_API_VERSION) {
logf("codec api version error");
lc_close(curr_handle);
curr_handle = NULL;

View file

@ -1,95 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2020 by 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 "action.h"
#include "core_alloc.h"
#include "core_keymap.h"
/*#define LOGF_ENABLE*/
#include "logf.h"
#if !defined(__PCTOOL__) || defined(CHECKWPS)
int core_set_keyremap(struct button_mapping* core_keymap, int count)
{
return action_set_keymap(core_keymap, count);
}
static int open_key_remap(const char *filename, int *countp)
{
int fd = open(filename, O_RDONLY);
if (fd < 0)
return fd;
size_t fsize = filesize(fd);
int count = fsize / sizeof(struct button_mapping);
if (count == 0 || (size_t)(count * sizeof(struct button_mapping)) != fsize)
{
logf("core_keyremap: bad filesize %d / %lu", count, (unsigned long)fsize);
goto error;
}
struct button_mapping header;
if(read(fd, &header, sizeof(header)) != (ssize_t)sizeof(header))
{
logf("core_keyremap: read error");
goto error;
}
if (header.action_code != KEYREMAP_VERSION ||
header.button_code != KEYREMAP_HEADERID ||
header.pre_button_code != count)
{
logf("core_keyremap: bad header %d", count);
goto error;
}
*countp = count - 1;
return fd;
error:
close(fd);
return -1;
}
int core_load_key_remap(const char *filename)
{
int count = 0; /* gcc falsely believes this may be used uninitialized */
int fd = open_key_remap(filename, &count);
if (fd < 0)
return -1;
size_t bufsize = count * sizeof(struct button_mapping);
int handle = core_alloc(bufsize);
if (handle > 0)
{
void *data = core_get_data_pinned(handle);
if (read(fd, data, bufsize) == (ssize_t)bufsize)
count = action_set_keymap_handle(handle, count);
core_put_data_pinned(data);
}
close(fd);
return count;
}
#endif /* !defined(__PCTOOL__) */

View file

@ -1,65 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2020 by 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.
*
****************************************************************************/
#ifndef CORE_KEYMAP_H
#define CORE_KEYMAP_H
#include <stdbool.h>
#include <inttypes.h>
#include "config.h"
#include "action.h"
#define KEYREMAP_VERSION 1
#define KEYREMAP_HEADERID (LAST_ACTION_PLACEHOLDER | (TARGET_ID << 8))
/* If exists remap file will be loaded at startup */
#define CORE_KEYREMAP_FILE ROCKBOX_DIR "/keyremap.kmf"
/* Allocates core buffer, copies keymap to allow buttons for actions to be remapped*/
int core_set_keyremap(struct button_mapping* core_keymap, int count);
/* load a remap file to allow buttons for actions to be remapped */
int core_load_key_remap(const char *filename);
/*
* entries consist of 3 int [action, button, prebtn]
* the header (VERSION, LAST_DEFINED_ACTION, count) is stripped by open_key_remap
*
* context look up table is at the beginning
* action_code contains (context | CONTEXT_REMAPPED)
* button_code contains index of first remapped action for the matched context
* prebtn_code contains count of actions in this remapped context
* [-1] REMAP_VERSION, REMAP_HEADERID, entry count(9) / DISCARDED AFTER LOAD
* [0] CORE_CONTEXT_REMAP(ctx1), offset1=(3), count=(1)
* [1] CORE_CONTEXT_REMAP(ctx2, offset2=(5), count=(2)
* [2] sentinel, 0, 0
* [3] act0, btn, 0
* [4] sentinel 0, 0
* [5] act1, btn, 0
* [6] act2, btn1
* [7] sentinel, 0, 0
*
* Note:
* last entry of each group is always the sentinel [CONTEXT_STOPSEARCHING, BUTTON_NONE, BUTTON_NONE]
* contexts must match exactly -- re-mapped contexts run before the built in w/ fall through contexts
* ie. you can't remap std_context and expect it to match std_context actions from the WPS context.
*/
#endif /* CORE_KEYMAP_H */

View file

@ -58,28 +58,28 @@ static bool search_for_cuesheet(const char *path, struct cuesheet_file *cue_file
slash_cuepath = &cuepath[slash - path];
dot = strrchr(slash_cuepath, '.');
if (dot)
strmemccpy(dot, ".cue", MAX_PATH - (dot-cuepath));
strlcpy(dot, ".cue", MAX_PATH - (dot-cuepath));
if (!dot || !file_exists(cuepath))
{
strcpy(cuepath, CUE_DIR);
if (strlcat(cuepath, slash, MAX_PATH) >= MAX_PATH)
goto skip; /* overflow */
dot = strrchr(cuepath, '.');
goto skip; /* overflow */
char *dot = strrchr(cuepath, '.');
strcpy(dot, ".cue");
if (!file_exists(cuepath))
{
skip:
if ((len+4) >= MAX_PATH)
return false;
strmemccpy(cuepath, path, MAX_PATH);
strlcpy(cuepath, path, MAX_PATH);
strlcat(cuepath, ".cue", MAX_PATH);
if (!file_exists(cuepath))
return false;
}
}
strmemccpy(cue_file->path, cuepath, MAX_PATH);
strlcpy(cue_file->path, cuepath, MAX_PATH);
return true;
}
@ -91,7 +91,7 @@ bool look_for_cuesheet_file(struct mp3entry *track_id3, struct cuesheet_file *cu
cue_file->pos = track_id3->embedded_cuesheet.pos;
cue_file->size = track_id3->embedded_cuesheet.size;
cue_file->encoding = track_id3->embedded_cuesheet.encoding;
strmemccpy(cue_file->path, track_id3->path, MAX_PATH);
strlcpy(cue_file->path, track_id3->path, MAX_PATH);
return true;
}
@ -118,86 +118,6 @@ static char *get_string(const char *line)
return start;
}
static unsigned long parse_cue_index(const char *line)
{
/* assumes strncmp(line, "INDEX 01", 8) & NULL terminated string */
/* INDEX 01 MM:SS:FF\0 (00:00:00\0 - 99:99:99\0)*/
const unsigned field_m[3] = {60 * 1000, 1000, 13}; /* MM:SS:~FF*/
const unsigned field_max[3] = {30000, 59, 74}; /* MM, SS, FF */
const char f_sep = ':';
int field = -1;
unsigned long offset = 0; /* ms from start of track */
unsigned long value = 0;
while (*line)
{
if (!isdigit(*line)) /* search for numbers */
{
line++;
continue;
}
while (isdigit(*line))
{
value = 10 * value + (*line - '0');
if (field >= 0 && value > field_max[field]) /* Sanity check bail early */
return 0;
line++;
}
if (field < 0) /*Filter INDEX 01*/
{
/* safe to assume value == 1 */
}
else if (field <= 2)
{
while(*line && *line != f_sep)
line++;
if (*line || field == 2) /* if *line valid we found f_sep */
offset += (unsigned long) field_m[field] * value;
}
else
break;
value = 0;
field++;
}
return offset;
}
enum eCS_SUPPORTED_TAGS {
eCS_TRACK = 0, eCS_INDEX_01, eCS_TITLE,
eCS_PERFORMER, eCS_SONGWRITER, eCS_FILE,
eCS_COUNT_TAGS_COUNT, eCS_NOTFOUND = -1
};
static enum eCS_SUPPORTED_TAGS cuesheet_tag_get_option(const char *option)
{
#define CS_OPTN(str) {str, sizeof(str)-1}
static const struct cs_option_t {
const char *str;
const int len;
} cs_options[eCS_COUNT_TAGS_COUNT + 1] = {
[eCS_TRACK] = CS_OPTN("TRACK"),
[eCS_INDEX_01] = CS_OPTN("INDEX 01"),
[eCS_TITLE] =CS_OPTN("TITLE"),
[eCS_PERFORMER] =CS_OPTN("PERFORMER"),
[eCS_SONGWRITER] =CS_OPTN("SONGWRITER"),
[eCS_FILE] =CS_OPTN("FILE"),
[eCS_COUNT_TAGS_COUNT] = {NULL, 0} /*SENTINEL*/
};
const struct cs_option_t *op;
for (int i=0; ((op=&cs_options[i]))->str != NULL; i++)
{
if (strncmp(option, op->str, op->len) == 0)
return i;
}
return eCS_NOTFOUND;
#undef CS_OPTN
}
/* parse cuesheet "cue_file" and store the information in "cue" */
bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
{
@ -223,25 +143,22 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
/* Look for a Unicode BOM */
unsigned char bom_read = 0;
if (read(fd, line, BOM_UTF_8_SIZE) > 0)
read(fd, line, BOM_UTF_8_SIZE);
if(!memcmp(line, BOM_UTF_8, BOM_UTF_8_SIZE))
{
if(!memcmp(line, BOM_UTF_8, BOM_UTF_8_SIZE))
{
char_enc = CHAR_ENC_UTF_8;
bom_read = BOM_UTF_8_SIZE;
}
else if(!memcmp(line, BOM_UTF_16_LE, BOM_UTF_16_SIZE))
{
char_enc = CHAR_ENC_UTF_16_LE;
bom_read = BOM_UTF_16_SIZE;
}
else if(!memcmp(line, BOM_UTF_16_BE, BOM_UTF_16_SIZE))
{
char_enc = CHAR_ENC_UTF_16_BE;
bom_read = BOM_UTF_16_SIZE;
}
char_enc = CHAR_ENC_UTF_8;
bom_read = BOM_UTF_8_SIZE;
}
else if(!memcmp(line, BOM_UTF_16_LE, BOM_UTF_16_SIZE))
{
char_enc = CHAR_ENC_UTF_16_LE;
bom_read = BOM_UTF_16_SIZE;
}
else if(!memcmp(line, BOM_UTF_16_BE, BOM_UTF_16_SIZE))
{
char_enc = CHAR_ENC_UTF_16_BE;
bom_read = BOM_UTF_16_SIZE;
}
if (bom_read < BOM_UTF_8_SIZE)
lseek(fd, cue_file->pos + bom_read, SEEK_SET);
if (is_embedded)
@ -281,18 +198,12 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
}
s = skip_whitespace(line);
/* RECOGNIZED TAGS ***********************
* eCS_TRACK = 0, eCS_INDEX_01, eCS_TITLE,
* eCS_PERFORMER, eCS_SONGWRITER, eCS_FILE,
*/
enum eCS_SUPPORTED_TAGS option = cuesheet_tag_get_option(s);
if (option == eCS_TRACK)
if (!strncmp(s, "TRACK", 5))
{
cue->track_count++;
}
else if (option == eCS_INDEX_01)
else if (!strncmp(s, "INDEX 01", 8))
{
#if 0
s = strchr(s,' ');
s = skip_whitespace(s);
s = strchr(s,' ');
@ -302,11 +213,11 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
cue->tracks[cue->track_count-1].offset += 1000 * atoi(s);
s = strchr(s,':') + 1;
cue->tracks[cue->track_count-1].offset += 13 * atoi(s);
#else
cue->tracks[cue->track_count-1].offset = parse_cue_index(s);
#endif
}
else if (option != eCS_NOTFOUND)
else if (!strncmp(s, "TITLE", 5)
|| !strncmp(s, "PERFORMER", 9)
|| !strncmp(s, "SONGWRITER", 10)
|| !strncmp(s, "FILE", 4))
{
char *dest = NULL;
char *string = get_string(s);
@ -316,24 +227,24 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
size_t count = MAX_NAME*3 + 1;
size_t count8859 = MAX_NAME;
switch (option)
switch (*s)
{
case eCS_TITLE: /* TITLE */
case 'T': /* TITLE */
dest = (cue->track_count <= 0) ? cue->title :
cue->tracks[cue->track_count-1].title;
break;
case eCS_PERFORMER: /* PERFORMER */
case 'P': /* PERFORMER */
dest = (cue->track_count <= 0) ? cue->performer :
cue->tracks[cue->track_count-1].performer;
break;
case eCS_SONGWRITER: /* SONGWRITER */
case 'S': /* SONGWRITER */
dest = (cue->track_count <= 0) ? cue->songwriter :
cue->tracks[cue->track_count-1].songwriter;
break;
case eCS_FILE: /* FILE */
case 'F': /* FILE */
if (is_embedded || cue->track_count > 0)
break;
@ -341,19 +252,9 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
count = MAX_PATH;
count8859 = MAX_PATH/3;
break;
case eCS_TRACK:
/*Fall-Through*/
case eCS_INDEX_01:
/*Fall-Through*/
case eCS_COUNT_TAGS_COUNT:
/*Fall-Through*/
case eCS_NOTFOUND: /*Shouldn't happen*/
logf(HZ * 2, "Bad Tag %d @ %s", (int) option, __func__);
dest = NULL;
break;
}
if (dest)
if (dest)
{
if (char_enc == CHAR_ENC_ISO_8859_1)
{
@ -363,11 +264,10 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
}
else
{
strmemccpy(dest, string, count);
strlcpy(dest, string, count);
}
}
}
}
if (is_embedded)
{
bytes_left -= line_len;
@ -386,7 +286,7 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
strcpy(cue->file, cue->path);
char *slash = strrchr(cue->file, '/');
if (!slash++) slash = cue->file;
strmemccpy(slash, line, MAX_PATH - (slash - cue->file));
strlcpy(slash, line, MAX_PATH - (slash - cue->file));
}
/* If some songs don't have performer info, we copy the cuesheet performer */
@ -394,10 +294,10 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
for (i = 0; i < cue->track_count; i++)
{
if (*(cue->tracks[i].performer) == '\0')
strmemccpy(cue->tracks[i].performer, cue->performer, MAX_NAME*3);
strlcpy(cue->tracks[i].performer, cue->performer, MAX_NAME*3);
if (*(cue->tracks[i].songwriter) == '\0')
strmemccpy(cue->tracks[i].songwriter, cue->songwriter, MAX_NAME*3);
strlcpy(cue->tracks[i].songwriter, cue->songwriter, MAX_NAME*3);
}
return true;
@ -413,8 +313,14 @@ static bool seek(unsigned long pos)
}
else
{
#if (CONFIG_CODEC == SWCODEC)
audio_pre_ff_rewind();
audio_ff_rewind(pos);
#else
audio_pause();
audio_ff_rewind(pos);
audio_resume();
#endif
return true;
}
}
@ -441,7 +347,7 @@ static const char* list_get_name_cb(int selected_item,
struct cuesheet *cue = (struct cuesheet *)data;
if (selected_item & 1)
strmemccpy(buffer, cue->tracks[selected_item/2].title, buffer_len);
strlcpy(buffer, cue->tracks[selected_item/2].title, buffer_len);
else
snprintf(buffer, buffer_len, "%02d. %s", selected_item/2+1,
cue->tracks[selected_item/2].performer);
@ -481,7 +387,7 @@ void browse_cuesheet(struct cuesheet *cue)
{
gui_synclist_draw(&lists);
action = get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
if (gui_synclist_do_button(&lists, &action))
if (gui_synclist_do_button(&lists, &action, LIST_WRAP_UNLESS_HELD))
continue;
switch (action)
{
@ -508,7 +414,7 @@ void browse_cuesheet(struct cuesheet *cue)
/* check that this cue is the same one that would be found by
a search from playback */
char file[MAX_PATH];
strmemccpy(file, cue->file, MAX_PATH);
strlcpy(file, cue->file, MAX_PATH);
if (!strcmp(cue->path, file) || /* if embedded */
(search_for_cuesheet(file, &cue_file) &&
@ -535,7 +441,7 @@ bool display_cuesheet_content(char* filename)
if (!cue || bufsize < sizeof(struct cuesheet))
return false;
strmemccpy(cue_file.path, filename, MAX_PATH);
strlcpy(cue_file.path, filename, MAX_PATH);
cue_file.pos = 0;
cue_file.size = 0;
@ -554,7 +460,7 @@ bool display_cuesheet_content(char* filename)
bool curr_cuesheet_skip(struct cuesheet *cue, int direction, unsigned long curr_pos)
{
int track = cue_find_current_track(cue, curr_pos);
if (direction >= 0 && track == cue->track_count - 1)
{
/* we want to get out of the cuesheet */
@ -565,12 +471,12 @@ bool curr_cuesheet_skip(struct cuesheet *cue, int direction, unsigned long curr_
if (!(direction <= 0 && track == 0))
{
/* If skipping forward, skip to next cuesheet segment. If skipping
backward before DEFAULT_SKIP_THRESH milliseconds have elapsed, skip
backward before DEFAULT_SKIP_TRESH milliseconds have elapsed, skip
to previous cuesheet segment. If skipping backward after
DEFAULT_SKIP_THRESH seconds have elapsed, skip to the start of the
DEFAULT_SKIP_TRESH seconds have elapsed, skip to the start of the
current cuesheet segment */
if (direction == 1 ||
((curr_pos - cue->tracks[track].offset) < DEFAULT_SKIP_THRESH))
if (direction == 1 ||
((curr_pos - cue->tracks[track].offset) < DEFAULT_SKIP_TRESH))
{
track += direction;
}
@ -582,6 +488,7 @@ bool curr_cuesheet_skip(struct cuesheet *cue, int direction, unsigned long curr_
}
#ifdef HAVE_LCD_BITMAP
static inline void draw_veritcal_line_mark(struct screen * screen,
int x, int y, int h)
{
@ -597,7 +504,7 @@ void cue_draw_markers(struct screen *screen, struct cuesheet *cue,
{
int i,xi;
unsigned long tracklen_seconds = tracklen/1000; /* duration in seconds */
for (i=1; i < cue->track_count; i++)
{
/* Convert seconds prior to multiplication to avoid overflow. */
@ -605,6 +512,7 @@ void cue_draw_markers(struct screen *screen, struct cuesheet *cue,
draw_veritcal_line_mark(screen, xi, y, h);
}
}
#endif
bool cuesheet_subtrack_changed(struct mp3entry *id3)
{

View file

@ -79,10 +79,12 @@ int cue_find_current_track(struct cuesheet *cue, unsigned long curpos);
/* skip to next track in the cuesheet towards "direction" (which is 1 or -1) */
bool curr_cuesheet_skip(struct cuesheet *cue, int direction, unsigned long curr_pos);
#ifdef HAVE_LCD_BITMAP
/* draw track markers on the progressbar */
void cue_draw_markers(struct screen *screen, struct cuesheet *cue,
unsigned long tracklen,
int x, int y, int w, int h);
#endif
/* check if the subtrack has changed */
bool cuesheet_subtrack_changed(struct mp3entry *id3);

File diff suppressed because it is too large Load diff

View file

@ -40,11 +40,9 @@
if (fn) fn(__VA_ARGS__)
static int enc_menuitem_callback(int action,
const struct menu_item_ex *this_item,
struct gui_synclist *this_list);
const struct menu_item_ex *this_item);
static int enc_menuitem_enteritem(int action,
const struct menu_item_ex *this_item,
struct gui_synclist *this_list);
const struct menu_item_ex *this_item);
static void enc_rec_settings_changed(struct encoder_config *cfg);
/* this is used by all encoder menu items,
MUST be initialised before the call to do_menu() */
@ -115,7 +113,7 @@ static void mp3_enc_convert_config(struct encoder_config *cfg,
}
else
{
if ((unsigned)global_settings.mp3_enc_config.bitrate >= MP3_ENC_NUM_BITR)
if ((unsigned)global_settings.mp3_enc_config.bitrate > MP3_ENC_NUM_BITR)
global_settings.mp3_enc_config.bitrate = MP3_ENC_BITRATE_CFG_DEFAULT;
cfg->mp3_enc.bitrate = mp3_enc_bitr[global_settings.mp3_enc_config.bitrate];
}
@ -193,9 +191,9 @@ static bool mp3_enc_bitrate(struct menucallback_data *data)
} /* mp3_enc_bitrate */
/* mp3_enc configuration menu */
MENUITEM_FUNCTION_W_PARAM(mp3_bitrate, 0, ID2P(LANG_BITRATE),
mp3_enc_bitrate, &menu_callback_data,
enc_menuitem_callback, Icon_NOICON);
MENUITEM_FUNCTION(mp3_bitrate, MENU_FUNC_USEPARAM, ID2P(LANG_BITRATE),
mp3_enc_bitrate,
&menu_callback_data, enc_menuitem_callback, Icon_NOICON);
MAKE_MENU( mp3_enc_menu, ID2P(LANG_ENCODER_SETTINGS),
enc_menuitem_enteritem, Icon_NOICON,
&mp3_bitrate);
@ -264,11 +262,9 @@ static inline bool rec_format_ok(int rec_format)
/* This is called before entering the menu with the encoder settings
Its needed to make sure the settings can take effect. */
static int enc_menuitem_enteritem(int action,
const struct menu_item_ex *this_item,
struct gui_synclist *this_list)
const struct menu_item_ex *this_item)
{
(void)this_item;
(void)this_list;
/* this struct must be init'ed before calling do_menu() so this is safe */
struct menucallback_data *data = &menu_callback_data;
if (action == ACTION_STD_OK) /* entering the item */
@ -281,12 +277,10 @@ static int enc_menuitem_enteritem(int action,
/* this is called when a encoder setting is exited
It is used to update the status bar and save the setting */
static int enc_menuitem_callback(int action,
const struct menu_item_ex *this_item,
struct gui_synclist *this_list)
const struct menu_item_ex *this_item)
{
(void)this_list;
struct menucallback_data *data =
(struct menucallback_data*)this_item->function_param->param;
(struct menucallback_data*)this_item->function->param;
if (action == ACTION_EXIT_MENUITEM)
{
@ -375,7 +369,7 @@ bool enc_get_caps(const struct encoder_config *cfg,
else
{
/* If no function provided...defaults to all */
caps->samplerate_caps = SAMPR_CAP_ALL_192;
caps->samplerate_caps = SAMPR_CAP_ALL;
caps->channel_caps = CHN_CAP_ALL;
}

View file

@ -2,7 +2,7 @@
when the .lng and .voice files are built. That means that a change in this
file will break compatibility with older .lng and .voice files and that those
version numbers should be updated. It also means that changing defines in
the various config*.h files could also break back compatibility */
the various config*.h files could also break back compatibility */
#if defined(HAVE_ACCESSORY_SUPPLY)
accessory_supply
@ -60,7 +60,9 @@ hold_button
hotkey
#endif
#if defined(HAVE_LCD_BITMAP)
lcd_bitmap
#endif
#if LCD_DEPTH > 1
lcd_non-mono
@ -78,6 +80,14 @@ lcd_invert
lcd_sleep
#endif
#if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F)
masf
#endif
#if (CONFIG_CODEC == MAS3507D)
masd
#endif
#if defined(HAVE_MORSE_INPUT)
morse_input
#endif
@ -105,12 +115,20 @@ radio_remote
#endif
#endif
#if defined(HAVE_RDS_CAP)
rds
#if (CONFIG_KEYPAD == RECORDER_PAD)
recorder_pad
#if defined(CONFIG_TUNER)
radio_screen_button_bar
#endif
#endif
#if defined(HAVE_RECORDING)
recording
#if CONFIG_CODEC == SWCODEC
recording_swcodec
#else
recording_hwcodec
#endif
#if defined(HAVE_LINE_IN)
recording_linein
#endif
@ -140,6 +158,10 @@ rtc
serial_port
#endif
#if defined(ARCHOS_RECORDER) || defined(ARCHOS_PLAYER)
soft_shutdown
#endif
#if defined(HAVE_SPDIF_POWER)
spdif_power
#endif
@ -148,7 +170,11 @@ spdif_power
speaker
#endif
#if CONFIG_CODEC == SWCODEC
swcodec
#else
hwcodec
#endif
#if defined(HAVE_TAGCACHE)
tagcache
@ -186,23 +212,14 @@ depth_3d
#endif
/* This should be AUDIOHW_HAVE_FILTER_ROLL_OFF but that is only defined later */
#if defined(DX50) || defined(HAVE_DF1704_CODEC) || defined(HAVE_PCM1792_CODEC) || defined(HAVE_CS4398) || defined(HAVE_WM8740) || defined(HAVE_ES9018) || defined(HAVE_XDUOO_LINUX_CODEC) || defined(HAVE_FIIO_LINUX_CODEC) || defined(HAVE_AK4376) || defined(HAVE_ES9218)
#if defined(DX50) || defined(HAVE_DF1704_CODEC) || defined(HAVE_PCM1792_CODEC) || defined(HAVE_CS4398) || defined(HAVE_WM8740) || defined(HAVE_ES9018)
filter_roll_off
#endif
/* This should be AUDIOHW_HAVE_POWER_MODE but that is not defined yet */
#if defined(HAVE_AK4376) || defined(HAVE_ES9218)
dac_power_mode
#endif
#if defined(HAVE_ES9018)
es9018
#endif
#if defined(HAVE_ES9218)
es9218
#endif
/* These features are only used by the manual so they won't break binary
* compatibility
*/
@ -233,6 +250,10 @@ disk_storage
remote_button_hold
#endif
#if defined(HAVE_LCD_CHARCELLS)
lcd_charcell
#endif
#if defined(HAVE_LCD_FLIP)
lcd_flip
#endif
@ -266,8 +287,6 @@ recording_digital
#if MEMORYSIZE <= 2
lowmem
#elif MEMORYSIZE > 8
himem
#endif
#if defined(HAVE_HARDWARE_CLICK)
@ -285,18 +304,3 @@ boot_data
#if defined(HAVE_MULTIBOOT)
multi_boot
#endif
#if defined(HIBY_LINUX)
hibylinux
#endif
#if defined(BUTTON_REC) || \
(CONFIG_KEYPAD == GIGABEAT_PAD) || \
(CONFIG_KEYPAD == IPOD_4G_PAD) || \
(CONFIG_KEYPAD == IRIVER_H10_PAD)
clear_settings_on_hold
#endif
#if defined(HAVE_PERCEPTUAL_VOLUME)
perceptual_volume
#endif

View file

@ -44,37 +44,21 @@
#include "filetree.h"
#include "misc.h"
#include "strnatcmp.h"
#ifdef HAVE_LCD_BITMAP
#include "keyboard.h"
#endif
#if CONFIG_TUNER
#include "radio.h"
#endif
#include "wps.h"
static struct compare_data
{
int sort_dir; /* qsort key for sorting directories */
int(*_compar)(const char*, const char*, size_t);
} cmp_data;
/* dummmy functions to allow compatibility with strncmp & strncasecmp */
static int strnatcmp_n(const char *a, const char *b, size_t n)
{
(void)n;
return strnatcmp(a, b);
}
static int strnatcasecmp_n(const char *a, const char *b, size_t n)
{
(void)n;
return strnatcasecmp(a, b);
}
static int compare_sort_dir; /* qsort key for sorting directories */
int ft_build_playlist(struct tree_context* c, int start_index)
{
int i;
int res = 0;
int start=start_index;
struct playlist_info *playlist = playlist_get_current();
tree_lock_cache(c);
struct entry *entries = tree_get_entries(c);
@ -83,9 +67,7 @@ int ft_build_playlist(struct tree_context* c, int start_index)
{
if((entries[i].attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO)
{
res = playlist_insert_track(playlist, entries[i].name,
PLAYLIST_INSERT_LAST, false, false);
if (res < 0)
if (playlist_add(entries[i].name) < 0)
break;
}
else
@ -97,6 +79,7 @@ int ft_build_playlist(struct tree_context* c, int start_index)
}
tree_unlock_cache(c);
return start_index;
}
@ -105,37 +88,40 @@ int ft_build_playlist(struct tree_context* c, int start_index)
* or started via bookmark autoload, true otherwise.
*
* Pointers to both the full pathname and the separated parts needed to
* avoid allocating yet another path buffer on the stack (and save some
* avoid allocating yet another path buffer on the stack (and save some
* code; the caller typically needs to create the full pathname anyway)...
*/
bool ft_play_playlist(char* pathname, char* dirname,
char* filename, bool skip_warn_and_bookmarks)
bool ft_play_playlist(char* pathname, char* dirname, char* filename)
{
if (global_settings.party_mode && audio_status())
if (global_settings.party_mode && audio_status())
{
splash(HZ, ID2P(LANG_PARTY_MODE));
return false;
}
if (!skip_warn_and_bookmarks)
if (bookmark_autoload(pathname))
{
int res = bookmark_autoload(pathname);
if (res == BOOKMARK_CANCEL || res == BOOKMARK_DO_RESUME || !warn_on_pl_erase())
return false;
return false;
}
splash(0, ID2P(LANG_WAIT));
/* about to create a new current playlist...
allow user to cancel the operation */
if (!warn_on_pl_erase())
return false;
if (playlist_create(dirname, filename) != -1)
{
if (global_settings.playlist_shuffle)
{
playlist_shuffle(current_tick, -1);
playlist_set_modified(NULL, false);
}
playlist_start(0, 0, 0);
return true;
}
return false;
}
@ -210,7 +196,7 @@ static int compare(const void* p1, const void* p2)
if (e1->attr & ATTR_DIRECTORY && e2->attr & ATTR_DIRECTORY)
{ /* two directories */
criteria = cmp_data.sort_dir;
criteria = compare_sort_dir;
#ifdef HAVE_MULTIVOLUME
if (e1->attr & ATTR_VOLUME || e2->attr & ATTR_VOLUME)
@ -245,23 +231,41 @@ static int compare(const void* p1, const void* p2)
if (t1 != t2) /* if different */
return (t1 - t2) * (criteria == SORT_TYPE_REVERSED ? -1 : 1);
/* else alphabetical sorting */
return cmp_data._compar(e1->name, e2->name, MAX_PATH);
/* else fall through to alphabetical sorting */
}
case SORT_DATE:
case SORT_DATE_REVERSED:
{
if (e1->time_write != e2->time_write)
return (e1->time_write - e2->time_write)
* (criteria == SORT_DATE_REVERSED ? -1 : 1);
/* else fall through to alphabetical sorting */
}
/* Ignore SORT_TYPE */
if (criteria == SORT_DATE || criteria == SORT_DATE_REVERSED)
{
if (e1->time_write != e2->time_write)
return (e1->time_write - e2->time_write)
* (criteria == SORT_DATE_REVERSED ? -1 : 1);
/* else fall through to alphabetical sorting */
}
case SORT_ALPHA:
case SORT_ALPHA_REVERSED:
{
return cmp_data._compar(e1->name, e2->name, MAX_PATH) *
(criteria == SORT_ALPHA_REVERSED ? -1 : 1);
if (global_settings.sort_case)
{
if (global_settings.interpret_numbers == SORT_INTERPRET_AS_NUMBER)
return strnatcmp(e1->name, e2->name)
* (criteria == SORT_ALPHA_REVERSED ? -1 : 1);
else
return strncmp(e1->name, e2->name, MAX_PATH)
* (criteria == SORT_ALPHA_REVERSED ? -1 : 1);
}
else
{
if (global_settings.interpret_numbers == SORT_INTERPRET_AS_NUMBER)
return strnatcasecmp(e1->name, e2->name)
* (criteria == SORT_ALPHA_REVERSED ? -1 : 1);
else
return strncasecmp(e1->name, e2->name, MAX_PATH)
* (criteria == SORT_ALPHA_REVERSED ? -1 : 1);
}
}
}
@ -295,11 +299,8 @@ int ft_load(struct tree_context* c, const char* tempdir)
int len;
struct dirinfo info;
struct entry* dptr = tree_get_entry_at(c, files_in_dir);
if (!dptr)
{
c->dirfull = true;
if (!entry)
break;
}
info = dir_get_info(dir, entry);
len = strlen((char *)entry->d_name);
@ -324,49 +325,50 @@ int ft_load(struct tree_context* c, const char* tempdir)
}
dptr->attr = info.attribute;
int dir_attr = (dptr->attr & ATTR_DIRECTORY);
/* check for known file types */
if ( !(dir_attr) )
if ( !(dptr->attr & ATTR_DIRECTORY) )
dptr->attr |= filetype_get_attr((char *)entry->d_name);
int file_attr = (dptr->attr & FILE_ATTR_MASK);
/* filter out non-visible files */
if ((!(dir_attr) && ((*c->dirfilter == SHOW_PLAYLIST &&
file_attr != FILE_ATTR_M3U) ||
((*c->dirfilter == SHOW_MUSIC && file_attr != FILE_ATTR_AUDIO) &&
file_attr != FILE_ATTR_M3U) ||
if ((!(dptr->attr & ATTR_DIRECTORY) && (
(*c->dirfilter == SHOW_PLAYLIST &&
(dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_M3U) ||
((*c->dirfilter == SHOW_MUSIC &&
(dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_AUDIO) &&
(dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_M3U) ||
(*c->dirfilter == SHOW_SUPPORTED && !filetype_supported(dptr->attr)))) ||
(*c->dirfilter == SHOW_WPS && file_attr != FILE_ATTR_WPS) ||
(*c->dirfilter == SHOW_FONT && file_attr != FILE_ATTR_FONT) ||
(*c->dirfilter == SHOW_SBS && file_attr != FILE_ATTR_SBS) ||
(*c->dirfilter == SHOW_WPS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_WPS) ||
#ifdef HAVE_LCD_BITMAP
(*c->dirfilter == SHOW_FONT && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FONT) ||
(*c->dirfilter == SHOW_SBS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_SBS) ||
#if CONFIG_TUNER
(*c->dirfilter == SHOW_FMS && file_attr != FILE_ATTR_FMS) ||
(*c->dirfilter == SHOW_FMS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FMS) ||
#endif
#endif
#ifdef HAVE_REMOTE_LCD
(*c->dirfilter == SHOW_RWPS && file_attr != FILE_ATTR_RWPS) ||
(*c->dirfilter == SHOW_RSBS && file_attr != FILE_ATTR_RSBS) ||
(*c->dirfilter == SHOW_RWPS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RWPS) ||
(*c->dirfilter == SHOW_RSBS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RSBS) ||
#if CONFIG_TUNER
(*c->dirfilter == SHOW_RFMS && file_attr != FILE_ATTR_RFMS) ||
(*c->dirfilter == SHOW_RFMS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RFMS) ||
#endif
#endif
#if CONFIG_TUNER
(*c->dirfilter == SHOW_FMR && file_attr != FILE_ATTR_FMR) ||
(*c->dirfilter == SHOW_FMR && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FMR) ||
#endif
(*c->dirfilter == SHOW_M3U && file_attr != FILE_ATTR_M3U) ||
(*c->dirfilter == SHOW_CFG && file_attr != FILE_ATTR_CFG) ||
(*c->dirfilter == SHOW_LNG && file_attr != FILE_ATTR_LNG) ||
(*c->dirfilter == SHOW_MOD && file_attr != FILE_ATTR_MOD) ||
(*c->dirfilter == SHOW_PLUGINS && file_attr != FILE_ATTR_ROCK &&
file_attr != FILE_ATTR_LUA &&
file_attr != FILE_ATTR_OPX) ||
(*c->dirfilter == SHOW_M3U && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_M3U) ||
(*c->dirfilter == SHOW_CFG && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_CFG) ||
(*c->dirfilter == SHOW_LNG && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_LNG) ||
(*c->dirfilter == SHOW_MOD && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_MOD) ||
(*c->dirfilter == SHOW_PLUGINS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_ROCK &&
(dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_LUA) ||
(callback_show_item && !callback_show_item(entry->d_name, dptr->attr, c)))
{
continue;
}
if (len > c->cache.name_buffer_size - name_buffer_used - 1) {
if ((len > c->cache.name_buffer_size - name_buffer_used - 1) ||
(files_in_dir >= c->cache.max_entries)) {
/* Tell the world that we ran out of buffer space */
c->dirfull = true;
break;
@ -379,29 +381,14 @@ int ft_load(struct tree_context* c, const char* tempdir)
strcpy(dptr->name, (char *)entry->d_name);
name_buffer_used += len + 1;
if (dir_attr) /* count the remaining dirs */
if (dptr->attr & ATTR_DIRECTORY) /* count the remaining dirs */
c->dirsindir++;
}
c->filesindir = files_in_dir;
c->dirlength = files_in_dir;
closedir(dir);
cmp_data.sort_dir = c->sort_dir;
if (global_settings.sort_case)
{
if (global_settings.interpret_numbers == SORT_INTERPRET_AS_NUMBER)
cmp_data._compar = strnatcmp_n;
else
cmp_data._compar = strncmp;
}
else
{
if (global_settings.interpret_numbers == SORT_INTERPRET_AS_NUMBER)
cmp_data._compar = strnatcasecmp_n;
else
cmp_data._compar = strncasecmp;
}
compare_sort_dir = c->sort_dir;
qsort(tree_get_entries(c), files_in_dir, sizeof(struct entry), compare);
/* If thumbnail talking is enabled, make an extra run to mark files with
@ -412,6 +399,7 @@ int ft_load(struct tree_context* c, const char* tempdir)
tree_unlock_cache(c);
return 0;
}
#ifdef HAVE_LCD_BITMAP
static void ft_load_font(char *file)
{
int current_font_id;
@ -440,20 +428,13 @@ static void ft_load_font(char *file)
screens[screen].setuifont(
font_load_ex(file,0,global_settings.glyphs_to_cache));
viewportmanager_theme_changed(THEME_UI_VIEWPORT);
}
static void ft_apply_skin_file(char *buf, char *file, const int maxlen)
{
splash(0, ID2P(LANG_WAIT));
set_file(buf, file, maxlen);
settings_apply_skins();
}
}
#endif
int ft_enter(struct tree_context* c)
{
int rc = GO_TO_PREVIOUS;
char buf[MAX_PATH];
struct entry* file = tree_get_entry_at(c, c->selected_item);
if (!file)
{
@ -487,7 +468,7 @@ int ft_enter(struct tree_context* c)
switch ( file_attr & FILE_ATTR_MASK ) {
case FILE_ATTR_M3U:
play = ft_play_playlist(buf, c->currdir, file->name, false);
play = ft_play_playlist(buf, c->currdir, file->name);
if (play)
{
@ -497,9 +478,7 @@ int ft_enter(struct tree_context* c)
break;
case FILE_ATTR_AUDIO:
{
int res = bookmark_autoload(c->currdir);
if (res == BOOKMARK_CANCEL || res == BOOKMARK_DO_RESUME)
if (bookmark_autoload(c->currdir))
break;
splash(0, ID2P(LANG_WAIT));
@ -529,12 +508,11 @@ int ft_enter(struct tree_context* c)
start_index = 0;
}
playlist_set_modified(NULL, false);
playlist_start(start_index, 0, 0);
play = true;
}
break;
}
#if CONFIG_TUNER
/* fmr preset file */
case FILE_ATTR_FMR:
@ -559,32 +537,51 @@ int ft_enter(struct tree_context* c)
break;
case FILE_ATTR_FMS:
ft_apply_skin_file(buf, global_settings.fms_file, MAX_FILENAME);
splash(0, ID2P(LANG_WAIT));
set_file(buf, (char *)global_settings.fms_file, MAX_FILENAME);
settings_apply_skins();
break;
#ifdef HAVE_REMOTE_LCD
case FILE_ATTR_RFMS:
ft_apply_skin_file(buf, global_settings.rfms_file, MAX_FILENAME);
splash(0, ID2P(LANG_WAIT));
set_file(buf, (char *)global_settings.rfms_file, MAX_FILENAME);
settings_apply_skins();
break;
#endif
#endif
#ifdef HAVE_LCD_BITMAP
case FILE_ATTR_SBS:
ft_apply_skin_file(buf, global_settings.sbs_file, MAX_FILENAME);
splash(0, ID2P(LANG_WAIT));
set_file(buf, (char *)global_settings.sbs_file, MAX_FILENAME);
settings_apply_skins();
break;
#endif
#ifdef HAVE_REMOTE_LCD
case FILE_ATTR_RSBS:
ft_apply_skin_file(buf, global_settings.rsbs_file, MAX_FILENAME);
splash(0, ID2P(LANG_WAIT));
set_file(buf, (char *)global_settings.rsbs_file, MAX_FILENAME);
settings_apply_skins();
break;
#endif
/* wps config file */
case FILE_ATTR_WPS:
ft_apply_skin_file(buf, global_settings.wps_file, MAX_FILENAME);
splash(0, ID2P(LANG_WAIT));
set_file(buf, (char *)global_settings.wps_file,
MAX_FILENAME);
settings_apply_skins();
break;
#if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
/* remote-wps config file */
case FILE_ATTR_RWPS:
ft_apply_skin_file(buf, global_settings.rwps_file, MAX_FILENAME);
splash(0, ID2P(LANG_WAIT));
set_file(buf, (char *)global_settings.rwps_file,
MAX_FILENAME);
settings_apply_skins();
break;
#endif
case FILE_ATTR_CFG:
splash(0, ID2P(LANG_WAIT));
if (!settings_load_config(buf,true))
@ -613,6 +610,7 @@ int ft_enter(struct tree_context* c)
splash(HZ, ID2P(LANG_LANGUAGE_LOADED));
break;
#ifdef HAVE_LCD_BITMAP
case FILE_ATTR_FONT:
ft_load_font(buf);
break;
@ -623,8 +621,9 @@ int ft_enter(struct tree_context* c)
splash(HZ, ID2P(LANG_KEYBOARD_LOADED));
set_file(buf, (char *)global_settings.kbd_file, MAX_FILENAME);
break;
#endif
#if defined(HAVE_ROLO)
#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
/* firmware file */
case FILE_ATTR_MOD:
splash(0, ID2P(LANG_WAIT));
@ -632,28 +631,30 @@ int ft_enter(struct tree_context* c)
rolo_load(buf);
break;
#endif
case FILE_ATTR_CUE:
display_cuesheet_content(buf);
break;
/* plugin file */
case FILE_ATTR_ROCK:
case FILE_ATTR_LUA:
{
char *plugin = buf, *argument = NULL;
char *plugin = buf, *argument = NULL, lua_path[MAX_PATH];
int ret;
if ((file_attr & FILE_ATTR_MASK) == FILE_ATTR_LUA) {
snprintf(lua_path, sizeof(lua_path)-1, "%s/lua.rock", VIEWERS_DIR); /* Use a #define here ? */
plugin = lua_path;
argument = buf;
}
if (global_settings.party_mode && audio_status()) {
splash(HZ, ID2P(LANG_PARTY_MODE));
break;
}
#ifdef PLUGINS_RUN_IN_BROWSER /* Stay in the filetree to run a plugin */
switch (plugin_load(plugin, argument))
ret = plugin_load(plugin, argument);
switch (ret)
{
case PLUGIN_GOTO_WPS:
play = true;
break;
case PLUGIN_GOTO_PLUGIN:
rc = GO_TO_PLUGIN;
break;
case PLUGIN_USB_CONNECTED:
if(*c->dirfilter > NUM_FILTER_MODES)
/* leave sub-browsers after usb, doing
@ -669,42 +670,36 @@ int ft_enter(struct tree_context* c)
default:
break;
}
#else /* Exit the filetree to run a plugin */
plugin_open(plugin, argument);
rc = GO_TO_PLUGIN;
#endif
break;
}
case FILE_ATTR_CUE:
display_cuesheet_content(buf);
break;
default:
{
const char* plugin;
char plugin_path[MAX_PATH];
const char *argument = buf;
if (global_settings.party_mode && audio_status()) {
splash(HZ, ID2P(LANG_PARTY_MODE));
break;
}
file = tree_get_entry_at(c, c->selected_item);
struct entry* file = tree_get_entry_at(c, c->selected_item);
if (!file)
{
splashf(HZ, str(LANG_READ_FAILED), str(LANG_UNKNOWN));
return rc;
}
plugin = filetype_get_plugin(file, plugin_path, sizeof(plugin_path));
plugin = filetype_get_plugin(file);
if (plugin)
{
#ifdef PLUGINS_RUN_IN_BROWSER /* Stay in the filetree to run a plugin */
switch (plugin_load(plugin, argument))
switch (plugin_load(plugin,buf))
{
case PLUGIN_USB_CONNECTED:
rc = GO_TO_FILEBROWSER;
break;
case PLUGIN_GOTO_PLUGIN:
rc = GO_TO_PLUGIN;
break;
case PLUGIN_GOTO_WPS:
rc = GO_TO_WPS;
break;
@ -715,10 +710,6 @@ int ft_enter(struct tree_context* c)
default:
break;
}
#else /* Exit the filetree to run a plugin */
plugin_open(plugin, argument);
rc = GO_TO_PLUGIN;
#endif
}
break;
}

View file

@ -26,7 +26,6 @@ int ft_load(struct tree_context* c, const char* tempdir);
int ft_enter(struct tree_context* c);
int ft_exit(struct tree_context* c);
int ft_build_playlist(struct tree_context* c, int start_index);
bool ft_play_playlist(char* pathname, char* dirname,
char* filename, bool skip_warn_and_bookmarks);
bool ft_play_playlist(char* pathname, char* dirname, char* filename);
#endif

View file

@ -38,180 +38,131 @@
#include "splash.h"
#include "core_alloc.h"
#include "icons.h"
/*#define LOGF_ENABLE*/
#include "logf.h"
/* max filetypes (plugins & icons stored here) */
#if CONFIG_CODEC == SWCODEC
#define MAX_FILETYPES 192
#else
#define MAX_FILETYPES 128
#endif
/* max viewer plugins */
#ifdef HAVE_LCD_BITMAP
#define MAX_VIEWERS 56
static void read_builtin_types_init(void) INIT_ATTR;
static void read_viewers_config_init(void) INIT_ATTR;
static void read_config_init(int fd) INIT_ATTR;
#else
#define MAX_VIEWERS 24
#endif
/* a table for the known file types */
static const struct filetype inbuilt_filetypes[] = {
{ "mp3", FILE_ATTR_AUDIO },
{ "mp2", FILE_ATTR_AUDIO },
{ "mpa", FILE_ATTR_AUDIO },
{ "mp1", FILE_ATTR_AUDIO },
{ "ogg", FILE_ATTR_AUDIO },
{ "oga", FILE_ATTR_AUDIO },
{ "wma", FILE_ATTR_AUDIO },
{ "wmv", FILE_ATTR_AUDIO },
{ "asf", FILE_ATTR_AUDIO },
{ "wav", FILE_ATTR_AUDIO },
{ "flac", FILE_ATTR_AUDIO },
{ "ac3", FILE_ATTR_AUDIO },
{ "a52", FILE_ATTR_AUDIO },
{ "mpc", FILE_ATTR_AUDIO },
{ "wv", FILE_ATTR_AUDIO },
{ "m4a", FILE_ATTR_AUDIO },
{ "m4b", FILE_ATTR_AUDIO },
{ "mp4", FILE_ATTR_AUDIO },
{ "mod", FILE_ATTR_AUDIO },
{ "mpga", FILE_ATTR_AUDIO },
{ "shn", FILE_ATTR_AUDIO },
{ "aif", FILE_ATTR_AUDIO },
{ "aiff", FILE_ATTR_AUDIO },
{ "spx" , FILE_ATTR_AUDIO },
{ "opus", FILE_ATTR_AUDIO },
{ "sid", FILE_ATTR_AUDIO },
{ "adx", FILE_ATTR_AUDIO },
{ "nsf", FILE_ATTR_AUDIO },
{ "nsfe", FILE_ATTR_AUDIO },
{ "spc", FILE_ATTR_AUDIO },
{ "ape", FILE_ATTR_AUDIO },
{ "mac", FILE_ATTR_AUDIO },
{ "sap" , FILE_ATTR_AUDIO },
{ "rm", FILE_ATTR_AUDIO },
{ "ra", FILE_ATTR_AUDIO },
{ "rmvb", FILE_ATTR_AUDIO },
{ "cmc", FILE_ATTR_AUDIO },
{ "cm3", FILE_ATTR_AUDIO },
{ "cmr", FILE_ATTR_AUDIO },
{ "cms", FILE_ATTR_AUDIO },
{ "dmc", FILE_ATTR_AUDIO },
{ "dlt", FILE_ATTR_AUDIO },
{ "mpt", FILE_ATTR_AUDIO },
{ "mpd", FILE_ATTR_AUDIO },
{ "rmt", FILE_ATTR_AUDIO },
{ "tmc", FILE_ATTR_AUDIO },
{ "tm8", FILE_ATTR_AUDIO },
{ "tm2", FILE_ATTR_AUDIO },
{ "oma", FILE_ATTR_AUDIO },
{ "aa3", FILE_ATTR_AUDIO },
{ "at3", FILE_ATTR_AUDIO },
{ "mmf", FILE_ATTR_AUDIO },
{ "au", FILE_ATTR_AUDIO },
{ "snd", FILE_ATTR_AUDIO },
{ "vox", FILE_ATTR_AUDIO },
{ "w64", FILE_ATTR_AUDIO },
{ "tta", FILE_ATTR_AUDIO },
{ "ay", FILE_ATTR_AUDIO },
{ "vtx", FILE_ATTR_AUDIO },
{ "gbs", FILE_ATTR_AUDIO },
{ "hes", FILE_ATTR_AUDIO },
{ "sgc", FILE_ATTR_AUDIO },
{ "vgm", FILE_ATTR_AUDIO },
{ "vgz", FILE_ATTR_AUDIO },
{ "kss", FILE_ATTR_AUDIO },
{ "aac", FILE_ATTR_AUDIO },
{ "m3u", FILE_ATTR_M3U },
{ "m3u8", FILE_ATTR_M3U },
{ "cfg", FILE_ATTR_CFG },
{ "wps", FILE_ATTR_WPS },
{ "mp3", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "mp2", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "mpa", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
#if CONFIG_CODEC == SWCODEC
/* Temporary hack to allow playlist creation */
{ "mp1", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "ogg", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "oga", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "wma", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "wmv", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "asf", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "wav", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "flac",FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "ac3", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "a52", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "mpc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "wv", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "m4a", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "m4b", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "mp4", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "mod", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "shn", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "aif", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "aiff",FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "spx" ,FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "opus",FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "sid", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "adx", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "nsf", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "nsfe",FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "spc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "ape", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "mac", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "sap" ,FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "rm", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "ra", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "rmvb",FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "cmc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "cm3", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "cmr", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "cms", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "dmc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "dlt", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "mpt", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "mpd", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "rmt", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "tmc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "tm8", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "tm2", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "oma", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "aa3", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "at3", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "mmf", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "au", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "snd", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "vox", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "w64", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "tta", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "ay", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "gbs", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "hes", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "sgc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "vgm", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "vgz", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "kss", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ "aac", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
#endif
{ "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
{ "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
{ "cfg", FILE_ATTR_CFG, Icon_Config, VOICE_EXT_CFG },
{ "wps", FILE_ATTR_WPS, Icon_Wps, VOICE_EXT_WPS },
#ifdef HAVE_REMOTE_LCD
{ "rwps", FILE_ATTR_RWPS },
{ "rwps",FILE_ATTR_RWPS, Icon_Wps, VOICE_EXT_RWPS },
#endif
#if CONFIG_TUNER
{ "fmr", FILE_ATTR_FMR },
{ "fms", FILE_ATTR_FMS },
{ "fmr", FILE_ATTR_FMR, Icon_Preset, LANG_FMR },
{ "fms", FILE_ATTR_FMS, Icon_Wps, VOICE_EXT_FMS },
#endif
{ "lng", FILE_ATTR_LNG, Icon_Language, LANG_LANGUAGE },
{ "rock",FILE_ATTR_ROCK,Icon_Plugin, VOICE_EXT_ROCK },
{ "lua", FILE_ATTR_LUA, Icon_Plugin, VOICE_EXT_ROCK },
#ifdef HAVE_LCD_BITMAP
{ "fnt", FILE_ATTR_FONT,Icon_Font, VOICE_EXT_FONT },
{ "kbd", FILE_ATTR_KBD, Icon_Keyboard, VOICE_EXT_KBD },
#endif
{ "bmark",FILE_ATTR_BMARK, Icon_Bookmark, VOICE_EXT_BMARK },
{ "cue", FILE_ATTR_CUE, Icon_Bookmark, VOICE_EXT_CUESHEET },
#ifdef HAVE_LCD_BITMAP
{ "sbs", FILE_ATTR_SBS, Icon_Wps, VOICE_EXT_SBS },
#endif
{ "log", FILE_ATTR_LOG },
{ "lng", FILE_ATTR_LNG },
{ "rock", FILE_ATTR_ROCK },
{ "lua", FILE_ATTR_LUA },
{ "opx", FILE_ATTR_OPX },
{ "fnt", FILE_ATTR_FONT },
{ "kbd", FILE_ATTR_KBD },
{ "bmark",FILE_ATTR_BMARK },
{ "cue", FILE_ATTR_CUE },
{ "sbs", FILE_ATTR_SBS },
#ifdef HAVE_REMOTE_LCD
{ "rsbs", FILE_ATTR_RSBS },
{ "rsbs", FILE_ATTR_RSBS, Icon_Wps, VOICE_EXT_RSBS },
#if CONFIG_TUNER
{ "rfms", FILE_ATTR_RFMS },
{ "rfms", FILE_ATTR_RFMS, Icon_Wps, VOICE_EXT_RFMS },
#endif
#endif
#ifdef BOOTFILE_EXT
{ BOOTFILE_EXT, FILE_ATTR_MOD },
{ BOOTFILE_EXT, FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ },
#endif
#ifdef BOOTFILE_EXT2
{ BOOTFILE_EXT2, FILE_ATTR_MOD },
{ BOOTFILE_EXT2, FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ },
#endif
};
struct fileattr_icon_voice {
int tree_attr;
uint16_t icon;
uint16_t voiceclip;
};
/* a table for the known file types icons & voice clips */
static const struct fileattr_icon_voice inbuilt_attr_icons_voices[] = {
{ FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA },
{ FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST },
{ FILE_ATTR_CFG, Icon_Config, VOICE_EXT_CFG },
{ FILE_ATTR_WPS, Icon_Wps, VOICE_EXT_WPS },
#ifdef HAVE_REMOTE_LCD
{FILE_ATTR_RWPS, Icon_Wps, VOICE_EXT_RWPS },
#endif
#if CONFIG_TUNER
{ FILE_ATTR_FMR, Icon_Preset, LANG_FMR },
{ FILE_ATTR_FMS, Icon_Wps, VOICE_EXT_FMS },
#endif
{ FILE_ATTR_LNG, Icon_Language, LANG_LANGUAGE },
{ FILE_ATTR_ROCK, Icon_Plugin, VOICE_EXT_ROCK },
{ FILE_ATTR_LUA, Icon_Plugin, VOICE_EXT_ROCK },
{ FILE_ATTR_OPX, Icon_Plugin, VOICE_EXT_ROCK },
{ FILE_ATTR_FONT, Icon_Font, VOICE_EXT_FONT },
{ FILE_ATTR_KBD, Icon_Keyboard, VOICE_EXT_KBD },
{ FILE_ATTR_BMARK, Icon_Bookmark, VOICE_EXT_BMARK },
{ FILE_ATTR_CUE, Icon_Bookmark, VOICE_EXT_CUESHEET },
{ FILE_ATTR_SBS, Icon_Wps, VOICE_EXT_SBS },
#ifdef HAVE_REMOTE_LCD
{ FILE_ATTR_RSBS, Icon_Wps, VOICE_EXT_RSBS },
#if CONFIG_TUNER
{ FILE_ATTR_RFMS, Icon_Wps, VOICE_EXT_RFMS },
#endif
#endif
#if defined(BOOTFILE_EXT) || defined(BOOTFILE_EXT2)
{ FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ },
#endif
};
long tree_get_filetype_voiceclip(int attr)
void tree_get_filetypes(const struct filetype** types, int* count)
{
if (global_settings.talk_filetype)
{
size_t count = ARRAY_SIZE(inbuilt_attr_icons_voices);
/* try to find a voice ID for the extension, if known */
attr &= FILE_ATTR_MASK; /* file type */
for (size_t i = count - 1; i < count; i--)
{
if (attr == inbuilt_attr_icons_voices[i].tree_attr)
{
logf("%s found attr %d id %d", __func__, attr,
inbuilt_attr_icons_voices[i].voiceclip);
return inbuilt_attr_icons_voices[i].voiceclip;
}
}
}
logf("%s not found attr %d", __func__, attr);
return -1;
*types = inbuilt_filetypes;
*count = sizeof(inbuilt_filetypes) / sizeof(*inbuilt_filetypes);
}
#define ROCK_EXTENSION "rock"
@ -247,8 +198,7 @@ static int filetype_count = 0;
static unsigned char highest_attr = 0;
static int viewer_count = 0;
static int strdup_handle, strdup_cur_idx;
static size_t strdup_bufsize;
static int strdup_handle, strdup_bufsize, strdup_cur_idx;
static int move_callback(int handle, void* current, void* new)
{
/*could compare to strdup_handle, but ops is only used once */
@ -305,6 +255,8 @@ static int find_extension(const char* extension)
return -1;
}
static void read_builtin_types(void);
static void read_config(int fd);
#ifdef HAVE_LCD_COLOR
/* Colors file format is similar to icons:
* ext:hex_color
@ -318,12 +270,9 @@ void read_color_theme_file(void) {
for (i = 0; i < MAX_FILETYPES; i++) {
custom_colors[i] = -1;
}
unknown_file.color = -1;
if (!global_settings.colors_file[0] || global_settings.colors_file[0] == '-')
return;
fd = open_pathfmt(buffer, sizeof(buffer), O_RDONLY,
THEME_DIR "/%s.colours", global_settings.colors_file);
snprintf(buffer, MAX_PATH, THEME_DIR "/%s.colours",
global_settings.colors_file);
fd = open(buffer, O_RDONLY);
if (fd < 0)
return;
while (read_line(fd, buffer, MAX_PATH) > 0)
@ -347,6 +296,7 @@ void read_color_theme_file(void) {
close(fd);
}
#endif
#ifdef HAVE_LCD_BITMAP
void read_viewer_theme_file(void)
{
char buffer[MAX_PATH];
@ -361,12 +311,12 @@ void read_viewer_theme_file(void)
{
custom_filetype_icons[i] = filetypes[i].icon;
}
fd = open_pathfmt(buffer, sizeof(buffer), O_RDONLY,
ICON_DIR "/%s.icons", global_settings.viewers_icon_file);
snprintf(buffer, MAX_PATH, "%s/%s.icons", ICON_DIR,
global_settings.viewers_icon_file);
fd = open(buffer, O_RDONLY);
if (fd < 0)
return;
while (read_line(fd, buffer, MAX_PATH) > 0)
{
if (!settings_parseline(buffer, &ext, &icon))
@ -397,31 +347,9 @@ void read_viewer_theme_file(void)
close(fd);
custom_icons_loaded = true;
}
#endif
static void read_viewers_config_init(void)
{
int fd = open(VIEWERS_CONFIG, O_RDONLY);
if(fd < 0)
return;
off_t filesz = filesize(fd);
if(filesz <= 0)
goto out;
/* estimate bufsize with the filesize, will not be larger */
strdup_bufsize = (size_t)filesz;
strdup_handle = core_alloc_ex(strdup_bufsize, &ops);
if(strdup_handle <= 0)
goto out;
read_config_init(fd);
core_shrink(strdup_handle, NULL, strdup_cur_idx);
out:
close(fd);
}
void filetype_init(void)
void filetype_init(void)
{
/* set the directory item first */
filetypes[0].extension = NULL;
@ -429,15 +357,31 @@ void filetype_init(void)
filetypes[0].attr = 0;
filetypes[0].icon = Icon_Folder;
/* estimate bufsize with the filesize, will not be larger */
viewer_count = 0;
filetype_count = 1;
read_builtin_types_init();
read_viewers_config_init();
int fd = open(VIEWERS_CONFIG, O_RDONLY);
if (fd < 0)
return;
strdup_bufsize = filesize(fd);
strdup_handle = core_alloc_ex("filetypes", strdup_bufsize, &ops);
if (strdup_handle <= 0)
{
close(fd);
return;
}
read_builtin_types();
read_config(fd);
close(fd);
#ifdef HAVE_LCD_BITMAP
read_viewer_theme_file();
#endif
#ifdef HAVE_LCD_COLOR
read_color_theme_file();
#endif
core_shrink(strdup_handle, core_get_data(strdup_handle), strdup_cur_idx);
}
/* remove all white spaces from string */
@ -456,35 +400,22 @@ static void rm_whitespaces(char* str)
*s = '\0';
}
static void read_builtin_types_init(void)
static void read_builtin_types(void)
{
int tree_attr;
size_t count = ARRAY_SIZE(inbuilt_filetypes);
size_t icon_count = ARRAY_SIZE(inbuilt_attr_icons_voices);
for(size_t i = 0; (i < count) && (filetype_count < MAX_FILETYPES); i++)
int count = sizeof(inbuilt_filetypes)/sizeof(*inbuilt_filetypes), i;
for(i=0; i<count && (filetype_count < MAX_FILETYPES); i++)
{
filetypes[filetype_count].extension = inbuilt_filetypes[i].extension;
filetypes[filetype_count].plugin = NULL;
tree_attr = inbuilt_filetypes[i].tree_attr;
filetypes[filetype_count].attr = tree_attr>>8;
filetypes[filetype_count].attr = inbuilt_filetypes[i].tree_attr>>8;
if (filetypes[filetype_count].attr > highest_attr)
highest_attr = filetypes[filetype_count].attr;
filetypes[filetype_count].icon = unknown_file.icon;
for (size_t j = icon_count - 1; j < icon_count; j--)
{
if (tree_attr == inbuilt_attr_icons_voices[j].tree_attr)
{
filetypes[filetype_count].icon = inbuilt_attr_icons_voices[j].icon;
break;
}
}
filetypes[filetype_count].icon = inbuilt_filetypes[i].icon;
filetype_count++;
}
}
static void read_config_init(int fd)
static void read_config(int fd)
{
char line[64], *s, *e;
char *extension, *plugin;
@ -604,37 +535,17 @@ int filetype_get_icon(int attr)
return filetypes[index].icon;
}
char* filetype_get_plugin(const struct entry* file, char *buffer, size_t buffer_len)
char* filetype_get_plugin(const struct entry* file)
{
static char plugin_name[MAX_PATH];
int index = find_attr(file->attr);
if (index < 0 || !buffer)
if (index < 0)
return NULL;
struct file_type *ft_indexed = &filetypes[index];
/* attempt to find a suitable viewer by file extension */
if(ft_indexed->plugin == NULL && ft_indexed->extension != NULL)
{
struct file_type *ft;
int i = filetype_count;
while (--i > index)
{
ft = &filetypes[i];
if (ft->plugin == NULL || ft->extension == NULL)
continue;
else if (strcmp(ft->extension, ft_indexed->extension) == 0)
{
/*splashf(HZ*3, "Found %d %s %s", i, ft->extension, ft->plugin);*/
ft_indexed = ft;
break;
}
}
}
if (ft_indexed->plugin == NULL)
if (filetypes[index].plugin == NULL)
return NULL;
snprintf(buffer, buffer_len, "%s/%s." ROCK_EXTENSION,
PLUGIN_DIR, ft_indexed->plugin);
return buffer;
snprintf(plugin_name, MAX_PATH, "%s/%s.%s",
PLUGIN_DIR, filetypes[index].plugin, ROCK_EXTENSION);
return plugin_name;
}
bool filetype_supported(int attr)
@ -667,32 +578,46 @@ static int openwith_get_talk(int selected_item, void * data)
{
(void)data;
char viewer_filename[MAX_FILENAME];
snprintf(viewer_filename, MAX_FILENAME, "%s." ROCK_EXTENSION,
filetypes[viewers[selected_item]].plugin);
snprintf(viewer_filename, MAX_FILENAME, "%s.%s",
filetypes[viewers[selected_item]].plugin, ROCK_EXTENSION);
talk_file_or_spell(PLUGIN_DIR, viewer_filename,
NULL, false);
return 0;
}
static int openwith_action_callback(int action, struct gui_synclist *lists)
{
struct cb_data *info = (struct cb_data *)lists->data;
int i;
if (action == ACTION_STD_OK)
{
char plugin[MAX_PATH];
i = viewers[gui_synclist_get_sel_pos(lists)];
snprintf(plugin, MAX_PATH, "%s/%s.%s",
PLUGIN_DIR, filetypes[i].plugin, ROCK_EXTENSION);
plugin_load(plugin, info->current_file);
return ACTION_STD_CANCEL;
}
return action;
}
int filetype_list_viewers(const char* current_file)
{
struct simplelist_info info;
simplelist_info_init(&info, str(LANG_ONPLAY_OPEN_WITH), viewer_count, NULL);
struct cb_data data = { current_file };
#ifndef HAVE_LCD_BITMAP
if (viewer_count == 0)
{
splash(HZ*2, ID2P(LANG_NO_VIEWERS));
return PLUGIN_OK;
}
#endif
simplelist_info_init(&info, str(LANG_ONPLAY_OPEN_WITH), viewer_count, &data);
info.action_callback = openwith_action_callback;
info.get_name = openwith_get_name;
info.get_icon = global_settings.show_icons?openwith_get_icon:NULL;
info.get_talk = openwith_get_talk;
int ret = simplelist_show_list(&info);
if (info.selection >= 0) /* run user selected viewer */
{
char plugin[MAX_PATH];
int i = viewers[info.selection];
snprintf(plugin, MAX_PATH, "%s/%s." ROCK_EXTENSION,
PLUGIN_DIR, filetypes[i].plugin);
ret = plugin_load(plugin, current_file);
}
return ret;
return simplelist_show_list(&info);
}
int filetype_load_plugin(const char* plugin, const char* file)
@ -717,7 +642,7 @@ int filetype_load_plugin(const char* plugin, const char* file)
}
if (i >= filetype_count)
return PLUGIN_ERROR;
snprintf(plugin_name, MAX_PATH, "%s/%s." ROCK_EXTENSION,
PLUGIN_DIR, filetypes[i].plugin);
snprintf(plugin_name, MAX_PATH, "%s/%s.%s",
PLUGIN_DIR, filetypes[i].plugin, ROCK_EXTENSION);
return plugin_load(plugin_name, file);
}

View file

@ -47,21 +47,19 @@
#define FILE_ATTR_LUA 0x1100 /* Lua rockbox plugin */
#define FILE_ATTR_FMS 0x1200 /* FM screen skin file */
#define FILE_ATTR_RFMS 0x1300 /* FM screen skin file */
#define FILE_ATTR_OPX 0x1400 /* open plugins shortcut */
#define FILE_ATTR_LOG 0x1500 /* log file */
#define FILE_ATTR_MASK 0xFF00 /* which bits tree.c uses for file types */
struct filetype {
char* extension;
int tree_attr;
enum themable_icons icon;
int voiceclip;
};
long tree_get_filetype_voiceclip(int attr);
void tree_get_filetypes(const struct filetype**, int*) INIT_ATTR;
/* init the filetypes structs.
uses audio buffer for storage, so call early in init... */
void filetype_init(void) INIT_ATTR;
void read_viewer_theme_file(void);
#ifdef HAVE_LCD_COLOR
void read_color_theme_file(void);
@ -74,7 +72,7 @@ int filetype_get_color(const char* name, int attr);
#endif
int filetype_get_icon(int attr);
/* return the plugin filename associated with the file */
char* filetype_get_plugin(const struct entry* file, char *buffer, size_t buffer_len);
char* filetype_get_plugin(const struct entry* file);
/* returns true if the attr is supported */
bool filetype_supported(int attr);

View file

@ -197,9 +197,6 @@ bool skinlist_draw(struct screen *display, struct gui_synclist *list)
wps.data = listcfg[screen]->data;
display_lines = skinlist_get_line_count(screen, list);
label = (char *)SKINOFFSETTOPTR(get_skin_buffer(wps.data), listcfg[screen]->label);
if (!label)
return false;
display->set_viewport(parent);
display->clear_viewport();
current_item = list->selected_item;
@ -213,7 +210,8 @@ bool skinlist_draw(struct screen *display, struct gui_synclist *list)
if (list_start_item+cur_line+1 > list->nb_items)
break;
current_drawing_line = list_start_item+cur_line;
is_selected = list_start_item+cur_line == list->selected_item;
is_selected = list->show_selection_marker &&
list_start_item+cur_line == list->selected_item;
for (viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), listcfg[screen]->data->tree);
viewport;
@ -221,9 +219,7 @@ bool skinlist_draw(struct screen *display, struct gui_synclist *list)
{
int original_x, original_y;
skin_viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), viewport->data);
char *viewport_label = NULL;
if (skin_viewport)
viewport_label = SKINOFFSETTOPTR(get_skin_buffer(wps.data), skin_viewport->label);
char *viewport_label = SKINOFFSETTOPTR(get_skin_buffer(wps.data), skin_viewport->label);
if (viewport->children == 0 || !viewport_label ||
(skin_viewport->label && strcmp(label, viewport_label))
)
@ -240,7 +236,7 @@ bool skinlist_draw(struct screen *display, struct gui_synclist *list)
int cols = (parent->width / listcfg[screen]->width);
current_column = (cur_line)%cols;
current_row = (cur_line)/cols;
skin_viewport->vp.x = parent->x + listcfg[screen]->width*current_column + original_x;
skin_viewport->vp.y = parent->y + listcfg[screen]->height*current_row + original_y;
}
@ -253,23 +249,23 @@ bool skinlist_draw(struct screen *display, struct gui_synclist *list)
(listcfg[screen]->height*cur_line);
}
display->set_viewport(&skin_viewport->vp);
#ifdef HAVE_LCD_BITMAP
/* Set images to not to be displayed */
struct skin_token_list *imglist = SKINOFFSETTOPTR(get_skin_buffer(wps.data), wps.data->images);
while (imglist)
{
struct wps_token *token = SKINOFFSETTOPTR(get_skin_buffer(wps.data), imglist->token);
struct gui_img *img = NULL;
if (token)
img = SKINOFFSETTOPTR(get_skin_buffer(wps.data), token->value.data);
if (img)
img->display = -1;
struct gui_img *img = SKINOFFSETTOPTR(get_skin_buffer(wps.data), token->value.data);
img->display = -1;
imglist = SKINOFFSETTOPTR(get_skin_buffer(wps.data), imglist->next);
}
#endif
struct skin_element** children = SKINOFFSETTOPTR(get_skin_buffer(wps.data), viewport->children);
if (children && *children)
skin_render_viewport(SKINOFFSETTOPTR(get_skin_buffer(wps.data), (intptr_t)children[0]),
&wps, skin_viewport, SKIN_REFRESH_ALL);
skin_render_viewport(SKINOFFSETTOPTR(get_skin_buffer(wps.data), (intptr_t)children[0]),
&wps, skin_viewport, SKIN_REFRESH_ALL);
#ifdef HAVE_LCD_BITMAP
wps_display_images(&wps, &skin_viewport->vp);
#endif
/* force disableing scroll because it breaks later */
if (!is_selected)
{
@ -286,3 +282,4 @@ bool skinlist_draw(struct screen *display, struct gui_synclist *list)
current_drawing_line = list->selected_item;
return true;
}

View file

@ -50,6 +50,7 @@
static struct viewport list_text[NB_SCREENS], title_text[NB_SCREENS];
#ifdef HAVE_TOUCHSCREEN
static int y_offset;
static bool hide_selection;
#endif
@ -90,57 +91,11 @@ static int list_icon_width(enum screen_type screen)
return get_icon_width(screen) + ICON_PADDING * 2;
}
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;
const 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)
static bool draw_title(struct screen *display, struct gui_synclist *list)
{
const int screen = display->screen_type;
struct viewport *title_text_vp = &title_text[screen];
struct line_desc linedes = LINE_DESC_DEFINIT;
struct line_desc line = LINE_DESC_DEFINIT;
if (sb_set_title_text(list->title, list->title_icon, screen))
return false; /* the sbs is handling the title */
@ -148,41 +103,29 @@ static bool draw_title(struct screen *display,
if (!list_display_title(list, screen))
return false;
*title_text_vp = *(list->parent[screen]);
linedes.height = list->line_height[screen];
title_text_vp->height = linedes.height;
line.height = list->line_height[screen];
title_text_vp->height = line.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)
linedes.separator_height = abs(global_settings.list_separator_height)
line.separator_height = abs(global_settings.list_separator_height)
+ (lcd_get_dpi() > 200 ? 2 : 1);
#endif
#ifdef HAVE_LCD_COLOR
if (list->title_color >= 0)
linedes.style |= (STYLE_COLORED|list->title_color);
line.style |= (STYLE_COLORED|list->title_color);
#endif
linedes.scroll = true;
line.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 && list->show_icons)
{
have_icons = true;
}
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);
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);
return true;
}
@ -191,30 +134,23 @@ 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 = (list->scrollbar == SCROLLBAR_LEFT);
const bool scrollbar_in_right = (list->scrollbar == SCROLLBAR_RIGHT);
const bool show_cursor = (list->cursor_style == SYNCLIST_CURSOR_NOSTYLE);
const bool have_icons = list->callback_get_item_icon && list->show_icons;
const bool scrollbar_in_left = (global_settings.scrollbar == SCROLLBAR_LEFT);
const bool scrollbar_in_right = (global_settings.scrollbar == SCROLLBAR_RIGHT);
const bool show_cursor = !global_settings.cursor_style &&
list->show_selection_marker;
const bool have_icons = global_settings.show_icons && list->callback_get_item_icon;
struct viewport *parent = (list->parent[screen]);
struct line_desc linedes = LINE_DESC_DEFINIT;
bool show_title;
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->set_viewport(parent);
display->clear_viewport();
display->scroll_stop_viewport(list_text_vp);
*list_text_vp = *parent;
if ((show_title = draw_title(display, list, callback_draw_item)))
if ((show_title = draw_title(display, list)))
{
int title_height = title_text[screen].height;
list_text_vp->y += title_height;
@ -234,15 +170,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;
if (list->selected_item == 0 || (list->nb_items < nb_lines))
y_offset = 0; /* reset in case it's a new list */
int draw_offset = list_start_item * linedes.height - list->y_pos;
int draw_offset = y_offset;
/* draw some extra items to not have empty lines at the top and bottom */
if (draw_offset > 0)
if (y_offset > 0)
{
/* make it negative for more consistent apparence when switching
* directions */
@ -250,56 +183,31 @@ void list_draw(struct screen *display, struct gui_synclist *list)
if (start > 0)
start--;
}
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 if (y_offset < 0)
end++;
#else
#define draw_offset 0
#endif
/* draw the scrollbar if its needed */
if (list->scrollbar != SCROLLBAR_OFF)
if (global_settings.scrollbar != SCROLLBAR_OFF)
{
/* if the scrollbar is shown the text viewport needs to shrink */
if (nb_lines < list->nb_items)
{
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
display->set_viewport(&vp);
gui_scrollbar_draw(display,
(scrollbar_in_left? 0: 1), 0, SCROLLBAR_WIDTH-1, vp.height,
scrollbar_items, scrollbar_min, scrollbar_max, VERTICAL);
display->set_viewport(last);
list->nb_items, list_start_item, list_start_item + nb_lines,
VERTICAL);
}
/* shift everything a bit in relation to the title */
else if (!VP_IS_RTL(list_text_vp) && scrollbar_in_left)
@ -308,17 +216,6 @@ void list_draw(struct screen *display, struct gui_synclist *list)
indent += SCROLLBAR_WIDTH;
}
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 */
@ -326,10 +223,13 @@ 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;
int line = i - start;
int line_indent = 0;
int style = STYLE_DEFAULT;
bool is_selected = false;
icon = list->callback_get_item_icon ?
list->callback_get_item_icon(i, list->data) : Icon_NOICON;
s = list->callback_get_item_name(i, list->data, entry_buffer,
sizeof(entry_buffer));
entry_name = P2STR(s);
@ -341,17 +241,18 @@ void list_draw(struct screen *display, struct gui_synclist *list)
}
if (line_indent)
{
if (list->show_icons)
line_indent *= icon_w;
if (global_settings.show_icons)
line_indent *= list_icon_width(screen);
else
line_indent *= character_width;
line_indent *= display->getcharwidth();
}
line_indent += indent;
display->set_viewport(list_text_vp);
/* position the string at the correct offset place */
int item_width,h;
display->getstringsize(entry_name, &item_width, &h);
item_offset = gui_list_get_item_offset(list, item_width, indent + (list->show_icons ? icon_w : 0),
item_offset = gui_list_get_item_offset(list, item_width, text_pos,
display, list_text_vp);
/* draw the selected line */
@ -361,25 +262,15 @@ void list_draw(struct screen *display, struct gui_synclist *list)
!hide_selection &&
#endif
i >= list->selected_item
&& i < list->selected_item + list->selected_size)
&& i < list->selected_item + list->selected_size
&& list->show_selection_marker)
{/* The selected item must be displayed scrolling */
#ifdef HAVE_LCD_COLOR
if (list->selection_color)
{
/* Display gradient line selector */
style = STYLE_GRADIENT;
linedes.text_color = list->selection_color->text_color;
linedes.line_color = list->selection_color->line_color;
linedes.line_end_color = list->selection_color->line_end_color;
}
else
#endif
if (list->cursor_style == SYNCLIST_CURSOR_INVERT
if (global_settings.cursor_style == 1
#ifdef HAVE_REMOTE_LCD
/* the global_settings.cursor_style check is here to make
* sure if they want the cursor instead of bar it will work
*/
|| (display->depth < 16 && list->cursor_style)
|| (display->depth < 16 && global_settings.cursor_style)
#endif
)
{
@ -387,14 +278,14 @@ void list_draw(struct screen *display, struct gui_synclist *list)
style = STYLE_INVERT;
}
#ifdef HAVE_LCD_COLOR
else if (list->cursor_style == SYNCLIST_CURSOR_COLOR)
else if (global_settings.cursor_style == 2)
{
/* Display colour line selector */
style = STYLE_COLORBAR;
linedes.text_color = global_settings.lst_color;
linedes.line_color = global_settings.lss_color;
}
else if (list->cursor_style == SYNCLIST_CURSOR_GRADIENT)
else if (global_settings.cursor_style == 3)
{
/* Display gradient line selector */
style = STYLE_GRADIENT;
@ -418,26 +309,30 @@ 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;
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);
/* 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);
}
display->set_viewport(parent);
display->update_viewport();
display->set_viewport(last_vp);
display->set_viewport(NULL);
}
#if defined(HAVE_TOUCHSCREEN)
@ -453,33 +348,29 @@ static enum {
SCROLL_KINETIC, /* state after releasing swipe */
} scroll_mode;
static int scrollbar_scroll(struct gui_synclist * gui_list, int y)
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)
{
const int line_height = gui_list->line_height[screen];
/* try to position the center of the scrollbar at the touch point */
int scrollbar_size = list_text[screen].height;
/* scrollbar scrolling is still line based */
y_offset = 0;
int scrollbar_size = nb_lines*gui_list->line_height[screen];
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;
}
int new_selection = (actual_y * gui_list->nb_items)
/ scrollbar_size;
gui_list->start_item[screen] = new_start;
gui_list->y_pos = new_y_pos;
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;
gui_list->start_item[screen] = start_item;
return ACTION_REDRAW;
}
@ -569,11 +460,9 @@ static void kinetic_force_stop(void)
/* helper for gui/list.c to cancel scrolling if a normal button event comes
* through dpad or keyboard or whatever */
void _gui_synclist_stop_kinetic_scrolling(struct gui_synclist * gui_list)
void _gui_synclist_stop_kinetic_scrolling(void)
{
const enum screen_type screen = screens[SCREEN_MAIN].screen_type;
gui_list->y_pos = gui_list->start_item[screen] * gui_list->line_height[screen];
y_offset = 0;
if (scroll_mode == SCROLL_KINETIC)
kinetic_force_stop();
scroll_mode = SCROLL_NONE;
@ -614,27 +503,23 @@ 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;
/* Move the y position and clamp it (funny things happen otherwise...) */
gui_list->y_pos -= difference;
if(gui_list->y_pos < 0)
gui_list->y_pos = 0;
else if(gui_list->y_pos > max_y_pos)
gui_list->y_pos = max_y_pos;
else
hit_end = false;
/* Get the list y position. When pos_y differs by a line height or more,
* we need to scroll the list by adjusting the start item accordingly */
int cur_y = gui_list->start_item[screen] * line_height;
int diff_y = cur_y - gui_list->y_pos;
if (abs(diff_y) >= line_height)
/* don't scroll at the edges of the list */
if ((old_start == 0 && difference > 0)
|| (old_start == (gui_list->nb_items - nb_lines) && difference < 0))
{
line_diff = diff_y/line_height;
y_offset = 0;
gui_list->start_item[screen] = old_start;
return scroll_mode != SCROLL_KINETIC; /* stop kinetic at the edges */
}
/* add up y_offset over time and translate to lines
* if scrolled enough */
y_offset += difference;
if (abs(y_offset) > line_height)
{
line_diff = y_offset/line_height;
y_offset -= line_diff * line_height;
}
if(line_diff != 0)
@ -651,14 +536,9 @@ static bool swipe_scroll(struct gui_synclist * gui_list, int difference)
gui_list->start_item[screen] = new_start_item;
/* keep selected item in sync */
gui_list->selected_item = new_start_item + selection_offset;
if(gui_list->selected_size > 1)
gui_list->selected_item -= (gui_list->selected_item % gui_list->selected_size);
}
if(hit_end)
return scroll_mode != SCROLL_KINETIC;
else
return true;
return true;
}
static int kinetic_callback(struct timeout *tmo)
@ -753,7 +633,7 @@ static int get_click_location(struct gui_synclist *list, int x, int y)
if (viewport_point_within_vp(title, x, y))
retval = TITLE_TEXT;
/* check the icon too */
if (list->title_icon != Icon_NOICON && list->show_icons)
if (list->title_icon != Icon_NOICON && global_settings.show_icons)
{
int width = list_icon_width(screen);
struct viewport vp = *title;
@ -771,19 +651,14 @@ static int get_click_location(struct gui_synclist *list, int x, int y)
{
bool on_scrollbar_clicked;
int adj_x = x - parent->x;
switch (list->scrollbar)
switch (global_settings.scrollbar)
{
case SCROLLBAR_OFF:
/*fall-through*/
default:
on_scrollbar_clicked = false;
break;
case SCROLLBAR_LEFT:
on_scrollbar_clicked = adj_x <= SCROLLBAR_WIDTH;
break;
on_scrollbar_clicked = adj_x <= SCROLLBAR_WIDTH; break;
case SCROLLBAR_RIGHT:
on_scrollbar_clicked = adj_x > (title->x + title->width - SCROLLBAR_WIDTH);
break;
on_scrollbar_clicked = adj_x > (title->x + title->width - SCROLLBAR_WIDTH); break;
default:
on_scrollbar_clicked = false; break;
}
if (on_scrollbar_clicked)
retval = SCROLLBAR;
@ -844,16 +719,13 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * list)
if(!skinlist_get_item(&screens[screen], list, adj_x, adj_y, &line))
{
/* selection needs to be corrected if items are only partially visible */
int cur_y = list->start_item[screen] * line_height;
line = (adj_y - (cur_y - list->y_pos)) / line_height;
line = (adj_y - y_offset) / line_height;
if (list_display_title(list, screen))
line -= 1; /* adjust for the list title */
}
if (list_start_item+line >= list->nb_items)
if (line >= list->nb_items)
return ACTION_NONE;
list->selected_item = list_start_item+line;
if(list->selected_size > 1)
list->selected_item -= (list->selected_item % list->selected_size);
gui_synclist_speak_item(list);
}
@ -871,7 +743,7 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * list)
if (click_loc & LIST)
{
/* held a single line for a while, bring up the context menu */
gui_synclist_select_item(list, list->selected_item);
gui_synclist_select_item(list, list_start_item + line);
/* don't sent context repeatedly */
action_wait_for_release();
initial_touch = true;
@ -883,7 +755,7 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * list)
initial_touch = true;
if (click_loc & LIST)
{ /* release on list item enters it */
gui_synclist_select_item(list, list->selected_item);
gui_synclist_select_item(list, list_start_item + line);
return ACTION_STD_OK;
}
else if (click_loc & TITLE_TEXT)
@ -952,7 +824,7 @@ unsigned gui_synclist_do_touchscreen(struct gui_synclist * list)
hide_selection = true;
/* similarly to swipe scroll, using the scrollbar grabs
* focus so the click location is irrelevant */
scrollbar_scroll(list, y);
scrollbar_scroll(list, adj_y);
if (action & BUTTON_REL)
scroll_mode = SCROLL_NONE;
break;

131
apps/gui/buttonbar.c Normal file
View file

@ -0,0 +1,131 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) Linus Nielsen Feltzing (2002)
*
* 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.
*
****************************************************************************/
/*
2005 Kevin Ferrare :
- Multi screen support
- Rewrote a lot of code to avoid global vars and make it accept eventually
more that 3 buttons on the bar (just the prototype of gui_buttonbar_set
and the constant BUTTONBAR_MAX_BUTTONS to modify)
2008 Jonathan Gordon
- redone to use viewports, items will NOT scroll in their vp.
Bar is always drawn at the bottom of the screen. This may be changed later.
Callers need to remember to adjust their viewports to not be overwitten
*/
#include "config.h"
#include "buttonbar.h"
#include "viewport.h"
#include "lcd.h"
#include "font.h"
#include "string-extra.h"
#include "settings.h"
static struct viewport bb_vp[NB_SCREENS];
void gui_buttonbar_init(struct gui_buttonbar * buttonbar)
{
gui_buttonbar_unset(buttonbar);
FOR_NB_SCREENS(i)
{
viewport_set_defaults(&bb_vp[i], i);
bb_vp[i].font = FONT_SYSFIXED;
bb_vp[i].y = screens[i].lcdheight - BUTTONBAR_HEIGHT;
bb_vp[i].height = BUTTONBAR_HEIGHT;
bb_vp[i].drawmode = DRMODE_COMPLEMENT;
}
}
void gui_buttonbar_set_display(struct gui_buttonbar * buttonbar,
struct screen * display)
{
buttonbar->display = display;
}
static void gui_buttonbar_draw_button(struct gui_buttonbar * buttonbar, int num)
{
int button_width;
int fh, fw;
struct screen * display = buttonbar->display;
struct viewport vp = bb_vp[display->screen_type];
button_width = display->lcdwidth/BUTTONBAR_MAX_BUTTONS;
vp.width = button_width-1;
vp.x = button_width * num;
display->set_viewport(&vp);
display->fill_viewport();
if(buttonbar->caption[num][0] != 0)
{
display->getstringsize(buttonbar->caption[num], &fw, &fh);
display->putsxy((button_width - fw)/2,
(vp.height-fh)/2, buttonbar->caption[num]);
}
display->set_viewport(NULL);
}
void gui_buttonbar_set(struct gui_buttonbar * buttonbar,
const char *caption1,
const char *caption2,
const char *caption3)
{
gui_buttonbar_unset(buttonbar);
if(caption1)
{
strlcpy(buttonbar->caption[0], caption1, BUTTONBAR_CAPTION_LENGTH);
}
if(caption2)
{
strlcpy(buttonbar->caption[1], caption2, BUTTONBAR_CAPTION_LENGTH);
}
if(caption3)
{
strlcpy(buttonbar->caption[2], caption3, BUTTONBAR_CAPTION_LENGTH);
}
}
void gui_buttonbar_unset(struct gui_buttonbar * buttonbar)
{
int i;
for(i = 0;i < BUTTONBAR_MAX_BUTTONS;i++)
buttonbar->caption[i][0] = 0;
}
void gui_buttonbar_draw(struct gui_buttonbar * buttonbar)
{
struct screen * display = buttonbar->display;
if(!global_settings.buttonbar || !gui_buttonbar_isset(buttonbar))
return;
int i;
display->set_viewport(&bb_vp[display->screen_type]);
display->clear_viewport();
for(i = 0;i < BUTTONBAR_MAX_BUTTONS;i++)
gui_buttonbar_draw_button(buttonbar, i);
display->set_viewport(&bb_vp[display->screen_type]);
display->update_viewport();
display->set_viewport(NULL);
}
bool gui_buttonbar_isset(struct gui_buttonbar * buttonbar)
{
/* If all buttons are unset, the button bar is considered disabled */
int i;
for(i = 0;i < BUTTONBAR_MAX_BUTTONS;i++)
if(buttonbar->caption[i][0] != 0)
return true;
return false;
}

85
apps/gui/buttonbar.h Normal file
View file

@ -0,0 +1,85 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 by Kevin Ferrare
*
* 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.
*
****************************************************************************/
#ifndef _GUI_BUTTONBAR_H_
#define _GUI_BUTTONBAR_H_
#include "config.h"
#include "button.h"
#include "screen_access.h"
#ifdef HAVE_BUTTONBAR
#define BUTTONBAR_HEIGHT 8
#define BUTTONBAR_MAX_BUTTONS 3
#define BUTTONBAR_CAPTION_LENGTH 8
struct gui_buttonbar
{
char caption[BUTTONBAR_MAX_BUTTONS][BUTTONBAR_CAPTION_LENGTH];
struct screen * display;
};
/*
* Initializes the buttonbar
* - buttonbar : the buttonbar
*/
extern void gui_buttonbar_init(struct gui_buttonbar * buttonbar);
/*
* Attach the buttonbar to a screen
* - buttonbar : the buttonbar
* - display : the display to attach the buttonbar
*/
extern void gui_buttonbar_set_display(struct gui_buttonbar * buttonbar,
struct screen * display);
/*
* Set the caption of the items of the buttonbar
* - buttonbar : the buttonbar
* - caption1,2,3 : the first, second and thirds items of the bar
*/
extern void gui_buttonbar_set(struct gui_buttonbar * buttonbar,
const char *caption1,
const char *caption2,
const char *caption3);
/*
* Disable the buttonbar
* - buttonbar : the buttonbar
*/
extern void gui_buttonbar_unset(struct gui_buttonbar * buttonbar);
/*
* Draw the buttonbar on it's attached screen
* - buttonbar : the buttonbar
*/
extern void gui_buttonbar_draw(struct gui_buttonbar * buttonbar);
/*
* Returns true if the buttonbar has something to display, false otherwise
* - buttonbar : the buttonbar
*/
extern bool gui_buttonbar_isset(struct gui_buttonbar * buttonbar);
#else
#define BUTTONBAR_HEIGHT 0
#endif
#endif /* _GUI_BUTTONBAR_H_ */

112
apps/gui/charcell/list.c Normal file
View file

@ -0,0 +1,112 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2007 by Jonathan Gordon
*
* 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.
*
****************************************************************************/
/* This file contains the code to draw the list widget on BITMAP LCDs. */
#include "config.h"
#include "lcd.h"
#include "font.h"
#include "button.h"
#include "string.h"
#include "settings.h"
#include "kernel.h"
#include "system.h"
#include "file.h"
#include "list.h"
#include "screen_access.h"
#include "scrollbar.h"
#include "lang.h"
#include "sound.h"
#include "misc.h"
void gui_synclist_scroll_stop(struct gui_synclist *lists)
{
(void)lists;
FOR_NB_SCREENS(i)
{
screens[i].scroll_stop();
}
}
void list_draw(struct screen *display, struct gui_synclist *gui_list)
{
bool draw_icons = (gui_list->callback_get_item_icon != NULL);
bool selected;
int i;
int start, end;
display->set_viewport(NULL);
display->clear_display();
start = 0;
end = display->getnblines();
struct line_desc desc = {
.height = -1,
.text_color = 1,
.line_color = 1,
.line_end_color = 1,
.style = STYLE_DEFAULT
};
for (i = start; i < end; i++)
{
unsigned const char *s;
char entry_buffer[MAX_PATH];
unsigned char *entry_name;
int current_item = gui_list->start_item[display->screen_type] + i;
/* When there are less items to display than the
* current available space on the screen, we stop*/
if(current_item >= gui_list->nb_items)
break;
s = gui_list->callback_get_item_name(current_item,
gui_list->data,
entry_buffer,
sizeof(entry_buffer));
entry_name = P2STR(s);
if (gui_list->show_selection_marker &&
current_item >= gui_list->selected_item &&
current_item < gui_list->selected_item + gui_list->selected_size)
selected = true; /* The selected item must be displayed scrolling */
else
selected = false;
desc.nlines = gui_list->selected_size,
desc.line = gui_list->selected_size > 1 ? i : 0,
desc.scroll = selected ? true : gui_list->scroll_all;
if (draw_icons)
put_line(display, 0, i, &desc, "$i$i$t",
selected ? Icon_Cursor : Icon_NOICON,
gui_list->callback_get_item_icon(current_item, gui_list->data),
entry_name);
else
put_line(display, 0, i, &desc, "$i$t",
selected ? Icon_Cursor : Icon_NOICON,
entry_name);
}
display->update_viewport();
display->update();
}

View file

@ -154,6 +154,7 @@ static void draw_screen(struct screen *display, char *title,
{
unsigned text_color = LCD_BLACK;
unsigned background_color = LCD_WHITE;
char buf[32];
int i, char_height, line_height;
int max_label_width;
int text_x, text_top;
@ -163,7 +164,7 @@ static void draw_screen(struct screen *display, char *title,
struct viewport vp;
viewport_set_defaults(&vp, display->screen_type);
struct viewport * last_vp = display->set_viewport(&vp);
display->set_viewport(&vp);
display->clear_viewport();
@ -252,16 +253,17 @@ static void draw_screen(struct screen *display, char *title,
set_drawinfo(display, mode, fg, bg);
/* Draw label */
buf[0] = str(LANG_COLOR_RGB_LABELS)[i];
buf[1] = '\0';
vp.flags &= ~VP_FLAG_ALIGNMENT_MASK;
display->putsxyf(text_x, text_top, "%c", str(LANG_COLOR_RGB_LABELS)[i]);
display->putsxy(text_x, text_top, buf);
/* Draw color value */
vp.flags |= VP_FLAG_ALIGN_RIGHT;
if (display->depth >= 24)
display->putsxyf(text_x, text_top, "%03d", rgb->rgb_val[i] & 0xFF);
snprintf(buf, 4, "%03d", rgb->rgb_val[i] & 0xFF);
else
display->putsxyf(text_x, text_top, "%02d", rgb->rgb_val[i] & 0x3F);
snprintf(buf, 3, "%02d", rgb->rgb_val[i] & 0x3F);
vp.flags |= VP_FLAG_ALIGN_RIGHT;
display->putsxy(text_x, text_top, buf);
/* Draw scrollbar */
gui_scrollbar_draw(display, /* screen */
@ -278,6 +280,9 @@ static void draw_screen(struct screen *display, char *title,
text_top += line_height;
} /* end for */
/* Format RGB: #rrggbb */
snprintf(buf, sizeof(buf), str(LANG_COLOR_RGB_VALUE),
rgb->red, rgb->green, rgb->blue);
vp.flags |= VP_FLAG_ALIGN_CENTER;
if (display->depth >= 16)
{
@ -296,9 +301,8 @@ static void draw_screen(struct screen *display, char *title,
/* Draw RGB: #rrggbb in middle of swatch */
set_drawinfo(display, DRMODE_FG, get_black_or_white(rgb),
background_color);
/* Format RGB: #rrggbb */
display->putsxyf(0, top + (height - char_height) / 2,
str(LANG_COLOR_RGB_VALUE), rgb->red, rgb->green, rgb->blue);
display->putsxy(0, top + (height - char_height) / 2, buf);
/* Draw border around the rect */
set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
@ -314,14 +318,12 @@ static void draw_screen(struct screen *display, char *title,
if (height >= char_height)
{
set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
/* Format RGB: #rrggbb */
display->putsxyf(0, top + (height - char_height) / 2,
str(LANG_COLOR_RGB_VALUE), rgb->red, rgb->green, rgb->blue);
display->putsxy(0, top + (height - char_height) / 2, buf);
}
}
display->update_viewport();
display->set_viewport(last_vp);
display->set_viewport(NULL);
}
#ifdef HAVE_TOUCHSCREEN
@ -339,7 +341,7 @@ static int touchscreen_slider(struct screen *display,
struct viewport vp;
viewport_set_defaults(&vp, display->screen_type);
struct viewport *last_vp = display->set_viewport(&vp);
display->set_viewport(&vp);
button = action_get_touchscreen_press_in_vp(&x, &y, &vp);
if (button == ACTION_UNKNOWN || button == BUTTON_NONE)
@ -371,7 +373,7 @@ static int touchscreen_slider(struct screen *display,
char_height*2 + /* + margins for bottom */
MARGIN_BOTTOM; /* colored rectangle */
display->set_viewport(last_vp);
display->set_viewport(NULL);
if (y < text_top)
{

View file

@ -8,7 +8,6 @@
*
* 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
@ -31,11 +30,7 @@
#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:
@ -61,31 +56,18 @@ 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 = ALIGN_UP(size, 4);
size = (size + 3) & ~3;
if (buffer_front + size > buffer_end)
{
return NULL;
@ -104,57 +86,32 @@ static char* folder_alloc_from_end(size_t size)
buffer_end -= size;
return buffer_end;
}
#if 0
/* returns the buffer size required to store the path + \0 */
static int get_full_pathsz(struct folder *start)
{
int reql = 0;
struct folder *next = start;
do
{
reql += strlen(next->name) + 1;
} while ((next = next->previous));
if (start->name[0] != '/') reql--;
if (--reql < 0) reql = 0;
return reql;
static void get_full_path_r(struct folder *start, char* dst)
{
if (start->previous)
get_full_path_r(start->previous, dst);
if (start->name && start->name[0] && strcmp(start->name, "/"))
{
strlcat(dst, "/", MAX_PATH);
strlcat(dst, start->name, MAX_PATH);
}
}
#endif
static size_t get_full_path(struct folder *start, char *dst, size_t dst_sz)
static char* get_full_path(struct folder *start)
{
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 */
static char buffer[MAX_PATH];
if (strcmp(start->name, "/"))
{
#define PATHMUTATE() \
({ \
prev = cur; \
cur = next; \
next = cur->previous;\
cur->previous = prev; \
})
PATHMUTATE();
buffer[0] = 0;
get_full_path_r(start, 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
else /* get_full_path_r() does the wrong thing for / */
return "/";
return buffer;
}
/* support function for qsort() */
@ -168,53 +125,47 @@ 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;
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;
}
strmemccpy(&fullpath[len], folder, sizeof(fullpath) - len);
logf("load_folder: [%s]", fullpath);
if (!strcmp(folder,"/"))
strlcpy(fullpath, folder, 2);
else
snprintf(fullpath, MAX_PATH, "%s/%s", parent ? path : "", folder);
if (!this)
return NULL;
dir = opendir(fullpath);
if (dir == NULL)
goto fail;
if (!dir)
return NULL;
this->previous = parent;
this->name = folder;
this->children = NULL;
this->children_count = 0;
if (parent)
this->depth = parent->depth + 1;
this->depth = parent ? parent->depth + 1 : 0;
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 ((dir_get_info(dir, entry).attribute & ATTR_DIRECTORY) == 0) {
if ((info.attribute & ATTR_DIRECTORY) == 0) {
continue;
}
/* skip . and .. */
char *dn = entry->d_name;
if ((dn[0] == '.') && (dn[1] == '\0' || (dn[1] == '.' && dn[2] == '\0')))
/* skip directories . and .. */
if ((!strcmp((char *)entry->d_name, ".")) ||
(!strcmp((char *)entry->d_name, ".."))) {
continue;
/* copy entry name to end of buffer, save pointer */
len = strlen((char *)entry->d_name);
char *name = folder_alloc_from_end(len+1); /*for NULL*/
if (name == NULL)
{
closedir(dir);
goto fail;
}
char *name = folder_alloc_from_end(len+1);
if (!name)
return NULL;
memcpy(name, (char *)entry->d_name, len+1);
child_count++;
first_child = name;
@ -223,29 +174,26 @@ 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 == NULL)
goto fail;
if (!this->children)
return NULL;
while (child_count)
{
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 */
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;
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;
@ -254,7 +202,7 @@ struct folder* load_root(void)
.name = "",
.children = &root_child,
.children_count = 1,
.depth = 0,
.depth = -1,
.previous = NULL,
};
@ -279,6 +227,7 @@ 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)
@ -310,22 +259,22 @@ static const char * folder_get_name(int selected_item, void * data,
struct folder *parent;
struct child *this = find_index(root, selected_item , &parent);
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';
buffer[0] = '\0';
if (parent->depth >= 0)
for(int i = 0; i <= parent->depth; i++)
strcat(buffer, "\t");
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), ")");
snprintf(&buffer[len], buffer_len - len, str(LANG_READ_FAILED),
this->name);
strlcat(buffer, ")", buffer_len);
}
}
@ -352,23 +301,6 @@ 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;
@ -387,13 +319,17 @@ static int folder_action_callback(int action, struct gui_synclist *list)
this->state = COLLAPSED;
break;
case COLLAPSED:
child_set_state_expand(this, parent);
if (this->folder == NULL)
this->folder = load_folder(parent, this->name);
this->state = this->folder ? (this->folder->children_count == 0 ?
SELECTED : EXPANDED) : EACCESS;
break;
case EACCESS:
/* cannot open, do nothing */
return action;
}
action = ACTION_REDRAW;
list->nb_items = count_items(root);
return ACTION_REDRAW;
}
else if (action == ACTION_STD_CONTEXT)
{
@ -403,198 +339,140 @@ 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];
switch (child->state)
{
case SELECTED:
case EXPANDED:
child->state = COLLAPSED;
break;
case COLLAPSED:
child->state = SELECTED;
break;
case EACCESS:
break;
}
if (child->state == SELECTED ||
child->state == EXPANDED)
child->state = COLLAPSED;
else if (child->state == COLLAPSED)
child->state = SELECTED;
}
break;
case SELECTED:
case COLLAPSED:
if (child_set_state_expand(this, parent) != EACCESS)
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++)
{
for (i = 0; i < (this->folder->children_count); i++)
{
child = &this->folder->children[i];
child->state = SELECTED;
}
child = &this->folder->children[i];
child->state = SELECTED;
}
break;
case EACCESS:
/* cannot open, do nothing */
return action;
}
action = ACTION_REDRAW;
}
if (action == ACTION_REDRAW)
list->nb_items = count_items(root);
return ACTION_REDRAW;
}
return action;
}
static struct child* find_from_filename(const char* filename, struct folder *root)
static struct child* find_from_filename(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 (filename[0] == '/') /* in the loop nothing starts with '/' */
if (slash == filename)
{
logf("find_from_filename [%s]", filename);
/* filename begins with /. in this case root must be the
* top level folder */
this = &root->children[0];
if (filename[1] == '\0')
if (!slash[1])
{ /* filename == "/" */
return this;
}
else /* filename == "/XXX/YYY". cascade down */
goto cascade;
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);
}
}
for (int i = 0; i < root->children_count; i++)
while (i < root->children_count)
{
this = &root->children[i];
/* when slash == NULL n will be really large but \0 stops the compare */
if (strncasecmp(this->name, filename, slash - filename) == 0)
if (!strcasecmp(this->name, filename))
{
if (slash == NULL)
if (!slash)
{ /* filename == XXX */
return this;
}
else
goto cascade;
{
/* 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);
}
}
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);
}
static int select_paths(struct folder* root, const char* filenames)
/* _modifies_ buf */
int select_paths(struct folder* root, char* buf)
{
/* 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 + 1 >= buflen)
continue;
strmemccpy(buf, sstr, len + 1);
struct child *item = find_from_filename(buf, root);
if (item)
item->state = SELECTED;
}
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, size_t buflen)
static void save_folders_r(struct folder *root, char* dst, size_t maxlen)
{
size_t len;
struct folder *curfolder;
char* name;
int i = 0;
for (int i = 0; i < root->children_count; i++)
while (i < root->children_count)
{
struct child *this = &root->children[i];
if (this->state == SELECTED)
{
if (this->folder == NULL)
{
curfolder = root;
name = this->name;
logf("save_folders_r: this->name[%s]", name);
}
if (this->folder)
snprintf(buffer_front, buffer_end - buffer_front,
"%s:", get_full_path(this->folder));
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;
strmemccpy(&dst[dlen], buffer_front, maxlen - dlen);
}
else
{
if (hashed.len + len >= maxlen)
{
hashed.maxlen_exceeded = 1;
continue;
}
get_hash(buffer_front, &hashed.val, len);
hashed.len += len;
char *p = get_full_path(root);
snprintf(buffer_front, buffer_end - buffer_front,
"%s/%s:", strcmp(p, "/") ? p : "",
strcmp(this->name, "/") ? this->name : "");
}
strlcat(dst, buffer_front, maxlen);
}
else if (this->state == EXPANDED)
save_folders_r(this->folder, dst, maxlen, buflen);
save_folders_r(this->folder, dst, maxlen);
i++;
}
}
static uint32_t save_folders(struct folder *root, char* dst, size_t maxlen)
static void save_folders(struct folder *root, char* dst, size_t maxlen)
{
hashed.len = 0;
hashed.val = 0;
hashed.maxlen_exceeded = 0;
size_t len = buffer_end - buffer_front;
int len;
dst[0] = '\0';
save_folders_r(root, dst, maxlen, len);
save_folders_r(root, dst, maxlen);
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)
@ -602,32 +480,40 @@ 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();
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);
if (nb_items > 0)
{
for(int i = 0; i < nb_items; i++)
select_paths(root, vect[i]);
}
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 */
if (hash != save_folders(root, hashed.buf, setting_len))
{ /* prompt for saving changes and commit if yes */
save_folders(root, copy, setting_len);
if (strcmp(copy, setting))
{ /* prompt for saving changes and commit if yes */
if (yesno_pop(ID2P(LANG_SAVE_CHANGES)))
{
save_folders(root, setting, setting_len);
strcpy(setting, copy);
settings_save();
logf("folders out: %s", setting);
return true;
}
}

View file

@ -28,11 +28,9 @@
#include "screen_access.h"
#include "icons.h"
#include "settings.h"
#include "rbpaths.h"
#include "bmp.h"
#include "filetypes.h"
#include "language.h"
#include "misc.h"
#include "bitmaps/default_icons.h"
#if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
@ -64,6 +62,7 @@ static struct iconset {
struct bitmap bmp;
bool loaded;
int handle;
int handle_locked;
} iconsets[Iconset_Count][NB_SCREENS];
#define ICON_HEIGHT(screen) (!iconsets[Iconset_user][screen].loaded ? \
@ -74,13 +73,13 @@ static struct iconset {
(*(inbuilt_iconset[screen])) : iconsets[Iconset_user][screen].bmp).width
/* x,y in letters, not pixles */
void screen_put_icon(struct screen * display,
void screen_put_icon(struct screen * display,
int x, int y, enum themable_icons icon)
{
screen_put_icon_with_offset(display, x, y, 0, 0, icon);
}
void screen_put_icon_with_offset(struct screen * display,
void screen_put_icon_with_offset(struct screen * display,
int x, int y, int off_x, int off_y,
enum themable_icons icon)
{
@ -107,7 +106,7 @@ void screen_put_iconxy(struct screen * display,
const int height = ICON_HEIGHT(screen);
const int is_rtl = lang_is_rtl();
const struct bitmap *iconset;
if (icon <= Icon_NOICON)
{
if (is_rtl)
@ -119,7 +118,7 @@ void screen_put_iconxy(struct screen * display,
{
iconset = &iconsets[Iconset_viewers][screen].bmp;
icon -= Icon_Last_Themeable;
if (!iconsets[Iconset_viewers][screen].loaded ||
if (!iconsets[Iconset_viewers][screen].loaded ||
(global_status.viewer_icon_count * height > iconset->height) ||
(icon * height + height > iconset->height))
{
@ -145,7 +144,11 @@ void screen_put_iconxy(struct screen * display,
void screen_put_cursorxy(struct screen * display, int x, int y, bool on)
{
#ifdef HAVE_LCD_BITMAP
screen_put_icon(display, x, y, on?Icon_Cursor:0);
#else
screen_put_icon(display, x, y, on?CURSOR_CHAR:-1);
#endif
}
static int buflib_move_callback(int handle, void* current, void* new)
@ -160,6 +163,8 @@ static int buflib_move_callback(int handle, void* current, void* new)
struct iconset *set = &iconsets[i][j];
if (set->bmp.data == current)
{
if (set->handle_locked > 0)
return BUFLIB_CB_CANNOT_MOVE;
set->bmp.data = new;
return BUFLIB_CB_OK;
}
@ -167,27 +172,48 @@ static int buflib_move_callback(int handle, void* current, void* new)
}
return BUFLIB_CB_OK;
}
static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL, NULL};
static void load_icons(const char* filename, enum Iconset iconset,
enum screen_type screen)
{
static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL, NULL};
const int bmpformat = (FORMAT_ANY|FORMAT_DITHER|FORMAT_TRANSPARENT);
int size_read;
int bmpformat = (FORMAT_ANY|FORMAT_DITHER|FORMAT_TRANSPARENT);
struct iconset *ic = &iconsets[iconset][screen];
ssize_t buf_reqd;
int fd;
ic->loaded = false;
ic->handle = CLB_ALOC_ERR;
if (filename[0] && filename[0] != '-')
{
char fname[MAX_PATH];
snprintf(fname, sizeof(fname), ICON_DIR "/%s.bmp", filename);
ic->handle = core_load_bmp(fname, &ic->bmp, bmpformat, &buf_reqd, &buflib_ops);
if (ic->handle != CLB_ALOC_ERR)
char path[MAX_PATH];
snprintf(path, sizeof(path), ICON_DIR "/%s.bmp", filename);
fd = open(path, O_RDONLY);
if (fd < 0)
return;
size_t buf_size = read_bmp_fd(fd, &ic->bmp, 0,
bmpformat|FORMAT_RETURN_SIZE, NULL);
ic->handle = core_alloc_ex(filename, buf_size, &buflib_ops);
if (ic->handle <= 0)
{
ic->bmp.data = core_get_data(ic->handle);
ic->loaded = true;
close(fd);
return;
}
lseek(fd, 0, SEEK_SET);
ic->bmp.data = core_get_data(ic->handle);
ic->handle_locked = 1;
size_read = read_bmp_fd(fd, &ic->bmp, buf_size, bmpformat, NULL);
close(fd);
ic->handle_locked = 0;
/* free unused alpha channel, if any */
core_shrink(ic->handle, ic->bmp.data, size_read);
if (size_read <= 0)
ic->handle = core_free(ic->handle);
else
ic->loaded = true;
}
}
@ -211,30 +237,31 @@ void icons_init(void)
{
load_icons(global_settings.icon_file, Iconset_user, SCREEN_MAIN);
if (global_settings.viewers_icon_file[0] == '-' ||
global_settings.viewers_icon_file[0] == '\0')
{
load_icons(DEFAULT_VIEWER_BMP, Iconset_viewers, SCREEN_MAIN);
}
else
if (global_settings.viewers_icon_file[0] &&
global_settings.viewers_icon_file[0] != '-')
{
load_icons(global_settings.viewers_icon_file,
Iconset_viewers, SCREEN_MAIN);
read_viewer_theme_file();
}
#if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
load_icons(global_settings.remote_icon_file,
Iconset_user, SCREEN_REMOTE);
if (global_settings.remote_viewers_icon_file[0] == '-' ||
global_settings.remote_viewers_icon_file[0] == '\0')
else
{
load_icons(DEFAULT_REMOTE_VIEWER_BMP,
load_icons(DEFAULT_VIEWER_BMP, Iconset_viewers, SCREEN_MAIN);
}
#if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
load_icons(global_settings.remote_icon_file,
Iconset_user, SCREEN_REMOTE);
if (global_settings.remote_viewers_icon_file[0] &&
global_settings.remote_viewers_icon_file[0] != '-')
{
load_icons(global_settings.remote_viewers_icon_file,
Iconset_viewers, SCREEN_REMOTE);
}
else
{
load_icons(global_settings.remote_viewers_icon_file,
load_icons(DEFAULT_REMOTE_VIEWER_BMP,
Iconset_viewers, SCREEN_REMOTE);
}
#endif

View file

@ -24,7 +24,11 @@
#include "screen_access.h"
/* Defines a type for the icons since it's not the same thing on
* char-based displays and bitmap displays */
#ifdef HAVE_LCD_BITMAP
typedef const unsigned char * ICON;
#else
typedef long ICON;
#endif
/* Don't #ifdef icon values, or we wont be able to use the same
bmp for every target. */
@ -85,6 +89,10 @@ extern void screen_put_cursorxy(struct screen * screen, int x, int y, bool on);
*/
extern void screen_put_iconxy(struct screen * screen,
int x, int y, enum themable_icons icon);
#ifdef HAVE_LCD_CHARCELLS
# define screen_put_icon(s, x, y, i) screen_put_iconxy(s, x, y, i)
# define screen_put_icon_with_offset(s, x, y, w, h, i) screen_put_icon(s, x, y, i)
#else
/* For both of these, the icon will be placed in the center of the rectangle */
/* as above, but x,y are letter position, NOT PIXEL */
extern void screen_put_icon(struct screen * screen,
@ -93,14 +101,23 @@ extern void screen_put_icon(struct screen * screen,
extern void screen_put_icon_with_offset(struct screen * display,
int x, int y, int off_x, int off_y,
enum themable_icons icon);
#endif
void icons_init(void);
#ifdef HAVE_LCD_CHARCELLS
# define CURSOR_CHAR 0xe10c
# define get_icon_width(a) 1
# define get_icon_height(a) 1 /* needs to be verified */
#else
int get_icon_width(enum screen_type screen_type);
int get_icon_height(enum screen_type screen_type);
int get_icon_format(enum screen_type screen_type);
#endif
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1)
#if (LCD_DEPTH > 1) || defined(HAVE_REMOTE_LCD) && (LCD_REMOTE_DEPTH > 1) \
&& !defined(HAVE_LCD_CHARCELLS)
int get_icon_format(enum screen_type screen_type);
#else
# define get_icon_format(a) FORMAT_MONO

View file

@ -41,7 +41,11 @@
#endif
#ifdef HAVE_LCD_CHARCELLS
#define style_line(d, x, y, l)
#else
static void style_line(struct screen *display, int x, int y, struct line_desc *line);
#endif
static void put_text(struct screen *display, int x, int y, struct line_desc *line,
const char *text, bool prevent_scroll, int text_skip_pixels);
@ -264,7 +268,8 @@ next:
else
{
/* any other character here is an erroneous format string */
display->putsxyf(xpos, y, "<E:%c>", ch);
snprintf(tempbuf, sizeof(tempbuf), "<E:%c>", ch);
display->putsxy(xpos, y, tempbuf);
/* Don't consider going forward, fix the caller */
return;
}
@ -293,6 +298,7 @@ next:
}
}
#ifdef HAVE_LCD_BITMAP
static void style_line(struct screen *display,
int x, int y, struct line_desc *line)
{
@ -378,6 +384,7 @@ static void style_line(struct screen *display,
}
#endif
}
#endif /* HAVE_LCD_BITMAP */
void vput_line(struct screen *display,
int x, int y, struct line_desc *line,

View file

@ -47,8 +47,17 @@
*/
#define FRAMEDROP_TRIGGER 6
#ifdef HAVE_LCD_BITMAP
static int offset_step = 16; /* pixels per screen scroll step */
/* should lines scroll out of the screen */
static bool offset_out_of_view = false;
#endif
static void gui_list_select_at_offset(struct gui_synclist * gui_list,
int offset);
void list_draw(struct screen *display, struct gui_synclist *list);
#ifdef HAVE_LCD_BITMAP
static long last_dirty_tick;
static struct viewport parent[NB_SCREENS];
@ -83,7 +92,23 @@ static void list_init_viewports(struct gui_synclist *list)
}
list->dirty_tick = current_tick;
}
#else
static struct viewport parent[NB_SCREENS] =
{
[SCREEN_MAIN] =
{
.x = 0,
.y = 0,
.width = LCD_WIDTH,
.height = LCD_HEIGHT
},
};
#define list_init_viewports(a)
#define list_is_dirty(a) false
#endif
#ifdef HAVE_LCD_BITMAP
static int list_nb_lines(struct gui_synclist *list, enum screen_type screen)
{
struct viewport *vp = list->parent[screen];
@ -123,17 +148,12 @@ void list_init_item_height(struct gui_synclist *list, enum screen_type screen)
#endif
}
static void gui_synclist_init_display_settings(struct gui_synclist * list)
{
struct user_settings *gs = &global_settings;
list->scrollbar = gs->scrollbar;
list->show_icons = gs->show_icons;
list->scroll_paginated = gs->scroll_paginated;
list->keyclick = gs->keyclick;
list->talk_menu = gs->talk_menu;
list->wraparound = gs->list_wraparound;
list->cursor_style = gs->cursor_style;
}
#else
#define list_display_title(l, i) false
#define list_get_nb_lines(list, screen) \
viewport_get_nb_lines((list)->parent[(screen)]);
#define list_init_item_height(l, i)
#endif
/*
* Initializes a scrolling list
@ -156,18 +176,14 @@ 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;
gui_synclist_init_display_settings(gui_list);
#ifdef HAVE_TOUCHSCREEN
gui_list->y_pos = 0;
#endif
FOR_NB_SCREENS(i)
{
gui_list->start_item[i] = 0;
#ifdef HAVE_LCD_BITMAP
gui_list->offset_position[i] = 0;
#endif
if (list_parent)
gui_list->parent[i] = &list_parent[i];
else
@ -176,6 +192,7 @@ void gui_synclist_init(struct gui_synclist * gui_list,
list_init_viewports(gui_list);
FOR_NB_SCREENS(i)
list_init_item_height(gui_list, i);
gui_list->limit_scroll = false;
gui_list->data = data;
gui_list->scroll_all = scroll_all;
gui_list->selected_size = selected_size;
@ -184,14 +201,22 @@ void gui_synclist_init(struct gui_synclist * gui_list,
gui_list->scheduled_talk_tick = gui_list->last_talked_tick = 0;
gui_list->dirty_tick = current_tick;
gui_list->show_selection_marker = true;
#ifdef HAVE_LCD_COLOR
gui_list->title_color = -1;
gui_list->callback_get_item_color = NULL;
gui_list->selection_color = NULL;
#endif
}
/* this toggles the selection bar or cursor */
void gui_synclist_hide_selection_marker(struct gui_synclist * lists, bool hide)
{
lists->show_selection_marker = !hide;
}
#ifdef HAVE_LCD_BITMAP
int gui_list_get_item_offset(struct gui_synclist * gui_list,
int item_width,
int text_pos,
@ -200,7 +225,7 @@ int gui_list_get_item_offset(struct gui_synclist * gui_list,
{
int item_offset;
if (global_settings.offset_out_of_view)
if (offset_out_of_view)
{
item_offset = gui_list->offset_position[display->screen_type];
}
@ -223,6 +248,7 @@ int gui_list_get_item_offset(struct gui_synclist * gui_list,
return item_offset;
}
#endif
/*
* Force a full screen update.
@ -238,7 +264,9 @@ void gui_synclist_draw(struct gui_synclist *gui_list)
}
FOR_NB_SCREENS(i)
{
#ifdef HAVE_LCD_BITMAP
if (!skinlist_draw(&screens[i], gui_list))
#endif
list_draw(&screens[i], gui_list);
}
}
@ -251,14 +279,23 @@ static void gui_list_put_selection_on_screen(struct gui_synclist * gui_list,
int bottom = MAX(0, gui_list->nb_items - nb_lines);
int new_start_item = gui_list->start_item[screen];
int difference = gui_list->selected_item - gui_list->start_item[screen];
#ifdef HAVE_LCD_CHARCELLS
const int scroll_limit_up = 0;
const int scroll_limit_down = 1;
#else
const int scroll_limit_up = (nb_lines < gui_list->selected_size+2 ? 0:1);
const int scroll_limit_down = (scroll_limit_up+gui_list->selected_size);
#endif
if (gui_list->selected_size >= nb_lines)
if (gui_list->show_selection_marker == false)
{
new_start_item = gui_list->selected_item;
}
else if (gui_list->scroll_paginated)
else if (gui_list->selected_size >= nb_lines)
{
new_start_item = gui_list->selected_item;
}
else if (global_settings.scroll_paginated)
{
nb_lines -= nb_lines%gui_list->selected_size;
if (difference < 0 || difference >= nb_lines)
@ -281,14 +318,15 @@ static void gui_list_put_selection_on_screen(struct gui_synclist * gui_list,
gui_list->start_item[screen] = bottom;
else
gui_list->start_item[screen] = new_start_item;
#ifdef HAVE_TOUCHSCREEN
gui_list->y_pos = gui_list->start_item[SCREEN_MAIN] * gui_list->line_height[SCREEN_MAIN];
#endif
}
static void edge_beep(struct gui_synclist * gui_list, bool wrap)
{
if (gui_list->keyclick)
#if CONFIG_CODEC != SWCODEC
(void)gui_list;
(void)wrap;
#else
if (global_settings.keyclick)
{
list_speak_item *cb = gui_list->callback_speak_item;
if (!wrap) /* a bounce */
@ -321,6 +359,7 @@ static void edge_beep(struct gui_synclist * gui_list, bool wrap)
talk_force_shutup();
}
}
#endif
}
static void _gui_synclist_speak_item(struct gui_synclist *lists)
@ -351,7 +390,7 @@ static void _gui_synclist_speak_item(struct gui_synclist *lists)
void gui_synclist_speak_item(struct gui_synclist *lists)
{
if (lists->talk_menu)
if (global_settings.talk_menu)
{
if (lists->nb_items == 0)
talk_id(VOICE_EMPTY_LIST, true);
@ -379,7 +418,7 @@ void gui_synclist_select_item(struct gui_synclist * gui_list, int item_number)
}
static void gui_list_select_at_offset(struct gui_synclist * gui_list,
int offset, bool allow_wrap)
int offset)
{
int new_selection;
if (gui_list->selected_size > 1)
@ -391,15 +430,37 @@ static void gui_list_select_at_offset(struct gui_synclist * gui_list,
if (new_selection >= gui_list->nb_items)
{
new_selection = allow_wrap ? 0 : gui_list->nb_items - gui_list->selected_size;
edge_beep(gui_list, allow_wrap);
new_selection = gui_list->limit_scroll ?
gui_list->nb_items - gui_list->selected_size : 0;
edge_beep(gui_list, !gui_list->limit_scroll);
}
else if (new_selection < 0)
{
new_selection = allow_wrap ? gui_list->nb_items - gui_list->selected_size : 0;
edge_beep(gui_list, allow_wrap);
new_selection = gui_list->limit_scroll ?
0 : gui_list->nb_items - gui_list->selected_size;
edge_beep(gui_list, !gui_list->limit_scroll);
}
else if (gui_list->show_selection_marker == false)
{
FOR_NB_SCREENS(i)
{
int nb_lines = list_get_nb_lines(gui_list, i);
if (offset > 0)
{
int screen_top = MAX(0, gui_list->nb_items - nb_lines);
gui_list->start_item[i] = MIN(screen_top, gui_list->start_item[i] +
gui_list->selected_size);
gui_list->selected_item = gui_list->start_item[i];
}
else
{
gui_list->start_item[i] = MAX(0, gui_list->start_item[i] -
gui_list->selected_size);
gui_list->selected_item = gui_list->start_item[i] + nb_lines;
}
}
return;
}
gui_synclist_select_item(gui_list, new_selection);
}
@ -430,27 +491,43 @@ void gui_synclist_del_item(struct gui_synclist * gui_list)
}
}
#ifdef HAVE_LCD_BITMAP
void gui_list_screen_scroll_step(int ofs)
{
offset_step = ofs;
}
void gui_list_screen_scroll_out_of_view(bool enable)
{
offset_out_of_view = enable;
}
#endif /* HAVE_LCD_BITMAP */
/*
* Set the title and title icon of the list. Setting title to NULL disables
* both the title and icon. Use NOICON if there is no icon.
*/
void gui_synclist_set_title(struct gui_synclist * gui_list,
const char * title, enum themable_icons icon)
char * title, enum themable_icons icon)
{
gui_list->title = title;
gui_list->title_icon = icon;
#ifdef HAVE_LCD_BITMAP
FOR_NB_SCREENS(i)
sb_set_title_text(title, icon, i);
#endif
send_event(GUI_EVENT_ACTIONUPDATE, (void*)1);
}
void gui_synclist_set_nb_items(struct gui_synclist * lists, int nb_items)
{
lists->nb_items = nb_items;
#ifdef HAVE_LCD_BITMAP
FOR_NB_SCREENS(i)
{
lists->offset_position[i] = 0;
}
#endif
}
int gui_synclist_get_nb_items(struct gui_synclist * lists)
{
@ -476,6 +553,10 @@ void gui_synclist_set_viewport_defaults(struct viewport *vp,
enum screen_type screen)
{
viewport_set_defaults(vp, screen);
#ifdef HAVE_BUTTONBAR
if (screens[screen].has_buttonbar)
vp->height -= BUTTONBAR_HEIGHT;
#endif
}
#ifdef HAVE_LCD_COLOR
@ -484,46 +565,32 @@ void gui_synclist_set_color_callback(struct gui_synclist * lists,
{
lists->callback_get_item_color = color_callback;
}
void gui_synclist_set_sel_color(struct gui_synclist * lists,
struct list_selection_color *list_sel_color)
{
lists->selection_color = list_sel_color;
if(list_sel_color)
{
FOR_NB_SCREENS(i) /* might need to be only SCREEN_MAIN */
{
lists->parent[i]->fg_pattern = list_sel_color->fg_color;
lists->parent[i]->bg_pattern = list_sel_color->bg_color;
}
}
else
list_init_viewports(lists);
}
#endif
static void gui_synclist_select_next_page(struct gui_synclist * lists,
enum screen_type screen,
bool allow_wrap)
enum screen_type screen)
{
int nb_lines = list_get_nb_lines(lists, screen);
if (lists->selected_size > 1)
nb_lines = MAX(1, nb_lines/lists->selected_size);
gui_list_select_at_offset(lists, nb_lines, allow_wrap);
gui_list_select_at_offset(lists, nb_lines);
}
static void gui_synclist_select_previous_page(struct gui_synclist * lists,
enum screen_type screen,
bool allow_wrap)
enum screen_type screen)
{
int nb_lines = list_get_nb_lines(lists, screen);
if (lists->selected_size > 1)
nb_lines = MAX(1, nb_lines/lists->selected_size);
gui_list_select_at_offset(lists, -nb_lines, allow_wrap);
gui_list_select_at_offset(lists, -nb_lines);
}
void gui_synclist_limit_scroll(struct gui_synclist * lists, bool scroll)
{
lists->limit_scroll = scroll;
}
#ifdef HAVE_LCD_BITMAP
/*
* Makes all the item in the list scroll by one step to the right.
* Should stop increasing the value when reaching the widest item value
@ -536,7 +603,7 @@ static void gui_synclist_scroll_right(struct gui_synclist * lists)
/* FIXME: This is a fake right boundry limiter. there should be some
* callback function to find the longest item on the list in pixels,
* to stop the list from scrolling past that point */
lists->offset_position[i] += global_settings.screen_scroll_step;
lists->offset_position[i] += offset_step;
if (lists->offset_position[i] > 1000)
lists->offset_position[i] = 1000;
}
@ -550,35 +617,32 @@ static void gui_synclist_scroll_left(struct gui_synclist * lists)
{
FOR_NB_SCREENS(i)
{
lists->offset_position[i] -= global_settings.screen_scroll_step;
lists->offset_position[i] -= offset_step;
if (lists->offset_position[i] < 0)
lists->offset_position[i] = 0;
}
}
#endif /* HAVE_LCD_BITMAP */
#if CONFIG_CODEC == SWCODEC
bool gui_synclist_keyclick_callback(int action, void* data)
{
struct gui_synclist *lists = (struct gui_synclist *)data;
/* Block the beep if we're at the end of the list and we're not wrapping. */
/* block the beep if we are at the end of the list and we are not wrapping.
* CAVEAT: mosts lists don't set limit_scroll untill it sees a repeat
* press at the end of the list so this can cause an extra beep.
*/
if (lists->limit_scroll == false)
return true;
if (lists->selected_item == 0)
{
if (action == ACTION_STD_PREVREPEAT)
return false;
if (action == ACTION_STD_PREV && !lists->wraparound)
return false;
}
return (action != ACTION_STD_PREV && action != ACTION_STD_PREVREPEAT);
if (lists->selected_item == lists->nb_items - lists->selected_size)
{
if (action == ACTION_STD_NEXTREPEAT)
return false;
if (action == ACTION_STD_NEXT && !lists->wraparound)
return false;
}
return (action != ACTION_STD_NEXT && action != ACTION_STD_NEXTREPEAT);
return action != ACTION_NONE;
}
#endif
/*
* Magic to make sure the list gets updated correctly if the skin does
@ -600,10 +664,13 @@ static void _lists_uiviewport_update_callback(unsigned short id, void *data)
gui_synclist_draw(current_lists);
}
bool gui_synclist_do_button(struct gui_synclist * lists, int *actionptr)
bool gui_synclist_do_button(struct gui_synclist * lists,
int *actionptr, enum list_wrap wrap)
{
int action = *actionptr;
#ifdef HAVE_LCD_BITMAP
static bool pgleft_allow_cancel = false;
#endif
#ifdef HAVE_WHEEL_ACCELERATION
int next_item_modifier = button_apply_acceleration(get_action_data());
@ -641,19 +708,29 @@ bool gui_synclist_do_button(struct gui_synclist * lists, int *actionptr)
action = *actionptr = gui_synclist_do_touchscreen(lists);
else if (action > ACTION_TOUCHSCREEN_MODE)
/* cancel kinetic if we got a normal button event */
_gui_synclist_stop_kinetic_scrolling(lists);
_gui_synclist_stop_kinetic_scrolling();
#endif
/* Disable the skin redraw callback */
current_lists = NULL;
/* Prevent list wraparound by repeating actions */
bool allow_wrap = lists->wraparound;
if (action == ACTION_STD_PREVREPEAT ||
action == ACTION_STD_NEXTREPEAT ||
action == ACTION_LISTTREE_PGUP ||
action == ACTION_LISTTREE_PGDOWN)
allow_wrap = false;
switch (wrap)
{
case LIST_WRAP_ON:
gui_synclist_limit_scroll(lists, false);
break;
case LIST_WRAP_OFF:
gui_synclist_limit_scroll(lists, true);
break;
case LIST_WRAP_UNLESS_HELD:
if (action == ACTION_STD_PREVREPEAT ||
action == ACTION_STD_NEXTREPEAT ||
action == ACTION_LISTTREE_PGUP ||
action == ACTION_LISTTREE_PGDOWN)
gui_synclist_limit_scroll(lists, true);
else gui_synclist_limit_scroll(lists, false);
break;
};
switch (action)
{
@ -663,15 +740,16 @@ bool gui_synclist_do_button(struct gui_synclist * lists, int *actionptr)
#ifdef HAVE_VOLUME_IN_LIST
case ACTION_LIST_VOLUP:
adjust_volume(1);
return true;
global_settings.volume += 2;
/* up two because the falthrough brings it down one */
case ACTION_LIST_VOLDOWN:
adjust_volume(-1);
global_settings.volume--;
setvol();
return true;
#endif
case ACTION_STD_PREV:
case ACTION_STD_PREVREPEAT:
gui_list_select_at_offset(lists, -next_item_modifier, allow_wrap);
gui_list_select_at_offset(lists, -next_item_modifier);
#ifndef HAVE_WHEEL_ACCELERATION
if (button_queue_count() < FRAMEDROP_TRIGGER)
#endif
@ -682,7 +760,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, int *actionptr)
case ACTION_STD_NEXT:
case ACTION_STD_NEXTREPEAT:
gui_list_select_at_offset(lists, next_item_modifier, allow_wrap);
gui_list_select_at_offset(lists, next_item_modifier);
#ifndef HAVE_WHEEL_ACCELERATION
if (button_queue_count() < FRAMEDROP_TRIGGER)
#endif
@ -691,6 +769,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, int *actionptr)
*actionptr = ACTION_STD_NEXT;
return true;
#ifdef HAVE_LCD_BITMAP
case ACTION_TREE_PGRIGHT:
gui_synclist_scroll_right(lists);
gui_synclist_draw(lists);
@ -706,11 +785,10 @@ bool gui_synclist_do_button(struct gui_synclist * lists, int *actionptr)
if (lists->offset_position[0] == 0)
{
pgleft_allow_cancel = true;
*actionptr = ACTION_STD_MENU;
*actionptr = ACTION_STD_CANCEL;
return true;
}
*actionptr = ACTION_TREE_PGLEFT;
/* fallthrough */
case ACTION_TREE_PGLEFT:
if(pgleft_allow_cancel && (lists->offset_position[0] == 0))
{
@ -722,6 +800,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, int *actionptr)
pgleft_allow_cancel = false; /* stop ACTION_TREE_PAGE_LEFT
skipping to root */
return true;
#endif
/* for pgup / pgdown, we are obliged to have a different behaviour depending
* on the screen for which the user pressed the key since for example, remote
* and main screen doesn't have the same number of lines */
@ -733,7 +812,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, int *actionptr)
SCREEN_REMOTE :
#endif
SCREEN_MAIN;
gui_synclist_select_previous_page(lists, screen, allow_wrap);
gui_synclist_select_previous_page(lists, screen);
gui_synclist_draw(lists);
yield();
*actionptr = ACTION_STD_NEXT;
@ -748,7 +827,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists, int *actionptr)
SCREEN_REMOTE :
#endif
SCREEN_MAIN;
gui_synclist_select_next_page(lists, screen, allow_wrap);
gui_synclist_select_next_page(lists, screen);
gui_synclist_draw(lists);
yield();
*actionptr = ACTION_STD_PREV;
@ -787,15 +866,25 @@ int list_do_action_timeout(struct gui_synclist *lists, int timeout)
}
bool list_do_action(int context, int timeout,
struct gui_synclist *lists, int *action)
struct gui_synclist *lists, int *action,
enum list_wrap wrap)
/* Combines the get_action() (with possibly overridden timeout) and
gui_synclist_do_button() calls. Returns the list action from
do_button, and places the action from get_action in *action. */
{
timeout = list_do_action_timeout(lists, timeout);
#if CONFIG_CODEC == SWCODEC
keyclick_set_callback(gui_synclist_keyclick_callback, lists);
#endif
*action = get_action(context, timeout);
return gui_synclist_do_button(lists, action);
return gui_synclist_do_button(lists, action, wrap);
}
bool gui_synclist_item_is_onscreen(struct gui_synclist *lists,
enum screen_type screen, int item)
{
int nb_lines = list_get_nb_lines(lists, screen);
return (unsigned)(item - lists->start_item[screen]) < (unsigned) nb_lines;
}
/* Simple use list implementation */
@ -855,13 +944,14 @@ 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;
if (info->get_name)
getname = info->get_name;
else
getname = simplelist_static_getname;
FOR_NB_SCREENS(i)
viewportmanager_theme_enable(i, !info->hide_theme, NULL);
viewportmanager_theme_enable(i, true, NULL);
gui_synclist_init(&lists, getname, info->callback_data,
info->scroll_all, info->selection_size, NULL);
@ -875,10 +965,14 @@ bool simplelist_show_list(struct simplelist_info *info)
#ifdef HAVE_LCD_COLOR
if (info->get_color)
gui_synclist_set_color_callback(&lists, info->get_color);
if (info->selection_color)
gui_synclist_set_sel_color(&lists, info->selection_color);
#endif
if (info->hide_selection)
{
gui_synclist_hide_selection_marker(&lists, true);
wrap = LIST_WRAP_OFF;
}
if (info->action_callback)
info->action_callback(ACTION_REDRAW, &lists);
@ -891,13 +985,12 @@ bool simplelist_show_list(struct simplelist_info *info)
gui_synclist_select_item(&lists, info->selection);
gui_synclist_draw(&lists);
if (info->speak_onshow)
gui_synclist_speak_item(&lists);
gui_synclist_speak_item(&lists);
while(1)
{
list_do_action(CONTEXT_LIST, info->timeout, &lists, &action);
list_do_action(CONTEXT_LIST, info->timeout,
&lists, &action, wrap);
/* We must yield in this case or no other thread can run */
if (info->timeout == TIMEOUT_NOBLOCK)
@ -923,11 +1016,6 @@ bool simplelist_show_list(struct simplelist_info *info)
info->selection = -1;
break;
}
else if (action == ACTION_STD_OK)
{
info->selection = gui_synclist_get_sel_pos(&lists);
break;
}
else if ((action == ACTION_REDRAW) ||
(list_is_dirty(&lists)) ||
(old_line_count != simplelist_line_count))
@ -944,12 +1032,6 @@ bool simplelist_show_list(struct simplelist_info *info)
return true;
}
talk_shutup();
#ifdef HAVE_LCD_COLOR
if (info->selection_color)
gui_synclist_set_sel_color(&lists, NULL);
#endif
FOR_NB_SCREENS(i)
viewportmanager_theme_undo(i, false);
return false;
@ -961,9 +1043,8 @@ void simplelist_info_init(struct simplelist_info *info, char* title,
info->title = title;
info->count = count;
info->selection_size = 1;
info->hide_selection = false;
info->scroll_all = false;
info->hide_theme = false;
info->speak_onshow = true;
info->timeout = HZ/10;
info->selection = 0;
info->action_callback = NULL;
@ -973,7 +1054,6 @@ void simplelist_info_init(struct simplelist_info *info, char* title,
info->get_talk = NULL;
#ifdef HAVE_LCD_COLOR
info->get_color = NULL;
info->selection_color = NULL;
#endif
info->callback_data = data;
simplelist_line_count = 0;

View file

@ -26,16 +26,13 @@
#include "icon.h"
#include "screen_access.h"
#include "skin_engine/skin_engine.h"
#include "line.h"
#define SCROLLBAR_WIDTH global_settings.scrollbar_width
enum synclist_cursor
{
SYNCLIST_CURSOR_NOSTYLE = 0,
SYNCLIST_CURSOR_INVERT,
SYNCLIST_CURSOR_COLOR,
SYNCLIST_CURSOR_GRADIENT,
enum list_wrap {
LIST_WRAP_ON = 0,
LIST_WRAP_OFF,
LIST_WRAP_UNLESS_HELD,
};
/*
@ -70,35 +67,6 @@ 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;
const 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
@ -117,78 +85,56 @@ typedef int list_speak_item(int selected_item, void * data);
* selected item, negative value for default coloring.
*/
typedef int list_get_color(int selected_item, void * data);
struct list_selection_color
{
/* text color, in native lcd format
* (convert with LCD_RGBPACK() if necessary) */
unsigned text_color;
/* only STYLE_GRADIENT supported set line_color & line_end_color the same
* for solid color, in native
* lcd format (convert with LCD_RGBPACK() if necessary) */
unsigned line_color;
unsigned line_end_color;
/* viewport foreground and background, in native
* lcd format (convert with LCD_RGBPACK() if necessary) */
unsigned fg_color;
unsigned bg_color;
/* To enable:
* call gui_synclist_set_sel_color(gui_synclist*, list_selection_color*)
* If using the default viewport you should call
* gui_synclist_set_sel_color(gui_synclist*, NULL) when finished */
};
#endif
struct gui_synclist
{
/*flags to hold settings show: icons, scrollbar etc..*/
int scrollbar;
int cursor_style;
bool show_icons;
bool keyclick;
bool talk_menu;
bool wraparound;
bool scroll_paginated;
/* whether the text of the whole items of the list have to be
/* defines wether the list should stop when reaching the top/bottom
* or should continue (by going to bottom/top) */
bool limit_scroll;
/* wether the text of the whole items of the list have to be
* scrolled or only for the selected item */
bool scroll_all;
int nb_items;
int selected_item;
#ifdef HAVE_TOUCHSCREEN
/* absolute Y coordinate, used for smooth scrolling */
int y_pos;
#endif
int start_item[NB_SCREENS]; /* the item that is displayed at the top of the screen */
/* the number of lines that are selected at the same time */
int selected_size;
/* the number of pixels each line occupies (including optional padding on touchscreen */
int line_height[NB_SCREENS];
#ifdef HAVE_LCD_BITMAP
int offset_position[NB_SCREENS]; /* the list's screen scroll placement in pixels */
#endif
long scheduled_talk_tick, last_talked_tick, dirty_tick;
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;
/* The optional title, set to NULL for none */
const char * title;
char * title;
/* Optional title icon */
enum themable_icons title_icon;
bool show_selection_marker; /* set to true by default */
#ifdef HAVE_LCD_COLOR
int title_color;
list_get_color *callback_get_item_color;
struct list_selection_color *selection_color;
#endif
struct viewport *parent[NB_SCREENS];
};
#ifdef HAVE_LCD_BITMAP
extern void list_init(void);
/* parse global setting to static int */
extern void gui_list_screen_scroll_step(int ofs);
/* parse global setting to static bool */
extern void gui_list_screen_scroll_out_of_view(bool enable);
#endif /* HAVE_LCD_BITMAP */
extern void gui_synclist_init(
struct gui_synclist * lists,
@ -204,7 +150,6 @@ extern void gui_synclist_set_voice_callback(struct gui_synclist * lists, list_sp
extern void gui_synclist_set_viewport_defaults(struct viewport *vp, enum screen_type screen);
#ifdef HAVE_LCD_COLOR
extern void gui_synclist_set_color_callback(struct gui_synclist * lists, list_get_color color_callback);
extern void gui_synclist_set_sel_color(struct gui_synclist * lists, struct list_selection_color *list_sel_color);
#endif
extern void gui_synclist_speak_item(struct gui_synclist * lists);
extern int gui_synclist_get_nb_items(struct gui_synclist * lists);
@ -217,18 +162,36 @@ extern void gui_synclist_select_item(struct gui_synclist * lists,
int item_number);
extern void gui_synclist_add_item(struct gui_synclist * lists);
extern void gui_synclist_del_item(struct gui_synclist * lists);
extern void gui_synclist_set_title(struct gui_synclist * lists, const char * title,
extern void gui_synclist_limit_scroll(struct gui_synclist * lists, bool scroll);
extern void gui_synclist_set_title(struct gui_synclist * lists, char * title,
enum themable_icons icon);
extern void gui_synclist_hide_selection_marker(struct gui_synclist *lists,
bool hide);
extern bool gui_synclist_item_is_onscreen(struct gui_synclist *lists,
enum screen_type screen, int item);
#if CONFIG_CODEC == SWCODEC
extern bool gui_synclist_keyclick_callback(int action, void* data);
#endif
/*
* Do the action implied by the given button,
* returns true if the action was handled.
* NOTE: *action may be changed regardless of return value
*/
extern bool gui_synclist_do_button(struct gui_synclist * lists, int *action);
#if !defined(PLUGIN)
struct listitem_viewport_cfg;
extern bool gui_synclist_do_button(struct gui_synclist * lists,
int *action,
enum list_wrap);
#if defined(HAVE_LCD_BITMAP) && !defined(PLUGIN)
struct listitem_viewport_cfg {
struct wps_data *data;
OFFSETTYPE(char *) label;
int width;
int height;
int xmargin;
int ymargin;
bool tile;
struct skin_viewport selected_item_vp;
};
bool skinlist_get_item(struct screen *display, struct gui_synclist *list, int x, int y, int *item);
bool skinlist_draw(struct screen *display, struct gui_synclist *list);
@ -243,13 +206,13 @@ enum themable_icons skinlist_get_item_icon(int offset, bool wrap);
bool skinlist_needs_scrollbar(enum screen_type screen);
void skinlist_get_scrollbar(int* nb_item, int* first_shown, int* last_shown);
int skinlist_get_line_count(enum screen_type screen, struct gui_synclist *list);
#endif /* !PLUGIN) */
#endif
#if defined(HAVE_TOUCHSCREEN)
/* this needs to be fixed if we ever get more than 1 touchscreen on a target */
extern unsigned gui_synclist_do_touchscreen(struct gui_synclist * gui_list);
/* only for private use in gui/list.c */
extern void _gui_synclist_stop_kinetic_scrolling(struct gui_synclist * gui_list);
extern void _gui_synclist_stop_kinetic_scrolling(void);
#endif
/* If the list has a pending postponed scheduled announcement, that
@ -260,7 +223,8 @@ extern int list_do_action_timeout(struct gui_synclist *lists, int timeout);
list_do_action_timeout) with the gui_synclist_do_button call, for
convenience. */
extern bool list_do_action(int context, int timeout,
struct gui_synclist *lists, int *action);
struct gui_synclist *lists, int *action,
enum list_wrap wrap);
/** Simplelist implementation.
@ -269,12 +233,11 @@ extern bool list_do_action(int context, int timeout,
**/
struct simplelist_info {
const char *title; /* title to show on the list */
char *title; /* title to show on the list */
int count; /* number of items in the list, each item is selection_size high */
int selection_size; /* list selection size, usually 1 */
bool hide_selection;
bool scroll_all;
bool hide_theme;
bool speak_onshow; /* list speaks first item or 'empty list' */
int timeout;
int selection; /* the item to select when the list is first displayed */
/* when the list is exited, this will be set to the
@ -291,7 +254,6 @@ struct simplelist_info {
list_speak_item *get_talk; /* can be NULL to not speak */
#ifdef HAVE_LCD_COLOR
list_get_color *get_color;
struct list_selection_color *selection_color;
#endif
void *callback_data; /* data for callbacks */
};
@ -317,16 +279,14 @@ void simplelist_addline(const char *fmt, ...);
/* setup the info struct. members not setup in this function need to be assigned manually
members set in this function:
info.selection_size = 1;
info.hide_selection = false;
info.scroll_all = false;
info.hide_theme = false;
info.speak_onshow = true;
info.action_callback = NULL;
info.title_icon = Icon_NOICON;
info.get_icon = NULL;
info.get_name = NULL;
info.get_voice = NULL;
info.get_color = NULL;
info.list_selection_color = NULL;
info.timeout = HZ/10;
info.selection = 0;
*/

View file

@ -79,14 +79,11 @@ static int calculate_mask_r(struct category *root, int mask)
while (i < root->children_count)
{
struct child *this = &root->children[i];
if (this)
{
if (this->state == SELECTED)
mask |= this->key_value;
if (this->state == SELECTED)
mask |= this->key_value;
else if (this->state == EXPANDED)
mask = calculate_mask_r(this->category, mask);
}
else if (this->state == EXPANDED)
mask = calculate_mask_r(this->category, mask);
i++;
}
return mask;
@ -100,7 +97,7 @@ static int count_items(struct category *start)
for (i=0; i<start->children_count; i++)
{
struct child *foo = &start->children[i];
if (foo && foo->state == EXPANDED)
if (foo->state == EXPANDED)
count += count_items(foo->category);
count++;
}
@ -123,7 +120,7 @@ static struct child* find_index(struct category *start,
return foo;
}
i++;
if (foo && foo->state == EXPANDED)
if (foo->state == EXPANDED)
{
struct child *bar = find_index(foo->category, index - i, parent);
if (bar)
@ -144,7 +141,7 @@ static int item_action_callback(int action, struct gui_synclist *list)
struct category *parent;
struct child *this = find_index(root, list->selected_item, &parent);
if (action == ACTION_STD_OK && this)
if (action == ACTION_STD_OK)
{
switch (this->state)
{
@ -197,18 +194,16 @@ static const char * item_get_name(int selected_item, void * data,
for(int i = 0; i <= parent->depth; i++)