Compare commits
15 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d4d233c31a | ||
|
|
45a9b54f24 | ||
|
|
8d37673a78 | ||
|
|
43c049b9ad | ||
|
|
4d510ab628 | ||
|
|
32e9698dac | ||
|
|
22638ede8d | ||
|
|
5f17935ac4 | ||
|
|
1b76c761d5 | ||
|
|
c593ad5264 | ||
|
|
4d633bb6b8 | ||
|
|
1ea74dc42b | ||
|
|
72e00216e1 | ||
|
|
280bbbfba7 | ||
|
|
67a1465f57 |
3489 changed files with 206199 additions and 301984 deletions
95
.gitignore
vendored
95
.gitignore
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
[gerrit]
|
||||
host=gerrit.rockbox.org
|
||||
port=29418
|
||||
project=rockbox.git
|
||||
defaultbranch=master
|
||||
|
|
@ -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)","")
|
||||
|
|
|
|||
61
apps/SOURCES
61
apps/SOURCES
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
322
apps/action.c
322
apps/action.c
|
|
@ -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 ***********************************************
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 : < $< > $@
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
#ifdef HAVE_LCD_BITMAP
|
||||
default_icons.bmp
|
||||
#endif
|
||||
|
||||
#if (CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(__APPLE__)
|
||||
osx_dummy.bmp
|
||||
|
|
|
|||
|
|
@ -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 |
|
|
@ -1,4 +1,6 @@
|
|||
#ifdef HAVE_LCD_BITMAP
|
||||
remote_default_icons.bmp
|
||||
#endif
|
||||
|
||||
#if (CONFIG_PLATFORM & PLATFORM_HOSTED) && defined(__APPLE__)
|
||||
osx_remote_dummy.bmp
|
||||
|
|
|
|||
1973
apps/bookmark.c
1973
apps/bookmark.c
File diff suppressed because it is too large
Load diff
|
|
@ -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);
|
||||
|
|
|
|||
120
apps/buffering.c
120
apps/buffering.c
|
|
@ -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
|
||||
============================
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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__) */
|
||||
|
|
@ -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 */
|
||||
|
||||
202
apps/cuesheet.c
202
apps/cuesheet.c
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
267
apps/filetree.c
267
apps/filetree.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
427
apps/filetypes.c
427
apps/filetypes.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
131
apps/gui/buttonbar.c
Normal 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
85
apps/gui/buttonbar.h
Normal 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
112
apps/gui/charcell/list.c
Normal 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();
|
||||
}
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
308
apps/gui/list.c
308
apps/gui/list.c
|
|
@ -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;
|
||||
|
|
|
|||
136
apps/gui/list.h
136
apps/gui/list.h
|
|
@ -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;
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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++)
|
||||