summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/SOURCES2
-rw-r--r--apps/abrepeat.h33
-rw-r--r--apps/action.c153
-rw-r--r--apps/action.h19
-rw-r--r--apps/alarm_menu.c161
-rw-r--r--apps/apps.make2
-rw-r--r--apps/bookmark.c1198
-rw-r--r--apps/bookmark.h8
-rw-r--r--apps/buffering.c113
-rw-r--r--apps/buffering.h7
-rw-r--r--apps/codecs.c5
-rw-r--r--apps/core_keymap.c95
-rw-r--r--apps/core_keymap.h65
-rw-r--r--apps/cuesheet.c133
-rw-r--r--apps/debug_menu.c272
-rw-r--r--apps/enc_config.c8
-rw-r--r--apps/features.txt17
-rw-r--r--apps/filetree.c202
-rw-r--r--apps/filetree.h3
-rw-r--r--apps/filetypes.c294
-rw-r--r--apps/filetypes.h6
-rw-r--r--apps/gui/bitmap/list-skinned.c3
-rw-r--r--apps/gui/bitmap/list.c251
-rw-r--r--apps/gui/color_picker.c26
-rw-r--r--apps/gui/folder_select.c429
-rw-r--r--apps/gui/icon.c56
-rw-r--r--apps/gui/line.c3
-rw-r--r--apps/gui/list.c199
-rw-r--r--apps/gui/list.h91
-rw-r--r--apps/gui/option_select.c94
-rw-r--r--apps/gui/option_select.h13
-rw-r--r--apps/gui/pitchscreen.c1055
-rw-r--r--apps/gui/quickscreen.c143
-rw-r--r--apps/gui/quickscreen.h10
-rw-r--r--apps/gui/skin_engine/skin_backdrops.c42
-rw-r--r--apps/gui/skin_engine/skin_display.c244
-rw-r--r--apps/gui/skin_engine/skin_display.h9
-rw-r--r--apps/gui/skin_engine/skin_engine.c97
-rw-r--r--apps/gui/skin_engine/skin_engine.h26
-rw-r--r--apps/gui/skin_engine/skin_parser.c447
-rw-r--r--apps/gui/skin_engine/skin_render.c44
-rw-r--r--apps/gui/skin_engine/skin_tokens.c59
-rw-r--r--apps/gui/skin_engine/skin_touchsupport.c17
-rw-r--r--apps/gui/skin_engine/wps_internals.h54
-rw-r--r--apps/gui/splash.c176
-rw-r--r--apps/gui/splash.h11
-rw-r--r--apps/gui/statusbar-skinned.c25
-rw-r--r--apps/gui/statusbar-skinned.h7
-rw-r--r--apps/gui/statusbar.c12
-rw-r--r--apps/gui/statusbar.h3
-rw-r--r--apps/gui/usb_screen.c18
-rw-r--r--apps/gui/viewport.c42
-rw-r--r--apps/gui/viewport.h1
-rw-r--r--apps/gui/wps.c566
-rw-r--r--apps/gui/wps.h37
-rw-r--r--apps/gui/yesno.c5
-rw-r--r--apps/hosted/android/keyboard.c2
-rw-r--r--apps/hosted/android/notification.c1
-rw-r--r--apps/iap/iap-core.c5
-rw-r--r--apps/iap/iap-lingo4.c21
-rw-r--r--apps/keymaps/keymap-agptekrocker.c22
-rw-r--r--apps/keymaps/keymap-c200.c1
-rw-r--r--apps/keymaps/keymap-clip.c11
-rw-r--r--apps/keymaps/keymap-creativezv.c2
-rw-r--r--apps/keymaps/keymap-creativezvm.c2
-rw-r--r--apps/keymaps/keymap-e200.c1
-rw-r--r--apps/keymaps/keymap-erosq.c7
-rw-r--r--apps/keymaps/keymap-fiiom3k.c119
-rw-r--r--apps/keymaps/keymap-fiiom3klinux.c3
-rw-r--r--apps/keymaps/keymap-fuze.c1
-rw-r--r--apps/keymaps/keymap-fuzeplus.c6
-rw-r--r--apps/keymaps/keymap-gigabeat-s.c2
-rw-r--r--apps/keymaps/keymap-gigabeat.c2
-rw-r--r--apps/keymaps/keymap-h10.c1
-rw-r--r--apps/keymaps/keymap-h1x0_h3x0.c2
-rw-r--r--apps/keymaps/keymap-hdd1630.c2
-rw-r--r--apps/keymaps/keymap-hdd6330.c2
-rw-r--r--apps/keymaps/keymap-hm60x.c1
-rw-r--r--apps/keymaps/keymap-hm801.c1
-rw-r--r--apps/keymaps/keymap-ihifi.c1
-rw-r--r--apps/keymaps/keymap-ihifi770.c1
-rw-r--r--apps/keymaps/keymap-ihifi800.c1
-rw-r--r--apps/keymaps/keymap-ipod.c2
-rw-r--r--apps/keymaps/keymap-m200.c1
-rw-r--r--apps/keymaps/keymap-ma.c3
-rw-r--r--apps/keymaps/keymap-meizu-m6sl.c2
-rw-r--r--apps/keymaps/keymap-mini2440.c2
-rw-r--r--apps/keymaps/keymap-mr100.c2
-rw-r--r--apps/keymaps/keymap-mr500.c2
-rw-r--r--apps/keymaps/keymap-nwz.c6
-rw-r--r--apps/keymaps/keymap-nwza860.c5
-rw-r--r--apps/keymaps/keymap-ondavx777.c2
-rw-r--r--apps/keymaps/keymap-rk27xx-generic.c2
-rw-r--r--apps/keymaps/keymap-sa9200.c1
-rw-r--r--apps/keymaps/keymap-shanlingq1.c2
-rw-r--r--apps/keymaps/keymap-touchscreen.c4
-rw-r--r--apps/keymaps/keymap-xduoox20.c3
-rw-r--r--apps/keymaps/keymap-xduoox3.c7
-rw-r--r--apps/keymaps/keymap-xduoox3ii.c3
-rw-r--r--apps/keymaps/keymap-yh8xx_yh9xx.c1
-rw-r--r--apps/keymaps/keymap-ypr0.c2
-rw-r--r--apps/keymaps/keymap-ypr1.c2
-rw-r--r--apps/keymaps/keymap-zen.c4
-rw-r--r--apps/keymaps/keymap-zenxfi2.c2
-rw-r--r--apps/keymaps/keymap-zenxfi3.c1
-rw-r--r--apps/lang/arabic.lang21
-rw-r--r--apps/lang/basque.lang19
-rw-r--r--apps/lang/bulgarian.lang23
-rw-r--r--apps/lang/catala.lang19
-rw-r--r--apps/lang/chinese-simp.lang921
-rw-r--r--apps/lang/chinese-trad.lang3400
-rw-r--r--apps/lang/czech.lang30
-rw-r--r--apps/lang/dansk.lang19
-rw-r--r--apps/lang/deutsch.lang23
-rw-r--r--apps/lang/english-us.lang801
-rw-r--r--apps/lang/english.lang786
-rw-r--r--apps/lang/espanol.lang19
-rw-r--r--apps/lang/finnish.lang19
-rw-r--r--apps/lang/francais.lang23
-rw-r--r--apps/lang/galego.lang19
-rw-r--r--apps/lang/greek.lang23
-rw-r--r--apps/lang/hebrew.lang35
-rw-r--r--apps/lang/hrvatski.lang19
-rw-r--r--apps/lang/italiano.lang735
-rw-r--r--apps/lang/japanese.lang23
-rw-r--r--apps/lang/korean.lang19
-rw-r--r--apps/lang/latviesu.lang17
-rw-r--r--apps/lang/lietuviu.lang19
-rw-r--r--apps/lang/magyar.lang19
-rw-r--r--apps/lang/nederlands.lang572
-rw-r--r--apps/lang/norsk-nynorsk.lang19
-rw-r--r--apps/lang/norsk.lang23
-rw-r--r--apps/lang/polski.lang812
-rw-r--r--apps/lang/portugues-brasileiro.lang19
-rw-r--r--apps/lang/portugues.lang21
-rw-r--r--apps/lang/romaneste.lang19
-rw-r--r--apps/lang/russian.lang30
-rw-r--r--apps/lang/slovak.lang1146
-rw-r--r--apps/lang/slovenscina.lang19
-rw-r--r--apps/lang/srpski.lang1174
-rw-r--r--apps/lang/svenska.lang21
-rw-r--r--apps/lang/tagalog.lang19
-rw-r--r--apps/lang/thai.lang19
-rw-r--r--apps/lang/turkce.lang6762
-rw-r--r--apps/lang/ukrainian.lang19
-rw-r--r--apps/lang/vlaams.lang25
-rw-r--r--apps/lang/walon.lang19
-rw-r--r--apps/logfdisp.c15
-rw-r--r--apps/main.c105
-rw-r--r--apps/menu.c94
-rw-r--r--apps/menu.h53
-rw-r--r--apps/menus/audiohw_eq_menu.c156
-rw-r--r--apps/menus/display_menu.c45
-rw-r--r--apps/menus/eq_menu.c57
-rw-r--r--apps/menus/main_menu.c53
-rw-r--r--apps/menus/playback_menu.c53
-rw-r--r--apps/menus/playlist_menu.c25
-rw-r--r--apps/menus/plugin_menu.c63
-rw-r--r--apps/menus/radio_menu.c33
-rw-r--r--apps/menus/recording_menu.c66
-rw-r--r--apps/menus/settings_menu.c88
-rw-r--r--apps/menus/sound_menu.c18
-rw-r--r--apps/menus/theme_menu.c82
-rw-r--r--apps/menus/time_menu.c20
-rw-r--r--apps/misc.c506
-rw-r--r--apps/misc.h48
-rw-r--r--apps/onplay.c1011
-rw-r--r--apps/onplay.h36
-rw-r--r--apps/open_plugin.c244
-rw-r--r--apps/open_plugin.h10
-rw-r--r--apps/pcmbuf.c3
-rw-r--r--apps/playback.c166
-rw-r--r--apps/playback.h3
-rw-r--r--apps/playlist.c4467
-rw-r--r--apps/playlist.h58
-rw-r--r--apps/playlist_catalog.c274
-rw-r--r--apps/playlist_catalog.h10
-rw-r--r--apps/playlist_viewer.c441
-rw-r--r--apps/playlist_viewer.h3
-rw-r--r--apps/plugin.c146
-rw-r--r--apps/plugin.h108
-rw-r--r--apps/plugins/2048.c14
-rw-r--r--apps/plugins/CATEGORIES8
-rw-r--r--apps/plugins/SOURCES20
-rw-r--r--apps/plugins/SOURCES.app_build1
-rw-r--r--apps/plugins/SUBDIRS3
-rw-r--r--apps/plugins/alarmclock.c6
-rw-r--r--apps/plugins/announce_status.c126
-rw-r--r--apps/plugins/battery_bench.c93
-rw-r--r--apps/plugins/bitmaps/native/SOURCES46
-rw-r--r--apps/plugins/bitmaps/native/_2048_tiles.26x26x2.bmpbin0 -> 6254 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.112x30x1.bmpbin0 -> 542 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.128x40x16.bmpbin0 -> 15414 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.128x42x1.bmpbin0 -> 736 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.128x42x2.bmpbin0 -> 2808 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.132x40x16.bmpbin0 -> 15894 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.138x46x2.bmpbin0 -> 3392 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.160x50x16.bmpbin0 -> 24054 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.160x53x1.bmpbin0 -> 1122 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.160x53x2.bmpbin0 -> 4312 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.176x54x16.bmpbin0 -> 28566 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.220x68x16.bmpbin0 -> 44934 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.240x74x16.bmpbin0 -> 53334 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.320x98x16.bmpbin0 -> 94136 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.480x149x16.bmpbin0 -> 214614 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.640x198x16.bmpbin0 -> 380214 bytes
-rw-r--r--apps/plugins/bitmaps/native/creditslogo.96x30x16.bmpbin0 -> 8694 bytes
-rw-r--r--apps/plugins/bitmaps/remote_native/SOURCES7
-rw-r--r--apps/plugins/bitmaps/remote_native/remote_creditslogo.128x42x1.bmpbin0 -> 736 bytes
-rw-r--r--apps/plugins/bitmaps/remote_native/remote_creditslogo.128x42x2.bmpbin0 -> 2808 bytes
-rw-r--r--apps/plugins/bounce.c23
-rw-r--r--apps/plugins/brickmania.c23
-rw-r--r--apps/plugins/bubbles.c10
-rw-r--r--apps/plugins/calendar.c13
-rw-r--r--apps/plugins/chessbox/chessbox.c3
-rw-r--r--apps/plugins/chessbox/chessbox_pgn.c4
-rw-r--r--apps/plugins/chessbox/chessbox_pgn.h2
-rw-r--r--apps/plugins/chopper.c33
-rw-r--r--apps/plugins/clix.c8
-rw-r--r--apps/plugins/clock/clock.c10
-rw-r--r--apps/plugins/codebuster.c7
-rw-r--r--apps/plugins/credits.c101
-rw-r--r--apps/plugins/cube.c12
-rw-r--r--apps/plugins/db_folder_select.c652
-rw-r--r--apps/plugins/demystify.c32
-rw-r--r--apps/plugins/dice.c7
-rw-r--r--apps/plugins/doom/d_deh.c3
-rw-r--r--apps/plugins/doom/i_video.c3
-rw-r--r--apps/plugins/doom/rockdoom.c8
-rw-r--r--apps/plugins/fft/fft.c42
-rw-r--r--apps/plugins/fire.c15
-rw-r--r--apps/plugins/fireworks.c17
-rw-r--r--apps/plugins/flipit.c4
-rw-r--r--apps/plugins/fractals/fractal.h2
-rw-r--r--apps/plugins/imageviewer/gif/gif.c16
-rw-r--r--apps/plugins/imageviewer/gif/gif_decoder.c45
-rw-r--r--apps/plugins/imageviewer/gif/gif_decoder.h1
-rw-r--r--apps/plugins/imageviewer/image_decoder.c5
-rw-r--r--apps/plugins/imageviewer/imageviewer.c74
-rw-r--r--apps/plugins/imageviewer/imageviewer.h14
-rw-r--r--apps/plugins/imageviewer/imageviewer_button.h8
-rw-r--r--apps/plugins/imageviewer/jpeg/yuv2rgb.c2
-rw-r--r--apps/plugins/imageviewer/ppm/ppm_decoder.c2
-rw-r--r--apps/plugins/invadrox.c2
-rw-r--r--apps/plugins/jackpot.c9
-rw-r--r--apps/plugins/jewels.c4
-rw-r--r--apps/plugins/keybox.c3
-rw-r--r--apps/plugins/keyremap.c2217
-rw-r--r--apps/plugins/lamp.c22
-rw-r--r--apps/plugins/lastfm_scrobbler.c625
-rw-r--r--apps/plugins/lib/SOURCES9
-rw-r--r--apps/plugins/lib/action_helper.c1
-rw-r--r--apps/plugins/lib/action_helper.h34
-rwxr-xr-xapps/plugins/lib/action_helper.pl211
-rw-r--r--apps/plugins/lib/arg_helper.c4
-rw-r--r--apps/plugins/lib/arg_helper.h2
-rw-r--r--apps/plugins/lib/bmp_smooth_scale.c2
-rw-r--r--apps/plugins/lib/button_helper.c1
-rw-r--r--apps/plugins/lib/button_helper.h40
-rwxr-xr-xapps/plugins/lib/button_helper.pl103
-rw-r--r--apps/plugins/lib/helper.c48
-rw-r--r--apps/plugins/lib/helper.h20
-rw-r--r--apps/plugins/lib/highscore.c9
-rw-r--r--apps/plugins/lib/id3.c46
-rw-r--r--apps/plugins/lib/id3.h (renamed from apps/scrobbler.h)13
-rw-r--r--apps/plugins/lib/mul_id3.c182
-rw-r--r--apps/plugins/lib/mul_id3.h28
-rw-r--r--apps/plugins/lib/osd.c8
-rw-r--r--apps/plugins/lib/overlay.c5
-rw-r--r--apps/plugins/lib/playback_control.c20
-rw-r--r--apps/plugins/lib/pluginlib_bmp.c2
-rw-r--r--apps/plugins/lib/printcell_helper.c534
-rw-r--r--apps/plugins/lib/printcell_helper.h45
-rw-r--r--apps/plugins/lib/wrappers.h1
-rw-r--r--apps/plugins/lib/xlcd_scroll.c4
-rw-r--r--apps/plugins/logo.c14
-rw-r--r--apps/plugins/lrcplayer.c32
-rwxr-xr-xapps/plugins/lua/rbdefines_helper.pl2
-rw-r--r--apps/plugins/lua/rocklib.c19
-rw-r--r--apps/plugins/lua/rocklib_events.c6
-rw-r--r--apps/plugins/lua/rocklib_img.c2
-rw-r--r--apps/plugins/lua_scripts/dbgettags.lua15
-rw-r--r--apps/plugins/lua_scripts/random_playlist.lua558
-rw-r--r--apps/plugins/main_menu_config.c2
-rw-r--r--apps/plugins/matrix.c9
-rw-r--r--apps/plugins/maze.c20
-rw-r--r--apps/plugins/mazezam.c9
-rw-r--r--apps/plugins/metronome.c6
-rw-r--r--apps/plugins/mikmod/mikmod.c19
-rw-r--r--apps/plugins/mosaique.c11
-rw-r--r--apps/plugins/mpegplayer/libmpeg2/idct_arm.S6
-rw-r--r--apps/plugins/mpegplayer/libmpeg2/idct_armv6.S7
-rw-r--r--apps/plugins/mpegplayer/mpeg_misc.c1
-rw-r--r--apps/plugins/mpegplayer/mpeg_misc.h24
-rw-r--r--apps/plugins/mpegplayer/mpegplayer.c5
-rw-r--r--apps/plugins/multiboot_select.c346
-rw-r--r--apps/plugins/open_plugins.c73
-rw-r--r--apps/plugins/oscilloscope.c16
-rw-r--r--apps/plugins/otp.c17
-rwxr-xr-xapps/plugins/pacbox/pacbox.c4
-rw-r--r--apps/plugins/pdbox/pdbox.c2
-rw-r--r--apps/plugins/pegbox.c4
-rw-r--r--apps/plugins/periodic_table.c1
-rw-r--r--apps/plugins/pictureflow/pictureflow.c1622
-rw-r--r--apps/plugins/pitch_detector.c5
-rw-r--r--apps/plugins/pitch_screen.c1279
-rw-r--r--apps/plugins/plasma.c17
-rw-r--r--apps/plugins/plugin_crt0.c3
-rw-r--r--apps/plugins/plugins.make29
-rw-r--r--apps/plugins/pong.c7
-rw-r--r--apps/plugins/properties.c403
-rw-r--r--apps/plugins/puzzles/rockbox.c15
-rw-r--r--apps/plugins/random_folder_advance_config.c3
-rw-r--r--apps/plugins/rb_info.c567
-rw-r--r--apps/plugins/resistor.c18
-rw-r--r--apps/plugins/robotfindskitten.c6
-rw-r--r--apps/plugins/rockblox.c14
-rw-r--r--apps/plugins/rockblox1d.c7
-rw-r--r--apps/plugins/rockboy/menu.c8
-rw-r--r--apps/plugins/rockboy/rockboy.c5
-rw-r--r--apps/plugins/rocklife.c12
-rw-r--r--apps/plugins/rockpaint.c18
-rw-r--r--apps/plugins/sdl/SDL_mixer/timidity/playmidi.c2
-rw-r--r--apps/plugins/sdl/main.c7
-rw-r--r--apps/plugins/shopper.c3
-rw-r--r--apps/plugins/shortcuts/shortcuts_view.c8
-rw-r--r--apps/plugins/sliding_puzzle.c8
-rw-r--r--apps/plugins/snake.c4
-rw-r--r--apps/plugins/snake2.c4
-rw-r--r--apps/plugins/snow.c8
-rw-r--r--apps/plugins/sokoban.c2
-rw-r--r--apps/plugins/solitaire.c5
-rw-r--r--apps/plugins/spacerocks.c19
-rw-r--r--apps/plugins/speedread.c24
-rw-r--r--apps/plugins/star.c4
-rw-r--r--apps/plugins/starfield.c18
-rw-r--r--apps/plugins/stats.c10
-rw-r--r--apps/plugins/superdom.c1
-rw-r--r--apps/plugins/test_disk.c6
-rw-r--r--apps/plugins/test_fps.c8
-rw-r--r--apps/plugins/test_gfx.c8
-rw-r--r--apps/plugins/test_grey.c8
-rw-r--r--apps/plugins/test_kbd.c46
-rw-r--r--apps/plugins/test_usb.c137
-rw-r--r--apps/plugins/test_viewports.c4
-rw-r--r--apps/plugins/text_editor.c3
-rw-r--r--apps/plugins/text_viewer/tv_menu.c78
-rw-r--r--apps/plugins/viewers.config3
-rw-r--r--apps/plugins/vu_meter.c13
-rw-r--r--apps/plugins/wormlet.c9
-rw-r--r--apps/plugins/xobox.c11
-rw-r--r--apps/plugins/xworld/engine.c2
-rw-r--r--apps/plugins/xworld/sys.c20
-rw-r--r--apps/radio/presets.c28
-rw-r--r--apps/radio/radio.c5
-rw-r--r--apps/radio/radio_skin.c16
-rw-r--r--apps/radio/radioart.c4
-rw-r--r--apps/rbcodec_helpers.c15
-rw-r--r--apps/recorder/albumart.c108
-rw-r--r--apps/recorder/albumart.h6
-rw-r--r--apps/recorder/jpeg_idct_arm.S12
-rw-r--r--apps/recorder/jpeg_load.c15
-rw-r--r--apps/recorder/jpeg_load.h7
-rw-r--r--apps/recorder/keyboard.c234
-rw-r--r--apps/recorder/pcm_record.c62
-rw-r--r--apps/recorder/peakmeter.c2
-rw-r--r--apps/recorder/recording.c263
-rw-r--r--apps/recorder/resize.c2
-rw-r--r--apps/root_menu.c227
-rw-r--r--apps/screen_access.c2
-rw-r--r--apps/screen_access.h1
-rw-r--r--apps/screens.c105
-rw-r--r--apps/screens.h7
-rw-r--r--apps/scrobbler.c287
-rw-r--r--apps/settings.c745
-rw-r--r--apps/settings.h67
-rw-r--r--apps/settings_list.c261
-rw-r--r--apps/settings_list.h10
-rw-r--r--apps/shortcuts.c96
-rw-r--r--apps/status.h2
-rw-r--r--apps/tagcache.c773
-rw-r--r--apps/tagcache.h87
-rw-r--r--apps/tagnavi.config19
-rw-r--r--apps/tagtree.c752
-rw-r--r--apps/tagtree.h9
-rw-r--r--apps/talk.c331
-rw-r--r--apps/talk.h7
-rw-r--r--apps/tree.c212
-rw-r--r--apps/tree.h27
-rw-r--r--apps/voice_thread.c2
390 files changed, 33104 insertions, 16975 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index 1628524805..444951bbcb 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -7,6 +7,7 @@ alarm_menu.c
#endif
abrepeat.c
bookmark.c
+core_keymap.c
debug_menu.c
filetypes.c
language.c
@@ -57,7 +58,6 @@ tree.c
tagtree.c
#endif
filetree.c
-scrobbler.c
#ifdef IPOD_ACCESSORY_PROTOCOL
iap/iap-core.c
iap/iap-lingo0.c
diff --git a/apps/abrepeat.h b/apps/abrepeat.h
index f7ee65247c..4d2c4ea001 100644
--- a/apps/abrepeat.h
+++ b/apps/abrepeat.h
@@ -20,9 +20,38 @@
****************************************************************************/
#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 */
diff --git a/apps/action.c b/apps/action.c
index b31c4fa927..208fea4a97 100644
--- a/apps/action.c
+++ b/apps/action.c
@@ -34,6 +34,7 @@
#include "button.h"
#include "action.h"
#include "kernel.h"
+#include "core_alloc.h"
#include "splash.h"
#include "settings.h"
@@ -69,6 +70,10 @@ 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,
@@ -120,7 +125,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 option NOUNMAPPED*/
+ /* Actions that are not mapped will not turn on the backlight */
case ACTION_UNKNOWN:
match = has_flag(mask, SEL_ACTION_NOUNMAPPED);
break;
@@ -128,15 +133,15 @@ 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:*/ /* seek not exempted outside of WPS */
+ /* 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 exempted outside of WPS
- //case ACTION_STD_NEXT:
+ /* case ACTION_STD_PREV: */ /* skip/scrollwheel not */
+ /* case ACTION_STD_NEXT: */ /* exempted outside of WPS */
case ACTION_WPS_SKIPNEXT:
case ACTION_WPS_SKIPPREV:
case ACTION_FM_NEXT_PRESET:
@@ -144,8 +149,8 @@ static bool is_action_filtered(int action, unsigned int mask, int context)
match = has_flag(mask, SEL_ACTION_SKIP);
break;
#ifdef HAVE_VOLUME_IN_LIST
- case ACTION_LIST_VOLUP: // volume exempted outside of WPS if the device supports it
- case ACTION_LIST_VOLDOWN:
+ 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:
@@ -499,7 +504,7 @@ static inline int action_code_worker(action_last_t *last,
int *end )
{
int ret = ACTION_UNKNOWN;
- int i = 0;
+ int i = *end;
unsigned int found = 0;
while (cur->items[i].button_code != BUTTON_NONE)
{
@@ -583,21 +588,52 @@ 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 = ACTION_NONE;
+ int action, i;
int context = cur->context;
- int i = 0;
-
cur->is_prebutton = false;
-#ifdef HAVE_LOCKED_ACTIONS
+#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); */
@@ -609,9 +645,13 @@ 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)
{
@@ -960,7 +1000,8 @@ 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 ((cur->context == CONTEXT_FM || cur->context == CONTEXT_WPS) && bl_is_off)
+ if (bl_is_off && (cur->context == CONTEXT_FM || cur->context == CONTEXT_WPS ||
+ cur->context == CONTEXT_MAINMENU))
{
filtered = is_action_filtered(action, last->backlight_mask, cur->context);
bl_activate = !is_action_discarded(cur, filtered, &last->bl_filter_tick);
@@ -1150,6 +1191,92 @@ 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))
{
diff --git a/apps/action.h b/apps/action.h
index ad91f31535..6e1278b33c 100644
--- a/apps/action.h
+++ b/apps/action.h
@@ -28,13 +28,15 @@
#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 */
-#ifdef HAVE_LOCKED_ACTIONS
+#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 */
-#endif
+
#define LAST_ITEM_IN_LIST { CONTEXT_STOPSEARCHING, BUTTON_NONE, BUTTON_NONE }
#define LAST_ITEM_IN_LIST__NEXTLIST(a) { a, BUTTON_NONE, BUTTON_NONE }
@@ -92,7 +94,7 @@ void set_selective_backlight_actions(bool selective, unsigned int mask,
enum {
CONTEXT_STD = 0,
/* These CONTEXT_ values were here before me,
- there values may have significance, so dont touch! */
+ their values may have significance, so dont touch! */
CONTEXT_WPS = 1,
CONTEXT_TREE = 2,
CONTEXT_RECORD = 3,
@@ -129,6 +131,7 @@ enum {
CONTEXT_USB_HID_MODE_PRESENTATION,
CONTEXT_USB_HID_MODE_BROWSER,
CONTEXT_USB_HID_MODE_MOUSE,
+ LAST_CONTEXT_PLACEHOLDER,
};
@@ -244,7 +247,6 @@ enum {
ACTION_SETTINGS_DEC,
ACTION_SETTINGS_DECREPEAT,
ACTION_SETTINGS_DECBIGSTEP,
- ACTION_SETTINGS_RESET,
ACTION_SETTINGS_SET, /* Used by touchscreen targets */
/* bookmark screen */
@@ -415,6 +417,10 @@ 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;
@@ -441,6 +447,11 @@ 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 */
diff --git a/apps/alarm_menu.c b/apps/alarm_menu.c
index 62b54a84bb..67f8d1e8dd 100644
--- a/apps/alarm_menu.c
+++ b/apps/alarm_menu.c
@@ -38,161 +38,56 @@
#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)
{
- 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];
- struct viewport * last_vp;
-
- rtc_get_alarm(&h, &m);
+ 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);
/* After a battery change the RTC values are out of range */
- 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);
- }
+ if (!valid_time(&atm))
+ memcpy(&atm, now, sizeof(struct tm));
+ atm.tm_sec = 0;
- 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;
- }
+ usb = set_time_screen(str(LANG_ALARM_MOD_TIME), &atm, false);
+ update = valid_time(&atm); /* set_time returns invalid time if canceled */
- FOR_NB_SCREENS(i)
- {
- last_vp = 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(last_vp);
- }
- button = get_action(CONTEXT_SETTINGS,HZ);
+ if (!usb && update)
+ {
- switch(button) {
- case ACTION_STD_OK:
+ 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;
/* prevent that an alarm occurs in the shutdown procedure */
/* accept alarms only if they are in 2 minutes or more */
- tm = get_time();
- togo = (m + h * 60 - tm->tm_min - tm->tm_hour * 60 + 1440) % 1440;
-
- if (togo > 1) {
+ if (mins_togo > 1) {
rtc_init();
- rtc_set_alarm(h,m);
+ rtc_set_alarm(atm.tm_hour,atm.tm_min);
rtc_enable_alarm(true);
if (global_settings.talk_menu)
{
talk_id(LANG_ALARM_MOD_TIME_TO_GO, true);
- talk_value(togo / 60, UNIT_HOUR, true);
- talk_value(togo % 60, UNIT_MIN, true);
+ talk_value(mins_togo / 60, UNIT_HOUR, true);
+ talk_value(mins_togo % 60, UNIT_MIN, true);
talk_force_enqueue_next();
}
splashf(HZ*2, str(LANG_ALARM_MOD_TIME_TO_GO),
- togo / 60, togo % 60);
- done = true;
+ mins_togo / 60, mins_togo % 60);
} else {
splash(HZ, ID2P(LANG_ALARM_MOD_ERROR));
- update = true;
- }
- break;
-
- /* inc(m) */
- case ACTION_SETTINGS_INC:
- case ACTION_SETTINGS_INCREPEAT:
- m += 5;
- if (m == 60) {
- h += 1;
- m = 0;
- hour_wrapped = true;
+ update = false;
}
- 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);
+ if (usb || !update)
+ {
+ if (!usb)
splash(HZ*2, ID2P(LANG_ALARM_MOD_DISABLE));
- 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;
- }
+ rtc_enable_alarm(false);
+ return 1;
}
return 0;
}
diff --git a/apps/apps.make b/apps/apps.make
index 6afcd12b5c..47b015bc92 100644
--- a/apps/apps.make
+++ b/apps/apps.make
@@ -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 : < $< > $@
diff --git a/apps/bookmark.c b/apps/bookmark.c
index 70dbd8075d..68c10b36e7 100644
--- a/apps/bookmark.c
+++ b/apps/bookmark.c
@@ -43,6 +43,9 @@
#include "file.h"
#include "pathfuncs.h"
+/*#define LOGF_ENABLE*/
+#include "logf.h"
+
#define MAX_BOOKMARKS 10
#define MAX_BOOKMARK_SIZE 350
#define RECENT_BOOKMARK_FILE ROCKBOX_DIR "/most-recent.bmark"
@@ -66,286 +69,289 @@ struct bookmark_list
#define BM_SPEED 0x02
/* bookmark values */
-static struct {
+struct resume_info{
+ const struct mp3entry *id3;
int resume_index;
unsigned long resume_offset;
int resume_seed;
- long resume_time;
+ long resume_elapsed;
int repeat_mode;
bool shuffle;
/* optional values */
int pitch;
int speed;
-} bm;
-
-static bool add_bookmark(const char* bookmark_file_name, const char* bookmark,
- bool most_recent);
-static char* create_bookmark(void);
-static bool delete_bookmark(const char* bookmark_file_name, int bookmark_id);
-static void say_bookmark(const char* bookmark,
- int bookmark_id, bool show_playlist_name);
-static bool play_bookmark(const char* bookmark);
-static bool generate_bookmark_file_name(const char *in);
-static bool parse_bookmark(const char *bookmark, const bool get_filenames, const bool strip_dir);
-static int buffer_bookmarks(struct bookmark_list* bookmarks, int first_line);
-static const char* get_bookmark_info(int list_index,
- void* data,
- char *buffer,
- size_t buffer_len);
-static int select_bookmark(const char* bookmark_file_name, bool show_dont_resume, char** selected_bookmark);
-static bool write_bookmark(bool create_bookmark_file, const char *bookmark);
-static int get_bookmark_count(const char* bookmark_file_name);
+};
-#define TEMP_BUF_SIZE (MAX_PATH + 1)
+/* Temp buffer used for reading, create_bookmark and filename creation */
+#define TEMP_BUF_SIZE (MAX(MAX_BOOKMARK_SIZE, MAX_PATH + 1))
static char global_temp_buffer[TEMP_BUF_SIZE];
-/* File name created by generate_bookmark_file_name */
-static char global_bookmark_file_name[MAX_PATH];
-static char global_read_buffer[MAX_BOOKMARK_SIZE];
-/* Bookmark created by create_bookmark*/
-static char global_bookmark[MAX_BOOKMARK_SIZE];
-/* Filename from parsed bookmark (can be made local where needed) */
-static char global_filename[MAX_PATH];
-/* ----------------------------------------------------------------------- */
-/* This is an interface function from the context menu. */
-/* Returns true on successful bookmark creation. */
-/* ----------------------------------------------------------------------- */
-bool bookmark_create_menu(void)
+static inline void get_hash(const char *key, uint32_t *hash, int len)
{
- return write_bookmark(true, create_bookmark());
+ *hash = crc_32(key, len, *hash); /* this is probably sufficient */
}
-/* ----------------------------------------------------------------------- */
-/* This function acts as the load interface from the context menu. */
-/* This function determines the bookmark file name and then loads that file*/
-/* for the user. The user can then select or delete previous bookmarks. */
-/* This function returns BOOKMARK_SUCCESS on the selection of a track to */
-/* resume, BOOKMARK_FAIL if the menu is exited without a selection and */
-/* BOOKMARK_USB_CONNECTED if the menu is forced to exit due to a USB */
-/* connection. */
-/* ----------------------------------------------------------------------- */
-int bookmark_load_menu(void)
+static const char* skip_tokens(const char* s, int ntokens)
{
- char* bookmark;
- int ret = BOOKMARK_FAIL;
-
- push_current_activity(ACTIVITY_BOOKMARKSLIST);
-
- char* name = playlist_get_name(NULL, global_temp_buffer,
- sizeof(global_temp_buffer));
- if (generate_bookmark_file_name(name))
+ for (int i = 0; i < ntokens; i++)
{
- ret = select_bookmark(global_bookmark_file_name, false, &bookmark);
- if (bookmark != NULL)
+ while (*s && *s != ';')
{
- ret = play_bookmark(bookmark) ? BOOKMARK_SUCCESS : BOOKMARK_FAIL;
+ s++;
+ }
+
+ if (*s)
+ {
+ s++;
}
}
+ return s;
+}
- pop_current_activity();
+static int int_token(const char **s)
+{
+ int ret = atoi(*s);
+ *s = skip_tokens(*s, 1);
return ret;
}
-/* ----------------------------------------------------------------------- */
-/* Gives the user a list of the Most Recent Bookmarks. This is an */
-/* interface function */
-/* Returns true on the successful selection of a recent bookmark. */
-/* ----------------------------------------------------------------------- */
-bool bookmark_mrb_load()
+static long long_token(const char **s)
{
- char* bookmark;
- bool ret = false;
+ /* Should be atol, but we don't have it. */
+ return int_token(s);
+}
- push_current_activity(ACTIVITY_BOOKMARKSLIST);
- select_bookmark(RECENT_BOOKMARK_FILE, false, &bookmark);
- if (bookmark != NULL)
+/*-------------------------------------------------------------------------*/
+/* Get the name of the playlist and the name of the track from a bookmark. */
+/* Returns true iff both were extracted. */
+/*-------------------------------------------------------------------------*/
+static bool bookmark_get_playlist_and_track_hash(const char *bookmark,
+ uint32_t *pl_hash,
+ uint32_t *track_hash)
+{
+ *pl_hash = 0;
+ *track_hash = 0;
+ int pl_len;
+ const char *pl_start, *pl_end, *track;
+
+ logf("%s", __func__);
+
+ pl_start = strchr(bookmark,'/');
+ if (!(pl_start))
+ return false;
+
+ pl_end = skip_tokens(pl_start, 1) - 1;
+ pl_len = pl_end - pl_start;
+
+ track = pl_end + 1;
+ get_hash(pl_start, pl_hash, pl_len);
+
+ if (global_settings.usemrb == BOOKMARK_ONE_PER_TRACK)
{
- ret = play_bookmark(bookmark);
+ get_hash(track, track_hash, strlen(track));
}
- pop_current_activity();
- return ret;
+
+ return true;
}
/* ----------------------------------------------------------------------- */
-/* This function handles an autobookmark creation. This is an interface */
-/* function. */
-/* Returns true on successful bookmark creation. */
+/* This function takes a bookmark and parses it. This function also */
+/* validates the bookmark. Valid filenamebuf indicates whether */
+/* the filename tokens are to be extracted. */
+/* Returns true on successful bookmark parse. */
/* ----------------------------------------------------------------------- */
-bool bookmark_autobookmark(bool prompt_ok)
+static bool parse_bookmark(char *filenamebuf,
+ size_t filenamebufsz,
+ const char *bookmark,
+ struct resume_info *resume_info,
+ const bool strip_dir)
{
- char* bookmark;
- bool update;
-
- if (!bookmark_is_bookmarkable_state())
- return false;
+ const char* s = bookmark;
+ const char* end;
- audio_pause(); /* first pause playback */
- update = (global_settings.autoupdatebookmark && bookmark_exists());
- bookmark = create_bookmark();
+#define GET_INT_TOKEN(var) var = int_token(&s)
+#define GET_LONG_TOKEN(var) var = long_token(&s)
+#define GET_BOOL_TOKEN(var) var = (int_token(&s) != 0)
- if (update)
- return write_bookmark(true, bookmark);
+ /* if new format bookmark, extract the optional content flags,
+ otherwise treat as an original format bookmark */
+ int opt_flags = 0;
+ int opt_pitch = 0;
+ int opt_speed = 0;
+ int old_format = ((strchr(s, '>') == s) ? 0 : 1);
+ if (old_format == 0) /* this is a new format bookmark */
+ {
+ s++;
+ GET_INT_TOKEN(opt_flags);
+ opt_pitch = (opt_flags & BM_PITCH) ? 1:0;
+ opt_speed = (opt_flags & BM_SPEED) ? 1:0;
+ }
- switch (global_settings.autocreatebookmark)
+ /* extract all original bookmark tokens */
+ if (resume_info)
{
- case BOOKMARK_YES:
- return write_bookmark(true, bookmark);
+ GET_INT_TOKEN(resume_info->resume_index);
+ GET_LONG_TOKEN(resume_info->resume_offset);
+ GET_INT_TOKEN(resume_info->resume_seed);
- case BOOKMARK_NO:
- return false;
+ s = skip_tokens(s, old_format); /* skip deprecated token */
- case BOOKMARK_RECENT_ONLY_YES:
- return write_bookmark(false, bookmark);
- }
- const char *lines[]={ID2P(LANG_AUTO_BOOKMARK_QUERY)};
- const struct text_message message={lines, 1};
+ GET_LONG_TOKEN(resume_info->resume_elapsed);
+ GET_INT_TOKEN(resume_info->repeat_mode);
+ GET_BOOL_TOKEN(resume_info->shuffle);
- if(prompt_ok && gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES)
+ /* extract all optional bookmark tokens */
+ if (opt_pitch != 0)
+ GET_INT_TOKEN(resume_info->pitch);
+ if (opt_speed != 0)
+ GET_INT_TOKEN(resume_info->speed);
+ }
+ else /* no resume info we just want the file name strings */
{
- if (global_settings.autocreatebookmark == BOOKMARK_RECENT_ONLY_ASK)
- return write_bookmark(false, bookmark);
- else
- return write_bookmark(true, bookmark);
+ #define DEFAULT_BM_TOKENS 6
+ int skipct = DEFAULT_BM_TOKENS + old_format + opt_pitch + opt_speed;
+ s = skip_tokens(s, skipct);
+ #undef DEFAULT_BM_TOKENS
}
- return false;
-}
-/* ----------------------------------------------------------------------- */
-/* This function takes the current current resume information and writes */
-/* that to the beginning of the bookmark file. */
-/* This file will contain N number of bookmarks in the following format: */
-/* resume_index*resume_offset*resume_seed*resume_first_index* */
-/* resume_file*milliseconds*MP3 Title* */
-/* Returns true on successful bookmark write. */
-/* Returns false if any part of the bookmarking process fails. It is */
-/* possible that a bookmark is successfully added to the most recent */
-/* bookmark list but fails to be added to the bookmark file or vice versa. */
-/* ------------------------------------------------------------------------*/
-static bool write_bookmark(bool create_bookmark_file, const char *bookmark)
-{
- bool ret=true;
-
- if (!bookmark)
+ if (*s == 0)
{
- ret = false; /* something didn't happen correctly, do nothing */
+ return false;
}
- else
- {
- if (global_settings.usemrb)
- ret = add_bookmark(RECENT_BOOKMARK_FILE, bookmark, true);
+ end = strchr(s, ';');
- /* writing the bookmark */
- if (create_bookmark_file)
+ /* extract file names */
+ if(filenamebuf)
+ {
+ size_t len = (end == NULL) ? strlen(s) : (size_t) (end - s);
+ len = MIN(TEMP_BUF_SIZE - 1, len);
+ strmemccpy(global_temp_buffer, s, len + 1);
+
+ if (end != NULL)
{
- char* name = playlist_get_name(NULL, global_temp_buffer,
- sizeof(global_temp_buffer));
- if (generate_bookmark_file_name(name))
- {
- ret = ret & add_bookmark(global_bookmark_file_name, bookmark, false);
- }
- else
+ end++;
+ if (strip_dir)
{
- ret = false; /* generating bookmark file failed */
+ s = strrchr(end, '/');
+ if (s)
+ {
+ end = s;
+ end++;
+ }
}
+ strmemccpy(filenamebuf, end, filenamebufsz);
}
- }
-
- splash(HZ, ret ? ID2P(LANG_BOOKMARK_CREATE_SUCCESS)
- : ID2P(LANG_BOOKMARK_CREATE_FAILURE));
+ }
- return ret;
+ return true;
}
-/* Get the name of the playlist and the name of the track from a bookmark. */
-/* Returns true iff both were extracted. */
-static bool get_playlist_and_track(const char *bookmark, char **pl_start,
- char **pl_end, char **track)
+/* ------------------------------------------------------------------------- */
+/* This function takes a filename and appends .tmp. This function also opens */
+/* the resulting file based on oflags, filename will be in buf on return */
+/* Returns file descriptor */
+/* --------------------------------------------------------------------------*/
+static int open_temp_bookmark(char *buf,
+ size_t bufsz,
+ int oflags,
+ const char* filename)
{
- *pl_start = strchr(bookmark,'/');
- if (!(*pl_start))
- return false;
- *pl_end = strrchr(bookmark,';');
- *track = *pl_end + 1;
- return true;
+ if(filename[0] == '/')
+ filename++;
+ /* Opening up a temp bookmark file */
+ int fd = open_pathfmt(buf, bufsz, oflags, "/%s.tmp", filename);
+#ifdef LOGF_ENABLE
+ if (oflags & O_PATH)
+ logf("tempfile path %s", buf);
+ else
+ logf("opening tempfile %s", buf);
+#endif
+ return fd;
}
/* ----------------------------------------------------------------------- */
/* This function adds a bookmark to a file. */
/* Returns true on successful bookmark add. */
/* ------------------------------------------------------------------------*/
-static bool add_bookmark(const char* bookmark_file_name, const char* bookmark,
+static bool add_bookmark(const char* bookmark_file_name,
+ const char* bookmark,
bool most_recent)
{
- int temp_bookmark_file = 0;
- int bookmark_file = 0;
- int bookmark_count = 0;
- char *pl_start = NULL, *bm_pl_start;
- char *pl_end = NULL, *bm_pl_end;
- int pl_len = 0, bm_pl_len;
- char *track = NULL, *bm_track;
- bool comp_playlist = false;
- bool comp_track = false;
- bool equal;
+ char fnamebuf[MAX_PATH];
+ int temp_bookmark_file = 0;
+ int bookmark_file = 0;
+ int bookmark_count = 0;
+ bool comp_playlist = false;
+ bool comp_track = false;
+ bool equal;
+ uint32_t pl_hash, pl_track_hash;
+ uint32_t bm_pl_hash, bm_pl_track_hash;
/* Opening up a temp bookmark file */
- snprintf(global_temp_buffer, sizeof(global_temp_buffer),
- "%s.tmp", bookmark_file_name);
- temp_bookmark_file = open(global_temp_buffer,
- O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (temp_bookmark_file < 0)
- return false; /* can't open the temp file */
+ temp_bookmark_file = open_temp_bookmark(fnamebuf,
+ sizeof(fnamebuf),
+ O_WRONLY | O_CREAT | O_TRUNC,
+ bookmark_file_name);
+
+ if (temp_bookmark_file < 0 || !bookmark)
+ return false; /* can't open the temp file or no bookmark */
if (most_recent && ((global_settings.usemrb == BOOKMARK_ONE_PER_PLAYLIST)
|| (global_settings.usemrb == BOOKMARK_ONE_PER_TRACK)))
{
- if (get_playlist_and_track(bookmark, &pl_start, &pl_end, &track))
+
+ if (bookmark_get_playlist_and_track_hash(bookmark, &pl_hash, &pl_track_hash))
{
comp_playlist = true;
- pl_len = pl_end - pl_start;
- if (global_settings.usemrb == BOOKMARK_ONE_PER_TRACK)
- comp_track = true;
+ comp_track = (global_settings.usemrb == BOOKMARK_ONE_PER_TRACK);
}
}
+ logf("adding bookmark to %s [%s]", fnamebuf, bookmark);
/* Writing the new bookmark to the begining of the temp file */
write(temp_bookmark_file, bookmark, strlen(bookmark));
write(temp_bookmark_file, "\n", 1);
bookmark_count++;
+ /* WARNING underlying buffer to *bookmrk gets overwritten after this point! */
+
/* Reading in the previous bookmarks and writing them to the temp file */
+ logf("opening old bookmark %s", bookmark_file_name);
bookmark_file = open(bookmark_file_name, O_RDONLY);
if (bookmark_file >= 0)
{
- while (read_line(bookmark_file, global_read_buffer,
- sizeof(global_read_buffer)) > 0)
+ while (read_line(bookmark_file, global_temp_buffer,
+ sizeof(global_temp_buffer)) > 0)
{
/* The MRB has a max of MAX_BOOKMARKS in it */
/* This keeps it from getting too large */
if (most_recent && (bookmark_count >= MAX_BOOKMARKS))
break;
- if (!parse_bookmark(global_read_buffer, false, false))
+ if (!parse_bookmark(NULL, 0, global_temp_buffer, NULL, false))
break;
equal = false;
if (comp_playlist)
{
- if (get_playlist_and_track(global_read_buffer, &bm_pl_start,
- &bm_pl_end, &bm_track))
+ if (bookmark_get_playlist_and_track_hash(global_temp_buffer,
+ &bm_pl_hash, &bm_pl_track_hash))
{
- bm_pl_len = bm_pl_end - bm_pl_start;
- equal = (pl_len == bm_pl_len) && !strncmp(pl_start, bm_pl_start, pl_len);
+ equal = (pl_hash == bm_pl_hash);
if (equal && comp_track)
- equal = !strcmp(track, bm_track);
+ {
+ equal = (pl_track_hash == bm_pl_track_hash);
+ }
}
}
if (!equal)
{
bookmark_count++;
- write(temp_bookmark_file, global_read_buffer,
- strlen(global_read_buffer));
+ /*logf("copying old bookmark [%s]", global_temp_buffer);*/
+ write(temp_bookmark_file, global_temp_buffer,
+ strlen(global_temp_buffer));
write(temp_bookmark_file, "\n", 1);
}
}
@@ -354,180 +360,233 @@ static bool add_bookmark(const char* bookmark_file_name, const char* bookmark,
close(temp_bookmark_file);
remove(bookmark_file_name);
- rename(global_temp_buffer, bookmark_file_name);
+ rename(fnamebuf, bookmark_file_name);
return true;
}
+/* ----------------------------------------------------------------------- */
+/* This function is used by multiple functions and is used to generate a */
+/* bookmark named based off of the input. */
+/* Changing this function could result in how the bookmarks are stored. */
+/* it would be here that the centralized/decentralized bookmark code */
+/* could be placed. */
+/* Returns true if the file name is generated, false if it was too long */
+/* ----------------------------------------------------------------------- */
+static bool generate_bookmark_file_name(char *filenamebuf,
+ size_t filenamebufsz,
+ const char *bmarknamein,
+ size_t bmarknamelen)
+{
+ /* if this is a root dir MP3, rename the bookmark file root_dir.bmark */
+ /* otherwise, name it based on the bmarknamein variable */
+ if (!strcmp("/", bmarknamein))
+ strmemccpy(filenamebuf, "/root_dir.bmark", filenamebufsz);
+ else
+ {
+ size_t buflen, len;
+ /* strmemccpy considers the NULL so bmarknamelen is one off */
+ buflen = MIN(filenamebufsz -1 , bmarknamelen);
+ if (buflen >= filenamebufsz)
+ return false;
+
+ strmemccpy(filenamebuf, bmarknamein, buflen + 1);
+
+ len = strlen(filenamebuf);
+
+#ifdef HAVE_MULTIVOLUME
+ /* The "root" of an extra volume need special handling too. */
+ const char *filename;
+ path_strip_volume(filenamebuf, &filename, true);
+ bool volume_root = *filename == '\0';
+#endif
+ if(filenamebuf[len-1] == '/') {
+ filenamebuf[len-1] = '\0';
+ }
+
+ const char *name = ".bmark";
+#ifdef HAVE_MULTIVOLUME
+ if (volume_root)
+ name = "/volume_dir.bmark";
+#endif
+ len = strlcat(filenamebuf, name, filenamebufsz);
+
+ if(len >= filenamebufsz)
+ return false;
+ }
+ logf ("generated name '%s' from '%.*s'",
+ filenamebuf, (int)bmarknamelen, bmarknamein);
+ return true;
+}
+
/* GCC 7 and up complain about the snprintf in create_bookmark() when
compiled with -D_FORTIFY_SOURCE or -Wformat-truncation
This is a false positive, so disable it here only */
-#if __GNUC__ >= 7
+/* SHOULD NO LONGER BE NEEDED --Bilgus 11-2022 */
+#if 0 /* __GNUC__ >= 7 */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-truncation"
#endif
/* ----------------------------------------------------------------------- */
/* This function takes the system resume data and formats it into a valid */
/* bookmark. */
-/* Returns not NULL on successful bookmark format. */
+/* playlist name and name len are passed back through the name/namelen */
+/* Return is not NULL on successful bookmark format. */
/* ----------------------------------------------------------------------- */
-static char* create_bookmark()
+static char* create_bookmark(char **name,
+ size_t *namelen,
+ struct resume_info *resume_info)
{
- int resume_index = 0;
- char *file;
-
- if (!bookmark_is_bookmarkable_state())
- return NULL; /* something didn't happen correctly, do nothing */
+ const char *file;
+ char *buf = global_temp_buffer;
+ size_t bufsz = sizeof(global_temp_buffer);
- /* grab the currently playing track */
- struct mp3entry *id3 = audio_current_track();
- if(!id3)
- return NULL;
-
- /* Get some basic resume information */
- /* queue_resume and queue_resume_index are not used and can be ignored.*/
- playlist_get_resume_info(&resume_index);
-
- /* Get the currently playing file minus the path */
- /* This is used when displaying the available bookmarks */
- file = strrchr(id3->path,'/');
- if(NULL == file)
+ if(!resume_info->id3)
return NULL;
- /* create the bookmark */
- playlist_get_name(NULL, global_temp_buffer, sizeof(global_temp_buffer));
- if (global_temp_buffer[strlen(global_temp_buffer) - 1] != '/')
- file = id3->path;
- else file++;
- snprintf(global_bookmark, sizeof(global_bookmark),
- /* new optional bookmark token descriptors should be inserted
- just before the "%s;%s" in this line... */
+ size_t bmarksz= snprintf(buf, bufsz,
+ /* new optional bookmark token descriptors should
+ be inserted just after ';"' in this line... */
#if defined(HAVE_PITCHCONTROL)
- ">%d;%d;%ld;%d;%ld;%d;%d;%ld;%ld;%s;%s",
+ ">%d;%d;%ld;%d;%ld;%d;%d;%ld;%ld;",
#else
- ">%d;%d;%ld;%d;%ld;%d;%d;%s;%s",
+ ">%d;%d;%ld;%d;%ld;%d;%d;",
#endif
- /* ... their flags should go here ... */
+ /* ... their flags should go here ... */
#if defined(HAVE_PITCHCONTROL)
- BM_PITCH | BM_SPEED,
+ BM_PITCH | BM_SPEED,
#else
- 0,
+ 0,
#endif
- resume_index,
- id3->offset,
- playlist_get_seed(NULL),
- id3->elapsed,
- global_settings.repeat_mode,
- global_settings.playlist_shuffle,
- /* ...and their values should go here */
+ resume_info->resume_index,
+ resume_info->id3->offset,
+ resume_info->resume_seed,
+ resume_info->id3->elapsed,
+ resume_info->repeat_mode,
+ resume_info->shuffle,
+ /* ...and their values should go here */
#if defined(HAVE_PITCHCONTROL)
- (long)sound_get_pitch(),
- (long)dsp_get_timestretch(),
+ (long)resume_info->pitch,
+ (long)resume_info->speed
#endif
- /* more mandatory tokens */
- global_temp_buffer,
- file);
+ ); /*sprintf*/
+/* mandatory tokens */
+ if (bmarksz >= bufsz) /* include NULL*/
+ return NULL;
+ buf += bmarksz;
+ bufsz -= bmarksz;
+
+ /* create the bookmark */
+ playlist_get_name(NULL, buf, bufsz);
+ bmarksz = strlen(buf);
+
+ if (bmarksz == 0 || (bmarksz + 1) >= bufsz) /* include the separator & NULL*/
+ return NULL;
+
+ *name = buf; /* return the playlist name through the *pointer */
+ *namelen = bmarksz; /* return the name length through the pointer */
+
+ /* Get the currently playing file minus the path */
+ /* This is used when displaying the available bookmarks */
+ file = strrchr(resume_info->id3->path,'/');
+ if(NULL == file)
+ return NULL;
+
+ if (buf[bmarksz - 1] != '/')
+ file = resume_info->id3->path;
+ else file++;
+
+ buf += bmarksz;
+ bufsz -= (bmarksz + 1);
+ buf[0] = ';';
+ buf[1] = '\0';
+
+ strlcat(buf, file, bufsz);
+ logf("%s [%s]", __func__, global_temp_buffer);
/* checking to see if the bookmark is valid */
- if (parse_bookmark(global_bookmark, false, false))
- return global_bookmark;
+ if (parse_bookmark(NULL, 0, global_temp_buffer, NULL, false))
+ return global_temp_buffer;
else
return NULL;
}
-#if __GNUC__ >= 7
+#if 0/* __GNUC__ >= 7*/
#pragma GCC diagnostic pop /* -Wformat-truncation */
#endif
/* ----------------------------------------------------------------------- */
-/* This function will determine if an autoload is necessary. This is an */
-/* interface function. */
-/* Returns true on bookmark load or bookmark selection. */
-/* ------------------------------------------------------------------------*/
-bool bookmark_autoload(const char* file)
+/* This function gets some basic resume information for the current song */
+/* from rockbox, */
+/* ----------------------------------------------------------------------- */
+static void get_track_resume_info(struct resume_info *resume_info)
{
- char* bookmark;
-
- if(global_settings.autoloadbookmark == BOOKMARK_NO)
- return false;
-
- /*Checking to see if a bookmark file exists.*/
- if(!generate_bookmark_file_name(file))
- {
- return false;
- }
-
- if(!file_exists(global_bookmark_file_name))
- return false;
-
- if(global_settings.autoloadbookmark == BOOKMARK_YES)
- {
- return bookmark_load(global_bookmark_file_name, true);
- }
- else
- {
- int ret = select_bookmark(global_bookmark_file_name, true, &bookmark);
-
- if (bookmark != NULL)
- {
- if (!play_bookmark(bookmark))
- {
- /* Selected bookmark not found. */
- splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
- }
-
- /* Act as if autoload was done even if it failed, since the
- * user did make an active selection.
- */
- return true;
- }
-
- return ret != BOOKMARK_SUCCESS;
- }
+ playlist_get_resume_info(&(resume_info->resume_index));
+ resume_info->resume_seed = playlist_get_seed(NULL);
+ resume_info->id3 = audio_current_track();
+ resume_info->repeat_mode = global_settings.repeat_mode;
+ resume_info->shuffle = global_settings.playlist_shuffle;
+#if defined(HAVE_PITCHCONTROL)
+ resume_info->pitch = sound_get_pitch();
+ resume_info->speed = dsp_get_timestretch();
+#endif
}
/* ----------------------------------------------------------------------- */
-/* This function loads the bookmark information into the resume memory. */
-/* This is an interface function. */
-/* Returns true on successful bookmark load. */
+/* This function takes the current current resume information and writes */
+/* that to the beginning of the bookmark file. */
+/* This file will contain N number of bookmarks in the following format: */
+/* resume_index*resume_offset*resume_seed*resume_first_index* */
+/* resume_file*milliseconds*MP3 Title* */
+/* Returns true on successful bookmark write. */
+/* Returns false if any part of the bookmarking process fails. It is */
+/* possible that a bookmark is successfully added to the most recent */
+/* bookmark list but fails to be added to the bookmark file or vice versa. */
/* ------------------------------------------------------------------------*/
-bool bookmark_load(const char* file, bool autoload)
+static bool write_bookmark(bool create_bookmark_file)
{
- int fd;
- char* bookmark = NULL;
+ logf("%s", __func__);
+ char bm_filename[MAX_PATH];
+ bool ret=true;
- if(autoload)
+ char *name = NULL;
+ size_t namelen = 0;
+ char* bm;
+ struct resume_info resume_info;
+
+ if (bookmark_is_bookmarkable_state())
{
- fd = open(file, O_RDONLY);
- if(fd >= 0)
+ get_track_resume_info(&resume_info);
+ /* writing the most recent bookmark */
+ if (global_settings.usemrb)
{
- if(read_line(fd, global_read_buffer, sizeof(global_read_buffer)) > 0)
- bookmark=global_read_buffer;
- close(fd);
+ /* since we use the same buffer bookmark needs created each time */
+ bm = create_bookmark(&name, &namelen, &resume_info);
+ ret = add_bookmark(RECENT_BOOKMARK_FILE, bm, true);
}
- }
- else
- {
- /* This is not an auto-load, so list the bookmarks */
- select_bookmark(file, false, &bookmark);
- }
- if (bookmark != NULL)
- {
- if (!play_bookmark(bookmark))
+ /* writing the directory bookmark */
+ if (create_bookmark_file)
{
- /* Selected bookmark not found. */
- if (!autoload)
+ bm = create_bookmark(&name, &namelen, &resume_info);
+ if (generate_bookmark_file_name(bm_filename,
+ sizeof(bm_filename), name, namelen))
{
- splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
+ ret &= add_bookmark(bm_filename, bm, false);
+ }
+ else
+ {
+ ret = false; /* generating bookmark file failed */
}
-
- return false;
}
}
+ else
+ ret = false;
- return true;
-}
+ splash(HZ, ret ? ID2P(LANG_BOOKMARK_CREATE_SUCCESS)
+ : ID2P(LANG_BOOKMARK_CREATE_FAILURE));
+ return ret;
+}
static int get_bookmark_count(const char* bookmark_file_name)
{
@@ -537,7 +596,7 @@ static int get_bookmark_count(const char* bookmark_file_name)
if(file < 0)
return -1;
- while(read_line(file, global_read_buffer, sizeof(global_read_buffer)) > 0)
+ while(read_line(file, global_temp_buffer, sizeof(global_temp_buffer)) > 0)
{
read_count++;
}
@@ -568,13 +627,13 @@ static int buffer_bookmarks(struct bookmark_list* bookmarks, int first_line)
bookmarks->count = 0;
bookmarks->reload = false;
- while(read_line(file, global_read_buffer, sizeof(global_read_buffer)) > 0)
+ while(read_line(file, global_temp_buffer, sizeof(global_temp_buffer)) > 0)
{
read_count++;
if (read_count >= first_line)
{
- dest -= strlen(global_read_buffer) + 1;
+ dest -= strlen(global_temp_buffer) + 1;
if (dest < ((char*) bookmarks) + sizeof(*bookmarks)
+ (sizeof(char*) * (bookmarks->count + 1)))
@@ -582,7 +641,7 @@ static int buffer_bookmarks(struct bookmark_list* bookmarks, int first_line)
break;
}
- strcpy(dest, global_read_buffer);
+ strcpy(dest, global_temp_buffer);
bookmarks->items[bookmarks->count] = dest;
bookmarks->count++;
}
@@ -597,6 +656,8 @@ static const char* get_bookmark_info(int list_index,
char *buffer,
size_t buffer_len)
{
+ char fnamebuf[MAX_PATH];
+ struct resume_info resume_info;
struct bookmark_list* bookmarks = (struct bookmark_list*) data;
int index = list_index / 2;
@@ -652,7 +713,8 @@ static const char* get_bookmark_info(int list_index,
}
}
- if (!parse_bookmark(bookmarks->items[index - bookmarks->start], true, true))
+ if (!parse_bookmark(fnamebuf, sizeof(fnamebuf),
+ bookmarks->items[index - bookmarks->start], &resume_info, true))
{
return list_index % 2 == 0 ? (char*) str(LANG_BOOKMARK_INVALID) : " ";
}
@@ -686,25 +748,73 @@ static const char* get_bookmark_info(int list_index,
}
else
{
- name = global_filename;
+ name = fnamebuf;
format = "%s";
}
- strrsplt(global_filename, '.');
- snprintf(buffer, buffer_len, format, name, global_filename);
+ strrsplt(fnamebuf, '.');
+ snprintf(buffer, buffer_len, format, name, fnamebuf);
return buffer;
}
else
{
char time_buf[32];
- format_time(time_buf, sizeof(time_buf), bm.resume_time);
- snprintf(buffer, buffer_len, "%s, %d%s", time_buf, bm.resume_index + 1,
- bm.shuffle ? (char*) str(LANG_BOOKMARK_SHUFFLE) : "");
+ format_time(time_buf, sizeof(time_buf), resume_info.resume_elapsed);
+ snprintf(buffer, buffer_len, "%s, %d%s", time_buf,
+ resume_info.resume_index + 1,
+ resume_info.shuffle ? (char*) str(LANG_BOOKMARK_SHUFFLE) : "");
return buffer;
}
}
+/* ----------------------------------------------------------------------- */
+/* This function parses a bookmark, says the voice UI part of it. */
+/* ------------------------------------------------------------------------*/
+static void say_bookmark(const char* bookmark,
+ int bookmark_id,
+ bool show_playlist_name)
+{
+ char fnamebuf[MAX_PATH];
+ struct resume_info resume_info;
+ if (!parse_bookmark(fnamebuf, sizeof(fnamebuf), bookmark, &resume_info, false))
+ {
+ talk_id(LANG_BOOKMARK_INVALID, false);
+ return;
+ }
+
+ talk_number(bookmark_id + 1, false);
+
+ bool is_dir = (global_temp_buffer[0]
+ && global_temp_buffer[strlen(global_temp_buffer)-1] == '/');
+
+ /* HWCODEC cannot enqueue voice file entries and .talk thumbnails
+ together, because there is no guarantee that the same mp3
+ parameters are used. */
+ if(show_playlist_name)
+ { /* It's useful to know which playlist this is */
+ if(is_dir)
+ talk_dir_or_spell(global_temp_buffer,
+ TALK_IDARRAY(VOICE_DIR), true);
+ else talk_file_or_spell(NULL, global_temp_buffer,
+ TALK_IDARRAY(LANG_PLAYLIST), true);
+ }
+
+ if(resume_info.shuffle)
+ talk_id(LANG_SHUFFLE, true);
+
+ talk_id(VOICE_BOOKMARK_SELECT_INDEX_TEXT, true);
+ talk_number(resume_info.resume_index + 1, true);
+ talk_id(LANG_TIME, true);
+ talk_value(resume_info.resume_elapsed / 1000, UNIT_TIME, true);
+
+ /* Track filename */
+ if(!is_dir)
+ global_temp_buffer[0] = 0;
+ talk_file_or_spell(global_temp_buffer, fnamebuf,
+ TALK_IDARRAY(VOICE_FILE), true);
+}
+
static int bookmark_list_voice_cb(int list_index, void* data)
{
struct bookmark_list* bookmarks = (struct bookmark_list*) data;
@@ -722,6 +832,57 @@ static int bookmark_list_voice_cb(int list_index, void* data)
}
/* ----------------------------------------------------------------------- */
+/* This function takes a location in a bookmark file and deletes that */
+/* bookmark. */
+/* Returns true on successful bookmark deletion. */
+/* ------------------------------------------------------------------------*/
+static bool delete_bookmark(const char* bookmark_file_name, int bookmark_id)
+{
+ int temp_bookmark_file = 0;
+ int bookmark_file = 0;
+ int bookmark_count = 0;
+
+ /* Opening up a temp bookmark file */
+ temp_bookmark_file = open_temp_bookmark(global_temp_buffer,
+ sizeof(global_temp_buffer),
+ O_WRONLY | O_CREAT | O_TRUNC,
+ bookmark_file_name);
+
+ if (temp_bookmark_file < 0)
+ return false; /* can't open the temp file */
+
+ /* Reading in the previous bookmarks and writing them to the temp file */
+ bookmark_file = open(bookmark_file_name, O_RDONLY);
+ if (bookmark_file >= 0)
+ {
+ while (read_line(bookmark_file, global_temp_buffer,
+ sizeof(global_temp_buffer)) > 0)
+ {
+ if (bookmark_id != bookmark_count)
+ {
+ write(temp_bookmark_file, global_temp_buffer,
+ strlen(global_temp_buffer));
+ write(temp_bookmark_file, "\n", 1);
+ }
+ bookmark_count++;
+ }
+ close(bookmark_file);
+ }
+ close(temp_bookmark_file);
+
+ /* only retrieve the path*/
+ open_temp_bookmark(global_temp_buffer,
+ sizeof(global_temp_buffer),
+ O_PATH,
+ bookmark_file_name);
+
+ remove(bookmark_file_name);
+ rename(global_temp_buffer, bookmark_file_name);
+
+ return true;
+}
+
+/* ----------------------------------------------------------------------- */
/* This displays the bookmarks in a file and allows the user to */
/* select one to play. */
/* *selected_bookmark contains a non NULL value on successful bookmark */
@@ -730,7 +891,9 @@ static int bookmark_list_voice_cb(int list_index, void* data)
/* if no selection was made and BOOKMARK_USB_CONNECTED if the selection */
/* menu is forced to exit due to a USB connection. */
/* ------------------------------------------------------------------------*/
-static int select_bookmark(const char* bookmark_file_name, bool show_dont_resume, char** selected_bookmark)
+static int select_bookmark(const char* bookmark_file_name,
+ bool show_dont_resume,
+ char** selected_bookmark)
{
struct bookmark_list* bookmarks;
struct gui_synclist list;
@@ -747,12 +910,13 @@ static int select_bookmark(const char* bookmark_file_name, bool show_dont_resume
bookmarks->filename = bookmark_file_name;
bookmarks->start = 0;
bookmarks->show_playlist_name
- = strcmp(bookmark_file_name, RECENT_BOOKMARK_FILE) == 0;
- gui_synclist_init(&list, &get_bookmark_info, (void*) bookmarks, false, 2, NULL);
+ = (strcmp(bookmark_file_name, RECENT_BOOKMARK_FILE) == 0);
+
+ gui_synclist_init(&list, &get_bookmark_info,
+ (void*) bookmarks, false, 2, NULL);
+
if(global_settings.talk_menu)
gui_synclist_set_voice_callback(&list, bookmark_list_voice_cb);
- gui_synclist_set_title(&list, str(LANG_BOOKMARK_SELECT_BOOKMARK),
- Icon_Bookmark);
while (!exit)
{
@@ -787,14 +951,15 @@ static int select_bookmark(const char* bookmark_file_name, bool show_dont_resume
}
buffer_bookmarks(bookmarks, bookmarks->start);
+ gui_synclist_set_title(&list, str(LANG_BOOKMARK_SELECT_BOOKMARK),
+ Icon_Bookmark);
gui_synclist_draw(&list);
cond_talk_ids_fq(VOICE_EXT_BMARK);
gui_synclist_speak_item(&list);
refresh = false;
}
- list_do_action(CONTEXT_BOOKMARKSCREEN, HZ / 2,
- &list, &action, LIST_WRAP_UNLESS_HELD);
+ list_do_action(CONTEXT_BOOKMARKSCREEN, HZ / 2, &list, &action);
item = gui_synclist_get_sel_pos(&list) / 2;
if (bookmarks->show_dont_resume)
@@ -843,17 +1008,7 @@ static int select_bookmark(const char* bookmark_file_name, bool show_dont_resume
case ACTION_BMS_DELETE:
if (item >= 0)
{
- const char *lines[]={
- ID2P(LANG_REALLY_DELETE)
- };
- const char *yes_lines[]={
- ID2P(LANG_DELETING)
- };
-
- const struct text_message message={lines, 1};
- const struct text_message yes_message={yes_lines, 1};
-
- if(gui_syncyesno_run(&message, &yes_message, NULL)==YESNO_YES)
+ if (confirm_delete_yesno("") == YESNO_YES)
{
delete_bookmark(bookmark_file_name, item);
bookmarks->reload = true;
@@ -879,264 +1034,247 @@ static int select_bookmark(const char* bookmark_file_name, bool show_dont_resume
}
/* ----------------------------------------------------------------------- */
-/* This function takes a location in a bookmark file and deletes that */
-/* bookmark. */
-/* Returns true on successful bookmark deletion. */
+/* This function parses a bookmark and then plays it. */
+/* Returns true on successful bookmark play. */
/* ------------------------------------------------------------------------*/
-static bool delete_bookmark(const char* bookmark_file_name, int bookmark_id)
+static bool play_bookmark(const char* bookmark)
{
- int temp_bookmark_file = 0;
- int bookmark_file = 0;
- int bookmark_count = 0;
-
- /* Opening up a temp bookmark file */
- snprintf(global_temp_buffer, sizeof(global_temp_buffer),
- "%s.tmp", bookmark_file_name);
- temp_bookmark_file = open(global_temp_buffer,
- O_WRONLY | O_CREAT | O_TRUNC, 0666);
-
- if (temp_bookmark_file < 0)
- return false; /* can't open the temp file */
+ char fnamebuf[MAX_PATH];
+ struct resume_info resume_info;
+#if defined(HAVE_PITCHCONTROL)
+ /* preset pitch and speed to 100% in case bookmark doesn't have info */
+ resume_info.pitch = sound_get_pitch();
+ resume_info.speed = dsp_get_timestretch();
+#endif
- /* Reading in the previous bookmarks and writing them to the temp file */
- bookmark_file = open(bookmark_file_name, O_RDONLY);
- if (bookmark_file >= 0)
+ if (parse_bookmark(fnamebuf, sizeof(fnamebuf), bookmark, &resume_info, true))
{
- while (read_line(bookmark_file, global_read_buffer,
- sizeof(global_read_buffer)) > 0)
+ global_settings.repeat_mode = resume_info.repeat_mode;
+ global_settings.playlist_shuffle = resume_info.shuffle;
+#if defined(HAVE_PITCHCONTROL)
+ sound_set_pitch(resume_info.pitch);
+ dsp_set_timestretch(resume_info.speed);
+#endif
+ if (!warn_on_pl_erase())
+ return false;
+ bool success = bookmark_play(global_temp_buffer, resume_info.resume_index,
+ resume_info.resume_elapsed, resume_info.resume_offset,
+ resume_info.resume_seed, fnamebuf);
+ if (success) /* verify we loaded the correct track */
{
- if (bookmark_id != bookmark_count)
+ const struct mp3entry *id3 = audio_current_track();
+ if (id3)
{
- write(temp_bookmark_file, global_read_buffer,
- strlen(global_read_buffer));
- write(temp_bookmark_file, "\n", 1);
+ const char *path;
+ const char *track;
+ path_basename(id3->path, &path);
+ path_basename(fnamebuf, &track);
+ if (strcmp(path, track) == 0)
+ {
+ return true;
+ }
}
- bookmark_count++;
+ audio_stop();
}
- close(bookmark_file);
}
- close(temp_bookmark_file);
-
- remove(bookmark_file_name);
- rename(global_temp_buffer, bookmark_file_name);
- return true;
+ return false;
}
+/*-------------------------------------------------------------------------*/
+/* PUBLIC INTERFACE -------------------------------------------------------*/
+/*-------------------------------------------------------------------------*/
+
+
/* ----------------------------------------------------------------------- */
-/* This function parses a bookmark, says the voice UI part of it. */
-/* ------------------------------------------------------------------------*/
-static void say_bookmark(const char* bookmark,
- int bookmark_id, bool show_playlist_name)
+/* This is an interface function from the context menu. */
+/* Returns true on successful bookmark creation. */
+/* ----------------------------------------------------------------------- */
+bool bookmark_create_menu(void)
{
- if (!parse_bookmark(bookmark, true, false))
- {
- talk_id(LANG_BOOKMARK_INVALID, false);
- return;
- }
-
- talk_number(bookmark_id + 1, false);
+ return write_bookmark(true);
+}
+/* ----------------------------------------------------------------------- */
+/* This function acts as the load interface from the context menu. */
+/* This function determines the bookmark file name and then loads that file*/
+/* for the user. The user can then select or delete previous bookmarks. */
+/* This function returns BOOKMARK_SUCCESS on the selection of a track to */
+/* resume, BOOKMARK_FAIL if the menu is exited without a selection and */
+/* BOOKMARK_USB_CONNECTED if the menu is forced to exit due to a USB */
+/* connection. */
+/* ----------------------------------------------------------------------- */
+int bookmark_load_menu(void)
+{
+ char bm_filename[MAX_PATH];
+ char* bookmark;
+ int ret = BOOKMARK_FAIL;
- bool is_dir = (global_temp_buffer[0]
- && global_temp_buffer[strlen(global_temp_buffer)-1] == '/');
+ push_current_activity(ACTIVITY_BOOKMARKSLIST);
- /* HWCODEC cannot enqueue voice file entries and .talk thumbnails
- together, because there is no guarantee that the same mp3
- parameters are used. */
- if(show_playlist_name)
- { /* It's useful to know which playlist this is */
- if(is_dir)
- talk_dir_or_spell(global_temp_buffer,
- TALK_IDARRAY(VOICE_DIR), true);
- else talk_file_or_spell(NULL, global_temp_buffer,
- TALK_IDARRAY(LANG_PLAYLIST), true);
+ char* name = playlist_get_name(NULL, global_temp_buffer,
+ sizeof(global_temp_buffer));
+ if (generate_bookmark_file_name(bm_filename, sizeof(bm_filename), name, -1))
+ {
+ ret = select_bookmark(bm_filename, false, &bookmark);
+ if (bookmark != NULL)
+ {
+ ret = play_bookmark(bookmark) ? BOOKMARK_SUCCESS : BOOKMARK_FAIL;
+ }
}
- if(bm.shuffle)
- talk_id(LANG_SHUFFLE, true);
-
- talk_id(VOICE_BOOKMARK_SELECT_INDEX_TEXT, true);
- talk_number(bm.resume_index + 1, true);
- talk_id(LANG_TIME, true);
- talk_value(bm.resume_time / 1000, UNIT_TIME, true);
-
- /* Track filename */
- if(!is_dir)
- global_temp_buffer[0] = 0;
- talk_file_or_spell(global_temp_buffer, global_filename,
- TALK_IDARRAY(VOICE_FILE), true);
+ pop_current_activity();
+ return ret;
}
/* ----------------------------------------------------------------------- */
-/* This function parses a bookmark and then plays it. */
-/* Returns true on successful bookmark play. */
-/* ------------------------------------------------------------------------*/
-static bool play_bookmark(const char* bookmark)
+/* Gives the user a list of the Most Recent Bookmarks. This is an */
+/* interface function */
+/* Returns true on the successful selection of a recent bookmark. */
+/* ----------------------------------------------------------------------- */
+bool bookmark_mrb_load()
{
-#if defined(HAVE_PITCHCONTROL)
- /* preset pitch and speed to 100% in case bookmark doesn't have info */
- bm.pitch = sound_get_pitch();
- bm.speed = dsp_get_timestretch();
-#endif
+ char* bookmark;
+ bool ret = false;
- if (parse_bookmark(bookmark, true, true))
+ push_current_activity(ACTIVITY_BOOKMARKSLIST);
+ select_bookmark(RECENT_BOOKMARK_FILE, false, &bookmark);
+ if (bookmark != NULL)
{
- global_settings.repeat_mode = bm.repeat_mode;
- global_settings.playlist_shuffle = bm.shuffle;
-#if defined(HAVE_PITCHCONTROL)
- sound_set_pitch(bm.pitch);
- dsp_set_timestretch(bm.speed);
-#endif
- if (!warn_on_pl_erase())
- return false;
- return bookmark_play(global_temp_buffer, bm.resume_index,
- bm.resume_time, bm.resume_offset, bm.resume_seed, global_filename);
+ ret = play_bookmark(bookmark);
}
- return false;
+ pop_current_activity();
+ return ret;
}
-static const char* skip_token(const char* s)
+/* ----------------------------------------------------------------------- */
+/* This function handles an autobookmark creation. This is an interface */
+/* function. */
+/* Returns true on successful bookmark creation. */
+/* ----------------------------------------------------------------------- */
+bool bookmark_autobookmark(bool prompt_ok)
{
- while (*s && *s != ';')
- {
- s++;
- }
+ logf("%s", __func__);
+ bool update;
+
+ if (!bookmark_is_bookmarkable_state())
+ return false;
+
+ audio_pause(); /* first pause playback */
+ update = (global_settings.autoupdatebookmark && bookmark_exists());
- if (*s)
+ if (update)
+ return write_bookmark(true);
+
+ switch (global_settings.autocreatebookmark)
{
- s++;
- }
+ case BOOKMARK_YES:
+ return write_bookmark(true);
- return s;
-}
+ case BOOKMARK_NO:
+ return false;
-static const char* int_token(const char* s, int* dest)
-{
- *dest = atoi(s);
- return skip_token(s);
-}
+ case BOOKMARK_RECENT_ONLY_YES:
+ return write_bookmark(false);
+ }
+ const char *lines[]={ID2P(LANG_AUTO_BOOKMARK_QUERY)};
+ const struct text_message message={lines, 1};
-static const char* long_token(const char* s, long* dest)
-{
- *dest = atoi(s); /* Should be atol, but we don't have it. */
- return skip_token(s);
+ if(prompt_ok && gui_syncyesno_run(&message, NULL, NULL)==YESNO_YES)
+ {
+ if (global_settings.autocreatebookmark == BOOKMARK_RECENT_ONLY_ASK)
+ return write_bookmark(false);
+ else
+ return write_bookmark(true);
+ }
+ return false;
}
/* ----------------------------------------------------------------------- */
-/* This function takes a bookmark and parses it. This function also */
-/* validates the bookmark. The parse_filenames flag indicates whether */
-/* the filename tokens are to be extracted. */
-/* Returns true on successful bookmark parse. */
-/* ----------------------------------------------------------------------- */
-static bool parse_bookmark(const char *bookmark, const bool parse_filenames, const bool strip_dir)
+/* This function will determine if an autoload is necessary. This is an */
+/* interface function. */
+/* Returns */
+/* BOOKMARK_DO_RESUME on bookmark load or bookmark selection. */
+/* BOOKMARK_DONT_RESUME if we're not going to resume */
+/* BOOKMARK_CANCEL if user canceled */
+/* ------------------------------------------------------------------------*/
+int bookmark_autoload(const char* file)
{
- const char* s = bookmark;
- const char* end;
+ logf("%s", __func__);
+ char bm_filename[MAX_PATH];
+ char* bookmark;
-#define GET_INT_TOKEN(var) s = int_token(s, &var)
-#define GET_LONG_TOKEN(var) s = long_token(s, &var)
-#define GET_BOOL_TOKEN(var) var = (atoi(s)!=0); s = skip_token(s)
+ if(global_settings.autoloadbookmark == BOOKMARK_NO)
+ return BOOKMARK_DONT_RESUME;
- /* if new format bookmark, extract the optional content flags,
- otherwise treat as an original format bookmark */
- int opt_flags = 0;
- bool new_format = (strchr(s, '>') == s);
- if (new_format)
+ /*Checking to see if a bookmark file exists.*/
+ if(!generate_bookmark_file_name(bm_filename, sizeof(bm_filename), file, -1))
{
- s++;
- GET_INT_TOKEN(opt_flags);
+ return BOOKMARK_DONT_RESUME;
}
- /* extract all original bookmark tokens */
- GET_INT_TOKEN(bm.resume_index);
- GET_LONG_TOKEN(bm.resume_offset);
- GET_INT_TOKEN(bm.resume_seed);
- if (!new_format) /* skip deprecated token */
- s = skip_token(s);
- GET_LONG_TOKEN(bm.resume_time);
- GET_INT_TOKEN(bm.repeat_mode);
- GET_BOOL_TOKEN(bm.shuffle);
-
- /* extract all optional bookmark tokens */
- if (opt_flags & BM_PITCH)
- GET_INT_TOKEN(bm.pitch);
- if (opt_flags & BM_SPEED)
- GET_INT_TOKEN(bm.speed);
+ if(!file_exists(bm_filename))
+ return BOOKMARK_DONT_RESUME;
- if (*s == 0)
+ if(global_settings.autoloadbookmark == BOOKMARK_YES)
{
- return false;
+ return (bookmark_load(bm_filename, true)
+ ? BOOKMARK_DO_RESUME : BOOKMARK_DONT_RESUME);
}
-
- end = strchr(s, ';');
-
- /* extract file names */
- if (parse_filenames)
+ else
{
- size_t len = (end == NULL) ? strlen(s) : (size_t) (end - s);
- len = MIN(TEMP_BUF_SIZE - 1, len);
- strlcpy(global_temp_buffer, s, len + 1);
+ int ret = select_bookmark(bm_filename, true, &bookmark);
- if (end != NULL)
+ if (bookmark != NULL)
{
- end++;
- if (strip_dir)
- {
- s = strrchr(end, '/');
- if (s)
- {
- end = s;
- end++;
- }
- }
- strlcpy(global_filename, end, MAX_PATH);
+ if (!play_bookmark(bookmark))
+ return BOOKMARK_CANCEL;
+ return BOOKMARK_DO_RESUME;
}
- }
- return true;
+ return (ret != BOOKMARK_SUCCESS) ? BOOKMARK_CANCEL : BOOKMARK_DONT_RESUME;
+ }
}
/* ----------------------------------------------------------------------- */
-/* This function is used by multiple functions and is used to generate a */
-/* bookmark named based off of the input. */
-/* Changing this function could result in how the bookmarks are stored. */
-/* it would be here that the centralized/decentralized bookmark code */
-/* could be placed. */
-/* Returns true if the file name is generated, false if it was too long */
-/* ----------------------------------------------------------------------- */
-static bool generate_bookmark_file_name(const char *in)
+/* This function loads the bookmark information into the resume memory. */
+/* This is an interface function. */
+/* Returns true on successful bookmark load. */
+/* ------------------------------------------------------------------------*/
+bool bookmark_load(const char* file, bool autoload)
{
- /* if this is a root dir MP3, rename the bookmark file root_dir.bmark */
- /* otherwise, name it based on the in variable */
- if (!strcmp("/", in))
- strcpy(global_bookmark_file_name, "/root_dir.bmark");
- else
- {
-#ifdef HAVE_MULTIVOLUME
- /* The "root" of an extra volume need special handling too. */
- const char *filename;
- path_strip_volume(in, &filename, true);
- bool volume_root = *filename == '\0';
-#endif
- size_t len = strlcpy(global_bookmark_file_name, in, MAX_PATH);
- if(len >= MAX_PATH)
- return false;
+ logf("%s", __func__);
+ int fd;
+ char* bookmark = NULL;
- if(global_bookmark_file_name[len-1] == '/') {
- global_bookmark_file_name[len-1] = '\0';
- len--;
+ if(autoload)
+ {
+ fd = open(file, O_RDONLY);
+ if(fd >= 0)
+ {
+ if(read_line(fd, global_temp_buffer, sizeof(global_temp_buffer)) > 0)
+ bookmark=global_temp_buffer;
+ close(fd);
}
+ }
+ else
+ {
+ /* This is not an auto-load, so list the bookmarks */
+ select_bookmark(file, false, &bookmark);
+ }
-#ifdef HAVE_MULTIVOLUME
- if (volume_root)
- len = strlcat(global_bookmark_file_name, "/volume_dir.bmark", MAX_PATH);
- else
-#endif
- len = strlcat(global_bookmark_file_name, ".bmark", MAX_PATH);
+ if (bookmark != NULL)
+ {
+ if (!play_bookmark(bookmark))
+ {
+ /* Selected bookmark not found. */
+ if (!autoload)
+ {
+ splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
+ }
- if(len >= MAX_PATH)
return false;
+ }
}
return true;
@@ -1148,13 +1286,14 @@ static bool generate_bookmark_file_name(const char *in)
/* ----------------------------------------------------------------------- */
bool bookmark_exists(void)
{
+ char bm_filename[MAX_PATH];
bool exist=false;
char* name = playlist_get_name(NULL, global_temp_buffer,
sizeof(global_temp_buffer));
- if (generate_bookmark_file_name(name))
+ if (generate_bookmark_file_name(bm_filename, sizeof(bm_filename), name, -1))
{
- exist = file_exists(global_bookmark_file_name);
+ exist = file_exists(bm_filename);
}
return exist;
}
@@ -1180,4 +1319,3 @@ bool bookmark_is_bookmarkable_state(void)
return true;
}
-
diff --git a/apps/bookmark.h b/apps/bookmark.h
index ff7b87c1bf..192e577ce6 100644
--- a/apps/bookmark.h
+++ b/apps/bookmark.h
@@ -29,11 +29,17 @@ 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);
-bool bookmark_autoload(const char* file);
+int bookmark_autoload(const char* file);
bool bookmark_load(const char* file, bool autoload);
bool bookmark_exists(void);
bool bookmark_is_bookmarkable_state(void);
diff --git a/apps/buffering.c b/apps/buffering.c
index 3adbc4a6b9..81b861ccf1 100644
--- a/apps/buffering.c
+++ b/apps/buffering.c
@@ -20,7 +20,6 @@
****************************************************************************/
#include "config.h"
#include <string.h>
-#include "strlcpy.h"
#include "system.h"
#include "storage.h"
#include "thread.h"
@@ -71,8 +70,6 @@
/* 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 */
@@ -295,12 +292,11 @@ static int next_handle_id(void)
{
static int cur_handle_id = 0;
- /* 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;
+ 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;
return next_hid;
}
@@ -420,7 +416,8 @@ add_handle(unsigned int flags, size_t data_size, const char *path,
h->signaled = 0; /* Data can be waited for */
/* Save the provided path */
- memcpy(h->path, path, pathsize);
+ if (path)
+ memcpy(h->path, path, pathsize);
/* Return the start of the data area */
*data_out = ringbuf_add(index, handlesize);
@@ -851,8 +848,9 @@ 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 bufidx, size_t max_size)
{
+ (void)path;
int rc;
struct bitmap *bmp = ringbuf_ptr(bufidx);
struct dim *dim = data->dim;
@@ -866,25 +864,20 @@ 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
- int free = (int)MIN(buffer_len - bytes_used(), buffer_len - bufidx)
- - sizeof(struct bitmap);
-
+ const int format = FORMAT_NATIVE | FORMAT_DITHER |
+ FORMAT_RESIZE | FORMAT_KEEP_ASPECT;
#ifdef HAVE_JPEG
if (aa != NULL) {
lseek(fd, aa->pos, SEEK_SET);
- rc = clip_jpeg_fd(fd, aa->size, bmp, free, FORMAT_NATIVE|FORMAT_DITHER|
- FORMAT_RESIZE|FORMAT_KEEP_ASPECT, NULL);
+ rc = clip_jpeg_fd(fd, aa->size, bmp, (int)max_size, format, NULL);
}
else if (strcmp(path + strlen(path) - 4, ".bmp"))
- rc = read_jpeg_fd(fd, bmp, free, FORMAT_NATIVE|FORMAT_DITHER|
- FORMAT_RESIZE|FORMAT_KEEP_ASPECT, NULL);
+ rc = read_jpeg_fd(fd, bmp, (int)max_size, format, NULL);
else
#endif
- rc = read_bmp_fd(fd, bmp, free, FORMAT_NATIVE|FORMAT_DITHER|
- FORMAT_RESIZE|FORMAT_KEEP_ASPECT, NULL);
+ rc = read_bmp_fd(fd, bmp, (int)max_size, format, NULL);
return rc + (rc > 0 ? sizeof(struct bitmap) : 0);
- (void)path;
}
#endif /* HAVE_ALBUMART */
@@ -970,11 +963,18 @@ int bufopen(const char *file, off_t offset, enum data_type type,
size_t size = 0;
#ifdef HAVE_ALBUMART
if (type == TYPE_BITMAP) {
- /* If albumart is embedded, the complete file is not buffered,
- * but only the jpeg part; filesize() would be wrong */
+ /* 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 */
struct bufopen_bitmap_data *aa = user_data;
- if (aa->embedded_albumart)
- size = aa->embedded_albumart->size;
+ 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
}
#endif
@@ -983,7 +983,10 @@ 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;
+ hflags |= H_CANWRAP;
+ /* Bitmaps need their space allocated up front */
+ if (type == TYPE_BITMAP)
+ hflags |= H_ALLOCALL;
size_t adjusted_offset = offset;
if (adjusted_offset > size)
@@ -1034,7 +1037,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);
+ int rc = load_image(fd, file, user_data, data, padded_size);
if (rc <= 0) {
handle_id = ERR_FILE_ERROR;
} else {
@@ -1433,62 +1436,6 @@ 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
============================
diff --git a/apps/buffering.h b/apps/buffering.h
index 1a75d865ae..bc47d6b1a1 100644
--- a/apps/buffering.h
+++ b/apps/buffering.h
@@ -46,8 +46,7 @@ enum data_type {
#define ERR_FILE_ERROR -4
#define ERR_HANDLE_NOT_DONE -5
#define ERR_UNSUPPORTED_TYPE -6
-#define ERR_WRONG_THREAD -7
-#define ERR_BITMAP_TOO_LARGE -8
+#define ERR_BITMAP_TOO_LARGE -7
/* Initialise the buffering subsystem */
void buffering_init(void) INIT_ATTR;
@@ -68,8 +67,6 @@ 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).
@@ -85,8 +82,6 @@ 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
diff --git a/apps/codecs.c b/apps/codecs.c
index 4d2dd34ce0..9f34d26e14 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -203,8 +203,9 @@ static int codec_load_ram(struct codec_api *api)
return CODEC_ERROR;
}
- if (hdr->api_version > CODEC_API_VERSION
- || hdr->api_version < CODEC_MIN_API_VERSION) {
+ if (hdr->api_version != CODEC_API_VERSION ||
+ c_hdr->api_size > sizeof(struct codec_api))
+ {
logf("codec api version error");
lc_close(curr_handle);
curr_handle = NULL;
diff --git a/apps/core_keymap.c b/apps/core_keymap.c
new file mode 100644
index 0000000000..89e7913c33
--- /dev/null
+++ b/apps/core_keymap.c
@@ -0,0 +1,95 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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__) */
diff --git a/apps/core_keymap.h b/apps/core_keymap.h
new file mode 100644
index 0000000000..2077daa685
--- /dev/null
+++ b/apps/core_keymap.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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 */
+
diff --git a/apps/cuesheet.c b/apps/cuesheet.c
index be89ef96cf..263fed154d 100644
--- a/apps/cuesheet.c
+++ b/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)
- strlcpy(dot, ".cue", MAX_PATH - (dot-cuepath));
+ strmemccpy(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 */
- char *dot = strrchr(cuepath, '.');
+ dot = strrchr(cuepath, '.');
strcpy(dot, ".cue");
if (!file_exists(cuepath))
{
skip:
if ((len+4) >= MAX_PATH)
return false;
- strlcpy(cuepath, path, MAX_PATH);
+ strmemccpy(cuepath, path, MAX_PATH);
strlcat(cuepath, ".cue", MAX_PATH);
if (!file_exists(cuepath))
return false;
}
}
- strlcpy(cue_file->path, cuepath, MAX_PATH);
+ strmemccpy(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;
- strlcpy(cue_file->path, track_id3->path, MAX_PATH);
+ strmemccpy(cue_file->path, track_id3->path, MAX_PATH);
return true;
}
@@ -123,6 +123,7 @@ 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 */
@@ -138,7 +139,7 @@ static unsigned long parse_cue_index(const char *line)
while (isdigit(*line))
{
value = 10 * value + (*line - '0');
- if (value > 99) /* Sanity check bail early */
+ if (field >= 0 && value > field_max[field]) /* Sanity check bail early */
return 0;
line++;
}
@@ -165,6 +166,38 @@ static unsigned long parse_cue_index(const char *line)
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)
{
@@ -190,22 +223,25 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
/* Look for a Unicode BOM */
unsigned char bom_read = 0;
- read(fd, line, 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))
+ if (read(fd, line, BOM_UTF_8_SIZE) > 0)
{
- char_enc = CHAR_ENC_UTF_16_BE;
- bom_read = BOM_UTF_16_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;
+ }
}
+
if (bom_read < BOM_UTF_8_SIZE)
lseek(fd, cue_file->pos + bom_read, SEEK_SET);
if (is_embedded)
@@ -245,11 +281,16 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
}
s = skip_whitespace(line);
- if (!strncmp(s, "TRACK", 5))
+/* 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)
{
cue->track_count++;
}
- else if (!strncmp(s, "INDEX 01", 8))
+ else if (option == eCS_INDEX_01)
{
#if 0
s = strchr(s,' ');
@@ -265,10 +306,7 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
cue->tracks[cue->track_count-1].offset = parse_cue_index(s);
#endif
}
- else if (!strncmp(s, "TITLE", 5)
- || !strncmp(s, "PERFORMER", 9)
- || !strncmp(s, "SONGWRITER", 10)
- || !strncmp(s, "FILE", 4))
+ else if (option != eCS_NOTFOUND)
{
char *dest = NULL;
char *string = get_string(s);
@@ -278,24 +316,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 (*s)
+ switch (option)
{
- case 'T': /* TITLE */
+ case eCS_TITLE: /* TITLE */
dest = (cue->track_count <= 0) ? cue->title :
cue->tracks[cue->track_count-1].title;
break;
- case 'P': /* PERFORMER */
+ case eCS_PERFORMER: /* PERFORMER */
dest = (cue->track_count <= 0) ? cue->performer :
cue->tracks[cue->track_count-1].performer;
break;
- case 'S': /* SONGWRITER */
+ case eCS_SONGWRITER: /* SONGWRITER */
dest = (cue->track_count <= 0) ? cue->songwriter :
cue->tracks[cue->track_count-1].songwriter;
break;
- case 'F': /* FILE */
+ case eCS_FILE: /* FILE */
if (is_embedded || cue->track_count > 0)
break;
@@ -303,6 +341,16 @@ 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)
@@ -315,10 +363,11 @@ bool parse_cuesheet(struct cuesheet_file *cue_file, struct cuesheet *cue)
}
else
{
- strlcpy(dest, string, count);
+ strmemccpy(dest, string, count);
}
}
}
+
if (is_embedded)
{
bytes_left -= line_len;
@@ -337,7 +386,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;
- strlcpy(slash, line, MAX_PATH - (slash - cue->file));
+ strmemccpy(slash, line, MAX_PATH - (slash - cue->file));
}
/* If some songs don't have performer info, we copy the cuesheet performer */
@@ -345,10 +394,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')
- strlcpy(cue->tracks[i].performer, cue->performer, MAX_NAME*3);
+ strmemccpy(cue->tracks[i].performer, cue->performer, MAX_NAME*3);
if (*(cue->tracks[i].songwriter) == '\0')
- strlcpy(cue->tracks[i].songwriter, cue->songwriter, MAX_NAME*3);
+ strmemccpy(cue->tracks[i].songwriter, cue->songwriter, MAX_NAME*3);
}
return true;
@@ -392,7 +441,7 @@ static const char* list_get_name_cb(int selected_item,
struct cuesheet *cue = (struct cuesheet *)data;
if (selected_item & 1)
- strlcpy(buffer, cue->tracks[selected_item/2].title, buffer_len);
+ strmemccpy(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);
@@ -432,7 +481,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, LIST_WRAP_UNLESS_HELD))
+ if (gui_synclist_do_button(&lists, &action))
continue;
switch (action)
{
@@ -459,7 +508,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];
- strlcpy(file, cue->file, MAX_PATH);
+ strmemccpy(file, cue->file, MAX_PATH);
if (!strcmp(cue->path, file) || /* if embedded */
(search_for_cuesheet(file, &cue_file) &&
@@ -486,7 +535,7 @@ bool display_cuesheet_content(char* filename)
if (!cue || bufsize < sizeof(struct cuesheet))
return false;
- strlcpy(cue_file.path, filename, MAX_PATH);
+ strmemccpy(cue_file.path, filename, MAX_PATH);
cue_file.pos = 0;
cue_file.size = 0;
@@ -516,12 +565,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_TRESH milliseconds have elapsed, skip
+ backward before DEFAULT_SKIP_THRESH milliseconds have elapsed, skip
to previous cuesheet segment. If skipping backward after
- DEFAULT_SKIP_TRESH seconds have elapsed, skip to the start of the
+ DEFAULT_SKIP_THRESH seconds have elapsed, skip to the start of the
current cuesheet segment */
if (direction == 1 ||
- ((curr_pos - cue->tracks[track].offset) < DEFAULT_SKIP_TRESH))
+ ((curr_pos - cue->tracks[track].offset) < DEFAULT_SKIP_THRESH))
{
track += direction;
}
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 33970da581..7fc93b315b 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -23,7 +23,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
-#include <string.h>
+#include <string-extra.h>
#include "lcd.h"
#include "lang.h"
#include "menu.h"
@@ -39,7 +39,6 @@
#include "audio.h"
#include "settings.h"
#include "list.h"
-#include "statusbar.h"
#include "dir.h"
#include "panic.h"
#include "screens.h"
@@ -128,12 +127,18 @@
#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR)
#include "bootdata.h"
+#include "multiboot.h"
+#include "rbpaths.h"
+#include "pathfuncs.h"
+#include "rb-loader.h"
#endif
+#define SCREEN_MAX_CHARS (LCD_WIDTH / SYSFONT_WIDTH)
+
static const char* threads_getname(int selected_item, void *data,
char *buffer, size_t buffer_len)
{
- (void)data;
+ int *x_offset = (int*) data;
#if NUM_CORES > 1
if (selected_item < (int)NUM_CORES)
@@ -153,36 +158,76 @@ static const char* threads_getname(int selected_item, void *data,
struct thread_debug_info threadinfo;
if (thread_get_debug_info(selected_item, &threadinfo) > 0)
{
- fmtstr = "%2d:" IF_COP(" (%d)") " %s" IF_PRIO(" %d %d")
+ fmtstr = "%2d:" IF_COP(" (%d)") " %s%n" IF_PRIO(" %d %d")
IFN_SDL(" %2d%%") " %s";
}
-
- snprintf(buffer, buffer_len, fmtstr,
+ int status_len;
+ size_t len = snprintf(buffer, buffer_len, fmtstr,
selected_item,
IF_COP(threadinfo.core,)
threadinfo.statusstr,
+ &status_len,
IF_PRIO(threadinfo.base_priority, threadinfo.current_priority,)
IFN_SDL(threadinfo.stack_usage,)
threadinfo.name);
- return buffer;
+ int start = 0;
+#if LCD_WIDTH <= 128
+ if (len >= SCREEN_MAX_CHARS)
+ {
+ int ch_offset = (*x_offset)%(len-1);
+ int rem = SCREEN_MAX_CHARS - (len - ch_offset);
+ if (rem > 0)
+ ch_offset -= rem;
+
+ if (ch_offset > 0)
+ {
+ /* don't scroll the # and status */
+ status_len++;
+ if ((unsigned int)ch_offset + status_len < buffer_len)
+ memmove(&buffer[ch_offset], &buffer[0], status_len);
+ start = ch_offset;
+ }
+ }
+#else
+ (void) x_offset;
+ (void) len;
+#endif
+ return &buffer[start];
}
static int dbg_threads_action_callback(int action, struct gui_synclist *lists)
{
- (void)lists;
+
if (action == ACTION_NONE)
+ {
+ return ACTION_REDRAW;
+ }
+#if LCD_WIDTH <= 128
+ int *x_offset = ((int*) lists->data);
+ if (action == ACTION_STD_OK)
+ {
+ *x_offset += 1;
action = ACTION_REDRAW;
+ }
+ else if (action != ACTION_UNKNOWN)
+ {
+ *x_offset = 0;
+ }
+#else
+ (void) lists;
+#endif
return action;
}
/* Test code!!! */
static bool dbg_os(void)
{
struct simplelist_info info;
+ int xoffset = 0;
+
simplelist_info_init(&info, IF_COP("Core and ") "Stack usage:",
- MAXTHREADS IF_COP( + NUM_CORES ), NULL);
- info.hide_selection = true;
- info.scroll_all = true;
+ MAXTHREADS IF_COP( + NUM_CORES ), &xoffset);
+ info.scroll_all = false;
info.action_callback = dbg_threads_action_callback;
info.get_name = threads_getname;
return simplelist_show_list(&info);
@@ -295,7 +340,6 @@ static bool dbg_cpuinfo(void)
info.get_name = get_cpuinfo;
info.action_callback = cpuinfo_cb;
info.timeout = HZ;
- info.hide_selection = true;
info.scroll_all = true;
return simplelist_show_list(&info);
}
@@ -330,6 +374,13 @@ static bool dbg_buffering_thread(void)
struct buffering_debug d;
size_t filebuflen = audio_get_filebuflen();
/* This is a size_t, but call it a long so it puts a - when it's bad. */
+#if LCD_WIDTH > 96
+ #define STR_DATAREM "data_rem"
+ const char * const fmt_used = "%s: %6ld/%ld";
+#else /* clipzip, ?*/
+ #define STR_DATAREM "remain"
+ const char * const fmt_used = "%s:%ld/%ld";
+#endif
#ifndef CPU_MULTI_FREQUENCY
boost_ticks = 0;
@@ -366,13 +417,13 @@ static bool dbg_buffering_thread(void)
screens[i].clear_display();
- screens[i].putsf(0, line++, "pcm: %6ld/%ld", (long) bufused, (long) bufsize);
+ screens[i].putsf(0, line++, fmt_used, "pcm", (long) bufused, (long) bufsize);
gui_scrollbar_draw(&screens[i],0, line*8, screens[i].lcdwidth, 6,
bufsize, 0, bufused, HORIZONTAL);
line++;
- screens[i].putsf(0, line++, "alloc: %6ld/%ld", audio_filebufused(),
+ screens[i].putsf(0, line++, fmt_used, "alloc", audio_filebufused(),
(long) filebuflen);
#if LCD_HEIGHT > 80 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_HEIGHT > 80)
@@ -382,7 +433,7 @@ static bool dbg_buffering_thread(void)
filebuflen, 0, audio_filebufused(), HORIZONTAL);
line++;
- screens[i].putsf(0, line++, "real: %6ld/%ld", (long)d.buffered_data,
+ screens[i].putsf(0, line++, fmt_used, "real", (long)d.buffered_data,
(long)filebuflen);
gui_scrollbar_draw(&screens[i],0, line*8, screens[i].lcdwidth, 6,
@@ -391,7 +442,7 @@ static bool dbg_buffering_thread(void)
}
#endif
- screens[i].putsf(0, line++, "usefl: %6ld/%ld", (long)(d.useful_data),
+ screens[i].putsf(0, line++, fmt_used, "usefl", (long)(d.useful_data),
(long)filebuflen);
#if LCD_HEIGHT > 80 || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_HEIGHT > 80)
@@ -403,7 +454,7 @@ static bool dbg_buffering_thread(void)
}
#endif
- screens[i].putsf(0, line++, "data_rem: %ld", (long)d.data_rem);
+ screens[i].putsf(0, line++, "%s: %ld", STR_DATAREM, (long)d.data_rem);
screens[i].putsf(0, line++, "track count: %2u", audio_track_count());
@@ -442,8 +493,10 @@ static bool dbg_buffering_thread(void)
screens[i].setfont(FONT_UI);
return false;
+#undef STR_DATAREM
}
+#ifdef BUFLIB_DEBUG_PRINT
static const char* bf_getname(int selected_item, void *data,
char *buffer, size_t buffer_len)
{
@@ -463,13 +516,12 @@ static int bf_action_cb(int action, struct gui_synclist* list)
else
{
splash(HZ/1, "Attempting a 64k allocation");
- int handle = core_alloc("test", 64<<10);
+ int handle = core_alloc(64<<10);
splash(HZ/2, (handle > 0) ? "Success":"Fail");
/* for some reason simplelist doesn't allow adding items here if
* info.get_name is given, so use normal list api */
gui_synclist_set_nb_items(list, core_get_num_blocks());
- if (handle > 0)
- core_free(handle);
+ core_free(handle);
}
action = ACTION_REDRAW;
}
@@ -485,6 +537,7 @@ static bool dbg_buflib_allocs(void)
info.timeout = HZ;
return simplelist_show_list(&info);
}
+#endif /* BUFLIB_DEBUG_PRINT */
#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
static const char* dbg_partitions_getname(int selected_item, void *data,
@@ -514,7 +567,6 @@ static bool dbg_partitions(void)
struct simplelist_info info;
simplelist_info_init(&info, "Partition Info", NUM_DRIVES * 4, NULL);
info.selection_size = 2;
- info.hide_selection = true;
info.scroll_all = true;
info.get_name = dbg_partitions_getname;
return simplelist_show_list(&info);
@@ -816,8 +868,7 @@ static int tsc2100debug_action_callback(int action, struct gui_synclist *lists)
if (action == ACTION_STD_OK)
{
*page = (*page+1)%3;
- snprintf(lists->title, 32,
- "tsc2100 registers - Page %d", *page);
+ snprintf((char*)lists->title, 32, "tsc2100 registers - Page %d", *page);
return ACTION_REDRAW;
}
return action;
@@ -825,7 +876,8 @@ static int tsc2100debug_action_callback(int action, struct gui_synclist *lists)
static bool tsc2100_debug(void)
{
int page = 0;
- char title[32] = "tsc2100 registers - Page 0";
+ char title[32];
+ snprintf(title, 32, "tsc2100 registers - Page %d", page);
struct simplelist_info info;
simplelist_info_init(&info, title, 32, &page);
info.timeout = HZ/100;
@@ -876,7 +928,7 @@ static bool view_battery(void)
else
grid = 5;
- lcd_putsf(0, 0, "battery %d.%03dV", power_history[0] / 1000,
+ lcd_putsf(0, 0, "%s %d.%03dV", "Battery", power_history[0] / 1000,
power_history[0] % 1000);
lcd_putsf(0, 1, "%d.%03d-%d.%03dV (%2dmV)",
minv / 1000, minv % 1000, maxv / 1000, maxv % 1000,
@@ -887,7 +939,7 @@ static bool view_battery(void)
grid = 10;
else
grid = 1;
- lcd_putsf(0, 0, "battery %d%%", power_history[0]);
+ lcd_putsf(0, 0, "%s %d%%", "Battery", power_history[0]);
lcd_putsf(0, 1, "%d%%-%d%% (%d %%)", minv, maxv, grid);
#endif
@@ -942,16 +994,16 @@ static bool view_battery(void)
lcd_putsf(0, 0, "Pwr status: %s",
charging_state() ? "charging" : "discharging");
#else
- lcd_puts(0, 0, "Power status: unknown");
+ lcd_putsf(0, 0, "Pwr status: %s", "unknown");
#endif
battery_read_info(&y, &z);
if (y > 0)
- lcd_putsf(0, 1, "Battery: %d.%03d V (%d %%)", y / 1000, y % 1000, z);
+ lcd_putsf(0, 1, "%s: %d.%03d V (%d %%)", "Battery", y / 1000, y % 1000, z);
else if (z > 0)
- lcd_putsf(0, 1, "Battery: %d %%", z);
+ lcd_putsf(0, 1, "%s: %d %%", "Battery", z);
#ifdef ADC_EXT_POWER
y = (adc_read(ADC_EXT_POWER) * EXT_SCALE_FACTOR) / 1000;
- lcd_putsf(0, 2, "External: %d.%03d V", y / 1000, y % 1000);
+ lcd_putsf(0, 2, "%s: %d.%03d V", "External", y / 1000, y % 1000);
#endif
#if CONFIG_CHARGING
#if defined IPOD_NANO || defined IPOD_VIDEO
@@ -965,7 +1017,7 @@ static bool view_battery(void)
usb_pwr ? "present" : "absent");
lcd_putsf(0, 4, "EXT pwr: %s",
ext_pwr ? "present" : "absent");
- lcd_putsf(0, 5, "Battery: %s",
+ lcd_putsf(0, 5, "%s: %s", "Battery",
charging ? "charging" : (usb_pwr||ext_pwr) ? "charged" : "discharging");
lcd_putsf(0, 6, "Dock mode: %s",
dock ? "enabled" : "disabled");
@@ -1019,7 +1071,7 @@ static bool view_battery(void)
lcd_putsf(0, line++, "State: %s", chrgstate_strings[y]);
- lcd_putsf(0, line++, "Battery Switch: %s",
+ lcd_putsf(0, line++, "%s Switch: %s", "Battery",
(st & POWER_INPUT_BATTERY) ? "On" : "Off");
y = chrgraw_adc_voltage();
@@ -1042,11 +1094,11 @@ static bool view_battery(void)
y = battery_adc_temp();
if (y != INT_MIN) {
- lcd_putsf(0, line++, "T Battery: %d\u00b0C (%d\u00b0F)", y,
- (9*y + 160) / 5);
+ lcd_putsf(0, line++, "T %s: %d\u00b0C (%d\u00b0F)",
+ "Battery", y, (9*y + 160) / 5);
} else {
/* Conversion disabled */
- lcd_puts(0, line++, "T Battery: ?");
+ lcd_putsf(0, line++, "T %s: ?", "Battery");
}
#elif defined(HAVE_AS3514) && CONFIG_CHARGING
static const char * const chrgstate_strings[] =
@@ -1073,7 +1125,7 @@ static bool view_battery(void)
y = pmu_read_battery_voltage();
lcd_putsf(17, 1, "RAW: %d.%03d V", y / 1000, y % 1000);
y = pmu_read_battery_current();
- lcd_putsf(0, 2, "Battery current: %d mA", y);
+ lcd_putsf(0, 2, "%s current: %d mA", "Battery", y);
lcd_putsf(0, 3, "PWRCON: %08x %08x", PWRCON, PWRCONEXT);
lcd_putsf(0, 4, "CLKCON: %08x %03x %03x", CLKCON, CLKCON2, CLKCON3);
lcd_putsf(0, 5, "PLL: %06x %06x %06x", PLL0PMS, PLL1PMS, PLL2PMS);
@@ -1099,9 +1151,9 @@ static bool view_battery(void)
lcd_putsf(0, 3, "Charger: %s",
charger_inserted() ? "present" : "absent");
x = (avr_hid_hdq_read_short(HDQ_REG_TEMP) / 4) - 273;
- lcd_putsf(0, 4, "Battery temperature: %d C", x);
+ lcd_putsf(0, 4, "%s temperature: %d C", "Battery", x);
x = (avr_hid_hdq_read_short(HDQ_REG_AI) * 357) / 200;
- lcd_putsf(0, 5, "Battery current: %d.%01d mA", x / 10, x % 10);
+ lcd_putsf(0, 5, "%s current: %d.%01d mA", "Battery", x / 10, x % 10);
x = (avr_hid_hdq_read_short(HDQ_REG_AP) * 292) / 20;
lcd_putsf(0, 6, "Discharge power: %d.%01d mW", x / 10, x % 10);
x = (avr_hid_hdq_read_short(HDQ_REG_SAE) * 292) / 2;
@@ -1139,13 +1191,17 @@ static bool view_battery(void)
power_history[0] % 1000);
#endif
- lcd_putsf(0, 6, "battery level: %d%%", battery_level());
+ lcd_putsf(0, 6, "%s level: %d%%", "Battery", battery_level());
int time_left = battery_time();
if (time_left >= 0)
lcd_putsf(0, 7, "Est. remain: %d m", time_left);
else
lcd_puts(0, 7, "Estimation n/a");
+
+#if (CONFIG_BATTERY_MEASURE & CURRENT_MEASURE)
+ lcd_putsf(0, 8, "%s current: %d mA", "Battery", battery_current());
+#endif
break;
}
@@ -1189,7 +1245,8 @@ static int disk_callback(int btn, struct gui_synclist *lists)
int *cardnum = (int*)lists->data;
unsigned char card_name[6];
unsigned char pbuf[32];
- char *title = lists->title;
+ /* Casting away const is safe; the buffer is defined as non-const. */
+ char *title = (char *)lists->title;
static const unsigned char i_vmin[] = { 0, 1, 5, 10, 25, 35, 60, 100 };
static const unsigned char i_vmax[] = { 1, 5, 10, 25, 35, 45, 80, 200 };
static const unsigned char * const kbit_units[] = { "kBit/s", "MBit/s", "GBit/s" };
@@ -1219,7 +1276,7 @@ static int disk_callback(int btn, struct gui_synclist *lists)
{
card_name[i] = card_extract_bits(card->cid, (103-8*i), 8);
}
- strlcpy(card_name, card_name, sizeof(card_name));
+ strmemccpy(card_name, card_name, sizeof(card_name));
simplelist_addline(
"%s Rev %d.%d", card_name,
(int) card_extract_bits(card->cid, 63, 4),
@@ -1572,7 +1629,8 @@ static int ata_smart_attr_to_string(
if (len >= name_sz) len = name_sz-1;
slen += len;
}
- snprintf(str+slen, size-slen, "%s", buf);
+
+ strmemccpy(str+slen, buf, size-slen);
}
return 1; /* ok */
@@ -1663,7 +1721,6 @@ static bool dbg_ata_smart(void)
struct simplelist_info info;
simplelist_info_init(&info, "S.M.A.R.T. Data [CONTEXT to dump]", 1, NULL);
info.action_callback = ata_smart_callback;
- info.hide_selection = true;
info.scroll_all = true;
return simplelist_show_list(&info);
}
@@ -1717,7 +1774,6 @@ static bool dbg_disk_info(void)
info.title = title;
#endif
info.action_callback = disk_callback;
- info.hide_selection = true;
info.scroll_all = true;
return simplelist_show_list(&info);
}
@@ -1786,7 +1842,6 @@ static bool dbg_dircache_info(void)
int syncbuild = 0;
simplelist_info_init(&info, "Dircache Info", 8, &syncbuild);
info.action_callback = dircache_callback;
- info.hide_selection = true;
info.scroll_all = true;
return simplelist_show_list(&info);
}
@@ -1799,6 +1854,7 @@ static int database_callback(int btn, struct gui_synclist *lists)
(void)lists;
struct tagcache_stat *stat = tagcache_get_stat();
static bool synced = false;
+ static int update_entries = 0;
simplelist_set_line_count(0);
@@ -1810,6 +1866,8 @@ static int database_callback(int btn, struct gui_synclist *lists)
stat->ramcache ? "Yes" : "No");
simplelist_addline("RAM: %d/%d B",
stat->ramcache_used, stat->ramcache_allocated);
+ simplelist_addline("Total entries: %d",
+ stat->total_entries);
simplelist_addline("Progress: %d%% (%d entries)",
stat->progress, stat->processed_entries);
simplelist_addline("Curfile: %s",
@@ -1831,12 +1889,19 @@ static int database_callback(int btn, struct gui_synclist *lists)
if (!btn && stat->curentry)
{
synced = true;
- return ACTION_REDRAW;
+ if (update_entries <= stat->processed_entries)
+ {
+ update_entries = stat->processed_entries + 100;
+ return ACTION_REDRAW;
+ }
+ return ACTION_NONE;
}
if (btn == ACTION_STD_CANCEL)
+ {
+ update_entries = 0;
tagcache_screensync_enable(false);
-
+ }
return btn;
}
static bool dbg_tagcache_info(void)
@@ -1844,7 +1909,6 @@ static bool dbg_tagcache_info(void)
struct simplelist_info info;
simplelist_info_init(&info, "Database Info", 8, NULL);
info.action_callback = database_callback;
- info.hide_selection = true;
info.scroll_all = true;
/* Don't do nonblock here, must give enough processing time
@@ -2026,12 +2090,12 @@ static int radio_callback(int btn, struct gui_synclist *lists)
tea5767_dbg_info(&nfo);
simplelist_addline("Philips regs:");
simplelist_addline(
- " Read: %02X %02X %02X %02X %02X",
+ " %s: %02X %02X %02X %02X %02X", "Read",
(unsigned)nfo.read_regs[0], (unsigned)nfo.read_regs[1],
(unsigned)nfo.read_regs[2], (unsigned)nfo.read_regs[3],
(unsigned)nfo.read_regs[4]);
simplelist_addline(
- " Write: %02X %02X %02X %02X %02X",
+ " %s: %02X %02X %02X %02X %02X", "Write",
(unsigned)nfo.write_regs[0], (unsigned)nfo.write_regs[1],
(unsigned)nfo.write_regs[2], (unsigned)nfo.write_regs[3],
(unsigned)nfo.write_regs[4]);
@@ -2097,7 +2161,7 @@ static int radio_callback(int btn, struct gui_synclist *lists)
struct tm* time = gmtime(&seconds);
simplelist_addline(
- "CT:%4d-%02d-%02d %02d:%02d",
+ "CT:%4d-%02d-%02d %02d:%02d:%02d",
time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
time->tm_hour, time->tm_min, time->tm_sec);
}
@@ -2117,7 +2181,6 @@ static bool dbg_fm_radio(void)
radio_hardware_present() ? "yes" : "no");
info.action_callback = radio_hardware_present()?radio_callback : NULL;
- info.hide_selection = true;
return simplelist_show_list(&info);
}
#endif /* CONFIG_TUNER */
@@ -2246,11 +2309,6 @@ static bool cpu_boost_log(void)
static bool cpu_boost_log_dump(void)
{
int fd;
-#if CONFIG_RTC
- struct tm *nowtm;
- char fname[MAX_PATH];
-#endif
-
int count = cpu_boost_log_getcount();
char *str = cpu_boost_log_getlog_first();
@@ -2261,11 +2319,12 @@ static bool cpu_boost_log_dump(void)
return false;
#if CONFIG_RTC
- nowtm = get_time();
- snprintf(fname, MAX_PATH, "%s/boostlog_%04d%02d%02d%02d%02d%02d.txt", ROCKBOX_DIR,
- nowtm->tm_year + 1900, nowtm->tm_mon + 1, nowtm->tm_mday,
- nowtm->tm_hour, nowtm->tm_min, nowtm->tm_sec);
- fd = open(fname, O_CREAT|O_WRONLY|O_TRUNC);
+ char fname[MAX_PATH];
+ struct tm *nowtm = get_time();
+ fd = open_pathfmt(fname, sizeof(fname), O_CREAT|O_WRONLY|O_TRUNC,
+ "%s/boostlog_%04d%02d%02d%02d%02d%02d.txt", ROCKBOX_DIR,
+ nowtm->tm_year + 1900, nowtm->tm_mon + 1, nowtm->tm_mday,
+ nowtm->tm_hour, nowtm->tm_min, nowtm->tm_sec);
#else
fd = open(ROCKBOX_DIR "/boostlog.txt", O_CREAT|O_WRONLY|O_TRUNC, 0666);
#endif
@@ -2389,7 +2448,6 @@ static bool dbg_talk(void)
else
simplelist_info_init(&list, "Voice Information:", 2, &data);
list.scroll_all = true;
- list.hide_selection = true;
list.timeout = HZ;
list.get_name = dbg_talk_get_name;
@@ -2429,7 +2487,6 @@ static bool dbg_isp1583(void)
isp1583.scroll_all = true;
simplelist_info_init(&isp1583, "ISP1583", dbg_usb_num_items(), NULL);
isp1583.timeout = HZ/100;
- isp1583.hide_selection = true;
isp1583.get_name = dbg_usb_item;
isp1583.action_callback = isp1583_action_callback;
return simplelist_show_list(&isp1583);
@@ -2455,83 +2512,34 @@ static bool dbg_pic(void)
pic.scroll_all = true;
simplelist_info_init(&pic, "PIC", pic_dbg_num_items(), NULL);
pic.timeout = HZ/100;
- pic.hide_selection = true;
pic.get_name = pic_dbg_item;
pic.action_callback = pic_action_callback;
return simplelist_show_list(&pic);
}
#endif
-static bool dbg_skin_engine(void)
-{
- struct simplelist_info info;
- int i, total = 0;
-#if defined(HAVE_BACKDROP_IMAGE)
- int ref_count;
- char *path;
- size_t bytes;
- int path_prefix_len = strlen(ROCKBOX_DIR "/wps/");
-#endif
- simplelist_info_init(&info, "Skin engine usage", 0, NULL);
- simplelist_set_line_count(0);
- info.hide_selection = true;
- FOR_NB_SCREENS(j) {
-#if NB_SCREENS > 1
- simplelist_addline("%s display:",
- j == 0 ? "Main" : "Remote");
-#endif
- for (i = 0; i < skin_get_num_skins(); i++) {
- struct skin_stats *stats = skin_get_stats(i, j);
- if (stats->buflib_handles)
- {
- simplelist_addline("Skin ID: %d, %d allocations",
- i, stats->buflib_handles);
- simplelist_addline("\tskin: %d bytes",
- stats->tree_size);
- simplelist_addline("\tImages: %d bytes",
- stats->images_size);
- simplelist_addline("\tTotal: %d bytes",
- stats->tree_size + stats->images_size);
- total += stats->tree_size + stats->images_size;
- }
- }
- }
- simplelist_addline("Skin total usage: %d bytes", total);
-#if defined(HAVE_BACKDROP_IMAGE)
- simplelist_addline("Backdrop Images:");
- i = 0;
- while (skin_backdrop_get_debug(i++, &path, &ref_count, &bytes)) {
- if (ref_count > 0) {
-
- if (!strncasecmp(path, ROCKBOX_DIR "/wps/", path_prefix_len))
- path += path_prefix_len;
- simplelist_addline("%s", path);
- simplelist_addline("\tref_count: %d", ref_count);
- simplelist_addline("\tsize: %d", bytes);
- total += bytes;
- }
- }
- simplelist_addline("Total usage: %d bytes", total);
-#endif
- return simplelist_show_list(&info);
-}
-
#if defined(HAVE_BOOTDATA) && !defined(SIMULATOR)
static bool dbg_boot_data(void)
{
- unsigned int crc = 0;
+ unsigned int crc = crc_32(boot_data.payload, boot_data.length, 0xffffffff);
struct simplelist_info info;
info.scroll_all = true;
simplelist_info_init(&info, "Boot data", 1, NULL);
simplelist_set_line_count(0);
- crc = crc_32(boot_data.payload, boot_data.length, 0xffffffff);
+
#if defined(HAVE_MULTIBOOT)
+ char rootpath[MAX_PATH / 2] = RB_ROOT_CONTENTS_DIR;
int boot_volume = 0;
if(crc == boot_data.crc)
{
boot_volume = boot_data.boot_volume; /* boot volume contained in uint8_t payload */
+ int rtlen = get_redirect_dir(rootpath, sizeof(rootpath), boot_volume, "", "");
+ while (rtlen > 0 && rootpath[--rtlen] == PATH_SEPCH) /* remove extra separators */
+ rootpath[rtlen] = '\0';
}
simplelist_addline("Boot Volume: <%lu>", boot_volume);
+ simplelist_addline("Root:");
+ simplelist_addline("%s", rootpath);
simplelist_addline("");
#endif
simplelist_addline("Bootdata RAW:");
@@ -2547,7 +2555,6 @@ static bool dbg_boot_data(void)
boot_data.payload[i+1], boot_data.payload[i+2], boot_data.payload[i+3]);
}
- info.hide_selection = true;
return simplelist_show_list(&info);
}
#endif /* defined(HAVE_BOOTDATA) && !defined(SIMULATOR) */
@@ -2624,7 +2631,9 @@ static const struct {
#ifdef PM_DEBUG
{ "pm histogram", peak_meter_histogram},
#endif /* PM_DEBUG */
+#ifdef BUFLIB_DEBUG_PRINT
{ "View buflib allocs", dbg_buflib_allocs },
+#endif
#ifndef SIMULATOR
#if CONFIG_TUNER
{ "FM Radio", dbg_fm_radio },
@@ -2691,6 +2700,24 @@ static const char* menu_get_name(int item, void * data,
return menuitems[item].desc;
}
+static int menu_get_talk(int item, void *data)
+{
+ (void)data;
+ if (global_settings.talk_menu && menuitems[item].desc)
+ {
+ talk_number(item + 1, true);
+ talk_id(VOICE_PAUSE, true);
+#if 0 /* no debug items currently have lang ids */
+ long id = P2ID((const unsigned char *)(menuitems[item].desc));
+ if(id>=0)
+ talk_id(id, true);
+ else
+#endif
+ talk_spell(menuitems[item].desc, true);
+ }
+ return 0;
+}
+
int debug_menu(void)
{
struct simplelist_info info;
@@ -2698,6 +2725,7 @@ int debug_menu(void)
simplelist_info_init(&info, "Debug Menu", ARRAYLEN(menuitems), NULL);
info.action_callback = menu_action_callback;
info.get_name = menu_get_name;
+ info.get_talk = menu_get_talk;
return (simplelist_show_list(&info)) ? 1 : 0;
}
diff --git a/apps/enc_config.c b/apps/enc_config.c
index 65ef65667a..b70ac03888 100644
--- a/apps/enc_config.c
+++ b/apps/enc_config.c
@@ -193,9 +193,9 @@ static bool mp3_enc_bitrate(struct menucallback_data *data)
} /* mp3_enc_bitrate */
/* mp3_enc configuration menu */
-MENUITEM_FUNCTION(mp3_bitrate, MENU_FUNC_USEPARAM, ID2P(LANG_BITRATE),
- mp3_enc_bitrate,
- &menu_callback_data, enc_menuitem_callback, Icon_NOICON);
+MENUITEM_FUNCTION_W_PARAM(mp3_bitrate, 0, 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);
@@ -286,7 +286,7 @@ static int enc_menuitem_callback(int action,
{
(void)this_list;
struct menucallback_data *data =
- (struct menucallback_data*)this_item->function->param;
+ (struct menucallback_data*)this_item->function_param->param;
if (action == ACTION_EXIT_MENUITEM)
{
diff --git a/apps/features.txt b/apps/features.txt
index 83c3f0a65f..bafaa11599 100644
--- a/apps/features.txt
+++ b/apps/features.txt
@@ -105,6 +105,10 @@ radio_remote
#endif
#endif
+#if defined(HAVE_RDS_CAP)
+rds
+#endif
+
#if defined(HAVE_RECORDING)
recording
#if defined(HAVE_LINE_IN)
@@ -262,6 +266,8 @@ recording_digital
#if MEMORYSIZE <= 2
lowmem
+#elif MEMORYSIZE > 8
+himem
#endif
#if defined(HAVE_HARDWARE_CLICK)
@@ -283,3 +289,14 @@ multi_boot
#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
diff --git a/apps/filetree.c b/apps/filetree.c
index efe5e80a0f..b652b6515b 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -51,11 +51,28 @@
#endif
#include "wps.h"
-static int compare_sort_dir; /* qsort key for sorting directories */
+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);
+}
int ft_build_playlist(struct tree_context* c, int start_index)
{
int i;
+ int res = 0;
int start=start_index;
tree_lock_cache(c);
@@ -65,7 +82,8 @@ int ft_build_playlist(struct tree_context* c, int start_index)
{
if((entries[i].attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO)
{
- if (playlist_add(entries[i].name) < 0)
+ res = playlist_add(entries[i].name);
+ if (res < 0)
break;
}
else
@@ -77,7 +95,6 @@ int ft_build_playlist(struct tree_context* c, int start_index)
}
tree_unlock_cache(c);
-
return start_index;
}
@@ -89,7 +106,8 @@ int ft_build_playlist(struct tree_context* c, int start_index)
* 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_dyn_warning)
+bool ft_play_playlist(char* pathname, char* dirname,
+ char* filename, bool skip_warn_and_bookmarks)
{
if (global_settings.party_mode && audio_status())
{
@@ -97,22 +115,15 @@ bool ft_play_playlist(char* pathname, char* dirname, char* filename, bool skip_d
return false;
}
- if (bookmark_autoload(pathname))
+ if (!skip_warn_and_bookmarks)
{
- return false;
+ int res = bookmark_autoload(pathname);
+ if (res == BOOKMARK_CANCEL || res == BOOKMARK_DO_RESUME || !warn_on_pl_erase())
+ return false;
}
splash(0, ID2P(LANG_WAIT));
- /* about to create a new current playlist...
- * allow user to cancel the operation.
- * Do not show if skip_dyn_warning is true */
- if (!skip_dyn_warning)
- {
- if (!warn_on_pl_erase())
- return false;
- }
-
if (playlist_create(dirname, filename) != -1)
{
if (global_settings.playlist_shuffle)
@@ -198,7 +209,7 @@ static int compare(const void* p1, const void* p2)
if (e1->attr & ATTR_DIRECTORY && e2->attr & ATTR_DIRECTORY)
{ /* two directories */
- criteria = compare_sort_dir;
+ criteria = cmp_data.sort_dir;
#ifdef HAVE_MULTIVOLUME
if (e1->attr & ATTR_VOLUME || e2->attr & ATTR_VOLUME)
@@ -233,41 +244,23 @@ static int compare(const void* p1, const void* p2)
if (t1 != t2) /* if different */
return (t1 - t2) * (criteria == SORT_TYPE_REVERSED ? -1 : 1);
- /* else fall through to alphabetical sorting */
+ /* else alphabetical sorting */
+ return cmp_data._compar(e1->name, e2->name, MAX_PATH);
}
case SORT_DATE:
case SORT_DATE_REVERSED:
- /* 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 */
- }
-
+ {
+ 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:
{
- 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);
- }
+ return cmp_data._compar(e1->name, e2->name, MAX_PATH) *
+ (criteria == SORT_ALPHA_REVERSED ? -1 : 1);
}
}
@@ -330,42 +323,43 @@ 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 ( !(dptr->attr & ATTR_DIRECTORY) )
+ if ( !(dir_attr) )
dptr->attr |= filetype_get_attr((char *)entry->d_name);
+ int file_attr = (dptr->attr & FILE_ATTR_MASK);
+
/* filter out non-visible files */
- 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) ||
+ 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) ||
(*c->dirfilter == SHOW_SUPPORTED && !filetype_supported(dptr->attr)))) ||
- (*c->dirfilter == SHOW_WPS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_WPS) ||
- (*c->dirfilter == SHOW_FONT && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FONT) ||
- (*c->dirfilter == SHOW_SBS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_SBS) ||
+ (*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) ||
#if CONFIG_TUNER
- (*c->dirfilter == SHOW_FMS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FMS) ||
+ (*c->dirfilter == SHOW_FMS && file_attr != FILE_ATTR_FMS) ||
#endif
#ifdef HAVE_REMOTE_LCD
- (*c->dirfilter == SHOW_RWPS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RWPS) ||
- (*c->dirfilter == SHOW_RSBS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RSBS) ||
+ (*c->dirfilter == SHOW_RWPS && file_attr != FILE_ATTR_RWPS) ||
+ (*c->dirfilter == SHOW_RSBS && file_attr != FILE_ATTR_RSBS) ||
#if CONFIG_TUNER
- (*c->dirfilter == SHOW_RFMS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_RFMS) ||
+ (*c->dirfilter == SHOW_RFMS && file_attr != FILE_ATTR_RFMS) ||
#endif
#endif
#if CONFIG_TUNER
- (*c->dirfilter == SHOW_FMR && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_FMR) ||
+ (*c->dirfilter == SHOW_FMR && file_attr != FILE_ATTR_FMR) ||
#endif
- (*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 &&
- (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_OPX) ||
+ (*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) ||
(callback_show_item && !callback_show_item(entry->d_name, dptr->attr, c)))
{
continue;
@@ -384,14 +378,29 @@ int ft_load(struct tree_context* c, const char* tempdir)
strcpy(dptr->name, (char *)entry->d_name);
name_buffer_used += len + 1;
- if (dptr->attr & ATTR_DIRECTORY) /* count the remaining dirs */
+ if (dir_attr) /* count the remaining dirs */
c->dirsindir++;
}
c->filesindir = files_in_dir;
c->dirlength = files_in_dir;
closedir(dir);
- compare_sort_dir = c->sort_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;
+ }
+
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
@@ -432,10 +441,17 @@ static void ft_load_font(char *file)
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();
+}
+
int ft_enter(struct tree_context* c)
{
int rc = GO_TO_PREVIOUS;
- static char buf[MAX_PATH];
+ char buf[MAX_PATH];
struct entry* file = tree_get_entry_at(c, c->selected_item);
if (!file)
@@ -480,7 +496,9 @@ int ft_enter(struct tree_context* c)
break;
case FILE_ATTR_AUDIO:
- if (bookmark_autoload(c->currdir))
+ {
+ int res = bookmark_autoload(c->currdir);
+ if (res == BOOKMARK_CANCEL || res == BOOKMARK_DO_RESUME)
break;
splash(0, ID2P(LANG_WAIT));
@@ -514,7 +532,7 @@ int ft_enter(struct tree_context* c)
play = true;
}
break;
-
+ }
#if CONFIG_TUNER
/* fmr preset file */
case FILE_ATTR_FMR:
@@ -539,49 +557,32 @@ int ft_enter(struct tree_context* c)
break;
case FILE_ATTR_FMS:
- splash(0, ID2P(LANG_WAIT));
- set_file(buf, (char *)global_settings.fms_file, MAX_FILENAME);
- settings_apply_skins();
+ ft_apply_skin_file(buf, global_settings.fms_file, MAX_FILENAME);
break;
#ifdef HAVE_REMOTE_LCD
case FILE_ATTR_RFMS:
- splash(0, ID2P(LANG_WAIT));
- set_file(buf, (char *)global_settings.rfms_file, MAX_FILENAME);
- settings_apply_skins();
+ ft_apply_skin_file(buf, global_settings.rfms_file, MAX_FILENAME);
break;
#endif
#endif
-
case FILE_ATTR_SBS:
- splash(0, ID2P(LANG_WAIT));
- set_file(buf, (char *)global_settings.sbs_file, MAX_FILENAME);
- settings_apply_skins();
+ ft_apply_skin_file(buf, global_settings.sbs_file, MAX_FILENAME);
break;
#ifdef HAVE_REMOTE_LCD
case FILE_ATTR_RSBS:
- splash(0, ID2P(LANG_WAIT));
- set_file(buf, (char *)global_settings.rsbs_file, MAX_FILENAME);
- settings_apply_skins();
+ ft_apply_skin_file(buf, global_settings.rsbs_file, MAX_FILENAME);
break;
#endif
/* wps config file */
case FILE_ATTR_WPS:
- splash(0, ID2P(LANG_WAIT));
- set_file(buf, (char *)global_settings.wps_file,
- MAX_FILENAME);
- settings_apply_skins();
+ ft_apply_skin_file(buf, global_settings.wps_file, MAX_FILENAME);
break;
-
#if defined(HAVE_REMOTE_LCD) && (NB_SCREENS > 1)
/* remote-wps config file */
case FILE_ATTR_RWPS:
- splash(0, ID2P(LANG_WAIT));
- set_file(buf, (char *)global_settings.rwps_file,
- MAX_FILENAME);
- settings_apply_skins();
+ ft_apply_skin_file(buf, global_settings.rwps_file, MAX_FILENAME);
break;
#endif
-
case FILE_ATTR_CFG:
splash(0, ID2P(LANG_WAIT));
if (!settings_load_config(buf,true))
@@ -641,6 +642,8 @@ int ft_enter(struct tree_context* c)
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))
{
case PLUGIN_GOTO_WPS:
@@ -664,6 +667,10 @@ 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;
}
@@ -677,7 +684,7 @@ int ft_enter(struct tree_context* c)
break;
}
- struct entry* file = tree_get_entry_at(c, c->selected_item);
+ file = tree_get_entry_at(c, c->selected_item);
if (!file)
{
splashf(HZ, str(LANG_READ_FAILED), str(LANG_UNKNOWN));
@@ -687,6 +694,7 @@ int ft_enter(struct tree_context* c)
plugin = filetype_get_plugin(file, plugin_path, sizeof(plugin_path));
if (plugin)
{
+#ifdef PLUGINS_RUN_IN_BROWSER /* Stay in the filetree to run a plugin */
switch (plugin_load(plugin, argument))
{
case PLUGIN_USB_CONNECTED:
@@ -705,6 +713,10 @@ 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;
}
diff --git a/apps/filetree.h b/apps/filetree.h
index 178ba0e973..7931c3c454 100644
--- a/apps/filetree.h
+++ b/apps/filetree.h
@@ -26,6 +26,7 @@ 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_dyn_warning);
+bool ft_play_playlist(char* pathname, char* dirname,
+ char* filename, bool skip_warn_and_bookmarks);
#endif
diff --git a/apps/filetypes.c b/apps/filetypes.c
index d68bab3daa..1944ee9383 100644
--- a/apps/filetypes.c
+++ b/apps/filetypes.c
@@ -38,6 +38,7 @@
#include "splash.h"
#include "core_alloc.h"
#include "icons.h"
+/*#define LOGF_ENABLE*/
#include "logf.h"
/* max filetypes (plugins & icons stored here) */
@@ -45,111 +46,171 @@
/* max viewer plugins */
#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;
+
/* a table for the known file types */
static const struct filetype inbuilt_filetypes[] = {
- { "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 },
- { "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 },
- { "vtx", 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 },
- { "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 },
+ { "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 },
#ifdef HAVE_REMOTE_LCD
- { "rwps",FILE_ATTR_RWPS, Icon_Wps, VOICE_EXT_RWPS },
+ { "rwps", FILE_ATTR_RWPS },
#endif
#if CONFIG_TUNER
- { "fmr", FILE_ATTR_FMR, Icon_Preset, LANG_FMR },
- { "fms", FILE_ATTR_FMS, Icon_Wps, VOICE_EXT_FMS },
+ { "fmr", FILE_ATTR_FMR },
+ { "fms", FILE_ATTR_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 },
- { "opx", FILE_ATTR_OPX, Icon_Plugin, VOICE_EXT_ROCK },
- { "fnt", FILE_ATTR_FONT,Icon_Font, VOICE_EXT_FONT },
- { "kbd", FILE_ATTR_KBD, Icon_Keyboard, VOICE_EXT_KBD },
- { "bmark",FILE_ATTR_BMARK, Icon_Bookmark, VOICE_EXT_BMARK },
- { "cue", FILE_ATTR_CUE, Icon_Bookmark, VOICE_EXT_CUESHEET },
- { "sbs", FILE_ATTR_SBS, Icon_Wps, VOICE_EXT_SBS },
+ { "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, Icon_Wps, VOICE_EXT_RSBS },
+ { "rsbs", FILE_ATTR_RSBS },
#if CONFIG_TUNER
- { "rfms", FILE_ATTR_RFMS, Icon_Wps, VOICE_EXT_RFMS },
+ { "rfms", FILE_ATTR_RFMS },
#endif
#endif
#ifdef BOOTFILE_EXT
- { BOOTFILE_EXT, FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ },
+ { BOOTFILE_EXT, FILE_ATTR_MOD },
#endif
#ifdef BOOTFILE_EXT2
- { BOOTFILE_EXT2, FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ },
+ { BOOTFILE_EXT2, FILE_ATTR_MOD },
+#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
};
-void tree_get_filetypes(const struct filetype** types, int* count)
+long tree_get_filetype_voiceclip(int attr)
{
- *types = inbuilt_filetypes;
- *count = sizeof(inbuilt_filetypes) / sizeof(*inbuilt_filetypes);
+ 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;
}
#define ROCK_EXTENSION "rock"
@@ -243,8 +304,6 @@ 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
@@ -261,9 +320,9 @@ void read_color_theme_file(void) {
unknown_file.color = -1;
if (!global_settings.colors_file[0] || global_settings.colors_file[0] == '-')
return;
- snprintf(buffer, MAX_PATH, THEME_DIR "/%s.colours",
- global_settings.colors_file);
- fd = open(buffer, O_RDONLY);
+
+ fd = open_pathfmt(buffer, sizeof(buffer), O_RDONLY,
+ THEME_DIR "/%s.colours", global_settings.colors_file);
if (fd < 0)
return;
while (read_line(fd, buffer, MAX_PATH) > 0)
@@ -301,12 +360,12 @@ void read_viewer_theme_file(void)
{
custom_filetype_icons[i] = filetypes[i].icon;
}
-
- snprintf(buffer, MAX_PATH, "%s/%s.icons", ICON_DIR,
- global_settings.viewers_icon_file);
- fd = open(buffer, O_RDONLY);
+
+ fd = open_pathfmt(buffer, sizeof(buffer), O_RDONLY,
+ ICON_DIR "/%s.icons", global_settings.viewers_icon_file);
if (fd < 0)
return;
+
while (read_line(fd, buffer, MAX_PATH) > 0)
{
if (!settings_parseline(buffer, &ext, &icon))
@@ -338,7 +397,7 @@ void read_viewer_theme_file(void)
custom_icons_loaded = true;
}
-static void read_viewers_config(void)
+static void read_viewers_config_init(void)
{
int fd = open(VIEWERS_CONFIG, O_RDONLY);
if(fd < 0)
@@ -350,18 +409,18 @@ static void read_viewers_config(void)
/* estimate bufsize with the filesize, will not be larger */
strdup_bufsize = (size_t)filesz;
- strdup_handle = core_alloc_ex("filetypes", strdup_bufsize, &ops);
+ strdup_handle = core_alloc_ex(strdup_bufsize, &ops);
if(strdup_handle <= 0)
goto out;
- read_config(fd);
- core_shrink(strdup_handle, core_get_data(strdup_handle), strdup_cur_idx);
+ 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;
@@ -372,8 +431,8 @@ void filetype_init(void)
viewer_count = 0;
filetype_count = 1;
- read_builtin_types();
- read_viewers_config();
+ read_builtin_types_init();
+ read_viewers_config_init();
read_viewer_theme_file();
#ifdef HAVE_LCD_COLOR
read_color_theme_file();
@@ -396,22 +455,35 @@ static void rm_whitespaces(char* str)
*s = '\0';
}
-static void read_builtin_types(void)
+static void read_builtin_types_init(void)
{
- int count = sizeof(inbuilt_filetypes)/sizeof(*inbuilt_filetypes), i;
- for(i=0; i<count && (filetype_count < MAX_FILETYPES); i++)
+ 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++)
{
filetypes[filetype_count].extension = inbuilt_filetypes[i].extension;
filetypes[filetype_count].plugin = NULL;
- filetypes[filetype_count].attr = inbuilt_filetypes[i].tree_attr>>8;
+
+ tree_attr = inbuilt_filetypes[i].tree_attr;
+ filetypes[filetype_count].attr = tree_attr>>8;
if (filetypes[filetype_count].attr > highest_attr)
highest_attr = filetypes[filetype_count].attr;
- filetypes[filetype_count].icon = inbuilt_filetypes[i].icon;
+
+ 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;
+ }
+ }
filetype_count++;
}
}
-static void read_config(int fd)
+static void read_config_init(int fd)
{
char line[64], *s, *e;
char *extension, *plugin;
@@ -617,7 +689,7 @@ int filetype_list_viewers(const char* current_file)
int i = viewers[info.selection];
snprintf(plugin, MAX_PATH, "%s/%s." ROCK_EXTENSION,
PLUGIN_DIR, filetypes[i].plugin);
- plugin_load(plugin, current_file);
+ ret = plugin_load(plugin, current_file);
}
return ret;
}
diff --git a/apps/filetypes.h b/apps/filetypes.h
index efe9f3f5df..5aae772a9c 100644
--- a/apps/filetypes.h
+++ b/apps/filetypes.h
@@ -53,14 +53,14 @@
struct filetype {
char* extension;
int tree_attr;
- enum themable_icons icon;
- int voiceclip;
};
-void tree_get_filetypes(const struct filetype**, int*) INIT_ATTR;
+
+long tree_get_filetype_voiceclip(int 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);
diff --git a/apps/gui/bitmap/list-skinned.c b/apps/gui/bitmap/list-skinned.c
index a67ac8cb0a..bebff821f8 100644
--- a/apps/gui/bitmap/list-skinned.c
+++ b/apps/gui/bitmap/list-skinned.c
@@ -213,8 +213,7 @@ 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->show_selection_marker &&
- list_start_item+cur_line == list->selected_item;
+ is_selected = list_start_item+cur_line == list->selected_item;
for (viewport = SKINOFFSETTOPTR(get_skin_buffer(wps.data), listcfg[screen]->data->tree);
viewport;
diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c
index ff0f5a29c1..1c9b73a5fe 100644
--- a/apps/gui/bitmap/list.c
+++ b/apps/gui/bitmap/list.c
@@ -90,11 +90,57 @@ static int list_icon_width(enum screen_type screen)
return get_icon_width(screen) + ICON_PADDING * 2;
}
-static bool draw_title(struct screen *display, struct gui_synclist *list)
+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)
{
const int screen = display->screen_type;
struct viewport *title_text_vp = &title_text[screen];
- struct line_desc line = LINE_DESC_DEFINIT;
+ struct line_desc linedes = LINE_DESC_DEFINIT;
if (sb_set_title_text(list->title, list->title_icon, screen))
return false; /* the sbs is handling the title */
@@ -102,29 +148,41 @@ static bool draw_title(struct screen *display, struct gui_synclist *list)
if (!list_display_title(list, screen))
return false;
*title_text_vp = *(list->parent[screen]);
- line.height = list->line_height[screen];
- title_text_vp->height = line.height;
+ linedes.height = list->line_height[screen];
+ title_text_vp->height = linedes.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)
- line.separator_height = abs(global_settings.list_separator_height)
+ linedes.separator_height = abs(global_settings.list_separator_height)
+ (lcd_get_dpi() > 200 ? 2 : 1);
#endif
#ifdef HAVE_LCD_COLOR
if (list->title_color >= 0)
- line.style |= (STYLE_COLORED|list->title_color);
+ linedes.style |= (STYLE_COLORED|list->title_color);
#endif
- line.scroll = true;
+ linedes.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;
+ }
- 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);
+ 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);
return true;
}
@@ -133,23 +191,30 @@ 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 = (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;
+ 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;
+
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->clear_viewport();
display->scroll_stop_viewport(list_text_vp);
*list_text_vp = *parent;
- if ((show_title = draw_title(display, list)))
+ if ((show_title = draw_title(display, list, callback_draw_item)))
{
int title_height = title_text[screen].height;
list_text_vp->y += title_height;
@@ -169,6 +234,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;
+
int draw_offset = list_start_item * linedes.height - list->y_pos;
/* draw some extra items to not have empty lines at the top and bottom */
if (draw_offset > 0)
@@ -179,31 +250,55 @@ void list_draw(struct screen *display, struct gui_synclist *list)
if (start > 0)
start--;
}
- else if (draw_offset < 0)
- end++;
+ 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
#define draw_offset 0
#endif
/* draw the scrollbar if its needed */
- if (global_settings.scrollbar != SCROLLBAR_OFF)
+ if (list->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
gui_scrollbar_draw(display,
(scrollbar_in_left? 0: 1), 0, SCROLLBAR_WIDTH-1, vp.height,
- list->nb_items, list_start_item, list_start_item + nb_lines,
- VERTICAL);
+ scrollbar_items, scrollbar_min, scrollbar_max, VERTICAL);
display->set_viewport(last);
}
/* shift everything a bit in relation to the title */
@@ -214,6 +309,16 @@ void list_draw(struct screen *display, struct gui_synclist *list)
}
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 */
@@ -221,7 +326,6 @@ 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;
@@ -237,17 +341,17 @@ void list_draw(struct screen *display, struct gui_synclist *list)
}
if (line_indent)
{
- if (global_settings.show_icons)
- line_indent *= list_icon_width(screen);
+ if (list->show_icons)
+ line_indent *= icon_w;
else
- line_indent *= display->getcharwidth();
+ line_indent *= character_width;
}
line_indent += indent;
/* 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, text_pos,
+ item_offset = gui_list_get_item_offset(list, item_width, indent + (list->show_icons ? icon_w : 0),
display, list_text_vp);
/* draw the selected line */
@@ -257,8 +361,7 @@ void list_draw(struct screen *display, struct gui_synclist *list)
!hide_selection &&
#endif
i >= list->selected_item
- && i < list->selected_item + list->selected_size
- && list->show_selection_marker)
+ && i < list->selected_item + list->selected_size)
{/* The selected item must be displayed scrolling */
#ifdef HAVE_LCD_COLOR
if (list->selection_color)
@@ -271,12 +374,12 @@ void list_draw(struct screen *display, struct gui_synclist *list)
}
else
#endif
- if (global_settings.cursor_style == 1
+ if (list->cursor_style == SYNCLIST_CURSOR_INVERT
#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 && global_settings.cursor_style)
+ || (display->depth < 16 && list->cursor_style)
#endif
)
{
@@ -284,14 +387,14 @@ void list_draw(struct screen *display, struct gui_synclist *list)
style = STYLE_INVERT;
}
#ifdef HAVE_LCD_COLOR
- else if (global_settings.cursor_style == 2)
+ else if (list->cursor_style == SYNCLIST_CURSOR_COLOR)
{
/* Display colour line selector */
style = STYLE_COLORBAR;
linedes.text_color = global_settings.lst_color;
linedes.line_color = global_settings.lss_color;
}
- else if (global_settings.cursor_style == 3)
+ else if (list->cursor_style == SYNCLIST_CURSOR_GRADIENT)
{
/* Display gradient line selector */
style = STYLE_GRADIENT;
@@ -315,27 +418,22 @@ 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;
- /* 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);
+
+
+ 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);
}
display->set_viewport(parent);
display->update_viewport();
@@ -360,21 +458,28 @@ 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)
{
- /* scrollbar scrolling is still line based */
- int scrollbar_size = nb_lines * gui_list->line_height[screen];
- int actual_y = y - list_text[screen].y;
- int new_selection = (actual_y * gui_list->nb_items) / scrollbar_size;
+ const int line_height = gui_list->line_height[screen];
- 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;
+ /* try to position the center of the scrollbar at the touch point */
+ int scrollbar_size = list_text[screen].height;
+ 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;
+ }
- gui_list->start_item[screen] = start_item;
- gui_list->y_pos = start_item * gui_list->line_height[screen];
+ gui_list->start_item[screen] = new_start;
+ gui_list->y_pos = new_y_pos;
return ACTION_REDRAW;
}
@@ -509,6 +614,7 @@ 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;
@@ -517,8 +623,8 @@ static bool swipe_scroll(struct gui_synclist * gui_list, int difference)
gui_list->y_pos -= difference;
if(gui_list->y_pos < 0)
gui_list->y_pos = 0;
- else if(gui_list->y_pos > (gui_list->nb_items - nb_lines) * line_height)
- gui_list->y_pos = (gui_list->nb_items - nb_lines) * line_height;
+ else if(gui_list->y_pos > max_y_pos)
+ gui_list->y_pos = max_y_pos;
else
hit_end = false;
@@ -647,7 +753,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 && global_settings.show_icons)
+ if (list->title_icon != Icon_NOICON && list->show_icons)
{
int width = list_icon_width(screen);
struct viewport vp = *title;
@@ -665,14 +771,19 @@ static int get_click_location(struct gui_synclist *list, int x, int y)
{
bool on_scrollbar_clicked;
int adj_x = x - parent->x;
- switch (global_settings.scrollbar)
+ switch (list->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;
- default:
- on_scrollbar_clicked = false; break;
+ on_scrollbar_clicked = adj_x > (title->x + title->width - SCROLLBAR_WIDTH);
+ break;
}
if (on_scrollbar_clicked)
retval = SCROLLBAR;
diff --git a/apps/gui/color_picker.c b/apps/gui/color_picker.c
index a32f1ee179..ef17c0a230 100644
--- a/apps/gui/color_picker.c
+++ b/apps/gui/color_picker.c
@@ -154,7 +154,6 @@ 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;
@@ -253,17 +252,16 @@ 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->putsxy(text_x, text_top, buf);
+ display->putsxyf(text_x, text_top, "%c", str(LANG_COLOR_RGB_LABELS)[i]);
/* Draw color value */
+ vp.flags |= VP_FLAG_ALIGN_RIGHT;
if (display->depth >= 24)
- snprintf(buf, 4, "%03d", rgb->rgb_val[i] & 0xFF);
+ display->putsxyf(text_x, text_top, "%03d", rgb->rgb_val[i] & 0xFF);
else
- snprintf(buf, 3, "%02d", rgb->rgb_val[i] & 0x3F);
- vp.flags |= VP_FLAG_ALIGN_RIGHT;
- display->putsxy(text_x, text_top, buf);
+ display->putsxyf(text_x, text_top, "%02d", rgb->rgb_val[i] & 0x3F);
+
+
/* Draw scrollbar */
gui_scrollbar_draw(display, /* screen */
@@ -280,9 +278,6 @@ 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)
{
@@ -301,8 +296,9 @@ 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);
-
- display->putsxy(0, top + (height - char_height) / 2, buf);
+ /* Format RGB: #rrggbb */
+ display->putsxyf(0, top + (height - char_height) / 2,
+ str(LANG_COLOR_RGB_VALUE), rgb->red, rgb->green, rgb->blue);
/* Draw border around the rect */
set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
@@ -318,7 +314,9 @@ static void draw_screen(struct screen *display, char *title,
if (height >= char_height)
{
set_drawinfo(display, DRMODE_SOLID, text_color, background_color);
- display->putsxy(0, top + (height - char_height) / 2, buf);
+ /* Format RGB: #rrggbb */
+ display->putsxyf(0, top + (height - char_height) / 2,
+ str(LANG_COLOR_RGB_VALUE), rgb->red, rgb->green, rgb->blue);
}
}
diff --git a/apps/gui/folder_select.c b/apps/gui/folder_select.c
index 706b166941..a76d77562b 100644
--- a/apps/gui/folder_select.c
+++ b/apps/gui/folder_select.c
@@ -8,6 +8,7 @@
*
* 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
@@ -30,7 +31,11 @@
#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:
@@ -56,18 +61,31 @@ 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 = (size + 3) & ~3;
+ size = ALIGN_UP(size, 4);
if (buffer_front + size > buffer_end)
{
return NULL;
@@ -86,32 +104,57 @@ static char* folder_alloc_from_end(size_t size)
buffer_end -= size;
return buffer_end;
}
-
-static void get_full_path_r(struct folder *start, char* dst)
+#if 0
+/* returns the buffer size required to store the path + \0 */
+static int get_full_pathsz(struct folder *start)
{
- if (start->previous)
- get_full_path_r(start->previous, dst);
-
- if (start->name && start->name[0] && strcmp(start->name, "/"))
+ int reql = 0;
+ struct folder *next = start;
+ do
{
- strlcat(dst, "/", MAX_PATH);
- strlcat(dst, start->name, MAX_PATH);
- }
+ reql += strlen(next->name) + 1;
+ } while ((next = next->previous));
+
+ if (start->name[0] != '/') reql--;
+ if (--reql < 0) reql = 0;
+ return reql;
}
+#endif
-static char* get_full_path(struct folder *start)
+static size_t get_full_path(struct folder *start, char *dst, size_t dst_sz)
{
- static char buffer[MAX_PATH];
-
- if (strcmp(start->name, "/"))
+ 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 */
{
- buffer[0] = 0;
- get_full_path_r(start, buffer);
+#define PATHMUTATE() \
+ ({ \
+ prev = cur; \
+ cur = next; \
+ next = cur->previous;\
+ cur->previous = prev; \
+ })
+ PATHMUTATE();
}
- else /* get_full_path_r() does the wrong thing for / */
- return "/";
-
- return 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
}
/* support function for qsort() */
@@ -125,49 +168,52 @@ 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;
- if (!strcmp(folder,"/"))
- strlcpy(fullpath, folder, 2);
- else
- snprintf(fullpath, MAX_PATH, "%s/%s", parent ? path : "", folder);
+ 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 (!this)
- return NULL;
dir = opendir(fullpath);
- if (!dir)
- return NULL;
+ if (dir == NULL)
+ goto fail;
this->previous = parent;
this->name = folder;
this->children = NULL;
this->children_count = 0;
- this->depth = parent ? parent->depth + 1 : 0;
+ if (parent)
+ this->depth = parent->depth + 1;
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 ((info.attribute & ATTR_DIRECTORY) == 0) {
+ if ((dir_get_info(dir, entry).attribute & ATTR_DIRECTORY) == 0) {
continue;
}
- /* skip directories . and .. */
- if ((!strcmp((char *)entry->d_name, ".")) ||
- (!strcmp((char *)entry->d_name, ".."))) {
+ /* skip . and .. */
+ char *dn = entry->d_name;
+ if ((dn[0] == '.') && (dn[1] == '\0' || (dn[1] == '.' && dn[2] == '\0')))
continue;
- }
- char *name = folder_alloc_from_end(len+1);
- if (!name)
+ /* 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);
- return NULL;
+ goto fail;
}
memcpy(name, (char *)entry->d_name, len+1);
child_count++;
@@ -177,26 +223,29 @@ 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)
- return NULL;
+ if (this->children == NULL)
+ goto fail;
+
while (child_count)
{
- 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;
+ 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 */
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;
@@ -205,7 +254,7 @@ struct folder* load_root(void)
.name = "",
.children = &root_child,
.children_count = 1,
- .depth = -1,
+ .depth = 0,
.previous = NULL,
};
@@ -230,7 +279,6 @@ 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)
@@ -262,22 +310,22 @@ static const char * folder_get_name(int selected_item, void * data,
struct folder *parent;
struct child *this = find_index(root, selected_item , &parent);
- buffer[0] = '\0';
-
- if (parent->depth >= 0)
- for(int i = 0; i <= parent->depth; i++)
- strcat(buffer, "\t");
-
+ 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';
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),
- this->name);
- strlcat(buffer, ")", buffer_len);
+ snprintf(&buffer[len], buffer_len - len, str(LANG_READ_FAILED), ")");
}
}
@@ -304,6 +352,23 @@ 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;
@@ -322,17 +387,13 @@ static int folder_action_callback(int action, struct gui_synclist *list)
this->state = COLLAPSED;
break;
case COLLAPSED:
- if (this->folder == NULL)
- this->folder = load_folder(parent, this->name);
- this->state = this->folder ? (this->folder->children_count == 0 ?
- SELECTED : EXPANDED) : EACCESS;
+ child_set_state_expand(this, parent);
break;
case EACCESS:
/* cannot open, do nothing */
return action;
}
- list->nb_items = count_items(root);
- return ACTION_REDRAW;
+ action = ACTION_REDRAW;
}
else if (action == ACTION_STD_CONTEXT)
{
@@ -342,140 +403,198 @@ 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];
- if (child->state == SELECTED ||
- child->state == EXPANDED)
- child->state = COLLAPSED;
- else if (child->state == COLLAPSED)
- child->state = SELECTED;
+ switch (child->state)
+ {
+ case SELECTED:
+ case EXPANDED:
+ child->state = COLLAPSED;
+ break;
+ case COLLAPSED:
+ child->state = SELECTED;
+ break;
+ case EACCESS:
+ break;
+ }
}
break;
case SELECTED:
case COLLAPSED:
- 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++)
+ if (child_set_state_expand(this, parent) != EACCESS)
{
- child = &this->folder->children[i];
- child->state = SELECTED;
+ for (i = 0; i < (this->folder->children_count); i++)
+ {
+ child = &this->folder->children[i];
+ child->state = SELECTED;
+ }
}
break;
case EACCESS:
/* cannot open, do nothing */
return action;
}
- list->nb_items = count_items(root);
- return ACTION_REDRAW;
+ action = ACTION_REDRAW;
}
-
-
+ if (action == ACTION_REDRAW)
+ list->nb_items = count_items(root);
return action;
}
-static struct child* find_from_filename(char* filename, struct folder *root)
+static struct child* find_from_filename(const 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 (slash == filename)
+ if (filename[0] == '/') /* in the loop nothing starts with '/' */
{
+ logf("find_from_filename [%s]", filename);
/* filename begins with /. in this case root must be the
* top level folder */
this = &root->children[0];
- if (!slash[1])
+ if (filename[1] == '\0')
{ /* filename == "/" */
return this;
}
- 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);
- }
+ else /* filename == "/XXX/YYY". cascade down */
+ goto cascade;
}
- while (i < root->children_count)
+ for (int i = 0; i < root->children_count; i++)
{
this = &root->children[i];
- if (!strcasecmp(this->name, filename))
+ /* when slash == NULL n will be really large but \0 stops the compare */
+ if (strncasecmp(this->name, filename, slash - filename) == 0)
{
- if (!slash)
+ if (slash == NULL)
{ /* filename == XXX */
return this;
}
else
- {
- /* 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);
- }
+ goto cascade;
}
- 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);
}
-/* _modifies_ buf */
-int select_paths(struct folder* root, char* buf)
+static int select_paths(struct folder* root, const char* filenames)
{
- struct child *item = find_from_filename(buf, root);
- if (item)
- item->state = SELECTED;
+ /* 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;
+ }
+
return 0;
}
-static void save_folders_r(struct folder *root, char* dst, size_t maxlen)
+static void save_folders_r(struct folder *root, char* dst, size_t maxlen, size_t buflen)
{
- int i = 0;
+ size_t len;
+ struct folder *curfolder;
+ char* name;
- while (i < root->children_count)
+ for (int i = 0; i < root->children_count; i++)
{
struct child *this = &root->children[i];
if (this->state == SELECTED)
{
- if (this->folder)
- snprintf(buffer_front, buffer_end - buffer_front,
- "%s:", get_full_path(this->folder));
+ if (this->folder == NULL)
+ {
+ curfolder = root;
+ name = this->name;
+ logf("save_folders_r: this->name[%s]", name);
+ }
else
{
- char *p = get_full_path(root);
- snprintf(buffer_front, buffer_end - buffer_front,
- "%s/%s:", strcmp(p, "/") ? p : "",
- strcmp(this->name, "/") ? this->name : "");
+ 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;
}
- strlcat(dst, buffer_front, maxlen);
}
else if (this->state == EXPANDED)
- save_folders_r(this->folder, dst, maxlen);
- i++;
+ save_folders_r(this->folder, dst, maxlen, buflen);
}
}
-static void save_folders(struct folder *root, char* dst, size_t maxlen)
+static uint32_t save_folders(struct folder *root, char* dst, size_t maxlen)
{
- int len;
+ hashed.len = 0;
+ hashed.val = 0;
+ hashed.maxlen_exceeded = 0;
+ size_t len = buffer_end - buffer_front;
dst[0] = '\0';
- save_folders_r(root, dst, maxlen);
+ save_folders_r(root, dst, maxlen, len);
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)
@@ -483,40 +602,32 @@ 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();
- if (nb_items > 0)
- {
- for(int i = 0; i < nb_items; i++)
- select_paths(root, vect[i]);
- }
-
+ 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);
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 */
- save_folders(root, copy, setting_len);
- if (strcmp(copy, setting))
- { /* prompt for saving changes and commit if yes */
+ if (hash != save_folders(root, hashed.buf, setting_len))
+ { /* prompt for saving changes and commit if yes */
if (yesno_pop(ID2P(LANG_SAVE_CHANGES)))
{
- strcpy(setting, copy);
+ save_folders(root, setting, setting_len);
settings_save();
+ logf("folders out: %s", setting);
return true;
}
}
diff --git a/apps/gui/icon.c b/apps/gui/icon.c
index 9fe7090f4a..7a59a72151 100644
--- a/apps/gui/icon.c
+++ b/apps/gui/icon.c
@@ -32,6 +32,7 @@
#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)
@@ -63,7 +64,6 @@ 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 ? \
@@ -160,8 +160,6 @@ 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;
}
@@ -169,59 +167,27 @@ 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)
{
- ssize_t size_read;
- ssize_t buf_size;
- int fd;
- int bmpformat = (FORMAT_ANY|FORMAT_DITHER|FORMAT_TRANSPARENT);
+ static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL, NULL};
+ const int bmpformat = (FORMAT_ANY|FORMAT_DITHER|FORMAT_TRANSPARENT);
struct iconset *ic = &iconsets[iconset][screen];
+ ssize_t buf_reqd;
ic->loaded = false;
- ic->handle = 0;
+ ic->handle = CLB_ALOC_ERR;
if (filename[0] && filename[0] != '-')
{
- char path[MAX_PATH];
-
- snprintf(path, sizeof(path), ICON_DIR "/%s.bmp", filename);
- fd = open(path, O_RDONLY);
- if (fd < 0)
- return;
- buf_size = read_bmp_fd(fd, &ic->bmp, 0,
- bmpformat|FORMAT_RETURN_SIZE, NULL);
- if (buf_size > 0)
- ic->handle = core_alloc_ex(filename, (size_t) buf_size, &buflib_ops);
-
- if (ic->handle <= 0)
- {
- /* error */
- goto finished;
- }
- 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);
- ic->handle_locked = 0;
-
- if (size_read < 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)
{
- /* error */
- size_read = 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->bmp.data = core_get_data(ic->handle);
ic->loaded = true;
-finished:
- close(fd);
- return;
+ }
}
}
diff --git a/apps/gui/line.c b/apps/gui/line.c
index d319ff3c51..7e84aa7b31 100644
--- a/apps/gui/line.c
+++ b/apps/gui/line.c
@@ -264,8 +264,7 @@ next:
else
{
/* any other character here is an erroneous format string */
- snprintf(tempbuf, sizeof(tempbuf), "<E:%c>", ch);
- display->putsxy(xpos, y, tempbuf);
+ display->putsxyf(xpos, y, "<E:%c>", ch);
/* Don't consider going forward, fix the caller */
return;
}
diff --git a/apps/gui/list.c b/apps/gui/list.c
index 13a850bd7b..652279a9de 100644
--- a/apps/gui/list.c
+++ b/apps/gui/list.c
@@ -47,12 +47,6 @@
*/
#define FRAMEDROP_TRIGGER 6
-static int offset_step = 16; /* pixels per screen scroll step */
-/* should lines scroll out of the screen */
-static bool offset_out_of_view = false;
-
-static void gui_list_select_at_offset(struct gui_synclist * gui_list,
- int offset);
void list_draw(struct screen *display, struct gui_synclist *list);
static long last_dirty_tick;
@@ -129,6 +123,18 @@ 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;
+}
+
/*
* Initializes a scrolling list
* - gui_list : the list structure to initialize
@@ -150,8 +156,11 @@ 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
@@ -167,7 +176,6 @@ 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;
@@ -176,7 +184,6 @@ 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;
@@ -185,13 +192,6 @@ void gui_synclist_init(struct gui_synclist * gui_list,
#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;
-}
-
-
int gui_list_get_item_offset(struct gui_synclist * gui_list,
int item_width,
int text_pos,
@@ -200,7 +200,7 @@ int gui_list_get_item_offset(struct gui_synclist * gui_list,
{
int item_offset;
- if (offset_out_of_view)
+ if (global_settings.offset_out_of_view)
{
item_offset = gui_list->offset_position[display->screen_type];
}
@@ -254,15 +254,11 @@ static void gui_list_put_selection_on_screen(struct gui_synclist * gui_list,
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);
- if (gui_list->show_selection_marker == false)
- {
- new_start_item = gui_list->selected_item;
- }
- else if (gui_list->selected_size >= nb_lines)
+ if (gui_list->selected_size >= nb_lines)
{
new_start_item = gui_list->selected_item;
}
- else if (global_settings.scroll_paginated)
+ else if (gui_list->scroll_paginated)
{
nb_lines -= nb_lines%gui_list->selected_size;
if (difference < 0 || difference >= nb_lines)
@@ -292,7 +288,7 @@ static void gui_list_put_selection_on_screen(struct gui_synclist * gui_list,
static void edge_beep(struct gui_synclist * gui_list, bool wrap)
{
- if (global_settings.keyclick)
+ if (gui_list->keyclick)
{
list_speak_item *cb = gui_list->callback_speak_item;
if (!wrap) /* a bounce */
@@ -355,7 +351,7 @@ static void _gui_synclist_speak_item(struct gui_synclist *lists)
void gui_synclist_speak_item(struct gui_synclist *lists)
{
- if (global_settings.talk_menu)
+ if (lists->talk_menu)
{
if (lists->nb_items == 0)
talk_id(VOICE_EMPTY_LIST, true);
@@ -383,7 +379,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)
+ int offset, bool allow_wrap)
{
int new_selection;
if (gui_list->selected_size > 1)
@@ -395,41 +391,15 @@ static void gui_list_select_at_offset(struct gui_synclist * gui_list,
if (new_selection >= gui_list->nb_items)
{
- new_selection = gui_list->limit_scroll ?
- gui_list->nb_items - gui_list->selected_size : 0;
- edge_beep(gui_list, !gui_list->limit_scroll);
+ new_selection = allow_wrap ? 0 : gui_list->nb_items - gui_list->selected_size;
+ edge_beep(gui_list, allow_wrap);
}
else if (new_selection < 0)
{
- new_selection = gui_list->limit_scroll ?
- 0 : gui_list->nb_items - gui_list->selected_size;
- edge_beep(gui_list, !gui_list->limit_scroll);
+ new_selection = allow_wrap ? gui_list->nb_items - gui_list->selected_size : 0;
+ edge_beep(gui_list, allow_wrap);
}
- 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;
- }
-#ifdef HAVE_TOUCHSCREEN
- gui_list->y_pos = gui_list->start_item[SCREEN_MAIN] * gui_list->line_height[SCREEN_MAIN];
-#endif
- }
- return;
- }
gui_synclist_select_item(gui_list, new_selection);
}
@@ -460,22 +430,12 @@ void gui_synclist_del_item(struct gui_synclist * gui_list)
}
}
-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;
-}
-
/*
* 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,
- char * title, enum themable_icons icon)
+ const char * title, enum themable_icons icon)
{
gui_list->title = title;
gui_list->title_icon = icon;
@@ -543,26 +503,25 @@ void gui_synclist_set_sel_color(struct gui_synclist * lists,
#endif
static void gui_synclist_select_next_page(struct gui_synclist * lists,
- enum screen_type screen)
+ enum screen_type screen,
+ bool allow_wrap)
{
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);
+
+ gui_list_select_at_offset(lists, nb_lines, allow_wrap);
}
static void gui_synclist_select_previous_page(struct gui_synclist * lists,
- enum screen_type screen)
+ enum screen_type screen,
+ bool allow_wrap)
{
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);
-}
-void gui_synclist_limit_scroll(struct gui_synclist * lists, bool scroll)
-{
- lists->limit_scroll = scroll;
+ gui_list_select_at_offset(lists, -nb_lines, allow_wrap);
}
/*
@@ -577,7 +536,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] += offset_step;
+ lists->offset_position[i] += global_settings.screen_scroll_step;
if (lists->offset_position[i] > 1000)
lists->offset_position[i] = 1000;
}
@@ -591,7 +550,7 @@ static void gui_synclist_scroll_left(struct gui_synclist * lists)
{
FOR_NB_SCREENS(i)
{
- lists->offset_position[i] -= offset_step;
+ lists->offset_position[i] -= global_settings.screen_scroll_step;
if (lists->offset_position[i] < 0)
lists->offset_position[i] = 0;
}
@@ -601,16 +560,22 @@ bool gui_synclist_keyclick_callback(int action, void* data)
{
struct gui_synclist *lists = (struct gui_synclist *)data;
- /* 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;
+ /* Block the beep if we're at the end of the list and we're not wrapping. */
if (lists->selected_item == 0)
- return (action != ACTION_STD_PREV && action != ACTION_STD_PREVREPEAT);
+ {
+ if (action == ACTION_STD_PREVREPEAT)
+ return false;
+ if (action == ACTION_STD_PREV && !lists->wraparound)
+ return false;
+ }
+
if (lists->selected_item == lists->nb_items - lists->selected_size)
- return (action != ACTION_STD_NEXT && action != ACTION_STD_NEXTREPEAT);
+ {
+ if (action == ACTION_STD_NEXTREPEAT)
+ return false;
+ if (action == ACTION_STD_NEXT && !lists->wraparound)
+ return false;
+ }
return action != ACTION_NONE;
}
@@ -635,8 +600,7 @@ 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, enum list_wrap wrap)
+bool gui_synclist_do_button(struct gui_synclist * lists, int *actionptr)
{
int action = *actionptr;
static bool pgleft_allow_cancel = false;
@@ -683,23 +647,13 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
/* Disable the skin redraw callback */
current_lists = NULL;
- 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;
- };
+ /* 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 (action)
{
@@ -709,17 +663,15 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
#ifdef HAVE_VOLUME_IN_LIST
case ACTION_LIST_VOLUP:
- global_settings.volume += sound_steps(SOUND_VOLUME);
- setvol();
+ adjust_volume(1);
return true;
case ACTION_LIST_VOLDOWN:
- global_settings.volume -= sound_steps(SOUND_VOLUME);
- setvol();
+ adjust_volume(-1);
return true;
#endif
case ACTION_STD_PREV:
case ACTION_STD_PREVREPEAT:
- gui_list_select_at_offset(lists, -next_item_modifier);
+ gui_list_select_at_offset(lists, -next_item_modifier, allow_wrap);
#ifndef HAVE_WHEEL_ACCELERATION
if (button_queue_count() < FRAMEDROP_TRIGGER)
#endif
@@ -730,7 +682,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
case ACTION_STD_NEXT:
case ACTION_STD_NEXTREPEAT:
- gui_list_select_at_offset(lists, next_item_modifier);
+ gui_list_select_at_offset(lists, next_item_modifier, allow_wrap);
#ifndef HAVE_WHEEL_ACCELERATION
if (button_queue_count() < FRAMEDROP_TRIGGER)
#endif
@@ -754,7 +706,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
if (lists->offset_position[0] == 0)
{
pgleft_allow_cancel = true;
- *actionptr = ACTION_STD_CANCEL;
+ *actionptr = ACTION_STD_MENU;
return true;
}
*actionptr = ACTION_TREE_PGLEFT;
@@ -781,7 +733,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
SCREEN_REMOTE :
#endif
SCREEN_MAIN;
- gui_synclist_select_previous_page(lists, screen);
+ gui_synclist_select_previous_page(lists, screen, allow_wrap);
gui_synclist_draw(lists);
yield();
*actionptr = ACTION_STD_NEXT;
@@ -796,7 +748,7 @@ bool gui_synclist_do_button(struct gui_synclist * lists,
SCREEN_REMOTE :
#endif
SCREEN_MAIN;
- gui_synclist_select_next_page(lists, screen);
+ gui_synclist_select_next_page(lists, screen, allow_wrap);
gui_synclist_draw(lists);
yield();
*actionptr = ACTION_STD_PREV;
@@ -835,8 +787,7 @@ 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,
- enum list_wrap wrap)
+ struct gui_synclist *lists, int *action)
/* 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. */
@@ -844,14 +795,7 @@ bool list_do_action(int context, int timeout,
timeout = list_do_action_timeout(lists, timeout);
keyclick_set_callback(gui_synclist_keyclick_callback, lists);
*action = get_action(context, timeout);
- 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;
+ return gui_synclist_do_button(lists, action);
}
/* Simple use list implementation */
@@ -911,7 +855,6 @@ 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
@@ -936,12 +879,6 @@ bool simplelist_show_list(struct simplelist_info *info)
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);
@@ -960,8 +897,7 @@ bool simplelist_show_list(struct simplelist_info *info)
while(1)
{
- list_do_action(CONTEXT_LIST, info->timeout,
- &lists, &action, wrap);
+ list_do_action(CONTEXT_LIST, info->timeout, &lists, &action);
/* We must yield in this case or no other thread can run */
if (info->timeout == TIMEOUT_NOBLOCK)
@@ -1025,7 +961,6 @@ 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;
diff --git a/apps/gui/list.h b/apps/gui/list.h
index 64ff3e3fdd..40a27d1061 100644
--- a/apps/gui/list.h
+++ b/apps/gui/list.h
@@ -30,10 +30,12 @@
#define SCROLLBAR_WIDTH global_settings.scrollbar_width
-enum list_wrap {
- LIST_WRAP_ON = 0,
- LIST_WRAP_OFF,
- LIST_WRAP_UNLESS_HELD,
+enum synclist_cursor
+{
+ SYNCLIST_CURSOR_NOSTYLE = 0,
+ SYNCLIST_CURSOR_INVERT,
+ SYNCLIST_CURSOR_COLOR,
+ SYNCLIST_CURSOR_GRADIENT,
};
/*
@@ -69,6 +71,35 @@ 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
* - data : a void pointer to the data you gave to the list when you
@@ -110,14 +141,20 @@ struct list_selection_color
struct gui_synclist
{
- /* 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
+ /*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
* 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;
@@ -133,14 +170,14 @@ struct gui_synclist
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 */
- char * title;
+ const 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;
@@ -152,11 +189,6 @@ struct gui_synclist
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);
extern void gui_synclist_init(
struct gui_synclist * lists,
@@ -185,13 +217,8 @@ 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_limit_scroll(struct gui_synclist * lists, bool scroll);
-extern void gui_synclist_set_title(struct gui_synclist * lists, char * title,
+extern void gui_synclist_set_title(struct gui_synclist * lists, const 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);
extern bool gui_synclist_keyclick_callback(int action, void* data);
/*
@@ -199,20 +226,9 @@ extern bool gui_synclist_keyclick_callback(int action, void* data);
* 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,
- enum list_wrap);
+extern bool gui_synclist_do_button(struct gui_synclist * lists, int *action);
#if !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;
-};
+struct listitem_viewport_cfg;
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);
@@ -244,8 +260,7 @@ 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,
- enum list_wrap wrap);
+ struct gui_synclist *lists, int *action);
/** Simplelist implementation.
@@ -254,10 +269,9 @@ extern bool list_do_action(int context, int timeout,
**/
struct simplelist_info {
- char *title; /* title to show on the list */
+ const 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' */
@@ -303,7 +317,6 @@ 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;
diff --git a/apps/gui/option_select.c b/apps/gui/option_select.c
index 9f1f0a64e3..8839f42e42 100644
--- a/apps/gui/option_select.c
+++ b/apps/gui/option_select.c
@@ -68,8 +68,8 @@ const char *option_get_valuestring(const struct settings_list *setting,
if ((setting->flags & F_BOOL_SETTING) == F_BOOL_SETTING)
{
bool val = (bool)temp_var;
- strlcpy(buffer, str(val? setting->bool_setting->lang_yes :
- setting->bool_setting->lang_no), buf_len);
+ strmemccpy(buffer, str(val? setting->bool_setting->lang_yes :
+ setting->bool_setting->lang_no), buf_len);
}
#if 0 /* probably dont need this one */
else if ((setting->flags & F_FILENAME) == F_FILENAME)
@@ -117,23 +117,21 @@ const char *option_get_valuestring(const struct settings_list *setting,
{
if (setting->flags & F_CHOICETALKS)
{
- int setting_id;
const struct choice_setting *info = setting->choice_setting;
if (info->talks[(int)temp_var] < LANG_LAST_INDEX_IN_ARRAY)
{
- strlcpy(buffer, str(info->talks[(int)temp_var]), buf_len);
+ strmemccpy(buffer, str(info->talks[(int)temp_var]), buf_len);
}
else
{
- find_setting(setting->setting, &setting_id);
- cfg_int_to_string(setting_id, (int)temp_var, buffer, buf_len);
+ cfg_int_to_string(setting, (int)temp_var, buffer, buf_len);
}
}
else
{
int value = (int)temp_var;
char *val = P2STR(setting->choice_setting->desc[value]);
- strlcpy(buffer, val, buf_len);
+ strmemccpy(buffer, val, buf_len);
}
}
return str;
@@ -334,29 +332,35 @@ static int selection_to_val(const struct settings_list *setting, int selection)
else if ((setting->flags & F_T_SOUND) == F_T_SOUND)
{
int setting_id = setting->sound_setting->setting;
-#ifndef ASCENDING_INT_SETTINGS
- step = sound_steps(setting_id);
- max = (setting_id == SOUND_VOLUME) ?
- global_settings.volume_limit : sound_max(setting_id);
- /* min = sound_min(setting_id); */
-#else
- step = -sound_steps(setting_id);
- /* min = sound_max(setting_id); */
- max = sound_min(setting_id);
-#endif
+ if(global_settings.list_order == LIST_ORDER_DESCENDING)
+ {
+ step = sound_steps(setting_id);
+ max = (setting_id == SOUND_VOLUME) ?
+ global_settings.volume_limit : sound_max(setting_id);
+ /* min = sound_min(setting_id); */
+ }
+ else
+ {
+ step = -sound_steps(setting_id);
+ /* min = sound_max(setting_id); */
+ max = sound_min(setting_id);
+ }
}
else if ((setting->flags & F_INT_SETTING) == F_INT_SETTING)
{
const struct int_setting *info = setting->int_setting;
-#ifndef ASCENDING_INT_SETTINGS
- /* min = info->min; */
- max = info->max;
- step = info->step;
-#else
- max = info->min;
- /* min = info->max; */
- step = -info->step;
-#endif
+ if(global_settings.list_order == LIST_ORDER_DESCENDING)
+ {
+ /* min = info->min; */
+ max = info->max;
+ step = info->step;
+ }
+ else
+ {
+ max = info->min;
+ /* min = info->max; */
+ step = -info->step;
+ }
}
return max- (selection * step);
}
@@ -424,11 +428,10 @@ static void val_to_selection(const struct settings_list *setting, int oldvalue,
int max = (setting_id == SOUND_VOLUME) ?
global_settings.volume_limit : sound_max(setting_id);
*nb_items = (max-min)/steps + 1;
-#ifndef ASCENDING_INT_SETTINGS
- *selected = (max - oldvalue) / steps;
-#else
- *selected = (oldvalue - min) / steps;
-#endif
+ if (global_settings.list_order == LIST_ORDER_DESCENDING)
+ *selected = (max - oldvalue) / steps;
+ else
+ *selected = (oldvalue - min) / steps;
*function = sound_get_fn(setting_id);
}
else
@@ -439,11 +442,10 @@ static void val_to_selection(const struct settings_list *setting, int oldvalue,
min = info->min;
step = info->step;
*nb_items = (max-min)/step + 1;
-#ifndef ASCENDING_INT_SETTINGS
- *selected = (max - oldvalue) / step;
-#else
- *selected = (oldvalue - min) / step;
-#endif
+ if(global_settings.list_order == LIST_ORDER_DESCENDING)
+ *selected = (max - oldvalue) / step;
+ else
+ *selected = (oldvalue - min) / step;
*function = info->option_callback;
}
}
@@ -502,15 +504,18 @@ bool option_screen(const struct settings_list *setting,
gui_synclist_set_nb_items(&lists, nb_items);
gui_synclist_select_item(&lists, selected);
- gui_synclist_limit_scroll(&lists, true);
gui_synclist_draw(&lists);
/* talk the item */
gui_synclist_speak_item(&lists);
while (!done)
{
+ /* override user wraparound setting; used mainly by EQ settings.
+ * Not sure this is justified? */
+ if (!allow_wrap)
+ lists.wraparound = false;
+
if (list_do_action(CONTEXT_LIST, HZ, /* HZ so the status bar redraws */
- &lists, &action,
- allow_wrap? LIST_WRAP_UNLESS_HELD: LIST_WRAP_OFF))
+ &lists, &action))
{
/* setting changed */
selected = gui_synclist_get_sel_pos(&lists);
@@ -520,7 +525,7 @@ bool option_screen(const struct settings_list *setting,
}
else if (action == ACTION_NONE)
continue;
- else if (action == ACTION_STD_CANCEL)
+ else if (action == ACTION_STD_CANCEL || action == ACTION_STD_MENU)
{
/* setting canceled, restore old value if changed */
if (*variable != oldvalue)
@@ -560,7 +565,10 @@ bool option_screen(const struct settings_list *setting,
function(*variable);
}
else if(default_event_handler(action) == SYS_USB_CONNECTED)
+ {
+ pop_current_activity();
return true;
+ }
/* callback */
if (function && !cb_on_select_only)
function(*variable);
@@ -573,9 +581,8 @@ bool option_screen(const struct settings_list *setting,
return false;
}
-int get_setting_info_for_bar(int setting_id, int *count, int *val)
+int get_setting_info_for_bar(const struct settings_list *setting, int *count, int *val)
{
- const struct settings_list *setting = &settings[setting_id];
int var_type = setting->flags&F_T_MASK;
void (*function)(int) = NULL;
int oldvalue;
@@ -600,9 +607,8 @@ int get_setting_info_for_bar(int setting_id, int *count, int *val)
}
#ifdef HAVE_TOUCHSCREEN
-void update_setting_value_from_touch(int setting_id, int selection)
+void update_setting_value_from_touch(const struct settings_list *setting, int selection)
{
- const struct settings_list *setting = &settings[setting_id];
int new_val = selection_to_val(setting, selection);
int var_type = setting->flags&F_T_MASK;
diff --git a/apps/gui/option_select.h b/apps/gui/option_select.h
index 476e7b81bd..eabe5825e7 100644
--- a/apps/gui/option_select.h
+++ b/apps/gui/option_select.h
@@ -25,11 +25,10 @@
#include "screen_access.h"
#include "settings.h"
-#if defined (HAVE_SCROLLWHEEL) && !defined(FIIO_M3K)
-/* Define this if your target makes sense to have
- smaller values at the top of the list increasing down the list */
-#define ASCENDING_INT_SETTINGS
-#endif
+enum {
+ LIST_ORDER_DESCENDING = 0,
+ LIST_ORDER_ASCENDING = 1,
+};
bool option_screen(const struct settings_list *setting,
struct viewport parent[NB_SCREENS],
@@ -47,9 +46,9 @@ void option_talk_value(const struct settings_list *setting, int value, bool enqu
/* only use this for int and bool settings */
int option_value_as_int(const struct settings_list *setting);
-int get_setting_info_for_bar(int setting_id, int *count, int *val);
+int get_setting_info_for_bar(const struct settings_list *setting, int *count, int *val);
#ifdef HAVE_TOUCHSCREEN
-void update_setting_value_from_touch(int setting_id, int selection);
+void update_setting_value_from_touch(const struct settings_list *setting, int selection);
#endif
#endif /* _GUI_OPTION_SELECT_H_ */
diff --git a/apps/gui/pitchscreen.c b/apps/gui/pitchscreen.c
index 871921a10f..9f42aedb5d 100644
--- a/apps/gui/pitchscreen.c
+++ b/apps/gui/pitchscreen.c
@@ -18,1059 +18,8 @@
* KIND, either express or implied.
*
****************************************************************************/
-
-#include <stdbool.h>
-#include <string.h>
-#include <stdio.h>
-#include <math.h>
-#include <stdlib.h> /* for abs() */
-#include "config.h"
-#include "action.h"
-#include "sound.h"
-#include "pcmbuf.h"
-#include "lang.h"
-#include "icons.h"
-#include "screens.h"
-#include "talk.h"
-#include "viewport.h"
-#include "font.h"
-#include "system.h"
-#include "misc.h"
-#include "pitchscreen.h"
-#include "settings.h"
-#include "tdspeed.h"
-
-#define ICON_BORDER 12 /* icons are currently 7x8, so add ~2 pixels */
- /* on both sides when drawing */
-
-#define PITCH_MAX (200 * PITCH_SPEED_PRECISION)
-#define PITCH_MIN (50 * PITCH_SPEED_PRECISION)
-#define PITCH_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* .1% */
-#define PITCH_BIG_DELTA (PITCH_SPEED_PRECISION) /* 1% */
-#define PITCH_NUDGE_DELTA (2 * PITCH_SPEED_PRECISION) /* 2% */
-
-#define SPEED_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* .1% */
-#define SPEED_BIG_DELTA (PITCH_SPEED_PRECISION) /* 1% */
-
-#define SEMITONE_SMALL_DELTA (PITCH_SPEED_PRECISION / 10) /* 10 cents */
-#define SEMITONE_BIG_DELTA PITCH_SPEED_PRECISION /* 1 semitone */
-
-enum
-{
- PITCH_TOP = 0,
- PITCH_MID,
- PITCH_BOTTOM,
- PITCH_ITEM_COUNT,
-};
-
-
-/* This is a table of semitone percentage values of the appropriate
- precision (based on PITCH_SPEED_PRECISION). Note that these are
- all constant expressions, which will be evaluated at compile time,
- so no need to worry about how complex the expressions look.
- That's just to get the precision right.
-
- I calculated these values, starting from 50, as
-
- x(n) = 50 * 2^(n/12)
-
- All that math in each entry simply converts the float constant
- to an integer equal to PITCH_SPEED_PRECISION times the float value,
- with as little precision loss as possible (i.e. correctly rounding
- the last digit).
-*/
-#define TO_INT_WITH_PRECISION(x) \
- ( (unsigned short)(((x) * PITCH_SPEED_PRECISION * 10 + 5) / 10) )
-
-static const unsigned short semitone_table[] =
-{
- TO_INT_WITH_PRECISION(50.00000000), /* Octave lower */
- TO_INT_WITH_PRECISION(52.97315472),
- TO_INT_WITH_PRECISION(56.12310242),
- TO_INT_WITH_PRECISION(59.46035575),
- TO_INT_WITH_PRECISION(62.99605249),
- TO_INT_WITH_PRECISION(66.74199271),
- TO_INT_WITH_PRECISION(70.71067812),
- TO_INT_WITH_PRECISION(74.91535384),
- TO_INT_WITH_PRECISION(79.37005260),
- TO_INT_WITH_PRECISION(84.08964153),
- TO_INT_WITH_PRECISION(89.08987181),
- TO_INT_WITH_PRECISION(94.38743127),
- TO_INT_WITH_PRECISION(100.0000000), /* Normal sound */
- TO_INT_WITH_PRECISION(105.9463094),
- TO_INT_WITH_PRECISION(112.2462048),
- TO_INT_WITH_PRECISION(118.9207115),
- TO_INT_WITH_PRECISION(125.9921049),
- TO_INT_WITH_PRECISION(133.4839854),
- TO_INT_WITH_PRECISION(141.4213562),
- TO_INT_WITH_PRECISION(149.8307077),
- TO_INT_WITH_PRECISION(158.7401052),
- TO_INT_WITH_PRECISION(168.1792831),
- TO_INT_WITH_PRECISION(178.1797436),
- TO_INT_WITH_PRECISION(188.7748625),
- TO_INT_WITH_PRECISION(200.0000000) /* Octave higher */
-};
-
-#define NUM_SEMITONES ((int)(sizeof(semitone_table)/sizeof(semitone_table[0])))
-#define SEMITONE_END (NUM_SEMITONES/2)
-#define SEMITONE_START (-SEMITONE_END)
-
-/* A table of values for approximating the cent curve with
- linear interpolation. Multipy the next lowest semitone
- by this much to find the corresponding cent percentage.
-
- These values were calculated as
- x(n) = 100 * 2^(n * 20/1200)
-*/
-
-static const unsigned short cent_interp[] =
-{
- TO_INT_WITH_PRECISION(100.0000000),
- TO_INT_WITH_PRECISION(101.1619440),
- TO_INT_WITH_PRECISION(102.3373892),
- TO_INT_WITH_PRECISION(103.5264924),
- TO_INT_WITH_PRECISION(104.7294123),
- /* this one's the next semitone but we have it here for convenience */
- TO_INT_WITH_PRECISION(105.9463094),
-};
-
-/* Number of cents between entries in the cent_interp table */
-#define CENT_INTERP_INTERVAL 20
-#define CENT_INTERP_NUM ((int)(sizeof(cent_interp)/sizeof(cent_interp[0])))
-
-/* This stores whether the pitch and speed are at their own limits */
-/* or that of the timestretching algorithm */
-static bool at_limit = false;
-
-/*
- *
- * The pitchscreen is divided into 3 viewports (each row is a viewport)
- * Then each viewport is again divided into 3 colums, each showsing some infos
- * Additionally, on touchscreen, each cell represents a button
- *
- * Below a sketch describing what each cell will show (what's drawn on it)
- * --------------------------
- * | | | | <-- pitch up in the middle (text and button)
- * | | | | <-- arrows for mode toggling on the sides for touchscreen
- * |------------------------|
- * | | | | <-- semitone/speed up/down on the sides
- * | | | | <-- reset pitch&speed in the middle
- * |------------------------|
- * | | | | <-- pitch down in the middle
- * | | | | <-- Two "OK" for exit on the sides for touchscreen
- * |------------------------|
- *
- *
- */
-
-static void speak_pitch_mode(bool enqueue)
-{
- bool timestretch_mode = global_settings.pitch_mode_timestretch && dsp_timestretch_available();
- if (timestretch_mode)
- talk_id(VOICE_PITCH_TIMESTRETCH_MODE, enqueue);
- if (global_settings.pitch_mode_semitone)
- talk_id(VOICE_PITCH_SEMITONE_MODE, timestretch_mode ? true : enqueue);
- else
- talk_id(VOICE_PITCH_ABSOLUTE_MODE, timestretch_mode ? true : enqueue);
- return;
-}
-
-/*
- * Fixes the viewports so they represent the 3 rows, and adds a little margin
- * on all sides for the icons (which are drawn outside of the grid
- *
- * The modified viewports need to be passed to the touchscreen handling function
- **/
-static void pitchscreen_fix_viewports(struct viewport *parent,
- struct viewport pitch_viewports[PITCH_ITEM_COUNT])
-{
- int i, font_height;
- font_height = font_get(parent->font)->height;
- for (i = 0; i < PITCH_ITEM_COUNT; i++)
- {
- pitch_viewports[i] = *parent;
- pitch_viewports[i].height = parent->height / PITCH_ITEM_COUNT;
- pitch_viewports[i].x += ICON_BORDER;
- pitch_viewports[i].width -= 2*ICON_BORDER;
- }
- pitch_viewports[PITCH_TOP].y += ICON_BORDER;
- pitch_viewports[PITCH_TOP].height -= ICON_BORDER;
-
- if(pitch_viewports[PITCH_MID].height < font_height * 2)
- pitch_viewports[PITCH_MID].height = font_height * 2;
-
- pitch_viewports[PITCH_MID].y = pitch_viewports[PITCH_TOP].y
- + pitch_viewports[PITCH_TOP].height;
-
- pitch_viewports[PITCH_BOTTOM].y = pitch_viewports[PITCH_MID].y
- + pitch_viewports[PITCH_MID].height;
-
- pitch_viewports[PITCH_BOTTOM].height -= ICON_BORDER;
-}
-
-/* must be called before pitchscreen_draw, or within
- * since it neither clears nor updates the display */
-static void pitchscreen_draw_icons(struct screen *display,
- struct viewport *parent)
-{
- display->set_viewport(parent);
- display->mono_bitmap(bitmap_icons_7x8[Icon_UpArrow],
- parent->width/2 - 3,
- 2, 7, 8);
- display->mono_bitmap(bitmap_icons_7x8[Icon_DownArrow],
- parent->width /2 - 3,
- parent->height - 10, 7, 8);
- display->mono_bitmap(bitmap_icons_7x8[Icon_FastForward],
- parent->width - 10,
- parent->height /2 - 4, 7, 8);
- display->mono_bitmap(bitmap_icons_7x8[Icon_FastBackward],
- 2,
- parent->height /2 - 4, 7, 8);
- display->update_viewport();
-}
-
-static void pitchscreen_draw(struct screen *display, int max_lines,
- struct viewport pitch_viewports[PITCH_ITEM_COUNT],
- int32_t pitch, int32_t semitone
- ,int32_t speed
- )
-{
- const char* ptr;
- char buf[32];
- int w, h;
- bool show_lang_pitch;
- struct viewport *last_vp = NULL;
-
- /* "Pitch up/Pitch down" - hide for a small screen,
- * the text is drawn centered automatically
- *
- * note: this assumes 5 lines always fit on a touchscreen (should be
- * reasonable) */
- if (max_lines >= 5)
- {
- int w, h;
- struct viewport *vp = &pitch_viewports[PITCH_TOP];
- last_vp = display->set_viewport(vp);
- display->clear_viewport();
-#ifdef HAVE_TOUCHSCREEN
- /* two arrows in the top row, left and right column */
- char *arrows[] = { "<", ">"};
- display->getstringsize(arrows[0], &w, &h);
- display->putsxy(0, vp->height/2 - h/2, arrows[0]);
- display->putsxy(vp->width - w, vp->height/2 - h/2, arrows[1]);
-#endif
- /* UP: Pitch Up */
- if (global_settings.pitch_mode_semitone)
- ptr = str(LANG_PITCH_UP_SEMITONE);
- else
- ptr = str(LANG_PITCH_UP);
-
- display->getstringsize(ptr, &w, NULL);
- /* draw text */
- display->putsxy(vp->width/2 - w/2, 0, ptr);
- display->update_viewport();
-
- /* DOWN: Pitch Down */
- vp = &pitch_viewports[PITCH_BOTTOM];
- display->set_viewport(vp);
- display->clear_viewport();
-
-#ifdef HAVE_TOUCHSCREEN
- ptr = str(LANG_KBD_OK);
- display->getstringsize(ptr, &w, &h);
- /* one OK in the middle first column of the vp (at half height) */
- display->putsxy(vp->width/6 - w/2, vp->height/2 - h/2, ptr);
- /* one OK in the middle of the last column of the vp (at half height) */
- display->putsxy(5*vp->width/6 - w/2, vp->height/2 - h/2, ptr);
-#endif
- if (global_settings.pitch_mode_semitone)
- ptr = str(LANG_PITCH_DOWN_SEMITONE);
- else
- ptr = str(LANG_PITCH_DOWN);
- display->getstringsize(ptr, &w, &h);
- /* draw text */
- display->putsxy(vp->width/2 - w/2, vp->height - h, ptr);
- display->update_viewport();
- }
-
- /* Middle section */
- display->set_viewport(&pitch_viewports[PITCH_MID]);
- display->clear_viewport();
- int width_used = 0;
-
- /* Middle section upper line - hide for a small screen */
- if ((show_lang_pitch = (max_lines >= 3)))
- {
- if(global_settings.pitch_mode_timestretch)
- {
- /* Pitch:XXX.X% */
- if(global_settings.pitch_mode_semitone)
- {
- snprintf(buf, sizeof(buf), "%s: %s%d.%02d", str(LANG_PITCH),
- semitone >= 0 ? "+" : "-",
- abs(semitone / PITCH_SPEED_PRECISION),
- abs((semitone % PITCH_SPEED_PRECISION) /
- (PITCH_SPEED_PRECISION / 100))
- );
- }
- else
- {
- snprintf(buf, sizeof(buf), "%s: %ld.%ld%%", str(LANG_PITCH),
- pitch / PITCH_SPEED_PRECISION,
- (pitch % PITCH_SPEED_PRECISION) /
- (PITCH_SPEED_PRECISION / 10));
- }
- }
- else
- {
- /* Rate */
- snprintf(buf, sizeof(buf), "%s:", str(LANG_PLAYBACK_RATE));
- }
- display->getstringsize(buf, &w, &h);
- display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2),
- (pitch_viewports[PITCH_MID].height / 2) - h, buf);
- if (w > width_used)
- width_used = w;
- }
-
- /* Middle section lower line */
- /* "Speed:XXX%" */
- if(global_settings.pitch_mode_timestretch)
- {
- snprintf(buf, sizeof(buf), "%s: %ld.%ld%%", str(LANG_SPEED),
- speed / PITCH_SPEED_PRECISION,
- (speed % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
- }
- else
- {
- if(global_settings.pitch_mode_semitone)
- {
- snprintf(buf, sizeof(buf), "%s%d.%02d",
- semitone >= 0 ? "+" : "-",
- abs(semitone / PITCH_SPEED_PRECISION),
- abs((semitone % PITCH_SPEED_PRECISION) /
- (PITCH_SPEED_PRECISION / 100))
- );
- }
- else
- {
- snprintf(buf, sizeof(buf), "%ld.%ld%%",
- pitch / PITCH_SPEED_PRECISION,
- (pitch % PITCH_SPEED_PRECISION) / (PITCH_SPEED_PRECISION / 10));
- }
- }
-
- display->getstringsize(buf, &w, &h);
- display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2),
- show_lang_pitch ? (pitch_viewports[PITCH_MID].height / 2) :
- (pitch_viewports[PITCH_MID].height / 2) - (h / 2),
- buf);
- if (w > width_used)
- width_used = w;
-
- /* "limit" and "timestretch" labels */
- if (max_lines >= 7)
- {
- if(at_limit)
- {
- const char * const p = str(LANG_STRETCH_LIMIT);
- display->getstringsize(p, &w, &h);
- display->putsxy((pitch_viewports[PITCH_MID].width / 2) - (w / 2),
- (pitch_viewports[PITCH_MID].height / 2) + h, p);
- if (w > width_used)
- width_used = w;
- }
- }
-
- /* Middle section left/right labels */
- const char *leftlabel = "-2%";
- const char *rightlabel = "+2%";
- if (global_settings.pitch_mode_timestretch)
- {
- leftlabel = "<<";
- rightlabel = ">>";
- }
-
- /* Only display if they fit */
- display->getstringsize(leftlabel, &w, &h);
- width_used += w;
- display->getstringsize(rightlabel, &w, &h);
- width_used += w;
-
- if (width_used <= pitch_viewports[PITCH_MID].width)
- {
- display->putsxy(0, (pitch_viewports[PITCH_MID].height / 2) - (h / 2),
- leftlabel);
- display->putsxy((pitch_viewports[PITCH_MID].width - w),
- (pitch_viewports[PITCH_MID].height / 2) - (h / 2),
- rightlabel);
- }
- display->update_viewport();
- display->set_viewport(last_vp);
-}
-
-static int32_t pitch_increase(int32_t pitch, int32_t pitch_delta, bool allow_cutoff
- /* need this to maintain correct pitch/speed caps */
- , int32_t speed
- )
-{
- int32_t new_pitch;
- int32_t new_stretch;
- at_limit = false;
-
- if (pitch_delta < 0)
- {
- /* for large jumps, snap up to whole numbers */
- if(allow_cutoff && pitch_delta <= -PITCH_SPEED_PRECISION &&
- (pitch + pitch_delta) % PITCH_SPEED_PRECISION != 0)
- {
- pitch_delta += PITCH_SPEED_PRECISION - ((pitch + pitch_delta) % PITCH_SPEED_PRECISION);
- }
-
- new_pitch = pitch + pitch_delta;
-
- if (new_pitch < PITCH_MIN)
- {
- if (!allow_cutoff)
- {
- return pitch;
- }
- new_pitch = PITCH_MIN;
- at_limit = true;
- }
- }
- else if (pitch_delta > 0)
- {
- /* for large jumps, snap down to whole numbers */
- if(allow_cutoff && pitch_delta >= PITCH_SPEED_PRECISION &&
- (pitch + pitch_delta) % PITCH_SPEED_PRECISION != 0)
- {
- pitch_delta -= (pitch + pitch_delta) % PITCH_SPEED_PRECISION;
- }
-
- new_pitch = pitch + pitch_delta;
-
- if (new_pitch > PITCH_MAX)
- {
- if (!allow_cutoff)
- return pitch;
- new_pitch = PITCH_MAX;
- at_limit = true;
- }
- }
- else
- {
- /* pitch_delta == 0 -> no real change */
- return pitch;
- }
- if (dsp_timestretch_available())
- {
- /* increase the multiple to increase precision of this calculation */
- new_stretch = GET_STRETCH(new_pitch, speed);
- if(new_stretch < STRETCH_MIN)
- {
- /* we have to ignore allow_cutoff, because we can't have the */
- /* stretch go higher than STRETCH_MAX */
- new_pitch = GET_PITCH(speed, STRETCH_MIN);
- }
- else if(new_stretch > STRETCH_MAX)
- {
- /* we have to ignore allow_cutoff, because we can't have the */
- /* stretch go higher than STRETCH_MAX */
- new_pitch = GET_PITCH(speed, STRETCH_MAX);
- }
-
- if(new_stretch >= STRETCH_MAX ||
- new_stretch <= STRETCH_MIN)
- {
- at_limit = true;
- }
- }
-
- sound_set_pitch(new_pitch);
-
- return new_pitch;
-}
-
-static int32_t get_semitone_from_pitch(int32_t pitch)
-{
- int semitone = 0;
- int32_t fractional_index = 0;
-
- while(semitone < NUM_SEMITONES - 1 &&
- pitch >= semitone_table[semitone + 1])
- {
- semitone++;
- }
-
-
- /* now find the fractional part */
- while(pitch > (cent_interp[fractional_index + 1] *
- semitone_table[semitone] / PITCH_SPEED_100))
- {
- /* Check to make sure fractional_index isn't too big */
- /* This should never happen. */
- if(fractional_index >= CENT_INTERP_NUM - 1)
- {
- break;
- }
- fractional_index++;
- }
-
- int32_t semitone_pitch_a = cent_interp[fractional_index] *
- semitone_table[semitone] /
- PITCH_SPEED_100;
- int32_t semitone_pitch_b = cent_interp[fractional_index + 1] *
- semitone_table[semitone] /
- PITCH_SPEED_100;
- /* this will be the integer offset from the cent_interp entry */
- int32_t semitone_frac_ofs = (pitch - semitone_pitch_a) * CENT_INTERP_INTERVAL /
- (semitone_pitch_b - semitone_pitch_a);
- semitone = (semitone + SEMITONE_START) * PITCH_SPEED_PRECISION +
- fractional_index * CENT_INTERP_INTERVAL +
- semitone_frac_ofs;
-
- return semitone;
-}
-
-static int32_t get_pitch_from_semitone(int32_t semitone)
-{
- int32_t adjusted_semitone = semitone - SEMITONE_START * PITCH_SPEED_PRECISION;
-
- /* Find the index into the semitone table */
- int32_t semitone_index = (adjusted_semitone / PITCH_SPEED_PRECISION);
-
- /* set pitch to the semitone's integer part value */
- int32_t pitch = semitone_table[semitone_index];
- /* get the range of the cent modification for future calculation */
- int32_t pitch_mod_a =
- cent_interp[(adjusted_semitone % PITCH_SPEED_PRECISION) /
- CENT_INTERP_INTERVAL];
- int32_t pitch_mod_b =
- cent_interp[(adjusted_semitone % PITCH_SPEED_PRECISION) /
- CENT_INTERP_INTERVAL + 1];
- /* figure out the cent mod amount based on the semitone fractional value */
- int32_t pitch_mod = pitch_mod_a + (pitch_mod_b - pitch_mod_a) *
- (adjusted_semitone % CENT_INTERP_INTERVAL) / CENT_INTERP_INTERVAL;
-
- /* modify pitch based on the mod amount we just calculated */
- return (pitch * pitch_mod + PITCH_SPEED_100 / 2) / PITCH_SPEED_100;
-}
-
-static int32_t pitch_increase_semitone(int32_t pitch,
- int32_t current_semitone,
- int32_t semitone_delta
- , int32_t speed
- )
-{
- int32_t new_semitone = current_semitone;
-
- /* snap to the delta interval */
- if(current_semitone % semitone_delta != 0)
- {
- if(current_semitone > 0 && semitone_delta > 0)
- new_semitone += semitone_delta;
- else if(current_semitone < 0 && semitone_delta < 0)
- new_semitone += semitone_delta;
-
- new_semitone -= new_semitone % semitone_delta;
- }
- else
- new_semitone += semitone_delta;
-
- /* clamp the pitch so it doesn't go beyond the pitch limits */
- if(new_semitone < (SEMITONE_START * PITCH_SPEED_PRECISION))
- {
- new_semitone = SEMITONE_START * PITCH_SPEED_PRECISION;
- at_limit = true;
- }
- else if(new_semitone > (SEMITONE_END * PITCH_SPEED_PRECISION))
- {
- new_semitone = SEMITONE_END * PITCH_SPEED_PRECISION;
- at_limit = true;
- }
-
- int32_t new_pitch = get_pitch_from_semitone(new_semitone);
-
- int32_t new_stretch = GET_STRETCH(new_pitch, speed);
-
- /* clamp the pitch so it doesn't go beyond the stretch limits */
- if( new_stretch > STRETCH_MAX)
- {
- new_pitch = GET_PITCH(speed, STRETCH_MAX);
- new_semitone = get_semitone_from_pitch(new_pitch);
- at_limit = true;
- }
- else if (new_stretch < STRETCH_MIN)
- {
- new_pitch = GET_PITCH(speed, STRETCH_MIN);
- new_semitone = get_semitone_from_pitch(new_pitch);
- at_limit = true;
- }
-
- pitch_increase(pitch, new_pitch - pitch, false
- , speed
- );
-
- return new_semitone;
-}
-
-#ifdef HAVE_TOUCHSCREEN
-/*
- * Check for touchscreen presses as per sketch above in this file
- *
- * goes through each row of the, checks whether the touchscreen
- * was pressed in it. Then it looks the columns of each row for specific actions
- */
-static int pitchscreen_do_touchscreen(struct viewport vps[])
-{
- short x, y;
- struct viewport *this_vp = &vps[PITCH_TOP];
- int ret;
- static bool wait_for_release = false;
- ret = action_get_touchscreen_press_in_vp(&x, &y, this_vp);
-
- /* top row */
- if (ret > ACTION_UNKNOWN)
- { /* press on top row, left or right column
- * only toggle mode if released */
- int column = this_vp->width / 3;
- if ((x < column || x > (2*column)) && (ret == BUTTON_REL))
- return ACTION_PS_TOGGLE_MODE;
-
-
- else if (x >= column && x <= (2*column))
- { /* center column pressed */
- if (ret == BUTTON_REPEAT)
- return ACTION_PS_INC_BIG;
- else if (ret & BUTTON_REL)
- return ACTION_PS_INC_SMALL;
- }
- return ACTION_NONE;
- }
-
- /* now the center row */
- this_vp = &vps[PITCH_MID];
- ret = action_get_touchscreen_press_in_vp(&x, &y, this_vp);
-
- if (ret > ACTION_UNKNOWN)
- {
- int column = this_vp->width / 3;
-
- if (x < column)
- { /* left column */
- if (ret & BUTTON_REL)
- {
- wait_for_release = false;
- return ACTION_PS_NUDGE_LEFTOFF;
- }
- else if (ret & BUTTON_REPEAT)
- return ACTION_PS_SLOWER;
- if (!wait_for_release)
- {
- wait_for_release = true;
- return ACTION_PS_NUDGE_LEFT;
- }
- }
- else if (x > (2*column))
- { /* right column */
- if (ret & BUTTON_REL)
- {
- wait_for_release = false;
- return ACTION_PS_NUDGE_RIGHTOFF;
- }
- else if (ret & BUTTON_REPEAT)
- return ACTION_PS_FASTER;
- if (!wait_for_release)
- {
- wait_for_release = true;
- return ACTION_PS_NUDGE_RIGHT;
- }
- }
- else
- /* center column was pressed */
- return ACTION_PS_RESET;
- }
-
- /* now the bottom row */
- this_vp = &vps[PITCH_BOTTOM];
- ret = action_get_touchscreen_press_in_vp(&x, &y, this_vp);
-
- if (ret > ACTION_UNKNOWN)
- {
- int column = this_vp->width / 3;
-
- /* left or right column is exit */
- if ((x < column || x > (2*column)) && (ret == BUTTON_REL))
- return ACTION_PS_EXIT;
- else if (x >= column && x <= (2*column))
- { /* center column was pressed */
- if (ret & BUTTON_REPEAT)
- return ACTION_PS_DEC_BIG;
- else if (ret & BUTTON_REL)
- return ACTION_PS_DEC_SMALL;
- }
- return ACTION_NONE;
- }
- return ACTION_NONE;
-}
-
-#endif
-/*
- returns:
- 0 on exit
- 1 if USB was connected
-*/
-
+#include "plugin.h"
int gui_syncpitchscreen_run(void)
{
- int button;
- int32_t pitch = sound_get_pitch();
- int32_t semitone;
-
- int32_t new_pitch;
- int32_t pitch_delta;
- bool nudged = false;
- int i, updated = 4, decimals = 0;
- bool exit = false;
- /* should maybe be passed per parameter later, not needed for now */
- struct viewport parent[NB_SCREENS];
- struct viewport pitch_viewports[NB_SCREENS][PITCH_ITEM_COUNT];
- int max_lines[NB_SCREENS];
-
- push_current_activity(ACTIVITY_PITCHSCREEN);
-
- int32_t new_speed = 0, new_stretch;
-
- /* the speed variable holds the apparent speed of the playback */
- int32_t speed;
- if (dsp_timestretch_available())
- {
- speed = GET_SPEED(pitch, dsp_get_timestretch());
- }
- else
- {
- speed = pitch;
- }
-
- /* Figure out whether to be in timestretch mode */
- if (global_settings.pitch_mode_timestretch && !dsp_timestretch_available())
- {
- global_settings.pitch_mode_timestretch = false;
- settings_save();
- }
-
- /* Count decimals for speaking */
- for (i = PITCH_SPEED_PRECISION; i >= 10; i /= 10)
- decimals++;
-
- /* set the semitone index based on the current pitch */
- semitone = get_semitone_from_pitch(pitch);
-
- /* initialize pitchscreen vps */
- FOR_NB_SCREENS(i)
- {
- viewport_set_defaults(&parent[i], i);
- max_lines[i] = viewport_get_nb_lines(&parent[i]);
- pitchscreen_fix_viewports(&parent[i], pitch_viewports[i]);
- screens[i].set_viewport(&parent[i]);
- screens[i].clear_viewport();
-
- /* also, draw the icons now, it's only needed once */
- pitchscreen_draw_icons(&screens[i], &parent[i]);
- }
- pcmbuf_set_low_latency(true);
-
- while (!exit)
- {
- FOR_NB_SCREENS(i)
- pitchscreen_draw(&screens[i], max_lines[i],
- pitch_viewports[i], pitch, semitone
- , speed
- );
- pitch_delta = 0;
- new_speed = 0;
-
- if (global_settings.talk_menu && updated)
- {
- talk_shutup();
- switch (updated)
- {
- case 1:
- if (global_settings.pitch_mode_semitone)
- talk_value_decimal(semitone, UNIT_SIGNED, decimals, false);
- else
- talk_value_decimal(pitch, UNIT_PERCENT, decimals, false);
- break;
- case 2:
- talk_value_decimal(speed, UNIT_PERCENT, decimals, false);
- break;
- case 3:
- speak_pitch_mode(false);
- break;
- case 4:
- if (global_settings.pitch_mode_timestretch && dsp_timestretch_available())
- talk_id(LANG_PITCH, false);
- else
- talk_id(LANG_PLAYBACK_RATE, false);
- talk_value_decimal(pitch, UNIT_PERCENT, decimals, true);
- if (global_settings.pitch_mode_timestretch && dsp_timestretch_available())
- {
- talk_id(LANG_SPEED, true);
- talk_value_decimal(speed, UNIT_PERCENT, decimals, true);
- }
- speak_pitch_mode(true);
- break;
- default:
- break;
- }
- }
- updated = 0;
-
- button = get_action(CONTEXT_PITCHSCREEN, HZ);
-
-#ifdef HAVE_TOUCHSCREEN
- if (button == ACTION_TOUCHSCREEN)
- {
- FOR_NB_SCREENS(i)
- button = pitchscreen_do_touchscreen(pitch_viewports[i]);
- }
-#endif
- switch (button)
- {
- case ACTION_PS_INC_SMALL:
- if(global_settings.pitch_mode_semitone)
- pitch_delta = SEMITONE_SMALL_DELTA;
- else
- pitch_delta = PITCH_SMALL_DELTA;
- updated = 1;
- break;
-
- case ACTION_PS_INC_BIG:
- if(global_settings.pitch_mode_semitone)
- pitch_delta = SEMITONE_BIG_DELTA;
- else
- pitch_delta = PITCH_BIG_DELTA;
- updated = 1;
- break;
-
- case ACTION_PS_DEC_SMALL:
- if(global_settings.pitch_mode_semitone)
- pitch_delta = -SEMITONE_SMALL_DELTA;
- else
- pitch_delta = -PITCH_SMALL_DELTA;
- updated = 1;
- break;
-
- case ACTION_PS_DEC_BIG:
- if(global_settings.pitch_mode_semitone)
- pitch_delta = -SEMITONE_BIG_DELTA;
- else
- pitch_delta = -PITCH_BIG_DELTA;
- updated = 1;
- break;
-
- case ACTION_PS_NUDGE_RIGHT:
- if (!global_settings.pitch_mode_timestretch)
- {
- new_pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false
- , speed
- );
- nudged = (new_pitch != pitch);
- pitch = new_pitch;
- semitone = get_semitone_from_pitch(pitch);
- speed = pitch;
- updated = nudged ? 1 : 0;
- break;
- }
- else
- {
- new_speed = speed + SPEED_SMALL_DELTA;
- at_limit = false;
- updated = 2;
- }
- break;
-
- case ACTION_PS_FASTER:
- if (global_settings.pitch_mode_timestretch)
- {
- new_speed = speed + SPEED_BIG_DELTA;
- /* snap to whole numbers */
- if(new_speed % PITCH_SPEED_PRECISION != 0)
- new_speed -= new_speed % PITCH_SPEED_PRECISION;
- at_limit = false;
- updated = 2;
- }
- break;
-
- case ACTION_PS_NUDGE_RIGHTOFF:
- if (nudged)
- {
- pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false
- , speed
- );
- speed = pitch;
- semitone = get_semitone_from_pitch(pitch);
- nudged = false;
- updated = 1;
- }
- break;
-
- case ACTION_PS_NUDGE_LEFT:
- if (!global_settings.pitch_mode_timestretch)
- {
- new_pitch = pitch_increase(pitch, -PITCH_NUDGE_DELTA, false
- , speed
- );
- nudged = (new_pitch != pitch);
- pitch = new_pitch;
- semitone = get_semitone_from_pitch(pitch);
- speed = pitch;
- updated = nudged ? 1 : 0;
- break;
- }
- else
- {
- new_speed = speed - SPEED_SMALL_DELTA;
- at_limit = false;
- updated = 2;
- }
- break;
-
- case ACTION_PS_SLOWER:
- if (global_settings.pitch_mode_timestretch)
- {
- new_speed = speed - SPEED_BIG_DELTA;
- /* snap to whole numbers */
- if(new_speed % PITCH_SPEED_PRECISION != 0)
- new_speed += PITCH_SPEED_PRECISION - speed % PITCH_SPEED_PRECISION;
- at_limit = false;
- updated = 2;
- }
- break;
-
- case ACTION_PS_NUDGE_LEFTOFF:
- if (nudged)
- {
- pitch = pitch_increase(pitch, PITCH_NUDGE_DELTA, false
- , speed
- );
- speed = pitch;
- semitone = get_semitone_from_pitch(pitch);
- nudged = false;
- updated = 1;
- }
- break;
-
- case ACTION_PS_RESET:
- pitch = PITCH_SPEED_100;
- sound_set_pitch(pitch);
- speed = PITCH_SPEED_100;
- if (dsp_timestretch_available())
- {
- dsp_set_timestretch(PITCH_SPEED_100);
- at_limit = false;
- }
- semitone = get_semitone_from_pitch(pitch);
- updated = 4;
- break;
-
- case ACTION_PS_TOGGLE_MODE:
- global_settings.pitch_mode_semitone = !global_settings.pitch_mode_semitone;
-
- if (dsp_timestretch_available() && !global_settings.pitch_mode_semitone)
- {
- global_settings.pitch_mode_timestretch = !global_settings.pitch_mode_timestretch;
- if(!global_settings.pitch_mode_timestretch)
- {
- /* no longer in timestretch mode. Reset speed */
- speed = pitch;
- dsp_set_timestretch(PITCH_SPEED_100);
- }
- }
- settings_save();
- updated = 3;
- break;
-
- case ACTION_PS_EXIT:
- exit = true;
- break;
-
- default:
- if (default_event_handler(button) == SYS_USB_CONNECTED)
- return 1;
- break;
- }
- if (pitch_delta)
- {
- if (global_settings.pitch_mode_semitone)
- {
- semitone = pitch_increase_semitone(pitch, semitone, pitch_delta
- , speed
- );
- pitch = get_pitch_from_semitone(semitone);
- }
- else
- {
- pitch = pitch_increase(pitch, pitch_delta, true
- , speed
- );
- semitone = get_semitone_from_pitch(pitch);
- }
- if (global_settings.pitch_mode_timestretch)
- {
- /* do this to make sure we properly obey the stretch limits */
- new_speed = speed;
- }
- else
- {
- speed = pitch;
- }
- }
-
- if(new_speed)
- {
- new_stretch = GET_STRETCH(pitch, new_speed);
-
- /* limit the amount of stretch */
- if(new_stretch > STRETCH_MAX)
- {
- new_stretch = STRETCH_MAX;
- new_speed = GET_SPEED(pitch, new_stretch);
- }
- else if(new_stretch < STRETCH_MIN)
- {
- new_stretch = STRETCH_MIN;
- new_speed = GET_SPEED(pitch, new_stretch);
- }
-
- new_stretch = GET_STRETCH(pitch, new_speed);
- if(new_stretch >= STRETCH_MAX ||
- new_stretch <= STRETCH_MIN)
- {
- at_limit = true;
- }
-
- /* set the amount of stretch */
- dsp_set_timestretch(new_stretch);
-
- /* update the speed variable with the new speed */
- speed = new_speed;
-
- /* Reset new_speed so we only call dsp_set_timestretch */
- /* when needed */
- new_speed = 0;
- }
- }
-
- pcmbuf_set_low_latency(false);
- pop_current_activity();
-
- /* Clean up */
- FOR_NB_SCREENS(i)
- {
- screens[i].set_viewport(NULL);
- }
-
- return 0;
+ return (plugin_load(VIEWERS_DIR"/pitch_screen.rock", NULL) == PLUGIN_USB_CONNECTED);
}
diff --git a/apps/gui/quickscreen.c b/apps/gui/quickscreen.c
index f8bf98d4ee..221dfe3111 100644
--- a/apps/gui/quickscreen.c
+++ b/apps/gui/quickscreen.c
@@ -39,6 +39,9 @@
#include "option_select.h"
#include "debug.h"
#include "shortcuts.h"
+#ifdef HAVE_ALBUMART
+#include "playback.h"
+#endif
/* 1 top, 1 bottom, 2 on either side, 1 for the icons
* if enough space, top and bottom have 2 lines */
@@ -248,20 +251,21 @@ static void talk_qs_option(const struct settings_list *opt, bool enqueue)
static bool gui_quickscreen_do_button(struct gui_quickscreen * qs, int button)
{
int item;
- bool invert = false;
+ bool previous = false;
switch(button)
{
case ACTION_QS_TOP:
- invert = true;
item = QUICKSCREEN_TOP;
break;
+
case ACTION_QS_LEFT:
- invert = true;
item = QUICKSCREEN_LEFT;
+ previous = true;
break;
case ACTION_QS_DOWN:
item = QUICKSCREEN_BOTTOM;
+ previous = true;
break;
case ACTION_QS_RIGHT:
@@ -271,47 +275,58 @@ static bool gui_quickscreen_do_button(struct gui_quickscreen * qs, int button)
default:
return false;
}
+
if (qs->items[item] == NULL)
return false;
-#ifdef ASCENDING_INT_SETTINGS
- if (((qs->items[item]->flags & F_INT_SETTING) == F_INT_SETTING) &&
- ( button == ACTION_QS_DOWN || button == ACTION_QS_TOP))
- {
- invert = !invert;
- }
-#endif
- option_select_next_val(qs->items[item], invert, true);
+
+ option_select_next_val(qs->items[item], previous, true);
talk_qs_option(qs->items[item], false);
return true;
}
#ifdef HAVE_TOUCHSCREEN
-static int quickscreen_touchscreen_button(const struct viewport
- vps[QUICKSCREEN_ITEM_COUNT])
+static int quickscreen_touchscreen_button(void)
{
short x,y;
- /* only hitting the text counts, everything else is exit */
if (action_get_touchscreen_press(&x, &y) != BUTTON_REL)
return ACTION_NONE;
- else if (viewport_point_within_vp(&vps[QUICKSCREEN_TOP], x, y))
+
+ enum { left=1, right=2, top=4, bottom=8 };
+
+ int bits = 0;
+
+ if(x < LCD_WIDTH/3)
+ bits |= left;
+ else if(x > 2*LCD_WIDTH/3)
+ bits |= right;
+
+ if(y < LCD_HEIGHT/3)
+ bits |= top;
+ else if(y > 2*LCD_HEIGHT/3)
+ bits |= bottom;
+
+ switch(bits) {
+ case top:
return ACTION_QS_TOP;
- else if (viewport_point_within_vp(&vps[QUICKSCREEN_BOTTOM], x, y))
+ case bottom:
return ACTION_QS_DOWN;
- else if (viewport_point_within_vp(&vps[QUICKSCREEN_LEFT], x, y))
+ case left:
return ACTION_QS_LEFT;
- else if (viewport_point_within_vp(&vps[QUICKSCREEN_RIGHT], x, y))
+ case right:
return ACTION_QS_RIGHT;
- return ACTION_STD_CANCEL;
+ default:
+ return ACTION_STD_CANCEL;
+ }
}
#endif
-static bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_enter, bool *usb)
+static int gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_enter, bool *usb)
{
int button;
struct viewport parent[NB_SCREENS];
struct viewport vps[NB_SCREENS][QUICKSCREEN_ITEM_COUNT];
struct viewport vp_icons[NB_SCREENS];
- bool changed = false;
+ int ret = QUICKSCREEN_OK;
/* To quit we need either :
* - a second press on the button that made us enter
* - an action taken while pressing the enter button,
@@ -343,7 +358,7 @@ static bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_ente
button = get_action(CONTEXT_QUICKSCREEN, HZ/5);
#ifdef HAVE_TOUCHSCREEN
if (button == ACTION_TOUCHSCREEN)
- button = quickscreen_touchscreen_button(vps[SCREEN_MAIN]);
+ button = quickscreen_touchscreen_button();
#endif
if (default_event_handler(button) == SYS_USB_CONNECTED)
{
@@ -352,7 +367,7 @@ static bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_ente
}
if (gui_quickscreen_do_button(qs, button))
{
- changed = true;
+ ret |= QUICKSCREEN_CHANGED;
can_quit = true;
FOR_NB_SCREENS(i)
gui_quickscreen_draw(qs, &screens[i], &parent[i],
@@ -363,17 +378,20 @@ static bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_ente
else if (button == button_enter)
can_quit = true;
else if (button == ACTION_QS_VOLUP) {
- global_settings.volume += sound_steps(SOUND_VOLUME);
- setvol();
+ adjust_volume(1);
FOR_NB_SCREENS(i)
skin_update(CUSTOM_STATUSBAR, i, SKIN_REFRESH_NON_STATIC);
}
else if (button == ACTION_QS_VOLDOWN) {
- global_settings.volume -= sound_steps(SOUND_VOLUME);
- setvol();
+ adjust_volume(-1);
FOR_NB_SCREENS(i)
skin_update(CUSTOM_STATUSBAR, i, SKIN_REFRESH_NON_STATIC);
}
+ else if (button == ACTION_STD_CONTEXT)
+ {
+ ret |= QUICKSCREEN_GOTO_SHORTCUTS_MENU;
+ break;
+ }
if ((button == button_enter) && can_quit)
break;
@@ -386,20 +404,15 @@ static bool gui_syncquickscreen_run(struct gui_quickscreen * qs, int button_ente
{ /* stop scrolling before exiting */
for (int j = 0; j < QUICKSCREEN_ITEM_COUNT; j++)
screens[i].scroll_stop_viewport(&vps[i][j]);
- viewportmanager_theme_undo(i, true);
+ viewportmanager_theme_undo(i, !(ret & QUICKSCREEN_GOTO_SHORTCUTS_MENU));
}
- pop_current_activity();
- return changed;
-}
+ if (ret & QUICKSCREEN_GOTO_SHORTCUTS_MENU) /* Eliminate flashing of parent during */
+ pop_current_activity_without_refresh(); /* transition to Shortcuts */
+ else
+ pop_current_activity();
-static const struct settings_list *get_setting(int gs_value,
- const struct settings_list *defaultval)
-{
- if (gs_value != -1 && gs_value < nb_settings &&
- is_setting_quickscreenable(&settings[gs_value]))
- return &settings[gs_value];
- return defaultval;
+ return ret;
}
int quick_screen_quick(int button_enter)
@@ -407,24 +420,22 @@ int quick_screen_quick(int button_enter)
struct gui_quickscreen qs;
bool oldshuffle = global_settings.playlist_shuffle;
int oldrepeat = global_settings.repeat_mode;
+#ifdef HAVE_ALBUMART
+ int old_album_art = global_settings.album_art;
+#endif
bool usb = false;
- if (global_settings.shortcuts_replaces_qs)
- return do_shortcut_menu(NULL);
+ for (int i = 0; i < 4; ++i)
+ {
+ qs.items[i] = global_settings.qs_items[i];
- qs.items[QUICKSCREEN_TOP] =
- get_setting(global_settings.qs_items[QUICKSCREEN_TOP], NULL);
- qs.items[QUICKSCREEN_LEFT] =
- get_setting(global_settings.qs_items[QUICKSCREEN_LEFT],
- find_setting(&global_settings.playlist_shuffle, NULL));
- qs.items[QUICKSCREEN_RIGHT] =
- get_setting(global_settings.qs_items[QUICKSCREEN_RIGHT],
- find_setting(&global_settings.repeat_mode, NULL));
- qs.items[QUICKSCREEN_BOTTOM] =
- get_setting(global_settings.qs_items[QUICKSCREEN_BOTTOM], NULL);
+ if (!is_setting_quickscreenable(qs.items[i]))
+ qs.items[i] = NULL;
+ }
qs.callback = NULL;
- if (gui_syncquickscreen_run(&qs, button_enter, &usb))
+ int ret = gui_syncquickscreen_run(&qs, button_enter, &usb);
+ if (ret & QUICKSCREEN_CHANGED)
{
settings_save();
/* make sure repeat/shuffle/any other nasty ones get updated */
@@ -442,17 +453,28 @@ int quick_screen_quick(int button_enter)
else
playlist_sort(NULL, true);
}
+#ifdef HAVE_ALBUMART
+ if (old_album_art != global_settings.album_art)
+ set_albumart_mode(global_settings.album_art);
+#endif
}
- return (usb ? 1:0);
+ if (usb)
+ return QUICKSCREEN_IN_USB;
+ return ret & QUICKSCREEN_GOTO_SHORTCUTS_MENU ? QUICKSCREEN_GOTO_SHORTCUTS_MENU :
+ QUICKSCREEN_OK;
}
/* stuff to make the quickscreen configurable */
bool is_setting_quickscreenable(const struct settings_list *setting)
{
+ if (!setting)
+ return true;
+
/* to keep things simple, only settings which have a lang_id set are ok */
- if (setting->lang_id < 0 || (setting->flags&F_BANFROMQS))
+ if (setting->lang_id < 0 || (setting->flags & F_BANFROMQS))
return false;
- switch (setting->flags&F_T_MASK)
+
+ switch (setting->flags & F_T_MASK)
{
case F_T_BOOL:
return true;
@@ -463,16 +485,3 @@ bool is_setting_quickscreenable(const struct settings_list *setting)
return false;
}
}
-
-void set_as_qs_item(const struct settings_list *setting,
- enum quickscreen_item item)
-{
- int i;
- for (i = 0; i < nb_settings; i++)
- {
- if (&settings[i] == setting)
- break;
- }
-
- global_settings.qs_items[item] = i;
-}
diff --git a/apps/gui/quickscreen.h b/apps/gui/quickscreen.h
index 015928ee8a..bd8008bd34 100644
--- a/apps/gui/quickscreen.h
+++ b/apps/gui/quickscreen.h
@@ -36,6 +36,13 @@ enum quickscreen_item {
QUICKSCREEN_ITEM_COUNT,
};
+enum quickscreen_return {
+ QUICKSCREEN_OK = 0,
+ QUICKSCREEN_IN_USB = 0x1,
+ QUICKSCREEN_GOTO_SHORTCUTS_MENU = 0x2,
+ QUICKSCREEN_CHANGED = 0x4,
+};
+
struct gui_quickscreen
{
const struct settings_list *items[QUICKSCREEN_ITEM_COUNT];
@@ -46,7 +53,6 @@ struct gui_quickscreen
extern int quick_screen_quick(int button_enter);
int quickscreen_set_option(void *data);
bool is_setting_quickscreenable(const struct settings_list *setting);
-void set_as_qs_item(const struct settings_list *setting,
- enum quickscreen_item item);
+
#endif /*_GUI_QUICK_SCREEN_H_*/
#endif /* HAVE_QUICKSCREEN */
diff --git a/apps/gui/skin_engine/skin_backdrops.c b/apps/gui/skin_engine/skin_backdrops.c
index 41de1e1f76..eecf5b0433 100644
--- a/apps/gui/skin_engine/skin_backdrops.c
+++ b/apps/gui/skin_engine/skin_backdrops.c
@@ -41,7 +41,6 @@ static struct skin_backdrop {
} backdrops[NB_BDROPS];
#define NB_BDROPS SKINNABLE_SCREENS_COUNT*NB_SCREENS
-static int handle_being_loaded;
static int current_lcd_backdrop[NB_SCREENS];
bool skin_backdrop_get_debug(int index, char **path, int *ref_count, size_t *size)
@@ -65,8 +64,8 @@ bool skin_backdrop_get_debug(int index, char **path, int *ref_count, size_t *siz
static int buflib_move_callback(int handle, void* current, void* new)
{
- if (handle == handle_being_loaded)
- return BUFLIB_CB_CANNOT_MOVE;
+ (void)handle;
+
for (int i=0; i<NB_BDROPS; i++)
{
if (backdrops[i].buffer == current)
@@ -81,8 +80,9 @@ static int buflib_move_callback(int handle, void* current, void* new)
}
static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL, NULL};
static bool first_go = true;
-void skin_backdrop_init(void)
+bool skin_backdrop_init(void)
{
+ bool go_status = first_go;
if (first_go)
{
for (int i=0; i<NB_BDROPS; i++)
@@ -95,9 +95,9 @@ void skin_backdrop_init(void)
}
FOR_NB_SCREENS(i)
current_lcd_backdrop[i] = -1;
- handle_being_loaded = -1;
first_go = false;
}
+ return go_status;
}
int skin_backdrop_assign(char* backdrop, char *bmpdir,
@@ -137,7 +137,7 @@ int skin_backdrop_assign(char* backdrop, char *bmpdir,
}
if (free >= 0)
{
- strlcpy(backdrops[free].name, filename, MAX_PATH);
+ strmemccpy(backdrops[free].name, filename, MAX_PATH);
backdrops[free].buffer = NULL;
backdrops[free].screen = screen;
backdrops[free].ref_count = 1;
@@ -174,22 +174,22 @@ bool skin_backdrops_preload(void)
}
if (*filename && *filename != '-')
{
- backdrops[i].buflib_handle = core_alloc_ex(filename, buf_size, &buflib_ops);
+ backdrops[i].buflib_handle = core_alloc_ex(buf_size, &buflib_ops);
if (backdrops[i].buflib_handle > 0)
{
backdrops[i].buffer = core_get_data(backdrops[i].buflib_handle);
if (strcmp(filename, BACKDROP_BUFFERNAME))
{
- handle_being_loaded = backdrops[i].buflib_handle;
+ core_pin(backdrops[i].buflib_handle);
backdrops[i].loaded =
screens[screen].backdrop_load(filename, backdrops[i].buffer);
+ core_unpin(backdrops[i].buflib_handle);
if (!backdrops[i].loaded)
{
core_free(backdrops[i].buflib_handle);
backdrops[i].buflib_handle = -1;
retval = false;
}
- handle_being_loaded = -1;
}
else
backdrops[i].loaded = true;
@@ -265,8 +265,7 @@ void skin_backdrop_unload(int backdrop_id)
backdrops[backdrop_id].ref_count--;
if (backdrops[backdrop_id].ref_count <= 0)
{
- if (backdrops[backdrop_id].buflib_handle > 0)
- core_free(backdrops[backdrop_id].buflib_handle);
+ core_free(backdrops[backdrop_id].buflib_handle);
backdrops[backdrop_id].buffer = NULL;
backdrops[backdrop_id].buflib_handle = -1;
backdrops[backdrop_id].loaded = false;
@@ -288,18 +287,17 @@ void skin_backdrop_load_setting(void)
if (backdrops[i].buflib_handle <= 0)
{
backdrops[i].buflib_handle =
- core_alloc_ex(global_settings.backdrop_file,
- LCD_BACKDROP_BYTES, &buflib_ops);
+ core_alloc_ex(LCD_BACKDROP_BYTES, &buflib_ops);
if (backdrops[i].buflib_handle <= 0)
return;
}
bool loaded;
+ core_pin(backdrops[i].buflib_handle);
backdrops[i].buffer = core_get_data(backdrops[i].buflib_handle);
- handle_being_loaded = backdrops[i].buflib_handle;
loaded = screens[SCREEN_MAIN].backdrop_load(
global_settings.backdrop_file,
backdrops[i].buffer);
- handle_being_loaded = -1;
+ core_unpin(backdrops[i].buflib_handle);
backdrops[i].name[2] = loaded ? '.' : '\0';
backdrops[i].loaded = loaded;
return;
@@ -331,8 +329,20 @@ void skin_backdrop_unload(int backdrop_id)
(void)backdrop_id;
}
#else
+static bool first_go = true;
+bool skin_backdrop_init(void)
+{
+ bool go_status = first_go;
+ first_go = false;
+ return go_status;
+}
-void skin_backdrop_init(void)
+void skin_backdrop_load_setting(void)
+{
+}
+
+void skin_backdrop_show(int backdrop_id)
{
+ (void) backdrop_id;
}
#endif
diff --git a/apps/gui/skin_engine/skin_display.c b/apps/gui/skin_engine/skin_display.c
index 4a3dcc2177..913bdcfbc4 100644
--- a/apps/gui/skin_engine/skin_display.c
+++ b/apps/gui/skin_engine/skin_display.c
@@ -46,6 +46,7 @@
#include "tagcache.h"
#include "list.h"
#include "option_select.h"
+#include "buffering.h"
#include "peakmeter.h"
/* Image stuff */
@@ -64,7 +65,7 @@
#endif
#include "root_menu.h"
-
+#include "wps.h"
#include "wps_internals.h"
#include "skin_engine.h"
#include "statusbar-skinned.h"
@@ -82,7 +83,7 @@ void skin_update(enum skinnable_screens skin, enum screen_type screen,
struct gui_wps *gwps = skin_get_gwps(skin, screen);
/* This maybe shouldnt be here,
* This is also safe for skined screen which dont use the id3 */
- struct mp3entry *id3 = skin_get_global_state()->id3;
+ struct mp3entry *id3 = get_wps_state()->id3;
bool cuesheet_update = (id3 != NULL ? cuesheet_subtrack_changed(id3) : false);
if (cuesheet_update)
skin_request_full_update(skin);
@@ -157,11 +158,12 @@ void ab_draw_markers(struct screen * screen, int capacity,
#endif
-void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb)
+void draw_progressbar(struct gui_wps *gwps, struct skin_viewport* skin_viewport,
+ int line, struct progressbar *pb)
{
struct screen *display = gwps->display;
- struct viewport *vp = SKINOFFSETTOPTR(get_skin_buffer(gwps->data), pb->vp);
- struct wps_state *state = skin_get_global_state();
+ struct viewport *vp = &skin_viewport->vp;
+ struct wps_state *state = get_wps_state();
struct mp3entry *id3 = state->id3;
int x = pb->x, y = pb->y, width = pb->width, height = pb->height;
unsigned long length, end;
@@ -183,8 +185,13 @@ void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb)
{
int minvol = sound_min(SOUND_VOLUME);
int maxvol = sound_max(SOUND_VOLUME);
- length = maxvol-minvol;
- end = global_settings.volume-minvol;
+#if defined(HAVE_PERCEPTUAL_VOLUME) || defined(HAVE_TOUCHSCREEN)
+ length = 1000;
+ end = to_normalized_volume(global_settings.volume, minvol, maxvol, length);
+#else
+ length = maxvol - minvol;
+ end = global_settings.volume - minvol;
+#endif
}
else if (pb->type == SKIN_TOKEN_BATTERY_PERCENTBAR)
{
@@ -210,7 +217,7 @@ void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb)
else if (pb->type == SKIN_TOKEN_SETTINGBAR)
{
int val, count;
- get_setting_info_for_bar(pb->setting_id, &count, &val);
+ get_setting_info_for_bar(pb->setting, &count, &val);
length = count - 1;
end = val;
}
@@ -411,8 +418,7 @@ void wps_display_images(struct gui_wps *gwps, struct viewport* vp)
#ifdef HAVE_ALBUMART
/* now draw the AA */
struct skin_albumart *aa = SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart);
- if (aa && SKINOFFSETTOPTR(get_skin_buffer(data), aa->vp) == vp
- && aa->draw_handle >= 0)
+ if (aa && aa->draw_handle >= 0)
{
draw_album_art(gwps, aa->draw_handle, false);
aa->draw_handle = -1;
@@ -499,78 +505,82 @@ void write_line(struct screen *display, struct align_pos *format_align,
/* CASE 1: left and centered string overlap */
/* there is a left string, need to merge left and center */
- if ((left_width != 0 && center_width != 0) &&
- (left_width + space_width > center_xpos)) {
- /* replace the former separator '\0' of left and
- center string with a space */
- *(--format_align->center) = ' ';
- /* calculate the new width and position of the merged string */
- left_width = left_width + space_width + center_width;
- /* there is no centered string anymore */
- center_width = 0;
- }
- /* there is no left string, move center to left */
- if ((left_width == 0 && center_width != 0) &&
- (left_width > center_xpos)) {
- /* move the center string to the left string */
- format_align->left = format_align->center;
- /* calculate the new width and position of the string */
- left_width = center_width;
- /* there is no centered string anymore */
- center_width = 0;
- }
+ if (center_width != 0)
+ {
+ if (left_width != 0 && left_width + space_width > center_xpos) {
+ /* replace the former separator '\0' of left and
+ center string with a space */
+ *(--format_align->center) = ' ';
+ /* calculate the new width and position of the merged string */
+ left_width = left_width + space_width + center_width;
+ /* there is no centered string anymore */
+ center_width = 0;
+ }
+ /* there is no left string, move center to left */
+ else if (left_width == 0 && center_xpos < 0) {
+ /* move the center string to the left string */
+ format_align->left = format_align->center;
+ /* calculate the new width and position of the string */
+ left_width = center_width;
+ /* there is no centered string anymore */
+ center_width = 0;
+ }
+ } /*(center_width != 0)*/
/* CASE 2: centered and right string overlap */
/* there is a right string, need to merge center and right */
- if ((center_width != 0 && right_width != 0) &&
- (center_xpos + center_width + space_width > right_xpos)) {
- /* replace the former separator '\0' of center and
- right string with a space */
- *(--format_align->right) = ' ';
- /* move the center string to the right after merge */
- format_align->right = format_align->center;
- /* calculate the new width and position of the merged string */
- right_width = center_width + space_width + right_width;
- right_xpos = (viewport_width - right_width);
- /* there is no centered string anymore */
- center_width = 0;
- }
- /* there is no right string, move center to right */
- if ((center_width != 0 && right_width == 0) &&
- (center_xpos + center_width > right_xpos)) {
- /* move the center string to the right string */
- format_align->right = format_align->center;
- /* calculate the new width and position of the string */
- right_width = center_width;
- right_xpos = (viewport_width - right_width);
- /* there is no centered string anymore */
- center_width = 0;
- }
+ if (center_width != 0)
+ {
+ int center_left_x = center_xpos + center_width;
+ if (right_width != 0 && center_left_x + space_width > right_xpos) {
+ /* replace the former separator '\0' of center and
+ right string with a space */
+ *(--format_align->right) = ' ';
+ /* move the center string to the right after merge */
+ format_align->right = format_align->center;
+ /* calculate the new width and position of the merged string */
+ right_width = center_width + space_width + right_width;
+ right_xpos = (viewport_width - right_width);
+ /* there is no centered string anymore */
+ center_width = 0;
+ }
+ /* there is no right string, move center to right */
+ else if (right_width == 0 && center_left_x > right_xpos) {
+ /* move the center string to the right string */
+ format_align->right = format_align->center;
+ /* calculate the new width and position of the string */
+ right_width = center_width;
+ right_xpos = (viewport_width - right_width);
+ /* there is no centered string anymore */
+ center_width = 0;
+ }
+ } /*(center_width != 0)*/
/* CASE 3: left and right overlap
There is no center string anymore, either there never
was one or it has been merged in case 1 or 2 */
/* there is a left string, need to merge left and right */
- if ((left_width != 0 && center_width == 0 && right_width != 0) &&
- (left_width + space_width > right_xpos)) {
- /* replace the former separator '\0' of left and
- right string with a space */
- *(--format_align->right) = ' ';
- /* calculate the new width and position of the string */
- left_width = left_width + space_width + right_width;
- /* there is no right string anymore */
- right_width = 0;
- }
- /* there is no left string, move right to left */
- if ((left_width == 0 && center_width == 0 && right_width != 0) &&
- (left_width > right_xpos)) {
- /* move the right string to the left string */
- format_align->left = format_align->right;
- /* calculate the new width and position of the string */
- left_width = right_width;
- /* there is no right string anymore */
- right_width = 0;
- }
+ if (center_width == 0 && right_width != 0)
+ {
+ if (left_width != 0 && left_width + space_width > right_xpos) {
+ /* replace the former separator '\0' of left and
+ right string with a space */
+ *(--format_align->right) = ' ';
+ /* calculate the new width and position of the string */
+ left_width = left_width + space_width + right_width;
+ /* there is no right string anymore */
+ right_width = 0;
+ }
+ /* there is no left string, move right to left */
+ else if (left_width == 0 && right_xpos < 0) {
+ /* move the right string to the left string */
+ format_align->left = format_align->right;
+ /* calculate the new width and position of the string */
+ left_width = right_width;
+ /* there is no right string anymore */
+ right_width = 0;
+ }
+ } /* (center_width == 0 && right_width != 0)*/
if (scroll && ((left_width > scroll_width) ||
(center_width > scroll_width) ||
@@ -601,9 +611,9 @@ void write_line(struct screen *display, struct align_pos *format_align,
char *center = format_align->center ?: "";
char *right = format_align->right ?: "";
- display->put_line(0, line, linedes, "$t$*s$t$*s$t", left,
- center_xpos - left_width, center,
- right_xpos - (center_xpos + center_width), right);
+ display->put_line(0, line, linedes, "$t$*s$t$*s$t", left_width == 0 ? "" : left ,
+ center_xpos - left_width, center_width == 0 ? "" : center,
+ right_xpos - center_xpos - center_width, right_width == 0 ? "" : right);
}
}
@@ -632,14 +642,86 @@ void draw_peakmeters(struct gui_wps *gwps, int line_number,
}
}
-bool skin_has_sbs(enum screen_type screen, struct wps_data *data)
+#ifdef HAVE_ALBUMART
+/* Draw the album art bitmap from the given handle ID onto the given WPS.
+ Call with clear = true to clear the bitmap instead of drawing it. */
+void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear)
+{
+ if (!gwps || !gwps->data || !gwps->display || handle_id < 0)
+ return;
+
+ struct wps_data *data = gwps->data;
+ struct skin_albumart *aa = SKINOFFSETTOPTR(get_skin_buffer(data), data->albumart);
+
+ if (!aa)
+ return;
+
+ struct bitmap *bmp;
+ if (bufgetdata(handle_id, 0, (void *)&bmp) <= 0)
+ return;
+
+ short x = aa->x;
+ short y = aa->y;
+ short width = bmp->width;
+ short height = bmp->height;
+
+ if (aa->width > 0)
+ {
+ /* Crop if the bitmap is too wide */
+ width = MIN(bmp->width, aa->width);
+
+ /* Align */
+ if (aa->xalign & WPS_ALBUMART_ALIGN_RIGHT)
+ x += aa->width - width;
+ else if (aa->xalign & WPS_ALBUMART_ALIGN_CENTER)
+ x += (aa->width - width) / 2;
+ }
+
+ if (aa->height > 0)
+ {
+ /* Crop if the bitmap is too high */
+ height = MIN(bmp->height, aa->height);
+
+ /* Align */
+ if (aa->yalign & WPS_ALBUMART_ALIGN_BOTTOM)
+ y += aa->height - height;
+ else if (aa->yalign & WPS_ALBUMART_ALIGN_CENTER)
+ y += (aa->height - height) / 2;
+ }
+
+ if (!clear)
+ {
+ /* Draw the bitmap */
+ gwps->display->bitmap_part((fb_data*)bmp->data, 0, 0,
+ STRIDE(gwps->display->screen_type,
+ bmp->width, bmp->height),
+ x, y, width, height);
+#ifdef HAVE_LCD_INVERT
+ if (global_settings.invert) {
+ gwps->display->set_drawmode(DRMODE_COMPLEMENT);
+ gwps->display->fillrect(x, y, width, height);
+ gwps->display->set_drawmode(DRMODE_SOLID);
+ }
+#endif
+ }
+ else
+ {
+ /* Clear the bitmap */
+ gwps->display->set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
+ gwps->display->fillrect(x, y, width, height);
+ gwps->display->set_drawmode(DRMODE_SOLID);
+ }
+}
+#endif
+
+bool skin_has_sbs(struct gui_wps *gwps)
{
- (void)screen;
- (void)data;
+ struct wps_data *data = gwps->data;
+
bool draw = false;
if (data->wps_sb_tag)
draw = data->show_sb_on_wps;
- else if (statusbar_position(screen) != STATUSBAR_OFF)
+ else if (statusbar_position(gwps->display->screen_type) != STATUSBAR_OFF)
draw = true;
return draw;
}
diff --git a/apps/gui/skin_engine/skin_display.h b/apps/gui/skin_engine/skin_display.h
index de1b0b20b5..56af12aa03 100644
--- a/apps/gui/skin_engine/skin_display.h
+++ b/apps/gui/skin_engine/skin_display.h
@@ -29,7 +29,8 @@
#define _SKIN_DISPLAY_H_
-void draw_progressbar(struct gui_wps *gwps, int line, struct progressbar *pb);
+void draw_progressbar(struct gui_wps *gwps, struct skin_viewport* skin_viewport,
+ int line, struct progressbar *pb);
void draw_playlist_viewer_list(struct gui_wps *gwps, struct playlistviewer *viewer);
/* clears the area where the image was shown */
void clear_image_pos(struct gui_wps *gwps, struct gui_img *img);
@@ -54,4 +55,10 @@ void write_line(struct screen *display, struct align_pos *format_align,
int line, bool scroll, struct line_desc *line_desc);
void draw_peakmeters(struct gui_wps *gwps, int line_number,
struct viewport *viewport);
+#ifdef HAVE_ALBUMART
+/* Draw the album art bitmap from the given handle ID onto the given Skin.
+ Call with clear = true to clear the bitmap instead of drawing it. */
+void draw_album_art(struct gui_wps *gwps, int handle_id, bool clear);
+#endif
+
#endif
diff --git a/apps/gui/skin_engine/skin_engine.c b/apps/gui/skin_engine/skin_engine.c
index ce3401f41c..c007ed35d4 100644
--- a/apps/gui/skin_engine/skin_engine.c
+++ b/apps/gui/skin_engine/skin_engine.c
@@ -34,9 +34,11 @@
#if CONFIG_TUNER
#include "radio.h"
#endif
+#include "gui/list.h"
#include "skin_engine.h"
#include "skin_buffer.h"
#include "statusbar-skinned.h"
+#include "wps_internals.h"
#define FAILSAFENAME "rockbox_failsafe"
@@ -51,7 +53,6 @@ static bool skins_initialised = false;
static char* get_skin_filename(char *buf, size_t buf_size,
enum skinnable_screens skin, enum screen_type screen);
-struct wps_state wps_state = { .id3 = NULL };
static struct gui_skin_helper {
int (*preproccess)(enum screen_type screen, struct wps_data *data);
int (*postproccess)(enum screen_type screen, struct wps_data *data);
@@ -149,13 +150,28 @@ void skin_unload_all(void)
gui_sync_skin_init();
}
+static void skin_reset_buffers(int item, int screen)
+{
+ skin_data_free_buflib_allocs(&skins[item][screen].data);
+#ifdef HAVE_ALBUMART
+ if (skins[item][screen].data.playback_aa_slot >= 0)
+ playback_release_aa_slot(skins[item][screen].data.playback_aa_slot);
+#endif
+#ifdef HAVE_BACKDROP_IMAGE
+ if (skins[item][screen].data.backdrop_id >= 0)
+ skin_backdrop_unload(skins[item][screen].data.backdrop_id);
+#endif
+}
+
void settings_apply_skins(void)
{
int i;
char filename[MAX_PATH];
- static bool first_run = true;
- skin_backdrop_init();
+ if (audio_status() & AUDIO_STATUS_PLAY)
+ audio_stop();
+
+ bool first_run = skin_backdrop_init();
skins_initialised = true;
/* Make sure each skin is loaded */
@@ -167,15 +183,7 @@ void settings_apply_skins(void)
if (!first_run)
{
- skin_data_free_buflib_allocs(&skins[i][j].data);
-#ifdef HAVE_ALBUMART
- if (skins[i][j].data.playback_aa_slot >= 0)
- playback_release_aa_slot(skins[i][j].data.playback_aa_slot);
-#endif
-#ifdef HAVE_BACKDROP_IMAGE
- if (skins[i][j].data.backdrop_id >= 0)
- skin_backdrop_unload(skins[i][j].data.backdrop_id);
-#endif
+ skin_reset_buffers(i, j);
}
gui_skin_reset(&skins[i][j]);
skins[i][j].gui_wps.display = &screens[j];
@@ -183,17 +191,14 @@ void settings_apply_skins(void)
skin_get_gwps(i, j);
}
}
- first_run = false;
-#ifdef HAVE_BACKDROP_IMAGE
+
/* any backdrop that was loaded with "-" has to be reloaded because
* the setting may have changed */
skin_backdrop_load_setting();
-#endif
viewportmanager_theme_changed(THEME_STATUSBAR);
-#ifdef HAVE_BACKDROP_IMAGE
+
FOR_NB_SCREENS(i)
skin_backdrop_show(sb_get_backdrop(i));
-#endif
}
void skin_load(enum skinnable_screens skin, enum screen_type screen,
@@ -304,11 +309,6 @@ struct gui_wps *skin_get_gwps(enum skinnable_screens skin, enum screen_type scre
return &skins[skin][screen].gui_wps;
}
-struct wps_state *skin_get_global_state(void)
-{
- return &wps_state;
-}
-
/* This is called to find out if we the screen needs a full update.
* if true you MUST do a full update as the next call will return false */
bool skin_do_full_update(enum skinnable_screens skin,
@@ -330,3 +330,56 @@ void skin_request_full_update(enum skinnable_screens skin)
FOR_NB_SCREENS(i)
skins[skin][i].needs_full_update = true;
}
+
+bool dbg_skin_engine(void)
+{
+ struct simplelist_info info;
+ int i, total = 0;
+#if defined(HAVE_BACKDROP_IMAGE)
+ int ref_count;
+ char *path;
+ size_t bytes;
+ int path_prefix_len = strlen(ROCKBOX_DIR "/wps/");
+#endif
+ simplelist_info_init(&info, "Skin engine usage", 0, NULL);
+ simplelist_set_line_count(0);
+ FOR_NB_SCREENS(j) {
+#if NB_SCREENS > 1
+ simplelist_addline("%s display:",
+ j == 0 ? "Main" : "Remote");
+#endif
+ for (i = 0; i < skin_get_num_skins(); i++) {
+ struct skin_stats *stats = skin_get_stats(i, j);
+ if (stats->buflib_handles)
+ {
+ simplelist_addline("Skin ID: %d, %d allocations",
+ i, stats->buflib_handles);
+ simplelist_addline("\tskin: %d bytes",
+ stats->tree_size);
+ simplelist_addline("\tImages: %d bytes",
+ stats->images_size);
+ simplelist_addline("\tTotal: %d bytes",
+ stats->tree_size + stats->images_size);
+ total += stats->tree_size + stats->images_size;
+ }
+ }
+ }
+ simplelist_addline("Skin total usage: %d bytes", total);
+#if defined(HAVE_BACKDROP_IMAGE)
+ simplelist_addline("Backdrop Images:");
+ i = 0;
+ while (skin_backdrop_get_debug(i++, &path, &ref_count, &bytes)) {
+ if (ref_count > 0) {
+
+ if (!strncasecmp(path, ROCKBOX_DIR "/wps/", path_prefix_len))
+ path += path_prefix_len;
+ simplelist_addline("%s", path);
+ simplelist_addline("\tref_count: %d", ref_count);
+ simplelist_addline("\tsize: %d", bytes);
+ total += bytes;
+ }
+ }
+ simplelist_addline("Total usage: %d bytes", total);
+#endif
+ return simplelist_show_list(&info);
+}
diff --git a/apps/gui/skin_engine/skin_engine.h b/apps/gui/skin_engine/skin_engine.h
index 3b757a5f8b..d04c873e84 100644
--- a/apps/gui/skin_engine/skin_engine.h
+++ b/apps/gui/skin_engine/skin_engine.h
@@ -26,8 +26,7 @@
#ifndef PLUGIN
#include "tag_table.h"
-
-#include "wps_internals.h" /* TODO: remove this line.. shoudlnt be needed */
+#include "screen_access.h"
enum skinnable_screens {
CUSTOM_STATUSBAR,
@@ -39,30 +38,26 @@ enum skinnable_screens {
SKINNABLE_SCREENS_COUNT
};
+struct skin_stats;
+struct skin_viewport;
+struct gui_wps;
+
#ifdef HAVE_TOUCHSCREEN
-int skin_get_touchaction(struct wps_data *data, int* edge_offset,
- struct touchregion **retregion);
-void skin_disarm_touchregions(struct wps_data *data);
+int skin_get_touchaction(struct gui_wps *gwps, int* edge_offset);
+void skin_disarm_touchregions(struct gui_wps *gwps);
#endif
/* Do a update_type update of the skinned screen */
void skin_update(enum skinnable_screens skin, enum screen_type screen,
unsigned int update_type);
-/*
- * setup up the skin-data from a format-buffer (isfile = false)
- * or from a skinfile (isfile = true)
- */
-bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
- const char *buf, bool isfile, struct skin_stats *stats);
-
-bool skin_has_sbs(enum screen_type screen, struct wps_data *data);
+bool skin_has_sbs(struct gui_wps *gwps);
/* load a backdrop into the skin buffer.
* reuse buffers if the file is already loaded */
char* skin_backdrop_load(char* backdrop, char *bmpdir, enum screen_type screen);
-void skin_backdrop_init(void);
+bool skin_backdrop_init(void);
int skin_backdrop_assign(char* backdrop, char *bmpdir,
enum screen_type screen);
bool skin_backdrops_preload(void);
@@ -81,7 +76,6 @@ int skin_wait_for_action(enum skinnable_screens skin, int context, int timeout);
void skin_load(enum skinnable_screens skin, enum screen_type screen,
const char *buf, bool isfile);
struct gui_wps *skin_get_gwps(enum skinnable_screens skin, enum screen_type screen);
-struct wps_state *skin_get_global_state(void);
void gui_sync_skin_init(void);
void skin_unload_all(void);
@@ -89,5 +83,7 @@ void skin_unload_all(void);
bool skin_do_full_update(enum skinnable_screens skin, enum screen_type screen);
void skin_request_full_update(enum skinnable_screens skin);
+bool dbg_skin_engine(void);
+
#endif /* !PLUGIN */
#endif
diff --git a/apps/gui/skin_engine/skin_parser.c b/apps/gui/skin_engine/skin_parser.c
index 4ebdcab722..6cc3c596b0 100644
--- a/apps/gui/skin_engine/skin_parser.c
+++ b/apps/gui/skin_engine/skin_parser.c
@@ -343,11 +343,12 @@ static int parse_image_display(struct skin_element *element,
if (element->params_count > 1)
{
- if (get_param(element, 1)->type == CODE)
+ struct skin_tag_parameter *param1 = get_param(element, 1);
+ if (param1->type == CODE)
id->token = get_param_code(element, 1)->data;
/* specify a number. 1 being the first subimage (i.e top) NOT 0 */
- else if (get_param(element, 1)->type == INTEGER)
- id->subimage = get_param(element, 1)->data.number - 1;
+ else if (param1->type == INTEGER)
+ id->subimage = param1->data.number - 1;
if (element->params_count > 2)
id->offset = get_param(element, 2)->data.number;
}
@@ -391,14 +392,16 @@ static int parse_image_load(struct skin_element *element,
subimages = get_param(element, 2)->data.number;
else if (element->params_count > 3)
{
- if (get_param(element, 2)->type == PERCENT)
- x = get_param(element, 2)->data.number * curr_vp->vp.width / 1000;
+ struct skin_tag_parameter *param2 = get_param(element, 2);
+ struct skin_tag_parameter *param3 = get_param(element, 3);
+ if (param2->type == PERCENT)
+ x = param2->data.number * curr_vp->vp.width / 1000;
else
- x = get_param(element, 2)->data.number;
- if (get_param(element, 3)->type == PERCENT)
- y = get_param(element, 3)->data.number * curr_vp->vp.height / 1000;
+ x = param2->data.number;
+ if (param3->type == PERCENT)
+ y = param3->data.number * curr_vp->vp.height / 1000;
else
- y = get_param(element, 3)->data.number;
+ y = param3->data.number;
if (element->params_count == 5)
subimages = get_param(element, 4)->data.number;
@@ -424,9 +427,6 @@ static int parse_image_load(struct skin_element *element,
img->is_9_segment = false;
img->loaded = false;
- /* save current viewport */
- img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
-
if (token->type == SKIN_TOKEN_IMAGE_DISPLAY)
token->value.data = PTRTOSKINOFFSET(skin_buffer, img);
@@ -494,7 +494,6 @@ static int parse_playlistview(struct skin_element *element,
struct playlistviewer *viewer = skin_buffer_alloc(sizeof(*viewer));
if (!viewer)
return WPS_ERROR_INVALID_PARAM;
- viewer->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
viewer->show_icons = true;
viewer->start_offset = get_param(element, 0)->data.number;
viewer->line = PTRTOSKINOFFSET(skin_buffer, get_param_code(element, 1));
@@ -561,6 +560,7 @@ static int parse_listitemviewport(struct skin_element *element,
struct wps_data *wps_data)
{
#ifndef __PCTOOL__
+ struct skin_tag_parameter *param;
struct listitem_viewport_cfg *cfg = skin_buffer_alloc(sizeof(*cfg));
if (!cfg)
return -1;
@@ -569,10 +569,15 @@ static int parse_listitemviewport(struct skin_element *element,
cfg->label = PTRTOSKINOFFSET(skin_buffer, get_param_text(element, 0));
cfg->width = -1;
cfg->height = -1;
- if (!isdefault(get_param(element, 1)))
- cfg->width = get_param(element, 1)->data.number;
- if (!isdefault(get_param(element, 2)))
- cfg->height = get_param(element, 2)->data.number;
+
+ param = get_param(element, 1);
+ if (!isdefault(param))
+ cfg->width = param->data.number;
+
+ param = get_param(element, 2);
+ if (!isdefault(param))
+ cfg->height = param->data.number;
+
if (element->params_count > 3 &&
!strcmp(get_param_text(element, 3), "tile"))
cfg->tile = true;
@@ -592,20 +597,26 @@ static int parse_viewporttextstyle(struct skin_element *element,
*line = (struct line_desc)LINE_DESC_DEFINIT;
unsigned colour;
- if (!strcmp(mode, "invert"))
+ static const char * const vp_options[] = { "invert", "color", "colour",
+ "clear", "gradient", NULL};
+
+ int vp_op = string_option(mode, vp_options, false);
+
+ if (vp_op == 0) /*invert*/
{
line->style = STYLE_INVERT;
}
- else if (!strcmp(mode, "colour") || !strcmp(mode, "color"))
+ else if (vp_op == 1 || vp_op == 2) /*color/colour*/
{
if (element->params_count < 2 ||
!parse_color(curr_screen, get_param_text(element, 1), &colour))
return 1;
- line->style = STYLE_COLORED;
+ /* STYLE_COLORED is only a modifier and can't be used on its own */
+ line->style = STYLE_COLORED | STYLE_DEFAULT;
line->text_color = colour;
}
#ifdef HAVE_LCD_COLOR
- else if (!strcmp(mode, "gradient"))
+ else if (vp_op == 4) /*gradient*/
{
int num_lines;
if (element->params_count < 2)
@@ -618,7 +629,7 @@ static int parse_viewporttextstyle(struct skin_element *element,
line->nlines = num_lines;
}
#endif
- else if (!strcmp(mode, "clear"))
+ else if (vp_op == 3) /*clear*/
{
line->style = STYLE_DEFAULT;
}
@@ -634,34 +645,39 @@ static int parse_drawrectangle( struct skin_element *element,
struct wps_data *wps_data)
{
(void)wps_data;
+ struct skin_tag_parameter *param;
struct draw_rectangle *rect = skin_buffer_alloc(sizeof(*rect));
if (!rect)
return -1;
- if (get_param(element, 0)->type == PERCENT)
- rect->x = get_param(element, 0)->data.number * curr_vp->vp.width / 1000;
+ param = get_param(element, 0);
+ if (param->type == PERCENT)
+ rect->x = param->data.number * curr_vp->vp.width / 1000;
else
- rect->x = get_param(element, 0)->data.number;
+ rect->x = param->data.number;
- if (get_param(element, 1)->type == PERCENT)
- rect->y = get_param(element, 1)->data.number * curr_vp->vp.height / 1000;
+ param = get_param(element, 1);
+ if (param->type == PERCENT)
+ rect->y = param->data.number * curr_vp->vp.height / 1000;
else
- rect->y = get_param(element, 1)->data.number;
+ rect->y = param->data.number;
- if (isdefault(get_param(element, 2)))
+ param = get_param(element, 2);
+ if (isdefault(param))
rect->width = curr_vp->vp.width - rect->x;
- else if (get_param(element, 2)->type == PERCENT)
- rect->width = get_param(element, 2)->data.number * curr_vp->vp.width / 1000;
+ else if (param->type == PERCENT)
+ rect->width = param->data.number * curr_vp->vp.width / 1000;
else
- rect->width = get_param(element, 2)->data.number;
+ rect->width = param->data.number;
- if (isdefault(get_param(element, 3)))
+ param = get_param(element, 3);
+ if (isdefault(param))
rect->height = curr_vp->vp.height - rect->y;
- else if (get_param(element, 3)->type == PERCENT)
- rect->height = get_param(element, 3)->data.number * curr_vp->vp.height / 1000;
+ else if (param->type == PERCENT)
+ rect->height = param->data.number * curr_vp->vp.height / 1000;
else
- rect->height = get_param(element, 3)->data.number;
+ rect->height = param->data.number;
rect->start_colour = curr_vp->vp.fg_pattern;
rect->end_colour = curr_vp->vp.fg_pattern;
@@ -695,8 +711,35 @@ static int parse_viewportcolour(struct skin_element *element,
return -1;
if (isdefault(param))
{
- colour->colour = get_viewport_default_colour(curr_screen,
- token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR);
+ unsigned int fg_color;
+ unsigned int bg_color;
+
+ switch (curr_screen)
+ {
+#if defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1
+ case SCREEN_REMOTE:
+ fg_color = LCD_REMOTE_DEFAULT_FG;
+ bg_color = LCD_REMOTE_DEFAULT_BG;
+ break;
+#endif
+ default:
+#if defined(HAVE_LCD_COLOR)
+ fg_color = global_settings.fg_color;
+ bg_color = global_settings.bg_color;
+#elif LCD_DEPTH > 1
+ fg_color = LCD_DEFAULT_FG;
+ bg_color = LCD_DEFAULT_BG;
+#else
+ fg_color = 0;
+ bg_color = 0;
+#endif
+ break;
+ }
+
+ if (token->type == SKIN_TOKEN_VIEWPORT_FGCOLOUR)
+ colour->colour = fg_color;
+ else
+ colour->colour = bg_color;
}
else
{
@@ -704,7 +747,6 @@ static int parse_viewportcolour(struct skin_element *element,
&colour->colour))
return -1;
}
- colour->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
token->value.data = PTRTOSKINOFFSET(skin_buffer, colour);
if (element->line == curr_viewport_element->line)
{
@@ -761,14 +803,14 @@ static int parse_setting_and_lang(struct skin_element *element,
*/
(void)wps_data;
char *temp = get_param_text(element, 0);
- int i;
if (token->type == SKIN_TOKEN_TRANSLATEDSTRING)
{
#ifndef __PCTOOL__
- i = lang_english_to_id(temp);
+ int i = lang_english_to_id(temp);
if (i < 0)
i = LANG_LAST_INDEX_IN_ARRAY;
+ token->value.i = i;
#endif
}
else if (element->params_count > 1)
@@ -781,12 +823,13 @@ static int parse_setting_and_lang(struct skin_element *element,
else
{
#ifndef __PCTOOL__
- if (find_setting_by_cfgname(temp, &i) == NULL)
+ const struct settings_list *setting = find_setting_by_cfgname(temp);
+ if (!setting)
return WPS_ERROR_INVALID_PARAM;
+
+ token->value.xdata = (void *)setting;
#endif
}
- /* Store the setting number */
- token->value.i = i;
return 0;
}
@@ -811,19 +854,38 @@ static int parse_logical_if(struct skin_element *element,
token->value.data = PTRTOSKINOFFSET(skin_buffer, lif);
lif->token = get_param_code(element, 0)->data;
- if (!strncmp(op, "=", 1))
- lif->op = IF_EQUALS;
- else if (!strncmp(op, "!=", 2))
- lif->op = IF_NOTEQUALS;
- else if (!strncmp(op, ">=", 2))
- lif->op = IF_GREATERTHAN_EQ;
- else if (!strncmp(op, "<=", 2))
- lif->op = IF_LESSTHAN_EQ;
- else if (!strncmp(op, ">", 2))
- lif->op = IF_GREATERTHAN;
- else if (!strncmp(op, "<", 1))
- lif->op = IF_LESSTHAN;
-
+ /* one or two operator conditionals */
+ #define OPS2VAL(op1, op2) ((int)op1 << 8 | (int)op2)
+ #define CLAUSE(op1, op2, symbol) {OPS2VAL(op1, op2), symbol }
+
+ struct clause_symbol {int value;int symbol;};
+ static const struct clause_symbol get_clause_match[] =
+ {
+ CLAUSE('=', '=', IF_EQUALS),
+ CLAUSE('!', '=', IF_NOTEQUALS),
+ CLAUSE('>', '=', IF_GREATERTHAN_EQ),
+ CLAUSE('<', '=', IF_LESSTHAN_EQ),
+ /*All Single value items @ end */
+ CLAUSE('>', 0, IF_GREATERTHAN),
+ CLAUSE('<', 0, IF_LESSTHAN),
+ CLAUSE('=', 0, IF_EQUALS),
+ };
+
+ int val1 = OPS2VAL(op[0], 0);
+ int val2;
+ if (val1 != 0) /* Empty string ?*/
+ {
+ val2 = OPS2VAL(op[0], op[1]);
+ for (unsigned int i = 0; i < ARRAYLEN(get_clause_match); i++)
+ {
+ const struct clause_symbol *sym = &get_clause_match[i];
+ if(sym->value == val1 || sym->value == val2)
+ {
+ lif->op = sym->symbol;
+ break;
+ }
+ }
+ }
memcpy(&lif->operand, get_param(element, 2), sizeof(lif->operand));
if (element->params_count > 3)
lif->num_options = get_param(element, 3)->data.number;
@@ -904,7 +966,6 @@ static int parse_progressbar_tag(struct skin_element* element,
if (!pb)
return WPS_ERROR_INVALID_PARAM;
- pb->vp = PTRTOSKINOFFSET(skin_buffer, vp);
pb->follow_lang_direction = follow_lang_direction > 0;
pb->nofill = false;
pb->noborder = false;
@@ -912,7 +973,7 @@ static int parse_progressbar_tag(struct skin_element* element,
pb->image = PTRTOSKINOFFSET(skin_buffer, NULL);
pb->slider = PTRTOSKINOFFSET(skin_buffer, NULL);
pb->backdrop = PTRTOSKINOFFSET(skin_buffer, NULL);
- pb->setting_id = -1;
+ pb->setting = NULL;
pb->invert_fill_direction = false;
pb->horizontal = true;
@@ -1009,20 +1070,37 @@ static int parse_progressbar_tag(struct skin_element* element,
}
pb->horizontal = pb->width > pb->height;
+
+ enum
+ {
+ eINVERT = 0, eNOFILL, eNOBORDER, eNOBAR, eSLIDER, eIMAGE,
+ eBACKDROP, eVERTICAL, eHORIZONTAL, eNOTOUCH, eSETTING,
+ e_PB_TAG_COUNT
+ };
+
+ static const char *pb_options[e_PB_TAG_COUNT + 1] = {[eINVERT] = "invert",
+ [eNOFILL] = "nofill", [eNOBORDER] = "noborder", [eNOBAR] = "nobar",
+ [eSLIDER] = "slider", [eIMAGE] = "image", [eBACKDROP] = "backdrop",
+ [eVERTICAL] = "vertical", [eHORIZONTAL] = "horizontal",
+ [eNOTOUCH] = "notouch", [eSETTING] = "setting", [e_PB_TAG_COUNT] = NULL};
+ int pb_op;
+
while (curr_param < element->params_count)
{
char* text;
param++;
text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
- if (!strcmp(text, "invert"))
+
+ pb_op = string_option(text, pb_options, false);
+ if (pb_op == eINVERT)
pb->invert_fill_direction = true;
- else if (!strcmp(text, "nofill"))
+ else if (pb_op == eNOFILL)
pb->nofill = true;
- else if (!strcmp(text, "noborder"))
+ else if (pb_op == eNOBORDER)
pb->noborder = true;
- else if (!strcmp(text, "nobar"))
+ else if (pb_op == eNOBAR)
pb->nobar = true;
- else if (!strcmp(text, "slider"))
+ else if (pb_op == eSLIDER)
{
if (curr_param+1 < element->params_count)
{
@@ -1035,7 +1113,7 @@ static int parse_progressbar_tag(struct skin_element* element,
else /* option needs the next param */
return -1;
}
- else if (!strcmp(text, "image"))
+ else if (pb_op == eIMAGE)
{
if (curr_param+1 < element->params_count)
{
@@ -1046,7 +1124,7 @@ static int parse_progressbar_tag(struct skin_element* element,
else /* option needs the next param */
return -1;
}
- else if (!strcmp(text, "backdrop"))
+ else if (pb_op == eBACKDROP)
{
if (curr_param+1 < element->params_count)
{
@@ -1060,31 +1138,32 @@ static int parse_progressbar_tag(struct skin_element* element,
else /* option needs the next param */
return -1;
}
- else if (!strcmp(text, "vertical"))
+ else if (pb_op == eVERTICAL)
{
pb->horizontal = false;
if (isdefault(get_param(element, 3)))
pb->height = vp->height - pb->y;
}
- else if (!strcmp(text, "horizontal"))
+ else if (pb_op == eHORIZONTAL)
pb->horizontal = true;
#ifdef HAVE_TOUCHSCREEN
- else if (!strcmp(text, "notouch"))
+ else if (pb_op == eNOTOUCH)
suppress_touchregion = true;
#endif
- else if (token->type == SKIN_TOKEN_SETTING && !strcmp(text, "setting"))
- {
+ else if (token->type == SKIN_TOKEN_SETTING && pb_op == eSETTING)
+ {
if (curr_param+1 < element->params_count)
{
curr_param++;
param++;
text = SKINOFFSETTOPTR(skin_buffer, param->data.text);
#ifndef __PCTOOL__
- if (find_setting_by_cfgname(text, &pb->setting_id) == NULL)
- return WPS_ERROR_INVALID_PARAM;
+ pb->setting = find_setting_by_cfgname(text);
+ if (!pb->setting)
+ return WPS_ERROR_INVALID_PARAM;
#endif
- }
- }
+ }
+ }
else if (curr_param == 4)
image_filename = text;
@@ -1114,7 +1193,6 @@ static int parse_progressbar_tag(struct skin_element* element,
img->display = -1;
img->using_preloaded_icons = false;
img->buflib_handle = -1;
- img->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
img->loaded = false;
struct skin_token_list *item = new_skin_token_list_item(NULL, img);
if (!item)
@@ -1187,7 +1265,7 @@ static int parse_progressbar_tag(struct skin_element* element,
region->reverse_bar = false;
region->allow_while_locked = false;
region->press_length = PRESS;
- region->last_press = 0xffff;
+ region->last_press = -1;
region->armed = false;
region->bar = PTRTOSKINOFFSET(skin_buffer, pb);
@@ -1219,24 +1297,28 @@ static int parse_albumart_load(struct skin_element* element,
aa->xalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
aa->yalign = WPS_ALBUMART_ALIGN_CENTER; /* default */
- aa->x = get_param(element, 0)->data.number;
- aa->y = get_param(element, 1)->data.number;
- aa->width = get_param(element, 2)->data.number;
- aa->height = get_param(element, 3)->data.number;
+ struct skin_tag_parameter *param0 = get_param(element, 0);
+ struct skin_tag_parameter *param1 = get_param(element, 1);
+ struct skin_tag_parameter *param2 = get_param(element, 2);
+ struct skin_tag_parameter *param3 = get_param(element, 3);
+
+ aa->x = param0->data.number;
+ aa->y = param1->data.number;
+ aa->width = param2->data.number;
+ aa->height = param3->data.number;
- if (!isdefault(get_param(element, 0)) && get_param(element, 0)->type == PERCENT)
- aa->x = get_param(element, 0)->data.number * curr_vp->vp.width / 1000;
+ if (!isdefault(param0) && param0->type == PERCENT)
+ aa->x = param0->data.number * curr_vp->vp.width / 1000;
- if (!isdefault(get_param(element, 1)) && get_param(element, 1)->type == PERCENT)
- aa->y = get_param(element, 1)->data.number * curr_vp->vp.height / 1000;
+ if (!isdefault(param1) && param1->type == PERCENT)
+ aa->y = param1->data.number * curr_vp->vp.height / 1000;
- if (!isdefault(get_param(element, 2)) && get_param(element, 2)->type == PERCENT)
- aa->width = get_param(element, 2)->data.number * curr_vp->vp.width / 1000;
+ if (!isdefault(param2) && param2->type == PERCENT)
+ aa->width = param2->data.number * curr_vp->vp.width / 1000;
- if (!isdefault(get_param(element, 3)) && get_param(element, 3)->type == PERCENT)
- aa->height = get_param(element, 3)->data.number * curr_vp->vp.height / 1000;
+ if (!isdefault(param3) && param3->type == PERCENT)
+ aa->height = param3->data.number * curr_vp->vp.height / 1000;
- aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
aa->draw_handle = -1;
/* if we got here, we parsed everything ok .. ! */
@@ -1341,27 +1423,32 @@ static int parse_skinvar( struct skin_element *element,
return 0;
case SKIN_TOKEN_VAR_SET:
{
+ static const char * const sv_options[] = {"touch", "set", "inc", "dec", NULL};
+
struct skin_var_changer *data = skin_buffer_alloc(sizeof(*data));
if (!data)
return WPS_ERROR_INVALID_PARAM;
data->var = PTRTOSKINOFFSET(skin_buffer, var);
+ char *text_param1 = get_param_text(element, 1);
+ int sv_op = string_option(text_param1, sv_options, false);
+
if (!isdefault(get_param(element, 2)))
data->newval = get_param(element, 2)->data.number;
- else if (strcmp(get_param_text(element, 1), "touch"))
+ else if (sv_op != 0) /*!touch*/
return WPS_ERROR_INVALID_PARAM;
data->max = 0;
- if (!strcmp(get_param_text(element, 1), "set"))
+ if (sv_op == 1) /*set*/
data->direct = true;
- else if (!strcmp(get_param_text(element, 1), "inc"))
+ else if (sv_op == 2) /*inc*/
{
data->direct = false;
}
- else if (!strcmp(get_param_text(element, 1), "dec"))
+ else if (sv_op == 3) /*dec*/
{
data->direct = false;
data->newval *= -1;
}
- else if (!strcmp(get_param_text(element, 1), "touch"))
+ else if (sv_op == 0) /*touch*/
{
data->direct = false;
data->newval = 0;
@@ -1403,12 +1490,12 @@ static int parse_lasttouch(struct skin_element *element,
for (i=0; i<element->params_count; i++)
{
- if (get_param(element, i)->type == STRING)
+ struct skin_tag_parameter *param = get_param(element, i);
+ if (param->type == STRING)
region = skin_find_item(get_param_text(element, i),
SKIN_FIND_TOUCHREGION, wps_data);
- else if (get_param(element, i)->type == INTEGER ||
- get_param(element, i)->type == DECIMAL)
- data->timeout = get_param(element, i)->data.number;
+ else if (param->type == INTEGER || param->type == DECIMAL)
+ data->timeout = param->data.number;
}
data->region = PTRTOSKINOFFSET(skin_buffer, region);
@@ -1461,48 +1548,48 @@ static int touchregion_setup_setting(struct skin_element *element, int param_no,
#ifndef __PCTOOL__
int p = param_no;
char *name = get_param_text(element, p++);
- int j;
-
- region->setting_data.setting = find_setting_by_cfgname(name, &j);
- if (region->setting_data.setting == NULL)
+ const struct settings_list *setting = find_setting_by_cfgname(name);
+ if (!setting)
return WPS_ERROR_INVALID_PARAM;
+ region->setting_data.setting = setting;
+
if (region->action == ACTION_SETTINGS_SET)
{
char* text;
int temp;
- struct touchsetting *setting =
+ struct touchsetting *touchsetting =
&region->setting_data;
if (element->params_count < p+1)
return -1;
text = get_param_text(element, p++);
- switch (settings[j].flags&F_T_MASK)
+ switch (setting->flags & F_T_MASK)
{
case F_T_CUSTOM:
- setting->value.text = PTRTOSKINOFFSET(skin_buffer, text);
+ touchsetting->value.text = PTRTOSKINOFFSET(skin_buffer, text);
break;
case F_T_INT:
case F_T_UINT:
- if (settings[j].cfg_vals == NULL)
+ if (setting->cfg_vals == NULL)
{
- setting->value.number = atoi(text);
+ touchsetting->value.number = atoi(text);
}
- else if (cfg_string_to_int(j, &temp, text))
+ else if (cfg_string_to_int(setting, &temp, text))
{
- if (settings[j].flags&F_TABLE_SETTING)
- setting->value.number =
- settings[j].table_setting->values[temp];
+ if (setting->flags & F_TABLE_SETTING)
+ touchsetting->value.number =
+ setting->table_setting->values[temp];
else
- setting->value.number = temp;
+ touchsetting->value.number = temp;
}
else
return -1;
break;
case F_T_BOOL:
- if (cfg_string_to_int(j, &temp, text))
+ if (cfg_string_to_int(setting, &temp, text))
{
- setting->value.number = temp;
+ touchsetting->value.number = temp;
}
else
return -1;
@@ -1602,7 +1689,7 @@ static int parse_touchregion(struct skin_element *element,
region->armed = false;
region->reverse_bar = false;
region->value = 0;
- region->last_press = 0xffff;
+ region->last_press = -1;
region->press_length = PRESS;
region->allow_while_locked = false;
region->bar = PTRTOSKINOFFSET(skin_buffer, NULL);
@@ -1640,16 +1727,21 @@ static int parse_touchregion(struct skin_element *element,
if (region->action == ACTION_NONE)
return WPS_ERROR_INVALID_PARAM;
}
+ static const char * const pm_options[] = {"allow_while_locked", "reverse_bar",
+ "repeat_press", "long_press", NULL};
+ int pm_op;
+
while (p < element->params_count)
{
char* param = get_param_text(element, p++);
- if (!strcmp(param, "allow_while_locked"))
+ pm_op = string_option(param, pm_options, false);
+ if (pm_op == 0)
region->allow_while_locked = true;
- else if (!strcmp(param, "reverse_bar"))
+ else if (pm_op == 1)
region->reverse_bar = true;
- else if (!strcmp(param, "repeat_press"))
+ else if (pm_op == 2)
region->press_length = REPEAT;
- else if (!strcmp(param, "long_press"))
+ else if (pm_op == 3)
region->press_length = LONG_PRESS;
}
struct skin_token_list *item = new_skin_token_list_item(NULL, region);
@@ -1758,9 +1850,7 @@ void skin_data_free_buflib_allocs(struct wps_data *wps_data)
abort:
wps_data->font_ids = PTRTOSKINOFFSET(skin_buffer, NULL); /* Safe if skin_buffer is NULL */
wps_data->images = PTRTOSKINOFFSET(skin_buffer, NULL);
- if (wps_data->buflib_handle > 0)
- core_free(wps_data->buflib_handle);
- wps_data->buflib_handle = -1;
+ wps_data->buflib_handle = core_free(wps_data->buflib_handle);
#endif
}
@@ -1801,13 +1891,11 @@ static void skin_data_reset(struct wps_data *wps_data)
}
#ifndef __PCTOOL__
-static int currently_loading_handle = -1;
static int buflib_move_callback(int handle, void* current, void* new)
{
+ (void)handle;
(void)current;
(void)new;
- if (handle == currently_loading_handle)
- return BUFLIB_CB_CANNOT_MOVE;
/* Any active skins may be scrolling - which means using viewports which
* will be moved after this callback returns. This is a hammer to make that
* safe. TODO: use a screwdriver instead.
@@ -1820,85 +1908,61 @@ 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 lock_handle(int handle)
-{
- currently_loading_handle = handle;
-}
-static void unlock_handle(void)
-{
- currently_loading_handle = -1;
-}
#endif
static int load_skin_bmp(struct wps_data *wps_data, struct bitmap *bitmap, char* bmpdir)
{
+
(void)wps_data; /* only needed for remote targets */
char img_path[MAX_PATH];
- int fd;
- int handle;
+
get_image_filename(bitmap->data, bmpdir,
img_path, sizeof(img_path));
- /* load the image */
- int format;
-#ifdef HAVE_REMOTE_LCD
- if (curr_screen == SCREEN_REMOTE)
- format = FORMAT_ANY|FORMAT_REMOTE;
- else
-#endif
- format = FORMAT_ANY|FORMAT_TRANSPARENT;
-
- fd = open(img_path, O_RDONLY);
+#ifdef __PCTOOL__ /* just check if image exists */
+ int fd = open(img_path, O_RDONLY);
if (fd < 0)
{
DEBUGF("Couldn't open %s\n", img_path);
return fd;
}
-#ifndef __PCTOOL__
- int buf_size = read_bmp_fd(fd, bitmap, 0,
- format|FORMAT_RETURN_SIZE, NULL);
- if(buf_size < 0)
- {
- close(fd);
- return buf_size;
- }
+ close(fd);
+ return 1;
+#else /* load the image */
+ static struct buflib_callbacks buflib_ops = {buflib_move_callback, NULL, NULL};
+ int handle;
+ int bmpformat;
+ ssize_t buf_reqd;
+#ifdef HAVE_REMOTE_LCD
+ if (curr_screen == SCREEN_REMOTE)
+ bmpformat = FORMAT_ANY|FORMAT_REMOTE;
+ else
+#endif
+ bmpformat = FORMAT_ANY|FORMAT_TRANSPARENT;
- handle = core_alloc_ex(bitmap->data, buf_size, &buflib_ops);
- if (handle <= 0)
+ handle = core_load_bmp(img_path, bitmap, bmpformat, &buf_reqd, &buflib_ops);
+ if (handle != CLB_ALOC_ERR)
{
- DEBUGF("Not enough skin buffer: need %zd more.\n",
- buf_size - skin_buffer_freespace());
- close(fd);
+ /* NOTE!: bitmap->data == NULL to force a crash later if the
+ caller doesnt call core_get_data() */
+ _stats->buflib_handles++;
+ _stats->images_size += buf_reqd;
return handle;
}
- _stats->buflib_handles++;
- _stats->images_size += buf_size;
- lseek(fd, 0, SEEK_SET);
- lock_handle(handle);
- bitmap->data = core_get_data(handle);
- int ret = read_bmp_fd(fd, bitmap, buf_size, format, NULL);
- bitmap->data = NULL; /* do this to force a crash later if the
- caller doesnt call core_get_data() */
- unlock_handle();
- close(fd);
- if (ret > 0)
+
+ if (buf_reqd == CLB_READ_ERR)
{
- /* free unused alpha channel, if any */
- core_shrink(handle, core_get_data(handle), ret);
- return handle;
+ /* Abort if we can't load an image */
+ DEBUGF("Couldn't load '%s' (%ld)\n", img_path, buf_reqd);
}
else
{
- /* Abort if we can't load an image */
- DEBUGF("Couldn't load '%s'\n", img_path);
- core_free(handle);
- return -1;
+ DEBUGF("Not enough skin buffer: need %zd more.\n",
+ buf_reqd - skin_buffer_freespace());
}
-#else /* !__PCTOOL__ */
- close(fd);
- return 1;
-#endif
+
+ return -1;
+#endif/* !__PCTOOL__ */
}
static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir)
@@ -1928,7 +1992,7 @@ static bool load_skin_bitmaps(struct wps_data *wps_data, char *bmpdir)
strcpy(path, img->bm.data);
handle = load_skin_bmp(wps_data, &img->bm, bmpdir);
img->buflib_handle = handle;
- img->loaded = img->buflib_handle >= 0;
+ img->loaded = img->buflib_handle > 0;
if (img->loaded)
{
@@ -2326,13 +2390,6 @@ static int skin_element_callback(struct skin_element* element, void* data)
break;
#endif
#ifdef HAVE_ALBUMART
- case SKIN_TOKEN_ALBUMART_DISPLAY:
- if (SKINOFFSETTOPTR(skin_buffer, wps_data->albumart))
- {
- struct skin_albumart *aa = SKINOFFSETTOPTR(skin_buffer, wps_data->albumart);
- aa->vp = PTRTOSKINOFFSET(skin_buffer, &curr_vp->vp);
- }
- break;
case SKIN_TOKEN_ALBUMART_LOAD:
function = parse_albumart_load;
break;
@@ -2468,8 +2525,9 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
skin_buffer = wps_buffer;
wps_buffer = (char*)buf;
}
- skin_buffer = ALIGN_UP(skin_buffer, 4); /* align on 4-byte boundary */
- buffersize -= 3;
+
+ /* align to long */
+ ALIGN_BUFFER(skin_buffer, buffersize, sizeof(long));
#ifdef HAVE_BACKDROP_IMAGE
backdrop_filename = "-";
wps_data->backdrop_id = -1;
@@ -2492,7 +2550,7 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
{
/* get the bitmap dir */
char *dot = strrchr(buf, '.');
- strlcpy(bmpdir, buf, dot - buf + 1);
+ strmemccpy(bmpdir, buf, dot - buf + 1);
}
else
{
@@ -2516,8 +2574,7 @@ bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
}
#endif
#ifndef __PCTOOL__
- wps_data->buflib_handle = core_alloc(isfile ? buf : "failsafe skin",
- skin_buffer_usage());
+ wps_data->buflib_handle = core_alloc(skin_buffer_usage());
if (wps_data->buflib_handle > 0)
{
wps_data->wps_loaded = true;
diff --git a/apps/gui/skin_engine/skin_render.c b/apps/gui/skin_engine/skin_render.c
index 1f777b6672..06f7d9798d 100644
--- a/apps/gui/skin_engine/skin_render.c
+++ b/apps/gui/skin_engine/skin_render.c
@@ -50,6 +50,7 @@
#include "root_menu.h"
#include "misc.h"
#include "list.h"
+#include "wps.h"
#define MAX_LINE 1024
@@ -66,7 +67,6 @@ struct skin_draw_info {
bool no_line_break;
bool line_scrolls;
bool force_redraw;
- bool viewport_change;
char *buf;
size_t buf_size;
@@ -74,6 +74,8 @@ struct skin_draw_info {
int offset; /* used by the playlist viewer */
};
+extern void sb_set_info_vp(enum screen_type screen, OFFSETTYPE(char*) label);
+
typedef bool (*skin_render_func)(struct skin_element* alternator, struct skin_draw_info *info);
bool skin_render_alternator(struct skin_element* alternator, struct skin_draw_info *info);
@@ -93,11 +95,11 @@ get_child(OFFSETTYPE(struct skin_element**) children, int child)
static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info,
- struct skin_element *element, struct skin_viewport* skin_vp)
+ struct skin_element *element)
{
struct wps_token *token = (struct wps_token *)SKINOFFSETTOPTR(skin_buffer, element->data);
if (!token) return false;
- struct viewport *vp = &skin_vp->vp;
+ struct skin_viewport *skin_vp = info->skin_vp;
struct wps_data *data = gwps->data;
bool do_refresh = (element->tag->flags & info->refresh_type) > 0;
@@ -108,9 +110,7 @@ static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info,
{
struct viewport_colour *col = SKINOFFSETTOPTR(skin_buffer, token->value.data);
if (!col) return false;
- struct viewport *vp = SKINOFFSETTOPTR(skin_buffer, col->vp);
- if (!vp) return false;
- vp->fg_pattern = col->colour;
+ skin_vp->vp.fg_pattern = col->colour;
skin_vp->fgbg_changed = true;
}
break;
@@ -118,9 +118,7 @@ static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info,
{
struct viewport_colour *col = SKINOFFSETTOPTR(skin_buffer, token->value.data);
if (!col) return false;
- struct viewport *vp = SKINOFFSETTOPTR(skin_buffer, col->vp);
- if (!vp) return false;
- vp->bg_pattern = col->colour;
+ skin_vp->vp.bg_pattern = col->colour;
skin_vp->fgbg_changed = true;
}
break;
@@ -196,7 +194,7 @@ static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info,
case SKIN_TOKEN_PEAKMETER:
data->peak_meter_enabled = true;
if (do_refresh)
- draw_peakmeters(gwps, info->line_number, vp);
+ draw_peakmeters(gwps, info->line_number, &skin_vp->vp);
break;
case SKIN_TOKEN_DRAWRECTANGLE:
if (do_refresh)
@@ -215,13 +213,13 @@ static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info,
#endif
{
#if LCD_DEPTH > 1
- unsigned backup = vp->fg_pattern;
- vp->fg_pattern = rect->start_colour;
+ unsigned backup = skin_vp->vp.fg_pattern;
+ skin_vp->vp.fg_pattern = rect->start_colour;
#endif
gwps->display->fillrect(rect->x, rect->y, rect->width,
rect->height);
#if LCD_DEPTH > 1
- vp->fg_pattern = backup;
+ skin_vp->vp.fg_pattern = backup;
#endif
}
}
@@ -239,7 +237,7 @@ static bool do_non_text_tags(struct gui_wps *gwps, struct skin_draw_info *info,
{
struct progressbar *bar = (struct progressbar*)SKINOFFSETTOPTR(skin_buffer, token->value.data);
if (do_refresh)
- draw_progressbar(gwps, info->line_number, bar);
+ draw_progressbar(gwps, info->skin_vp, info->line_number, bar);
}
break;
case SKIN_TOKEN_IMAGE_DISPLAY:
@@ -582,7 +580,7 @@ static bool skin_render_line(struct skin_element* line, struct skin_draw_info *i
{
break;
}
- if (!do_non_text_tags(info->gwps, info, child, info->skin_vp))
+ if (!do_non_text_tags(info->gwps, info, child))
{
static char tempbuf[128];
const char *valuestr = get_token_value(info->gwps, SKINOFFSETTOPTR(skin_buffer, child->data),
@@ -590,10 +588,6 @@ static bool skin_render_line(struct skin_element* line, struct skin_draw_info *i
sizeof(tempbuf), NULL);
if (valuestr)
{
-#if defined(ONDA_VX747) || defined(ONDA_VX747P)
- /* Doesn't redraw (in sim at least) */
- needs_update = true;
-#endif
#if CONFIG_RTC
if (child->tag->flags&SKIN_RTC_REFRESH)
needs_update = needs_update || info->refresh_type&SKIN_REFRESH_DYNAMIC;
@@ -606,10 +600,6 @@ static bool skin_render_line(struct skin_element* line, struct skin_draw_info *i
}
break;
case TEXT:
-#if defined(ONDA_VX747) || defined(ONDA_VX747P)
- /* Doesn't redraw (in sim at least) */
- needs_update = true;
-#endif
strlcat(info->cur_align_start, SKINOFFSETTOPTR(skin_buffer, child->data),
info->buf_size - (info->cur_align_start-info->buf));
needs_update = needs_update ||
@@ -943,7 +933,7 @@ void skin_render_playlistviewer(struct playlistviewer* viewer,
struct align_pos * align = &info.align;
bool needs_update;
int cur_pos, start_item, max;
- int nb_lines = viewport_get_nb_lines(SKINOFFSETTOPTR(skin_buffer, viewer->vp));
+ int nb_lines = viewport_get_nb_lines(&skin_viewport->vp);
#if CONFIG_TUNER
if (get_current_activity() == ACTIVITY_FM)
{
@@ -954,8 +944,8 @@ void skin_render_playlistviewer(struct playlistviewer* viewer,
else
#endif
{
- struct cuesheet *cue = skin_get_global_state()->id3 ?
- skin_get_global_state()->id3->cuesheet : NULL;
+ struct wps_state *state = get_wps_state();
+ struct cuesheet *cue = state->id3 ? state->id3->cuesheet : NULL;
cur_pos = playlist_get_display_index();
max = playlist_amount()+1;
if (cue)
@@ -989,7 +979,7 @@ void skin_render_playlistviewer(struct playlistviewer* viewer,
/* only update if the line needs to be, and there is something to write */
if (refresh_type && needs_update)
{
- struct viewport *vp = SKINOFFSETTOPTR(skin_buffer, viewer->vp);
+ struct viewport *vp = &skin_viewport->vp;
if (!info.force_redraw)
display->scroll_stop_viewport_rect(vp,
0, info.line_number*display->getcharheight(),
diff --git a/apps/gui/skin_engine/skin_tokens.c b/apps/gui/skin_engine/skin_tokens.c
index a4c9af7539..f6c166b140 100644
--- a/apps/gui/skin_engine/skin_tokens.c
+++ b/apps/gui/skin_engine/skin_tokens.c
@@ -66,11 +66,10 @@
#include "fixedpoint.h"
#endif
#include "list.h"
+#include "wps.h"
#define NOINLINE __attribute__ ((noinline))
-extern struct wps_state wps_state;
-
static const char* get_codectype(const struct mp3entry* id3)
{
if (id3 && id3->codectype < AFMT_NUM_CODECS) {
@@ -115,7 +114,7 @@ char* get_dir(char* buf, int buf_size, const char* path, int level)
return NULL;
len = MIN(last_sep - sep, buf_size - 1);
- strlcpy(buf, sep + 1, len + 1);
+ strmemccpy(buf, sep + 1, len + 1);
return buf;
}
@@ -228,7 +227,7 @@ static const char* get_filename_token(struct wps_token *token, char* filename,
const char *get_id3_token(struct wps_token *token, struct mp3entry *id3,
char *filename, char *buf, int buf_size, int limit, int *intval)
{
- struct wps_state *state = &wps_state;
+ struct wps_state *state = get_wps_state();
if (id3)
{
unsigned long length = id3->length;
@@ -540,7 +539,7 @@ const char *get_radio_token(struct wps_token *token, int preset_offset,
static struct mp3entry* get_mp3entry_from_offset(int offset, char **filename)
{
struct mp3entry* pid3 = NULL;
- struct wps_state *state = skin_get_global_state();
+ struct wps_state *state = get_wps_state();
struct cuesheet *cue = state->id3 ? state->id3->cuesheet : NULL;
const char *fname = NULL;
if (cue && cue->curr_track_idx + offset < cue->track_count)
@@ -678,7 +677,7 @@ const char *get_token_value(struct gui_wps *gwps,
return NULL;
struct wps_data *data = gwps->data;
- struct wps_state *state = skin_get_global_state();
+ struct wps_state *state = get_wps_state();
struct mp3entry *id3; /* Think very carefully about using this.
maybe get_id3_token() is the better place? */
const char *out_text = NULL;
@@ -1040,37 +1039,19 @@ const char *get_token_value(struct gui_wps *gwps,
case SKIN_TOKEN_PLAYBACK_STATUS:
{
int status = current_playmode();
- /* music */
- int mode = 1; /* stop */
- if (status == STATUS_PLAY)
- mode = 2; /* play */
- if (state->is_fading ||
- (status == STATUS_PAUSE && !status_get_ffmode()))
- mode = 3; /* pause */
- else
- { /* ff / rwd */
- if (status_get_ffmode() == STATUS_FASTFORWARD)
- mode = 4;
- if (status_get_ffmode() == STATUS_FASTBACKWARD)
- mode = 5;
+ switch (status) {
+ case STATUS_STOP:
+ numeric_ret = 1;
+ break;
+ case STATUS_PLAY:
+ numeric_ret = 2;
+ break;
+ default:
+ numeric_ret = status + 1;
+ break;
}
-#ifdef HAVE_RECORDING
- /* recording */
- if (status == STATUS_RECORD)
- mode = 6;
- else if (status == STATUS_RECORD_PAUSE)
- mode = 7;
-#endif
-#if CONFIG_TUNER
- /* radio */
- if (status == STATUS_RADIO)
- mode = 8;
- else if (status == STATUS_RADIO_PAUSE)
- mode = 9;
-#endif
- numeric_ret = mode;
- snprintf(buf, buf_size, "%d", mode-1);
+ snprintf(buf, buf_size, "%d", numeric_ret-1);
numeric_buf = buf;
goto gtv_ret_numeric_tag_info;
}
@@ -1367,7 +1348,7 @@ const char *get_token_value(struct gui_wps *gwps,
case SKIN_TOKEN_LASTTOUCH:
{
#ifdef HAVE_TOUCHSCREEN
- unsigned int last_touch = touchscreen_last_touch();
+ long last_touch = touchscreen_last_touch();
char *skin_base = get_skin_buffer(data);
struct touchregion_lastpress *data = SKINOFFSETTOPTR(skin_base, token->value.data);
if (!data) return NULL;
@@ -1375,7 +1356,7 @@ const char *get_token_value(struct gui_wps *gwps,
if (region)
last_touch = region->last_press;
- if (last_touch != 0xffff &&
+ if (last_touch != -1 &&
TIME_BEFORE(current_tick, data->timeout + last_touch))
return "t";
#endif
@@ -1390,7 +1371,7 @@ const char *get_token_value(struct gui_wps *gwps,
case SKIN_TOKEN_SETTING:
{
- const struct settings_list *s = settings+token->value.i;
+ const struct settings_list *s = token->value.xdata;
if (intval)
{
/* Handle contionals */
@@ -1461,7 +1442,7 @@ const char *get_token_value(struct gui_wps *gwps,
goto gtv_ret_numeric_tag_info;
}
}
- cfg_to_string(token->value.i,buf,buf_size);
+ cfg_to_string(s, buf, buf_size);
numeric_buf = buf;
goto gtv_ret_numeric_tag_info;
}
diff --git a/apps/gui/skin_engine/skin_touchsupport.c b/apps/gui/skin_engine/skin_touchsupport.c
index 045bc809c8..b952709562 100644
--- a/apps/gui/skin_engine/skin_touchsupport.c
+++ b/apps/gui/skin_engine/skin_touchsupport.c
@@ -35,8 +35,9 @@
#include "dsp_misc.h"
/** Disarms all touchregions. */
-void skin_disarm_touchregions(struct wps_data *data)
+void skin_disarm_touchregions(struct gui_wps *gwps)
{
+ struct wps_data *data = gwps->data;
char* skin_buffer = get_skin_buffer(data);
struct skin_token_list *regions = SKINOFFSETTOPTR(skin_buffer, data->touchregions);
while (regions)
@@ -52,9 +53,9 @@ void skin_disarm_touchregions(struct wps_data *data)
* egde_offset is a percentage value for the position of the touch
* inside the bar for regions which arnt WPS_TOUCHREGION_ACTION type.
*/
-int skin_get_touchaction(struct wps_data *data, int* edge_offset,
- struct touchregion **retregion)
+int skin_get_touchaction(struct gui_wps *gwps, int* edge_offset)
{
+ struct wps_data *data = gwps->data;
int returncode = ACTION_NONE;
short x,y;
short vx, vy;
@@ -162,9 +163,7 @@ int skin_get_touchaction(struct wps_data *data, int* edge_offset,
/* On release, all regions are disarmed. */
if (released)
- skin_disarm_touchregions(data);
- if (retregion && temp)
- *retregion = temp;
+ skin_disarm_touchregions(gwps);
if (temp && temp->press_length == LONG_PRESS)
temp->armed = false;
@@ -301,7 +300,7 @@ int skin_get_touchaction(struct wps_data *data, int* edge_offset,
case ACTION_TOUCH_REPMODE: /* cycle the repeat mode setting */
{
const struct settings_list *rep_setting =
- find_setting(&global_settings.repeat_mode, NULL);
+ find_setting(&global_settings.repeat_mode);
option_select_next_val(rep_setting, false, true);
audio_flush_and_reload_tracks();
returncode = ACTION_REDRAW;
@@ -314,9 +313,9 @@ int skin_get_touchaction(struct wps_data *data, int* edge_offset,
if (bar && edge_offset)
{
int val, count;
- get_setting_info_for_bar(bar->setting_id, &count, &val);
+ get_setting_info_for_bar(bar->setting, &count, &val);
val = *edge_offset * count / 1000;
- update_setting_value_from_touch(bar->setting_id, val);
+ update_setting_value_from_touch(bar->setting, val);
}
}
break;
diff --git a/apps/gui/skin_engine/wps_internals.h b/apps/gui/skin_engine/wps_internals.h
index bf368bc4f3..6b9719282e 100644
--- a/apps/gui/skin_engine/wps_internals.h
+++ b/apps/gui/skin_engine/wps_internals.h
@@ -31,6 +31,8 @@
#include "core_alloc.h"
#endif
+struct wps_data;
+
struct skin_stats {
size_t buflib_handles;
size_t tree_size;
@@ -42,6 +44,13 @@ struct skin_stats *skin_get_stats(int number, int screen);
#define skin_clear_stats(stats) memset(stats, 0, sizeof(struct skin_stats))
bool skin_backdrop_get_debug(int index, char **path, int *ref_count, size_t *size);
+/*
+ * setup up the skin-data from a format-buffer (isfile = false)
+ * or from a skinfile (isfile = true)
+ */
+bool skin_data_load(enum screen_type screen, struct wps_data *wps_data,
+ const char *buf, bool isfile, struct skin_stats *stats);
+
/* Timeout unit expressed in HZ. In WPS, all timeouts are given in seconds
(possibly with a decimal fraction) but stored as integer values.
E.g. 2.5 is stored as 25. This means 25 tenth of a second, i.e. 25 units.
@@ -64,6 +73,7 @@ struct wps_token {
unsigned short i;
long l;
OFFSETTYPE(void*) data;
+ void *xdata;
} value;
enum skin_token_type type; /* enough to store the token type */
@@ -81,7 +91,6 @@ struct skin_token_list {
};
struct gui_img {
- OFFSETTYPE(struct viewport*) vp; /* The viewport to display this image in */
short int x; /* x-pos */
short int y; /* y-pos */
short int num_subimages; /* number of sub-images */
@@ -104,7 +113,6 @@ struct image_display {
struct progressbar {
enum skin_token_type type;
- OFFSETTYPE(struct viewport *) vp;
/* regular pb */
short x;
/* >=0: explicitly set in the tag -> y-coord within the viewport
@@ -124,7 +132,7 @@ struct progressbar {
OFFSETTYPE(struct gui_img *) slider;
bool horizontal;
OFFSETTYPE(struct gui_img *) backdrop;
- int setting_id; /* for the setting bar type */
+ const struct settings_list *setting;
};
@@ -189,7 +197,6 @@ struct skin_viewport {
#endif
};
struct viewport_colour {
- OFFSETTYPE(struct viewport *) vp;
unsigned colour;
};
@@ -236,7 +243,6 @@ struct touchregion_lastpress {
#endif
struct playlistviewer {
- OFFSETTYPE(struct viewport *) vp;
bool show_icons;
int start_offset;
OFFSETTYPE(struct skin_element *) line;
@@ -267,7 +273,6 @@ struct skin_albumart {
unsigned char yalign; /* WPS_ALBUMART_ALIGN_TOP, _CENTER, _BOTTOM */
unsigned char state; /* WPS_ALBUMART_NONE, _CHECK, _LOAD */
- OFFSETTYPE(struct viewport *) vp;
int draw_handle;
};
#endif
@@ -313,6 +318,17 @@ struct listitem {
short offset;
};
+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;
+};
+
#ifdef HAVE_SKIN_VARIABLES
struct skin_var {
OFFSETTYPE(const char *) label;
@@ -372,7 +388,7 @@ struct wps_data
#ifndef __PCTOOL__
static inline char* get_skin_buffer(struct wps_data* data)
{
- if (data->buflib_handle >= 0)
+ if (data->buflib_handle > 0)
return core_get_data(data->buflib_handle);
return NULL;
}
@@ -382,30 +398,6 @@ static inline char* get_skin_buffer(struct wps_data* data)
/* wps_data end */
-/* wps_state
- holds the data which belongs to the current played track,
- the track which will be played afterwards, current path to the track
- and some status infos */
-struct wps_state
-{
- struct mp3entry* id3;
- struct mp3entry* nid3;
- int ff_rewind_count;
- bool ff_rewind;
- bool paused;
- bool is_fading;
-};
-
-/* change the ff/rew-status
- if ff_rew = true then we are in skipping mode
- else we are in normal mode */
-/* void wps_state_update_ff_rew(bool ff_rew); Currently unused */
-
-/* change the tag-information of the current played track
- and the following track */
-/* void wps_state_update_id3_nid3(struct mp3entry *id3, struct mp3entry *nid3); Currently unused */
-/* wps_state end*/
-
/* gui_wps
defines a wps with its data, state,
and the screen on which the wps-content should be drawn */
diff --git a/apps/gui/splash.c b/apps/gui/splash.c
index b85e4693aa..d0f1fbb67c 100644
--- a/apps/gui/splash.c
+++ b/apps/gui/splash.c
@@ -29,71 +29,84 @@
#include "talk.h"
#include "splash.h"
#include "viewport.h"
-#include "strtok_r.h"
+#include "strptokspn_r.h"
+#include "scrollbar.h"
+#include "font.h"
+
+static long progress_next_tick = 0;
#define MAXLINES (LCD_HEIGHT/6)
#define MAXBUFFER 512
#define RECT_SPACING 2
#define SPLASH_MEMORY_INTERVAL (HZ)
-static void splash_internal(struct screen * screen, const char *fmt, va_list ap)
+static bool splash_internal(struct screen * screen, const char *fmt, va_list ap,
+ struct viewport *vp, int addl_lines)
{
char splash_buf[MAXBUFFER];
- char *lines[MAXLINES];
-
- char *next;
- char *lastbreak = NULL;
- char *store = NULL;
+ struct splash_lines {
+ const char *str;
+ size_t len;
+ } lines[MAXLINES];
+ const char *next;
+ const char *lastbreak = NULL;
+ const char *store = NULL;
int line = 0;
int x = 0;
int y, i;
- int space_w, w, h;
- struct viewport vp;
+ int space_w, w, chr_h;
int width, height;
int maxw = 0;
+ int fontnum = vp->font;
- viewport_set_defaults(&vp, screen->screen_type);
- struct viewport *last_vp = screen->set_viewport(&vp);
-
- screen->getstringsize(" ", &space_w, &h);
- y = h;
+ char lastbrkchr;
+ size_t len, next_len;
+ const char matchstr[] = "\r\n\f\v\t ";
+ font_getstringsize(" ", &space_w, &chr_h, fontnum);
+ y = chr_h + (addl_lines * chr_h);
vsnprintf(splash_buf, sizeof(splash_buf), fmt, ap);
va_end(ap);
/* break splash string into display lines, doing proper word wrap */
-
- next = strtok_r(splash_buf, " ", &store);
+ next = strptokspn_r(splash_buf, matchstr, &next_len, &store);
if (!next)
- goto end; /* nothing to display */
+ return false; /* nothing to display */
- lines[0] = next;
+ lines[line].len = next_len;
+ lines[line].str = next;
while (true)
{
- screen->getstringsize(next, &w, NULL);
+ w = font_getstringnsize(next, next_len, NULL, NULL, fontnum);
if (lastbreak)
{
- if (x + (next - lastbreak) * space_w + w
- > vp.width - RECT_SPACING*2)
- { /* too wide, wrap */
+ len = next - lastbreak;
+ int next_w = len * space_w;
+ if (x + next_w + w > vp->width - RECT_SPACING*2 || lastbrkchr != ' ')
+ { /* too wide, or control character wrap */
if (x > maxw)
maxw = x;
- if ((y + h > vp.height) || (line >= (MAXLINES-1)))
+ if ((y + chr_h * 2 > vp->height) || (line >= (MAXLINES-1)))
break; /* screen full or out of lines */
x = 0;
- y += h;
- lines[++line] = next;
+ y += chr_h;
+ lines[++line].len = next_len;
+ lines[line].str = next;
}
else
{
/* restore & calculate spacing */
- *lastbreak = ' ';
- x += (next - lastbreak) * space_w;
+ lines[line].len += next_len + 1;
+ x += next_w;
}
}
x += w;
- lastbreak = next + strlen(next);
- next = strtok_r(NULL, " ", &store);
+
+ lastbreak = next + next_len;
+ lastbrkchr = *lastbreak;
+
+ next = strptokspn_r(NULL, matchstr, &next_len, &store);
+
if (!next)
{ /* no more words */
if (x > maxw)
@@ -111,53 +124,48 @@ static void splash_internal(struct screen * screen, const char *fmt, va_list ap)
width = maxw + 2*RECT_SPACING;
height = y + 2*RECT_SPACING;
- if (width > vp.width)
- width = vp.width;
- if (height > vp.height)
- height = vp.height;
+ if (width > vp->width)
+ width = vp->width;
+ if (height > vp->height)
+ height = vp->height;
- vp.x += (vp.width - width) / 2;
- vp.y += (vp.height - height) / 2;
- vp.width = width;
- vp.height = height;
+ vp->x += (vp->width - width) / 2;
+ vp->y += (vp->height - height) / 2;
+ vp->width = width;
+ vp->height = height;
- vp.flags |= VP_FLAG_ALIGN_CENTER;
+ vp->flags |= VP_FLAG_ALIGN_CENTER;
#if LCD_DEPTH > 1
if (screen->depth > 1)
{
- vp.drawmode = DRMODE_FG;
- /* can't do vp.fg_pattern here, since set_foreground does a bit more on
+ vp->drawmode = DRMODE_FG;
+ /* can't do vp->fg_pattern here, since set_foreground does a bit more on
* greyscale */
screen->set_foreground(SCREEN_COLOR_TO_NATIVE(screen, LCD_LIGHTGRAY));
}
else
#endif
- vp.drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
+ vp->drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
screen->fill_viewport();
#if LCD_DEPTH > 1
if (screen->depth > 1)
- /* can't do vp.fg_pattern here, since set_foreground does a bit more on
+ /* can't do vp->fg_pattern here, since set_foreground does a bit more on
* greyscale */
screen->set_foreground(SCREEN_COLOR_TO_NATIVE(screen, LCD_BLACK));
else
#endif
- vp.drawmode = DRMODE_SOLID;
+ vp->drawmode = DRMODE_SOLID;
screen->draw_border_viewport();
- /* prepare putting the text */
- y = RECT_SPACING;
-
/* print the message to screen */
- for (i = 0; i <= line; i++, y+=h)
+ for(i = 0, y = RECT_SPACING; i <= line; i++, y+= chr_h)
{
- screen->putsxy(0, y, lines[i]);
+ screen->putsxyf(0, y, "%.*s", lines[i].len, lines[i].str);
}
- screen->update_viewport();
-end:
- screen->set_viewport(last_vp);
+ return true; /* needs update */
}
void splashf(int ticks, const char *fmt, ...)
@@ -169,9 +177,17 @@ void splashf(int ticks, const char *fmt, ...)
fmt = P2STR((unsigned char *)fmt);
FOR_NB_SCREENS(i)
{
+ struct screen * screen = &(screens[i]);
+ struct viewport vp;
+ viewport_set_defaults(&vp, screen->screen_type);
+ struct viewport *last_vp = screen->set_viewport(&vp);
+
va_start(ap, fmt);
- splash_internal(&(screens[i]), fmt, ap);
+ if (splash_internal(screen, fmt, ap, &vp, 0))
+ screen->update_viewport();
va_end(ap);
+
+ screen->set_viewport(last_vp);
}
if (ticks)
sleep(ticks);
@@ -189,3 +205,59 @@ void splash(int ticks, const char *str)
#endif
splashf(ticks, "%s", P2STR((const unsigned char*)str));
}
+
+/* set delay before progress meter is shown */
+void splash_progress_set_delay(long delay_ticks)
+{
+ progress_next_tick = current_tick + delay_ticks;
+}
+
+/* splash a progress meter */
+void splash_progress(int current, int total, const char *fmt, ...)
+{
+ va_list ap;
+ int vp_flag = VP_FLAG_VP_DIRTY;
+ /* progress update tick */
+ long now = current_tick;
+
+ if (current < total)
+ {
+ if(TIME_BEFORE(now, progress_next_tick))
+ return;
+ /* limit to 20fps */
+ progress_next_tick = now + HZ/20;
+ vp_flag = 0; /* don't mark vp dirty to prevent flashing */
+ }
+
+ /* If fmt is a lang ID then get the corresponding string (which
+ still might contain % place holders). */
+ fmt = P2STR((unsigned char *)fmt);
+ FOR_NB_SCREENS(i)
+ {
+ struct screen * screen = &(screens[i]);
+ struct viewport vp;
+ viewport_set_defaults(&vp, screen->screen_type);
+ struct viewport *last_vp = screen->set_viewport_ex(&vp, vp_flag);
+
+ va_start(ap, fmt);
+ if (splash_internal(screen, fmt, ap, &vp, 1))
+ {
+ int size = screen->getcharheight();
+ int x = RECT_SPACING;
+ int y = vp.height - size - RECT_SPACING;
+ int w = vp.width - RECT_SPACING * 2;
+ int h = size;
+#ifdef HAVE_LCD_COLOR
+ const int sb_flags = HORIZONTAL | FOREGROUND;
+#else
+ const int sb_flags = HORIZONTAL;
+#endif
+ gui_scrollbar_draw(screen, x, y, w, h, total, 0, current, sb_flags);
+
+ screen->update_viewport();
+ }
+ va_end(ap);
+
+ screen->set_viewport(last_vp);
+ }
+}
diff --git a/apps/gui/splash.h b/apps/gui/splash.h
index 76b4c16d0c..f7ff44e00b 100644
--- a/apps/gui/splash.h
+++ b/apps/gui/splash.h
@@ -39,4 +39,15 @@ extern void splashf(int ticks, const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3);
* it will be voiced
*/
extern void splash(int ticks, const char *str);
+
+/* set a delay before displaying the progress meter the first time */
+extern void splash_progress_set_delay(long delay_ticks);
+/*
+ * Puts a splash message centered on all the screens with a progressbar
+ * - current : current progress increment
+ * - total : total increments
+ * - fmt : what to say *printf style
+ * updates limited internally to 20 fps - call repeatedly to update progress
+ */
+extern void splash_progress(int current, int total, const char *fmt, ...) ATTRIBUTE_PRINTF(3, 4);
#endif /* _GUI_ICON_H_ */
diff --git a/apps/gui/statusbar-skinned.c b/apps/gui/statusbar-skinned.c
index 63f3197faa..8dd66641dd 100644
--- a/apps/gui/statusbar-skinned.c
+++ b/apps/gui/statusbar-skinned.c
@@ -27,7 +27,6 @@
#include "appevents.h"
#include "screens.h"
#include "screen_access.h"
-#include "strlcpy.h"
#include "skin_parser.h"
#include "skin_buffer.h"
#include "skin_engine/skin_engine.h"
@@ -49,11 +48,13 @@
static int update_delay = DEFAULT_UPDATE_DELAY;
static bool sbs_has_title[NB_SCREENS];
-static char* sbs_title[NB_SCREENS];
+static const char* sbs_title[NB_SCREENS];
static enum themable_icons sbs_icon[NB_SCREENS];
static bool sbs_loaded[NB_SCREENS] = { false };
-bool sb_set_title_text(char* title, enum themable_icons icon, enum screen_type screen)
+void sb_set_info_vp(enum screen_type screen, OFFSETTYPE(char*) label);
+
+bool sb_set_title_text(const char* title, enum themable_icons icon, enum screen_type screen)
{
sbs_title[screen] = title;
/* Icon_NOICON == -1 which the skin engine wants at position 1, so + 2 */
@@ -156,7 +157,12 @@ int sb_get_backdrop(enum screen_type screen)
else
return -1;
}
-
+#else
+int sb_get_backdrop(enum screen_type screen)
+{
+ (void) screen;
+ return -1;
+}
#endif
static bool force_waiting = false;
void sb_skin_update(enum screen_type screen, bool force)
@@ -300,18 +306,17 @@ void sb_bypass_touchregions(bool enable)
int sb_touch_to_button(int context)
{
- struct touchregion *region;
static int last_context = -1;
int button, offset;
if (bypass_sb_touchregions)
return ACTION_TOUCHSCREEN;
-
+
+ struct gui_wps *gwps = skin_get_gwps(CUSTOM_STATUSBAR, SCREEN_MAIN);
if (last_context != context)
- skin_disarm_touchregions(skin_get_gwps(CUSTOM_STATUSBAR, SCREEN_MAIN)->data);
+ skin_disarm_touchregions(gwps);
last_context = context;
- button = skin_get_touchaction(skin_get_gwps(CUSTOM_STATUSBAR, SCREEN_MAIN)->data,
- &offset, &region);
-
+
+ button = skin_get_touchaction(gwps, &offset);
switch (button)
{
#ifdef HAVE_VOLUME_IN_LIST
diff --git a/apps/gui/statusbar-skinned.h b/apps/gui/statusbar-skinned.h
index ad102bef47..e8fa14e676 100644
--- a/apps/gui/statusbar-skinned.h
+++ b/apps/gui/statusbar-skinned.h
@@ -30,16 +30,15 @@
#include "icon.h"
#include "skin_engine/skin_engine.h"
-void sb_skin_data_load(enum screen_type screen, const char *buf, bool isfile);
+struct wps_data;
char* sb_create_from_settings(enum screen_type screen);
void sb_skin_init(void) INIT_ATTR;
-void sb_set_info_vp(enum screen_type screen, OFFSETTYPE(char*) label);
struct viewport *sb_skin_get_info_vp(enum screen_type screen);
void sb_skin_update(enum screen_type screen, bool force);
void sb_skin_set_update_delay(int delay);
-bool sb_set_title_text(char* title, enum themable_icons icon, enum screen_type screen);
+bool sb_set_title_text(const char* title, enum themable_icons icon, enum screen_type screen);
void sb_skin_has_title(enum screen_type screen);
const char* sb_get_title(enum screen_type screen);
enum themable_icons sb_get_icon(enum screen_type screen);
@@ -49,9 +48,7 @@ void sb_bypass_touchregions(bool enable);
int sb_touch_to_button(int context);
#endif
-#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
int sb_get_backdrop(enum screen_type screen);
-#endif
int sb_preproccess(enum screen_type screen, struct wps_data *data);
int sb_postproccess(enum screen_type screen, struct wps_data *data);
diff --git a/apps/gui/statusbar.c b/apps/gui/statusbar.c
index a961d191b2..74da14bd3f 100644
--- a/apps/gui/statusbar.c
+++ b/apps/gui/statusbar.c
@@ -725,18 +725,6 @@ void gui_syncstatusbar_init(struct gui_syncstatusbar * bars)
}
}
-void gui_syncstatusbar_draw(struct gui_syncstatusbar * bars,
- bool force_redraw)
-{
- if(!global_settings.statusbar)
- return;
- struct viewport viewport;
- FOR_NB_SCREENS(i) {
- GET_RECT(viewport,statusbar_position(i),&screens[i]);
- gui_statusbar_draw( &(bars->statusbars[i]), force_redraw, &viewport );
- }
-}
-
#ifdef HAVE_REMOTE_LCD
enum statusbar_values statusbar_position(int screen)
diff --git a/apps/gui/statusbar.h b/apps/gui/statusbar.h
index a676c7b143..c62434155d 100644
--- a/apps/gui/statusbar.h
+++ b/apps/gui/statusbar.h
@@ -99,8 +99,7 @@ struct gui_syncstatusbar
};
extern void gui_syncstatusbar_init(struct gui_syncstatusbar * bars) INIT_ATTR;
-extern void gui_syncstatusbar_draw(struct gui_syncstatusbar * bars,
- bool force_redraw);
+
#if !defined(HAVE_REMOTE_LCD) || defined(__PCTOOL__)
#include "settings.h"
#define statusbar_position(a) ((enum statusbar_values)global_settings.statusbar)
diff --git a/apps/gui/usb_screen.c b/apps/gui/usb_screen.c
index 31321ec005..fb59f820b6 100644
--- a/apps/gui/usb_screen.c
+++ b/apps/gui/usb_screen.c
@@ -41,6 +41,7 @@
#include "skin_engine/skin_engine.h"
#include "playlist.h"
#include "misc.h"
+#include "icons.h"
#include "bitmaps/usblogo.h"
@@ -155,7 +156,24 @@ static void usb_screen_fix_viewports(struct screen *screen,
*logo = *parent;
logo->x = parent->x + parent->width - logo_width;
+#ifdef HAVE_LCD_SPLIT
+ switch (statusbar_position(screen))
+ {
+ /* start beyond split */
+ case STATUSBAR_OFF:
+ logo->y = parent->y + LCD_SPLIT_POS;
+ break;
+ case STATUSBAR_TOP:
+ logo->y = parent->y + LCD_SPLIT_POS - STATUSBAR_HEIGHT;
+ break;
+ /* start at the top for maximum space */
+ default:
+ logo->y = parent->y;
+ break;
+ }
+#else
logo->y = parent->y + (parent->height - logo_height) / 2;
+#endif
logo->width = logo_width;
logo->height = logo_height;
diff --git a/apps/gui/viewport.c b/apps/gui/viewport.c
index 3dd8bca979..e90426a132 100644
--- a/apps/gui/viewport.c
+++ b/apps/gui/viewport.c
@@ -233,7 +233,7 @@ static void viewportmanager_redraw(unsigned short id, void* data)
}
}
-void viewportmanager_init()
+void viewportmanager_init(void)
{
FOR_NB_SCREENS(i)
{
@@ -332,7 +332,7 @@ void viewport_set_defaults(struct viewport *vp,
const enum screen_type screen)
{
vp->buffer = NULL; /* use default frame_buffer */
-
+ vp->flags = VP_DEFAULT_FLAGS;
#if !defined(__PCTOOL__)
struct viewport *sbs_area = NULL;
if (!is_theme_enabled(screen))
@@ -348,41 +348,3 @@ void viewport_set_defaults(struct viewport *vp,
#endif /* !__PCTOOL__ */
viewport_set_fullscreen(vp, screen);
}
-
-
-int get_viewport_default_colour(enum screen_type screen, bool fgcolour)
-{
- (void)screen; (void)fgcolour;
-#if (LCD_DEPTH > 1) || (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
- int colour;
- if (fgcolour)
- {
-#if (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
- if (screen == SCREEN_REMOTE)
- colour = REMOTE_FG_FALLBACK;
- else
-#endif
-#if defined(HAVE_LCD_COLOR)
- colour = global_settings.fg_color;
-#else
- colour = FG_FALLBACK;
-#endif
- }
- else
- {
-#if (defined(HAVE_REMOTE_LCD) && LCD_REMOTE_DEPTH > 1)
- if (screen == SCREEN_REMOTE)
- colour = REMOTE_BG_FALLBACK;
- else
-#endif
-#if defined(HAVE_LCD_COLOR)
- colour = global_settings.bg_color;
-#else
- colour = BG_FALLBACK;
-#endif
- }
- return colour;
-#else
- return 0;
-#endif /* LCD_DEPTH > 1 || LCD_REMOTE_DEPTH > 1 */
-}
diff --git a/apps/gui/viewport.h b/apps/gui/viewport.h
index 2810be2ac3..c57a58b232 100644
--- a/apps/gui/viewport.h
+++ b/apps/gui/viewport.h
@@ -43,7 +43,6 @@ void viewport_set_defaults(struct viewport *vp,
const enum screen_type screen);
void viewport_set_fullscreen(struct viewport *vp,
const enum screen_type screen);
-int get_viewport_default_colour(enum screen_type screen, bool fgcolour);
#ifndef __PCTOOL__
diff --git a/apps/gui/wps.c b/apps/gui/wps.c
index cdb34ab447..d35a5ac6d2 100644
--- a/apps/gui/wps.c
+++ b/apps/gui/wps.c
@@ -53,6 +53,7 @@
#include "root_menu.h"
#include "backdrop.h"
#include "quickscreen.h"
+#include "shortcuts.h"
#include "pitchscreen.h"
#include "appevents.h"
#include "viewport.h"
@@ -61,14 +62,15 @@
#include "playlist_viewer.h"
#include "wps.h"
#include "statusbar-skinned.h"
-
-#define RESTORE_WPS_INSTANTLY 0l
-#define RESTORE_WPS_NEXT_SECOND ((long)(HZ+current_tick))
+#include "skin_engine/wps_internals.h"
+#include "open_plugin.h"
#define FF_REWIND_MAX_PERCENT 3 /* cap ff/rewind step size at max % of file */
/* 3% of 30min file == 54s step size */
#define MIN_FF_REWIND_STEP 500
+static struct wps_state wps_state;
+
/* initial setup of wps_data */
static void wps_state_init(void);
static void track_info_callback(unsigned short id, void *param);
@@ -114,7 +116,7 @@ static void update_non_static(void)
skin_update(WPS, i, SKIN_REFRESH_NON_STATIC);
}
-void pause_action(bool may_fade, bool updatewps)
+void pause_action(bool updatewps)
{
/* Do audio first, then update, unless skin were to use its local
status in which case, reverse it */
@@ -131,11 +133,9 @@ void pause_action(bool may_fade, bool updatewps)
- global_settings.pause_rewind * 1000;
audio_ff_rewind(newpos > 0 ? newpos : 0);
}
-
- (void)may_fade;
}
-void unpause_action(bool may_fade, bool updatewps)
+void unpause_action(bool updatewps)
{
/* Do audio first, then update, unless skin were to use its local
status in which case, reverse it */
@@ -143,24 +143,15 @@ void unpause_action(bool may_fade, bool updatewps)
if (updatewps)
update_non_static();
-
- (void)may_fade;
-}
-
-static bool update_onvol_change(enum screen_type screen)
-{
- skin_update(WPS, screen, SKIN_REFRESH_NON_STATIC);
-
- return false;
}
-
#ifdef HAVE_TOUCHSCREEN
-static int skintouch_to_wps(struct wps_data *data)
+static int skintouch_to_wps(void)
{
int offset = 0;
- struct touchregion *region;
- int button = skin_get_touchaction(data, &offset, &region);
+ struct wps_state *gstate = get_wps_state();
+ struct gui_wps *gwps = skin_get_gwps(WPS, SCREEN_MAIN);
+ int button = skin_get_touchaction(gwps, &offset);
switch (button)
{
case ACTION_STD_PREV:
@@ -182,17 +173,17 @@ static int skintouch_to_wps(struct wps_data *data)
return ACTION_WPS_HOTKEY;
#endif
case ACTION_TOUCH_SCROLLBAR:
- skin_get_global_state()->id3->elapsed = skin_get_global_state()->id3->length*offset/1000;
+ gstate->id3->elapsed = gstate->id3->length*offset/1000;
audio_pre_ff_rewind();
- audio_ff_rewind(skin_get_global_state()->id3->elapsed);
+ audio_ff_rewind(gstate->id3->elapsed);
return ACTION_TOUCHSCREEN;
case ACTION_TOUCH_VOLUME:
{
const int min_vol = sound_min(SOUND_VOLUME);
const int max_vol = sound_max(SOUND_VOLUME);
const int step_vol = sound_steps(SOUND_VOLUME);
- global_settings.volume = (offset * (max_vol - min_vol)) / 1000;
- global_settings.volume += min_vol;
+
+ global_settings.volume = from_normalized_volume(offset, min_vol, max_vol, 1000);
global_settings.volume -= (global_settings.volume % step_vol);
setvol();
}
@@ -202,7 +193,7 @@ static int skintouch_to_wps(struct wps_data *data)
}
#endif /* HAVE_TOUCHSCREEN */
-bool ffwd_rew(int button)
+static bool ffwd_rew(int button, bool seek_from_end)
{
unsigned int step = 0; /* current ff/rewind step */
unsigned int max_step = 0; /* maximum ff/rewind step */
@@ -210,7 +201,10 @@ bool ffwd_rew(int button)
int direction = -1; /* forward=1 or backward=-1 */
bool exit = false;
bool usb = false;
+ bool ff_rewind = false;
const long ff_rw_accel = (global_settings.ff_rewind_accel + 3);
+ struct wps_state *gstate = get_wps_state();
+ struct mp3entry *old_id3 = gstate->id3;
if (button == ACTION_NONE)
{
@@ -219,27 +213,37 @@ bool ffwd_rew(int button)
}
while (!exit)
{
+ struct mp3entry *id3 = gstate->id3;
+ if (id3 != old_id3)
+ {
+ ff_rewind = false;
+ ff_rewind_count = 0;
+ old_id3 = id3;
+ }
+ if (id3 && seek_from_end)
+ id3->elapsed = id3->length;
+
switch ( button )
{
case ACTION_WPS_SEEKFWD:
direction = 1;
/* Fallthrough */
case ACTION_WPS_SEEKBACK:
- if (skin_get_global_state()->ff_rewind)
+ if (ff_rewind)
{
if (direction == 1)
{
/* fast forwarding, calc max step relative to end */
- max_step = (skin_get_global_state()->id3->length -
- (skin_get_global_state()->id3->elapsed +
+ max_step = (id3->length -
+ (id3->elapsed +
ff_rewind_count)) *
FF_REWIND_MAX_PERCENT / 100;
}
else
{
/* rewinding, calc max step relative to start */
- max_step = (skin_get_global_state()->id3->elapsed + ff_rewind_count) *
- FF_REWIND_MAX_PERCENT / 100;
+ max_step = (id3->elapsed + ff_rewind_count) *
+ FF_REWIND_MAX_PERCENT / 100;
}
max_step = MAX(max_step, MIN_FF_REWIND_STEP);
@@ -254,8 +258,7 @@ bool ffwd_rew(int button)
}
else
{
- if ( (audio_status() & AUDIO_STATUS_PLAY) &&
- skin_get_global_state()->id3 && skin_get_global_state()->id3->length )
+ if ((audio_status() & AUDIO_STATUS_PLAY) && id3 && id3->length )
{
audio_pre_ff_rewind();
if (direction > 0)
@@ -263,7 +266,7 @@ bool ffwd_rew(int button)
else
status_set_ffmode(STATUS_FASTBACKWARD);
- skin_get_global_state()->ff_rewind = true;
+ ff_rewind = true;
step = 1000 * global_settings.ff_rewind_min_step;
}
@@ -272,19 +275,17 @@ bool ffwd_rew(int button)
}
if (direction > 0) {
- if ((skin_get_global_state()->id3->elapsed + ff_rewind_count) >
- skin_get_global_state()->id3->length)
- ff_rewind_count = skin_get_global_state()->id3->length -
- skin_get_global_state()->id3->elapsed;
+ if ((id3->elapsed + ff_rewind_count) > id3->length)
+ ff_rewind_count = id3->length - id3->elapsed;
}
else {
- if ((int)(skin_get_global_state()->id3->elapsed + ff_rewind_count) < 0)
- ff_rewind_count = -skin_get_global_state()->id3->elapsed;
+ if ((int)(id3->elapsed + ff_rewind_count) < 0)
+ ff_rewind_count = -id3->elapsed;
}
/* set the wps state ff_rewind_count so the progess info
displays corectly */
- skin_get_global_state()->ff_rewind_count = ff_rewind_count;
+ gstate->ff_rewind_count = ff_rewind_count;
FOR_NB_SCREENS(i)
{
@@ -296,10 +297,10 @@ bool ffwd_rew(int button)
break;
case ACTION_WPS_STOPSEEK:
- skin_get_global_state()->id3->elapsed = skin_get_global_state()->id3->elapsed+ff_rewind_count;
- audio_ff_rewind(skin_get_global_state()->id3->elapsed);
- skin_get_global_state()->ff_rewind_count = 0;
- skin_get_global_state()->ff_rewind = false;
+ id3->elapsed = id3->elapsed + ff_rewind_count;
+ audio_ff_rewind(id3->elapsed);
+ gstate->ff_rewind_count = 0;
+ ff_rewind = false;
status_set_ffmode(0);
exit = true;
break;
@@ -317,20 +318,21 @@ bool ffwd_rew(int button)
button = get_action(CONTEXT_WPS|ALLOW_SOFTLOCK,TIMEOUT_BLOCK);
#ifdef HAVE_TOUCHSCREEN
if (button == ACTION_TOUCHSCREEN)
- button = skintouch_to_wps(skin_get_gwps(WPS, SCREEN_MAIN)->data);
+ button = skintouch_to_wps();
#endif
- if (button != ACTION_WPS_SEEKFWD &&
- button != ACTION_WPS_SEEKBACK)
+ if (button != ACTION_WPS_SEEKFWD
+ && button != ACTION_WPS_SEEKBACK
+ && button != 0)
button = ACTION_WPS_STOPSEEK;
}
}
return usb;
}
-#if defined(HAVE_BACKLIGHT) || defined(HAVE_REMOTE_LCD)
static void gwps_caption_backlight(struct wps_state *state)
{
- if (state && state->id3)
+#if defined(HAVE_BACKLIGHT) || defined(HAVE_REMOTE_LCD)
+ if (state->id3)
{
#ifdef HAVE_BACKLIGHT
if (global_settings.caption_backlight)
@@ -366,9 +368,10 @@ static void gwps_caption_backlight(struct wps_state *state)
}
#endif
}
+#else
+ (void) state;
+#endif /* def HAVE_BACKLIGHT || def HAVE_REMOTE_LCD */
}
-#endif
-
static void change_dir(int direction)
{
@@ -385,7 +388,7 @@ static void change_dir(int direction)
static void prev_track(unsigned long skip_thresh)
{
- struct wps_state *state = skin_get_global_state();
+ struct wps_state *state = get_wps_state();
if (state->id3->elapsed < skip_thresh)
{
audio_prev();
@@ -406,7 +409,7 @@ static void prev_track(unsigned long skip_thresh)
static void next_track(void)
{
- struct wps_state *state = skin_get_global_state();
+ struct wps_state *state = get_wps_state();
/* take care of if we're playing a cuesheet */
if (state->id3->cuesheet)
{
@@ -423,7 +426,7 @@ static void next_track(void)
static void play_hop(int direction)
{
- struct wps_state *state = skin_get_global_state();
+ struct wps_state *state = get_wps_state();
struct cuesheet *cue = state->id3->cuesheet;
long step = global_settings.skip_length*1000;
long elapsed = state->id3->elapsed;
@@ -442,26 +445,26 @@ static void play_hop(int direction)
{
if (direction < 0)
{
- prev_track(DEFAULT_SKIP_TRESH);
+ prev_track(DEFAULT_SKIP_THRESH);
return;
}
- else if (remaining < DEFAULT_SKIP_TRESH*2)
+ else if (remaining < DEFAULT_SKIP_THRESH*2)
{
next_track();
return;
}
else
- elapsed += (remaining - DEFAULT_SKIP_TRESH*2);
+ elapsed += (remaining - DEFAULT_SKIP_THRESH*2);
}
else if (!global_settings.prevent_skip &&
(!step ||
(direction > 0 && step >= remaining) ||
- (direction < 0 && elapsed < DEFAULT_SKIP_TRESH)))
+ (direction < 0 && elapsed < DEFAULT_SKIP_THRESH)))
{ /* Do normal track skipping */
if (direction > 0)
next_track();
else if (direction < 0)
- prev_track(DEFAULT_SKIP_TRESH);
+ prev_track(DEFAULT_SKIP_THRESH);
return;
}
else if (direction == 1 && step >= remaining)
@@ -485,7 +488,6 @@ static void play_hop(int direction)
audio_ff_rewind(elapsed);
}
-
#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
/*
* If the user is unable to see the wps, because the display is deactivated,
@@ -502,16 +504,19 @@ static void wps_lcd_activation_hook(unsigned short id, void *param)
}
#endif
-static void gwps_leave_wps(void)
+static void gwps_leave_wps(bool theme_enabled)
{
FOR_NB_SCREENS(i)
{
- skin_get_gwps(WPS, i)->display->scroll_stop();
+ struct gui_wps *gwps = skin_get_gwps(WPS, i);
+ gwps->display->scroll_stop();
+ if (theme_enabled)
+ {
#ifdef HAVE_BACKDROP_IMAGE
- skin_backdrop_show(sb_get_backdrop(i));
+ skin_backdrop_show(sb_get_backdrop(i));
#endif
- viewportmanager_theme_undo(i, skin_has_sbs(i, skin_get_gwps(WPS, i)->data));
-
+ viewportmanager_theme_undo(i, skin_has_sbs(gwps));
+ }
}
#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
@@ -525,19 +530,30 @@ static void gwps_leave_wps(void)
#endif
}
+static void restore_theme(void)
+{
+ FOR_NB_SCREENS(i)
+ {
+ struct gui_wps *gwps = skin_get_gwps(WPS, i);
+ struct screen *display = gwps->display;
+ display->scroll_stop();
+ viewportmanager_theme_enable(i, skin_has_sbs(gwps), NULL);
+ }
+}
+
/*
* display the wps on entering or restoring */
-static void gwps_enter_wps(void)
+static void gwps_enter_wps(bool theme_enabled)
{
struct gui_wps *gwps;
struct screen *display;
+ if (theme_enabled)
+ restore_theme();
FOR_NB_SCREENS(i)
{
gwps = skin_get_gwps(WPS, i);
display = gwps->display;
display->scroll_stop();
- viewportmanager_theme_enable(i, skin_has_sbs(i, skin_get_gwps(WPS, i)->data), NULL);
-
/* Update the values in the first (default) viewport - in case the user
has modified the statusbar or colour settings */
#if LCD_DEPTH > 1
@@ -563,7 +579,7 @@ static void gwps_enter_wps(void)
}
#ifdef HAVE_TOUCHSCREEN
gwps = skin_get_gwps(WPS, SCREEN_MAIN);
- skin_disarm_touchregions(gwps->data);
+ skin_disarm_touchregions(gwps);
if (gwps->data->touchregions < 0)
touchscreen_set_mode(TOUCHSCREEN_BUTTON);
#endif
@@ -573,16 +589,16 @@ static void gwps_enter_wps(void)
void wps_do_playpause(bool updatewps)
{
- struct wps_state *state = skin_get_global_state();
+ struct wps_state *state = get_wps_state();
if ( state->paused )
{
state->paused = false;
- unpause_action(true, updatewps);
+ unpause_action(updatewps);
}
else
{
state->paused = true;
- pause_action(true, updatewps);
+ pause_action(updatewps);
settings_save();
#if !defined(HAVE_SW_POWEROFF)
call_storage_idle_notifys(true); /* make sure resume info is saved */
@@ -590,6 +606,57 @@ void wps_do_playpause(bool updatewps)
}
}
+static long do_wps_exit(long action, bool bookmark)
+{
+ audio_pause();
+ update_non_static();
+ if (bookmark)
+ bookmark_autobookmark(true);
+ audio_stop();
+
+ ab_reset_markers();
+
+ gwps_leave_wps(true);
+#ifdef HAVE_RECORDING
+ if (action == ACTION_WPS_REC)
+ return GO_TO_RECSCREEN;
+#else
+ (void)action;
+#endif
+ if (global_settings.browse_current)
+ return GO_TO_PREVIOUS_BROWSER;
+ return GO_TO_PREVIOUS;
+}
+
+static long do_party_mode(long action)
+{
+ if (global_settings.party_mode)
+ {
+ switch (action)
+ {
+#ifdef ACTION_WPSAB_SINGLE
+ case ACTION_WPSAB_SINGLE:
+ if (!ab_repeat_mode_enabled())
+ break;
+ /* Note: currently all targets use ACTION_WPS_BROWSE
+ * if mapped to any of below actions this will cause problems */
+#endif
+ case ACTION_WPS_PLAY:
+ case ACTION_WPS_SEEKFWD:
+ case ACTION_WPS_SEEKBACK:
+ case ACTION_WPS_SKIPPREV:
+ case ACTION_WPS_SKIPNEXT:
+ case ACTION_WPS_ABSETB_NEXTDIR:
+ case ACTION_WPS_ABSETA_PREVDIR:
+ case ACTION_WPS_STOP:
+ return ACTION_NONE;
+ break;
+ default:
+ break;
+ }
+ }
+ return action;
+}
/* The WPS can be left in two ways:
* a) call a function, which draws over the wps. In this case, the wps
@@ -597,31 +664,28 @@ void wps_do_playpause(bool updatewps)
* b) return with a value evaluated by root_menu.c, in this case the wps
* is really left, and root_menu will handle the next screen
*
- * In either way, call gwps_leave_wps(), in order to restore the correct
+ * In either way, call gwps_leave_wps(true), in order to restore the correct
* "main screen" backdrops and statusbars
*/
long gui_wps_show(void)
{
long button = 0;
bool restore = true;
- long restoretimer = RESTORE_WPS_INSTANTLY; /* timer to delay screen redraw temporarily */
bool exit = false;
bool bookmark = false;
bool update = false;
- bool vol_changed = false;
+ bool theme_enabled = true;
long last_left = 0, last_right = 0;
- struct wps_state *state = skin_get_global_state();
+ struct wps_state *state = get_wps_state();
-#ifdef AB_REPEAT_ENABLE
ab_repeat_init();
ab_reset_markers();
-#endif
- wps_state_init();
+ wps_state_init();
while ( 1 )
{
+ bool hotkey = false;
bool audio_paused = (audio_status() & AUDIO_STATUS_PAUSE)?true:false;
-
/* did someone else (i.e power thread) change audio pause mode? */
if (state->paused != audio_paused) {
state->paused = audio_paused;
@@ -635,8 +699,53 @@ long gui_wps_show(void)
#endif
}
}
- button = skin_wait_for_action(WPS, CONTEXT_WPS|ALLOW_SOFTLOCK,
- restore ? 1 : HZ/5);
+
+ if (restore)
+ {
+ restore = false;
+#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
+ add_event(LCD_EVENT_ACTIVATION, wps_lcd_activation_hook);
+#endif
+ /* we remove the update delay since it's not very usable in the wps,
+ * e.g. during volume changing or ffwd/rewind */
+ sb_skin_set_update_delay(0);
+ skin_request_full_update(WPS);
+ update = true;
+ gwps_enter_wps(theme_enabled);
+ theme_enabled = true;
+ }
+ else
+ {
+ gwps_caption_backlight(state);
+
+ FOR_NB_SCREENS(i)
+ {
+#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
+ /* currently, all remotes are readable without backlight
+ * so still update those */
+ if (lcd_active() || (i != SCREEN_MAIN))
+#endif
+ {
+ bool full_update = skin_do_full_update(WPS, i);
+ if (update || full_update)
+ {
+ skin_update(WPS, i, full_update ?
+ SKIN_REFRESH_ALL : SKIN_REFRESH_NON_STATIC);
+ }
+ }
+ }
+ update = false;
+ }
+
+ if (exit)
+ {
+ return do_wps_exit(button, bookmark);
+ }
+
+ if (button && !IS_SYSEVENT(button) )
+ storage_spin();
+
+ button = skin_wait_for_action(WPS, CONTEXT_WPS|ALLOW_SOFTLOCK, HZ/5);
/* Exit if audio has stopped playing. This happens e.g. at end of
playlist or if using the sleep timer. */
@@ -644,46 +753,64 @@ long gui_wps_show(void)
exit = true;
#ifdef HAVE_TOUCHSCREEN
if (button == ACTION_TOUCHSCREEN)
- button = skintouch_to_wps(skin_get_gwps(WPS, SCREEN_MAIN)->data);
+ button = skintouch_to_wps();
#endif
+ button = do_party_mode(button); /* block select actions in party mode */
+
/* The iPods/X5/M5 use a single button for the A-B mode markers,
defined as ACTION_WPSAB_SINGLE in their config files. */
#ifdef ACTION_WPSAB_SINGLE
- if (!global_settings.party_mode && ab_repeat_mode_enabled())
+ static int wps_ab_state = 0;
+ if (button == ACTION_WPSAB_SINGLE && ab_repeat_mode_enabled())
{
- static int wps_ab_state = 0;
- if (button == ACTION_WPSAB_SINGLE)
+ switch (wps_ab_state)
{
- switch (wps_ab_state)
- {
- case 0: /* set the A spot */
- button = ACTION_WPS_ABSETA_PREVDIR;
- break;
- case 1: /* set the B spot */
- button = ACTION_WPS_ABSETB_NEXTDIR;
- break;
- case 2:
- button = ACTION_WPS_ABRESET;
- break;
- }
- wps_ab_state = (wps_ab_state+1) % 3;
+ case 0: /* set the A spot */
+ button = ACTION_WPS_ABSETA_PREVDIR;
+ break;
+ case 1: /* set the B spot */
+ button = ACTION_WPS_ABSETB_NEXTDIR;
+ break;
+ case 2:
+ button = ACTION_WPS_ABRESET;
+ break;
}
+ wps_ab_state = (wps_ab_state+1) % 3;
}
-#endif
+#endif /* def ACTION_WPSAB_SINGLE */
+
switch(button)
{
#ifdef HAVE_HOTKEY
case ACTION_WPS_HOTKEY:
+ {
+ hotkey = true;
if (!global_settings.hotkey_wps)
break;
- /* fall through */
-#endif
+ if (get_hotkey(global_settings.hotkey_wps)->flags & HOTKEY_FLAG_NOSBS)
+ {
+ /* leave WPS without re-enabling theme */
+ theme_enabled = false;
+ gwps_leave_wps(theme_enabled);
+ onplay(state->id3->path,
+ FILE_ATTR_AUDIO, CONTEXT_WPS, hotkey);
+ if (!audio_status())
+ {
+ /* re-enable theme since we're returning to SBS */
+ gwps_leave_wps(true);
+ return GO_TO_ROOT;
+ }
+ restore = true;
+ break;
+ }
+ }
+ /* fall through */
+#endif /* def HAVE_HOTKEY */
case ACTION_WPS_CONTEXT:
{
- bool hotkey = button == ACTION_WPS_HOTKEY;
- gwps_leave_wps();
+ gwps_leave_wps(true);
int retval = onplay(state->id3->path,
- FILE_ATTR_AUDIO, CONTEXT_WPS, hotkey);
+ FILE_ATTR_AUDIO, CONTEXT_WPS, hotkey);
/* if music is stopped in the context menu we want to exit the wps */
if (retval == ONPLAY_MAINMENU
|| !audio_status())
@@ -691,39 +818,46 @@ long gui_wps_show(void)
else if (retval == ONPLAY_PLAYLIST)
return GO_TO_PLAYLIST_VIEWER;
else if (retval == ONPLAY_PLUGIN)
- return GO_TO_PLUGIN;
+ {
+ restore_theme();
+ theme_enabled = false;
+ open_plugin_run(ID2P(LANG_OPEN_PLUGIN_SET_WPS_CONTEXT_PLUGIN));
+ }
+
restore = true;
}
break;
case ACTION_WPS_BROWSE:
- gwps_leave_wps();
+ gwps_leave_wps(true);
return GO_TO_PREVIOUS_BROWSER;
break;
/* play/pause */
case ACTION_WPS_PLAY:
- if (global_settings.party_mode)
- break;
wps_do_playpause(true);
break;
- case ACTION_WPS_VOLUP:
- global_settings.volume += sound_steps(SOUND_VOLUME);
- vol_changed = true;
- break;
+ case ACTION_WPS_VOLUP: /* fall through */
case ACTION_WPS_VOLDOWN:
- global_settings.volume -= sound_steps(SOUND_VOLUME);
- vol_changed = true;
+ if (button == ACTION_WPS_VOLUP)
+ adjust_volume(1);
+ else
+ adjust_volume(-1);
+
+ setvol();
+ FOR_NB_SCREENS(i)
+ {
+ skin_update(WPS, i, SKIN_REFRESH_NON_STATIC);
+ }
+ update = false;
break;
/* fast forward
OR next dir if this is straight after ACTION_WPS_SKIPNEXT */
case ACTION_WPS_SEEKFWD:
- if (global_settings.party_mode)
- break;
if (current_tick -last_right < HZ)
{
- if (state->id3->cuesheet)
+ if (state->id3->cuesheet && playlist_check(1))
{
audio_next();
}
@@ -733,37 +867,42 @@ long gui_wps_show(void)
}
}
else
- ffwd_rew(ACTION_WPS_SEEKFWD);
+ ffwd_rew(ACTION_WPS_SEEKFWD, false);
last_right = last_left = 0;
break;
/* fast rewind
OR prev dir if this is straight after ACTION_WPS_SKIPPREV,*/
case ACTION_WPS_SEEKBACK:
- if (global_settings.party_mode)
- break;
- if (current_tick -last_left < HZ)
+ if (current_tick - last_left < HZ)
{
- if (state->id3->cuesheet)
+ if (state->id3->cuesheet && playlist_check(-1))
{
- audio_pre_ff_rewind();
- audio_ff_rewind(0);
+ audio_prev();
}
else
{
change_dir(-1);
}
+ } else if (global_settings.rewind_across_tracks
+ && get_wps_state()->id3->elapsed < DEFAULT_SKIP_THRESH
+ && playlist_check(-1))
+ {
+ if (!audio_paused)
+ audio_pause();
+ audio_prev();
+ ffwd_rew(ACTION_WPS_SEEKBACK, true);
+ if (!audio_paused)
+ audio_resume();
}
else
- ffwd_rew(ACTION_WPS_SEEKBACK);
+ ffwd_rew(ACTION_WPS_SEEKBACK, false);
last_left = last_right = 0;
break;
/* prev / restart */
case ACTION_WPS_SKIPPREV:
- if (global_settings.party_mode)
- break;
last_left = current_tick;
-#ifdef AB_REPEAT_ENABLE
+
/* if we're in A/B repeat mode and the current position
is past the A marker, jump back to the A marker... */
if ( ab_repeat_mode_enabled() && ab_after_A_marker(state->id3->elapsed) )
@@ -771,19 +910,15 @@ long gui_wps_show(void)
ab_jump_to_A_marker();
break;
}
- else
- /* ...otherwise, do it normally */
-#endif
+ else /* ...otherwise, do it normally */
play_hop(-1);
break;
/* next
OR if skip length set, hop by predetermined amount. */
case ACTION_WPS_SKIPNEXT:
- if (global_settings.party_mode)
- break;
last_right = current_tick;
-#ifdef AB_REPEAT_ENABLE
+
/* if we're in A/B repeat mode and the current position is
before the A marker, jump to the A marker... */
if ( ab_repeat_mode_enabled() )
@@ -794,43 +929,33 @@ long gui_wps_show(void)
break;
}
}
- else
- /* ...otherwise, do it normally */
-#endif
+ else /* ...otherwise, do it normally */
play_hop(1);
break;
/* next / prev directories */
/* and set A-B markers if in a-b mode */
case ACTION_WPS_ABSETB_NEXTDIR:
- if (global_settings.party_mode)
- break;
-#if defined(AB_REPEAT_ENABLE)
if (ab_repeat_mode_enabled())
{
ab_set_B_marker(state->id3->elapsed);
ab_jump_to_A_marker();
}
else
-#endif
{
change_dir(1);
}
break;
case ACTION_WPS_ABSETA_PREVDIR:
- if (global_settings.party_mode)
- break;
-#if defined(AB_REPEAT_ENABLE)
if (ab_repeat_mode_enabled())
ab_set_A_marker(state->id3->elapsed);
else
-#endif
{
change_dir(-1);
}
break;
/* menu key functions */
case ACTION_WPS_MENU:
- gwps_leave_wps();
+ gwps_leave_wps(true);
return GO_TO_ROOT;
break;
@@ -838,16 +963,25 @@ long gui_wps_show(void)
#ifdef HAVE_QUICKSCREEN
case ACTION_WPS_QUICKSCREEN:
{
- gwps_leave_wps();
- if (global_settings.shortcuts_replaces_qs)
+ gwps_leave_wps(true);
+ bool enter_shortcuts_menu = global_settings.shortcuts_replaces_qs;
+ if (!enter_shortcuts_menu)
{
- global_status.last_screen = GO_TO_SHORTCUTMENU;
int ret = quick_screen_quick(button);
+ if (ret == QUICKSCREEN_IN_USB)
+ return GO_TO_ROOT;
+ else if (ret == QUICKSCREEN_GOTO_SHORTCUTS_MENU)
+ enter_shortcuts_menu = true;
+ else
+ restore = true;
+ }
+
+ if (enter_shortcuts_menu) /* enter_shortcuts_menu */
+ {
+ global_status.last_screen = GO_TO_SHORTCUTMENU;
+ int ret = do_shortcut_menu(NULL);
return (ret == GO_TO_PREVIOUS ? GO_TO_WPS : ret);
}
- else if (quick_screen_quick(button) > 0)
- return GO_TO_ROOT;
- restore = true;
}
break;
#endif /* HAVE_QUICKSCREEN */
@@ -858,7 +992,7 @@ long gui_wps_show(void)
#ifdef HAVE_PITCHCONTROL
case ACTION_WPS_PITCHSCREEN:
{
- gwps_leave_wps();
+ gwps_leave_wps(true);
if (1 == gui_syncpitchscreen_run())
return GO_TO_ROOT;
restore = true;
@@ -866,7 +1000,6 @@ long gui_wps_show(void)
break;
#endif /* HAVE_PITCHCONTROL */
-#ifdef AB_REPEAT_ENABLE
/* reset A&B markers */
case ACTION_WPS_ABRESET:
if (ab_repeat_mode_enabled())
@@ -875,18 +1008,15 @@ long gui_wps_show(void)
update = true;
}
break;
-#endif /* AB_REPEAT_ENABLE */
/* stop and exit wps */
case ACTION_WPS_STOP:
- if (global_settings.party_mode)
- break;
bookmark = true;
exit = true;
break;
case ACTION_WPS_LIST_BOOKMARKS:
- gwps_leave_wps();
+ gwps_leave_wps(true);
if (bookmark_load_menu() == BOOKMARK_USB_CONNECTED)
{
return GO_TO_ROOT;
@@ -895,15 +1025,17 @@ long gui_wps_show(void)
break;
case ACTION_WPS_CREATE_BOOKMARK:
- gwps_leave_wps();
+ gwps_leave_wps(true);
bookmark_create_menu();
restore = true;
break;
case ACTION_WPS_ID3SCREEN:
{
- gwps_leave_wps();
- if (browse_id3())
+ gwps_leave_wps(true);
+ if (browse_id3(audio_current_track(),
+ playlist_get_display_index(),
+ playlist_amount(), NULL))
return GO_TO_ROOT;
restore = true;
}
@@ -915,7 +1047,7 @@ long gui_wps_show(void)
break;
case ACTION_NONE: /* Timeout, do a partial update */
update = true;
- ffwd_rew(button); /* hopefully fix the ffw/rwd bug */
+ ffwd_rew(button, false); /* hopefully fix the ffw/rwd bug */
break;
#ifdef HAVE_RECORDING
case ACTION_WPS_REC:
@@ -923,7 +1055,7 @@ long gui_wps_show(void)
break;
#endif
case ACTION_WPS_VIEW_PLAYLIST:
- gwps_leave_wps();
+ gwps_leave_wps(true);
return GO_TO_PLAYLIST_VIEWER;
break;
default:
@@ -932,99 +1064,25 @@ long gui_wps_show(void)
case SYS_USB_CONNECTED:
case SYS_CALL_INCOMING:
case BUTTON_MULTIMEDIA_STOP:
- gwps_leave_wps();
+ gwps_leave_wps(true);
return GO_TO_ROOT;
}
update = true;
break;
}
-
- if (vol_changed)
- {
- bool res = false;
- vol_changed = false;
- setvol();
- FOR_NB_SCREENS(i)
- {
- if(update_onvol_change(i))
- res = true;
- }
- if (res) {
- restore = true;
- restoretimer = RESTORE_WPS_NEXT_SECOND;
- }
- }
-
-
- if (restore &&
- ((restoretimer == RESTORE_WPS_INSTANTLY) ||
- TIME_AFTER(current_tick, restoretimer)))
- {
- restore = false;
- restoretimer = RESTORE_WPS_INSTANTLY;
-#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
- add_event(LCD_EVENT_ACTIVATION, wps_lcd_activation_hook);
-#endif
- /* we remove the update delay since it's not very usable in the wps,
- * e.g. during volume changing or ffwd/rewind */
- sb_skin_set_update_delay(0);
- skin_request_full_update(WPS);
- update = true;
- gwps_enter_wps();
- }
- else
- {
-#if defined(HAVE_BACKLIGHT) || defined(HAVE_REMOTE_LCD)
- gwps_caption_backlight(state);
-#endif
- FOR_NB_SCREENS(i)
- {
-#if defined(HAVE_LCD_ENABLE) || defined(HAVE_LCD_SLEEP)
- /* currently, all remotes are readable without backlight
- * so still update those */
- if (lcd_active() || (i != SCREEN_MAIN))
-#endif
- {
- bool full_update = skin_do_full_update(WPS, i);
- if (update || full_update)
- {
- skin_update(WPS, i, full_update ?
- SKIN_REFRESH_ALL : SKIN_REFRESH_NON_STATIC);
- }
- }
- }
- update = false;
- }
-
- if (exit) {
- audio_pause();
- update_non_static();
- if (bookmark)
- bookmark_autobookmark(true);
- audio_stop();
-#ifdef AB_REPEAT_ENABLE
- ab_reset_markers();
-#endif
- gwps_leave_wps();
-#ifdef HAVE_RECORDING
- if (button == ACTION_WPS_REC)
- return GO_TO_RECSCREEN;
-#endif
- if (global_settings.browse_current)
- return GO_TO_PREVIOUS_BROWSER;
- return GO_TO_PREVIOUS;
- }
-
- if (button && !IS_SYSEVENT(button) )
- storage_spin();
}
return GO_TO_ROOT; /* unreachable - just to reduce compiler warnings */
}
+struct wps_state *get_wps_state(void)
+{
+ return &wps_state;
+}
+
/* this is called from the playback thread so NO DRAWING! */
static void track_info_callback(unsigned short id, void *param)
{
- struct wps_state *state = skin_get_global_state();
+ struct wps_state *state = get_wps_state();
if (id == PLAYBACK_EVENT_TRACK_CHANGE || id == PLAYBACK_EVENT_CUR_TRACK_READY)
{
@@ -1040,14 +1098,13 @@ static void track_info_callback(unsigned short id, void *param)
state->id3 = audio_current_track();
}
#endif
- skin_get_global_state()->nid3 = audio_next_track();
+ state->nid3 = audio_next_track();
skin_request_full_update(WPS);
}
static void wps_state_init(void)
{
- struct wps_state *state = skin_get_global_state();
- state->ff_rewind = false;
+ struct wps_state *state = get_wps_state();
state->paused = false;
if(audio_status() & AUDIO_STATUS_PLAY)
{
@@ -1071,16 +1128,3 @@ static void wps_state_init(void)
add_event(PLAYBACK_EVENT_TRACK_SKIP, track_info_callback);
#endif
}
-
-
-#ifdef IPOD_ACCESSORY_PROTOCOL
-bool is_wps_fading(void)
-{
- return skin_get_global_state()->is_fading;
-}
-
-int wps_get_ff_rewind_count(void)
-{
- return skin_get_global_state()->ff_rewind_count;
-}
-#endif
diff --git a/apps/gui/wps.h b/apps/gui/wps.h
index a463b0e9bb..001c112a4d 100644
--- a/apps/gui/wps.h
+++ b/apps/gui/wps.h
@@ -20,35 +20,30 @@
****************************************************************************/
#ifndef _WPS_H_
#define _WPS_H_
+
#include <stdbool.h>
-#include "config.h"
-#include "screen_access.h"
-
-long gui_wps_show(void);
-
-/* wrapper for the wps to load the skin (.wps/.rwps) files */
-void wps_data_load(enum screen_type, const char *, bool);
-void gui_sync_wps_init(void) INIT_ATTR;
+struct mp3entry;
-/* fade (if enabled) and pause the audio, optionally rewind a little */
-void pause_action(bool may_fade, bool updatewps);
-void unpause_action(bool may_fade, bool updatewps);
+/* Please don't add anything else to here... */
+struct wps_state
+{
+ struct mp3entry *id3;
+ struct mp3entry *nid3;
+ int ff_rewind_count;
+ bool paused;
+};
-/* fades the volume, e.g. on pause or stop */
-void fade(bool fade_in, bool updatewps);
+long gui_wps_show(void);
-bool ffwd_rew(int button);
+/* fade (if enabled) and pause the audio, optionally rewind a little */
+void pause_action(bool updatewps);
+void unpause_action(bool updatewps);
void wps_do_playpause(bool updatewps);
-#ifdef IPOD_ACCESSORY_PROTOCOL
-/* whether the wps is fading the volume due to pausing/stopping */
-bool is_wps_fading(void);
-/* return length of the current ff or rewin action, IAP needs this */
-int wps_get_ff_rewind_count(void);
-#endif /* IPOD_ACCESSORY_PROTOCOL */
+struct wps_state *get_wps_state(void);
/* in milliseconds */
-#define DEFAULT_SKIP_TRESH 3000l
+#define DEFAULT_SKIP_THRESH 3000l
#endif /* _WPS_H_ */
diff --git a/apps/gui/yesno.c b/apps/gui/yesno.c
index a79b8ae644..c763753cd7 100644
--- a/apps/gui/yesno.c
+++ b/apps/gui/yesno.c
@@ -253,14 +253,15 @@ enum yesno_res gui_syncyesno_run(const struct text_message * main_message,
if(result_displayed)
sleep(HZ);
+ exit:
+ remove_event_ex(GUI_EVENT_NEED_UI_UPDATE, gui_yesno_ui_update, &yn[0]);
+
FOR_NB_SCREENS(i)
{
screens[i].scroll_stop_viewport(yn[i].vp);
viewportmanager_theme_undo(i, true);
}
- exit:
- remove_event_ex(GUI_EVENT_NEED_UI_UPDATE, gui_yesno_ui_update, &yn[0]);
#ifdef HAVE_TOUCHSCREEN
touchscreen_set_mode(old_mode);
#endif
diff --git a/apps/hosted/android/keyboard.c b/apps/hosted/android/keyboard.c
index eda951a7c9..b74f67e782 100644
--- a/apps/hosted/android/keyboard.c
+++ b/apps/hosted/android/keyboard.c
@@ -100,7 +100,7 @@ int kbd_input(char* text, int buflen, unsigned short *kbd)
if (accepted)
{
utf8_string = e->GetStringUTFChars(env_ptr, new_string, 0);
- strlcpy(text, utf8_string, buflen);
+ strmemccpy(text, utf8_string, buflen);
e->ReleaseStringUTFChars(env_ptr, new_string, utf8_string);
e->DeleteGlobalRef(env_ptr, new_string);
}
diff --git a/apps/hosted/android/notification.c b/apps/hosted/android/notification.c
index 39c8b07737..a5b60c1013 100644
--- a/apps/hosted/android/notification.c
+++ b/apps/hosted/android/notification.c
@@ -29,6 +29,7 @@
#include "misc.h"
#include "thread.h"
#include "debug.h"
+#include "audio.h"
extern JNIEnv *env_ptr;
extern jclass RockboxService_class;
diff --git a/apps/iap/iap-core.c b/apps/iap/iap-core.c
index 885ba2c188..da04a67311 100644
--- a/apps/iap/iap-core.c
+++ b/apps/iap/iap-core.c
@@ -19,8 +19,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
-#include <string.h>
+#include "string-extra.h"
#include "panic.h"
#include "iap-core.h"
#include "iap-lingo.h"
@@ -364,6 +364,7 @@ static void iap_thread(void)
/* Handle poweroff message */
case SYS_POWEROFF:
+ case SYS_REBOOT:
{
iap_shutdown = true;
break;
@@ -452,7 +453,7 @@ static void iap_malloc(void)
return;
#ifdef IAP_MALLOC_DYNAMIC
- iap_buffer_handle = core_alloc_ex("iap", IAP_MALLOC_SIZE, &iap_buflib_callbacks);
+ iap_buffer_handle = core_alloc_ex(IAP_MALLOC_SIZE, &iap_buflib_callbacks);
if (iap_buffer_handle < 0)
panicf("Could not allocate buffer memory");
iap_buffers = core_get_data(iap_buffer_handle);
diff --git a/apps/iap/iap-lingo4.c b/apps/iap/iap-lingo4.c
index 4ec5c462a1..eb629407f2 100644
--- a/apps/iap/iap-lingo4.c
+++ b/apps/iap/iap-lingo4.c
@@ -24,6 +24,7 @@
#include "filetree.h"
#include "wps.h"
#include "playback.h"
+#include "string-extra.h"
/*
* This macro is meant to be used inside an IAP mode message handler.
@@ -87,7 +88,7 @@ static void get_playlist_name(unsigned char *dest,
}
}
if (playlist_file != NULL) {
- strlcpy(dest, playlist_file->d_name, max_length);
+ strmemccpy(dest, playlist_file->d_name, max_length);
}
closedir(dp);
}
@@ -1218,7 +1219,7 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf)
{
memcpy(cur_dbrecord, buf + 3, 5);
- int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
+ int paused = !!(audio_status() & AUDIO_STATUS_PAUSE);
uint32_t index;
uint32_t trackcount;
index = get_u32(&cur_dbrecord[1]);
@@ -1430,7 +1431,6 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf)
unsigned int number_of_playlists = nbr_total_playlists();
uint32_t trackcount;
trackcount = playlist_amount();
- size_t len;
if ((buf[3] == 0x05) && ((start_index + read_count ) > trackcount))
{
@@ -1465,22 +1465,21 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf)
switch(buf[3])
{
case 0x05:
- len = strlcpy((char *)&data[7], id3.title,64);
+ strmemccpy((char *)&data[7], id3.title,64);
break;
case 0x02:
- len = strlcpy((char *)&data[7], id3.artist,64);
+ strmemccpy((char *)&data[7], id3.artist,64);
break;
case 0x03:
- len = strlcpy((char *)&data[7], id3.album,64);
+ strmemccpy((char *)&data[7], id3.album,64);
break;
case 0x04:
case 0x06:
- len = strlcpy((char *)&data[7], "Not Supported",14);
+ strmemccpy((char *)&data[7], "Not Supported",14);
break;
}
break;
}
- (void)len; /* Shut up, compiler */
put_u32(&data[3], start_index+counter);
iap_send_pkt(data, 7 + strlen(data+7) + 1);
yield();
@@ -2003,7 +2002,7 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf)
*
*/
{
- int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
+ int paused = !!(audio_status() & AUDIO_STATUS_PAUSE);
uint32_t index;
uint32_t trackcount;
index = get_u32(&buf[3]);
@@ -2821,7 +2820,7 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf)
*
*/
{
- int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
+ int paused = !!(audio_status() & AUDIO_STATUS_PAUSE);
long tracknum = get_u32(&buf[3]);
audio_pause();
@@ -2977,7 +2976,7 @@ void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf)
{
memcpy(cur_dbrecord, buf + 3, 5);
- int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
+ int paused = !!(audio_status() & AUDIO_STATUS_PAUSE);
unsigned int number_of_playlists = nbr_total_playlists();
uint32_t index;
uint32_t trackcount;
diff --git a/apps/keymaps/keymap-agptekrocker.c b/apps/keymaps/keymap-agptekrocker.c
index 4d7139ffd5..5ca834ab51 100644
--- a/apps/keymaps/keymap-agptekrocker.c
+++ b/apps/keymaps/keymap-agptekrocker.c
@@ -96,7 +96,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_SETTINGS_DEC, BUTTON_VOLDOWN, BUTTON_NONE },
{ ACTION_SETTINGS_DECREPEAT, BUTTON_VOLDOWN|BUTTON_REPEAT, BUTTON_NONE },
/* ACTION_SETTINGS_DECBIGSTEP */
- { ACTION_SETTINGS_RESET, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT },
/* ACTION_SETTINGS_SET, Used by touchscreen targets */
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
}; /* button_context_settings */
@@ -140,15 +139,16 @@ static const struct button_mapping button_context_yesno[] = {
}; /* button_context_settings_yesno */
static const struct button_mapping button_context_quickscreen[] = {
- { ACTION_QS_TOP, BUTTON_UP|BUTTON_REL, BUTTON_NONE },
- { ACTION_QS_TOP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_QS_DOWN, BUTTON_DOWN|BUTTON_REL, BUTTON_NONE },
- { ACTION_QS_DOWN, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_QS_LEFT, BUTTON_LEFT|BUTTON_REL, BUTTON_NONE },
- { ACTION_QS_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_QS_RIGHT, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE },
- { ACTION_QS_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_STD_CANCEL, BUTTON_SELECT, BUTTON_NONE },
+ { ACTION_QS_TOP, BUTTON_UP|BUTTON_REL, BUTTON_NONE },
+ { ACTION_QS_TOP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_QS_DOWN, BUTTON_DOWN|BUTTON_REL, BUTTON_NONE },
+ { ACTION_QS_DOWN, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_QS_LEFT, BUTTON_LEFT|BUTTON_REL, BUTTON_NONE },
+ { ACTION_QS_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_QS_RIGHT, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE },
+ { ACTION_QS_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_STD_CONTEXT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT },
+ { ACTION_STD_CANCEL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT },
LAST_ITEM_IN_LIST
}; /* button_context_quickscreen */
@@ -221,7 +221,7 @@ static const struct button_mapping button_context_bmark[] = {
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_STD:
return button_context_standard;
diff --git a/apps/keymaps/keymap-c200.c b/apps/keymaps/keymap-c200.c
index 2e26f424cc..6ca1702e5f 100644
--- a/apps/keymaps/keymap-c200.c
+++ b/apps/keymaps/keymap-c200.c
@@ -88,7 +88,6 @@ static const struct button_mapping button_context_wps[] = {
static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_SELECT, BUTTON_NONE },
{ ACTION_SETTINGS_INC, BUTTON_UP, BUTTON_NONE },
{ ACTION_SETTINGS_INCREPEAT,BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
diff --git a/apps/keymaps/keymap-clip.c b/apps/keymaps/keymap-clip.c
index 7c8fb69471..494c9a734c 100644
--- a/apps/keymaps/keymap-clip.c
+++ b/apps/keymaps/keymap-clip.c
@@ -98,7 +98,6 @@ static const struct button_mapping button_context_wps[] = {
static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_OK, BUTTON_HOME|BUTTON_REL, BUTTON_HOME },
{ ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_SELECT, BUTTON_NONE },
{ ACTION_SETTINGS_INC, BUTTON_UP, BUTTON_NONE },
{ ACTION_SETTINGS_INCREPEAT,BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
@@ -180,7 +179,7 @@ static const struct button_mapping button_context_quickscreen[] = {
{ ACTION_NONE, BUTTON_LEFT, BUTTON_NONE },
{ ACTION_STD_CANCEL, BUTTON_POWER|BUTTON_REL, BUTTON_NONE },
{ ACTION_STD_CANCEL, BUTTON_HOME, BUTTON_NONE },
- { ACTION_STD_CANCEL, BUTTON_SELECT, BUTTON_NONE },
+ { ACTION_STD_CANCEL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT },
{ ACTION_QS_TOP, BUTTON_UP|BUTTON_REL, BUTTON_NONE },
{ ACTION_QS_TOP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_QS_DOWN, BUTTON_DOWN|BUTTON_REL, BUTTON_NONE },
@@ -213,9 +212,11 @@ static const struct button_mapping button_context_pitchscreen[] = {
{ ACTION_PS_NUDGE_LEFTOFF, BUTTON_LEFT|BUTTON_REL, BUTTON_NONE },
{ ACTION_PS_NUDGE_RIGHT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_PS_NUDGE_RIGHTOFF, BUTTON_RIGHT|BUTTON_REL, BUTTON_NONE },
- { ACTION_PS_TOGGLE_MODE, BUTTON_HOME|BUTTON_REL, BUTTON_HOME },
- { ACTION_PS_RESET, BUTTON_SELECT, BUTTON_NONE },
+ { ACTION_PS_TOGGLE_MODE, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT },
+ { ACTION_PS_RESET, BUTTON_HOME|BUTTON_REPEAT, BUTTON_HOME },
+ { ACTION_PS_RESET, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT },
{ ACTION_PS_EXIT, BUTTON_POWER, BUTTON_NONE },
+ { ACTION_PS_EXIT, BUTTON_HOME|BUTTON_REL, BUTTON_HOME },
{ ACTION_PS_SLOWER, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_PS_FASTER, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
@@ -398,7 +399,7 @@ static const struct button_mapping button_context_usb_hid_mode_mouse[] = {
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_STD:
return button_context_standard;
diff --git a/apps/keymaps/keymap-creativezv.c b/apps/keymaps/keymap-creativezv.c
index f2bcfd80f7..3242e8924f 100644
--- a/apps/keymaps/keymap-creativezv.c
+++ b/apps/keymaps/keymap-creativezv.c
@@ -134,7 +134,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_LEFT },
{ ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_RIGHT },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -147,7 +146,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_BACK, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settingsgraphical */
diff --git a/apps/keymaps/keymap-creativezvm.c b/apps/keymaps/keymap-creativezvm.c
index 7a0cb5965a..47b24bf8b3 100644
--- a/apps/keymaps/keymap-creativezvm.c
+++ b/apps/keymaps/keymap-creativezvm.c
@@ -133,7 +133,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_LEFT },
{ ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_RIGHT },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -146,7 +145,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_BACK, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settingsgraphical */
diff --git a/apps/keymaps/keymap-e200.c b/apps/keymaps/keymap-e200.c
index 538cd7cb8a..20cc16f2dc 100644
--- a/apps/keymaps/keymap-e200.c
+++ b/apps/keymaps/keymap-e200.c
@@ -100,7 +100,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_UP },
{ ACTION_STD_NEXT, BUTTON_DOWN|BUTTON_REL, BUTTON_DOWN },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_DOWN },
- { ACTION_SETTINGS_RESET, BUTTON_SELECT, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
}; /* button_context_settings */
diff --git a/apps/keymaps/keymap-erosq.c b/apps/keymaps/keymap-erosq.c
index 59b70d24ca..054da96201 100644
--- a/apps/keymaps/keymap-erosq.c
+++ b/apps/keymaps/keymap-erosq.c
@@ -87,7 +87,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_SETTINGS_INCBIGSTEP, BUTTON_VOL_UP, BUTTON_NONE },
{ ACTION_SETTINGS_DEC, BUTTON_SCROLL_BACK, BUTTON_NONE },
{ ACTION_SETTINGS_DECBIGSTEP, BUTTON_VOL_DOWN, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
}; /* button_context_settings */
@@ -131,6 +130,7 @@ static const struct button_mapping button_context_quickscreen[] = {
{ ACTION_QS_DOWN, BUTTON_NEXT|BUTTON_REL, BUTTON_NONE },
{ ACTION_QS_DOWN, BUTTON_NEXT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE },
+ { ACTION_STD_CONTEXT,BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU },
LAST_ITEM_IN_LIST
}; /* button_context_quickscreen */
@@ -194,7 +194,7 @@ static const struct button_mapping button_context_bmark[] = {
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_STD:
return button_context_standard;
@@ -212,7 +212,8 @@ const struct button_mapping* get_context_mapping(int context)
return button_context_list;
case CONTEXT_SETTINGS:
- case CONTEXT_SETTINGS_EQ:
+ case CONTEXT_SETTINGS_EQ:
+ case CONTEXT_SETTINGS_COLOURCHOOSER:
return button_context_settings;
case CONTEXT_SETTINGS_TIME:
diff --git a/apps/keymaps/keymap-fiiom3k.c b/apps/keymaps/keymap-fiiom3k.c
index 4cd2691d33..01fe3a689c 100644
--- a/apps/keymaps/keymap-fiiom3k.c
+++ b/apps/keymaps/keymap-fiiom3k.c
@@ -40,39 +40,41 @@ static const struct button_mapping button_context_standard[] = {
{ACTION_STD_OK, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT},
{ACTION_STD_CANCEL, BUTTON_BACK|BUTTON_REL, BUTTON_BACK},
{ACTION_STD_CONTEXT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT},
- {ACTION_STD_CONTEXT, BUTTON_MENU|BUTTON_REL, BUTTON_MENU},
- {ACTION_STD_MENU, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK},
- {ACTION_STD_QUICKSCREEN, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU},
+ {ACTION_STD_QUICKSCREEN, BUTTON_MENU|BUTTON_REL, BUTTON_MENU},
+ {ACTION_STD_MENU, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU},
{ACTION_STD_KEYLOCK, BUTTON_POWER|BUTTON_REL, BUTTON_POWER},
- {ACTION_STD_HOTKEY, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY},
LAST_ITEM_IN_LIST
}; /* button_context_standard */
static const struct button_mapping button_context_wps[] = {
{ACTION_WPS_PLAY, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY},
- {ACTION_WPS_PLAY, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT},
+ {ACTION_WPS_VIEW_PLAYLIST, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT},
{ACTION_WPS_STOP, BUTTON_POWER|BUTTON_REPEAT, BUTTON_POWER},
{ACTION_WPS_VOLUP, BUTTON_VOL_UP, BUTTON_NONE},
{ACTION_WPS_VOLUP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE},
{ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_WPS_VOLUP, BUTTON_SCROLL_BACK, BUTTON_NONE},
+ {ACTION_WPS_VOLUP, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_WPS_VOLDOWN, BUTTON_SCROLL_FWD, BUTTON_NONE},
+ {ACTION_WPS_VOLDOWN, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_WPS_VOLUP, BUTTON_UP|BUTTON_REL, BUTTON_UP},
+ {ACTION_WPS_VOLDOWN, BUTTON_DOWN|BUTTON_REL, BUTTON_DOWN},
{ACTION_WPS_SKIPNEXT, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT},
{ACTION_WPS_SKIPPREV, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT},
{ACTION_WPS_SEEKFWD, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_WPS_STOPSEEK, BUTTON_RIGHT|BUTTON_REL, BUTTON_RIGHT|BUTTON_REPEAT},
{ACTION_WPS_SEEKBACK, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_WPS_STOPSEEK, BUTTON_LEFT|BUTTON_REL, BUTTON_LEFT|BUTTON_REPEAT},
- {ACTION_WPS_BROWSE, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK},
- {ACTION_WPS_MENU, BUTTON_BACK|BUTTON_REL, BUTTON_BACK},
- {ACTION_WPS_CONTEXT, BUTTON_MENU|BUTTON_REL, BUTTON_MENU},
- {ACTION_WPS_QUICKSCREEN, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU},
+ {ACTION_WPS_BROWSE, BUTTON_BACK|BUTTON_REL, BUTTON_BACK},
+ {ACTION_WPS_QUICKSCREEN, BUTTON_MENU|BUTTON_REL, BUTTON_MENU},
+ {ACTION_WPS_MENU, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU},
{ACTION_STD_KEYLOCK, BUTTON_POWER|BUTTON_REL, BUTTON_POWER},
{ACTION_WPS_HOTKEY, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY},
- {ACTION_WPS_VIEW_PLAYLIST, BUTTON_SCROLL_FWD, BUTTON_NONE},
- {ACTION_WPS_VIEW_PLAYLIST, BUTTON_SCROLL_BACK, BUTTON_NONE},
+ {ACTION_WPS_CONTEXT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT},
{ACTION_WPS_ABSETA_PREVDIR, BUTTON_UP|BUTTON_REPEAT, BUTTON_UP},
{ACTION_WPS_ABSETB_NEXTDIR, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_DOWN},
- {ACTION_WPS_ABRESET, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT},
+ {ACTION_WPS_ABRESET, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK},
LAST_ITEM_IN_LIST
}; /* button_context_wps */
@@ -87,11 +89,20 @@ static const struct button_mapping button_context_wps_locked[] = {
}; /* button_context_wps_locked */
static const struct button_mapping button_context_tree[] = {
- {ACTION_TREE_STOP, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY},
- {ACTION_TREE_WPS, BUTTON_BACK|BUTTON_REPEAT, BUTTON_BACK},
+ {ACTION_TREE_WPS, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY },
+ {ACTION_TREE_HOTKEY, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY},
+ {ACTION_TREE_STOP, BUTTON_POWER|BUTTON_REPEAT, BUTTON_POWER},
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_LIST)
}; /* button_context_tree */
+
+static const struct button_mapping button_context_tree_scroll_lr[] = {
+ { ACTION_TREE_ROOT_INIT, BUTTON_MENU|BUTTON_REPEAT, BUTTON_MENU },
+ { ACTION_TREE_PGLEFT, BUTTON_MENU|BUTTON_REPEAT, BUTTON_NONE },
+ { ACTION_TREE_PGRIGHT, BUTTON_BACK|BUTTON_REPEAT, BUTTON_NONE },
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_CUSTOM|CONTEXT_TREE),
+}; /* button_context_tree_scroll_lr */
+
static const struct button_mapping button_context_bmark[] = {
{ACTION_BMS_DELETE, BUTTON_PLAY, BUTTON_NONE},
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_TREE),
@@ -120,7 +131,6 @@ static const struct button_mapping button_context_settings[] = {
{ACTION_SETTINGS_DEC, BUTTON_SCROLL_FWD, BUTTON_NONE},
{ACTION_SETTINGS_DECREPEAT, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_SETTINGS_DECBIGSTEP, BUTTON_VOL_DOWN, BUTTON_NONE},
- {ACTION_SETTINGS_RESET, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT},
{ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE},
{ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_STD_PREV, BUTTON_LEFT, BUTTON_NONE},
@@ -128,6 +138,16 @@ static const struct button_mapping button_context_settings[] = {
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
+static const struct button_mapping button_context_settings_rectrigger[] = {
+ {ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE},
+ {ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_SETTINGS_INCBIGSTEP, BUTTON_VOL_UP, BUTTON_NONE},
+ {ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE},
+ {ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_SETTINGS_DECBIGSTEP, BUTTON_VOL_DOWN, BUTTON_NONE},
+ LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
+}; /* button_context_settings_rectrigger */
+
static const struct button_mapping button_context_settings_eq[] = {
{ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE},
{ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
@@ -140,14 +160,26 @@ static const struct button_mapping button_context_settings_eq[] = {
static const struct button_mapping button_context_quickscreen[] = {
{ACTION_QS_TOP, BUTTON_UP, BUTTON_NONE},
+ {ACTION_QS_TOP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_QS_TOP, BUTTON_SCROLL_BACK, BUTTON_NONE},
+ {ACTION_QS_TOP, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_QS_DOWN, BUTTON_DOWN, BUTTON_NONE},
+ {ACTION_QS_DOWN, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_QS_DOWN, BUTTON_SCROLL_FWD, BUTTON_NONE},
+ {ACTION_QS_DOWN, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_QS_LEFT, BUTTON_LEFT, BUTTON_NONE},
+ {ACTION_QS_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_QS_RIGHT, BUTTON_RIGHT, BUTTON_NONE},
+ {ACTION_QS_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_QS_VOLUP, BUTTON_VOL_UP, BUTTON_NONE},
+ {ACTION_QS_VOLUP, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_QS_VOLDOWN, BUTTON_VOL_DOWN, BUTTON_NONE},
- {ACTION_STD_CANCEL, BUTTON_SELECT, BUTTON_NONE},
+ {ACTION_QS_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_STD_CONTEXT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT},
+ {ACTION_STD_CANCEL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT},
{ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE},
{ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_MENU, BUTTON_NONE},
LAST_ITEM_IN_LIST
}; /* button_context_quickscreen */
@@ -172,7 +204,7 @@ static const struct button_mapping button_context_pitchscreen[] = {
static const struct button_mapping button_context_yesnoscreen[] = {
{ACTION_YESNO_ACCEPT, BUTTON_PLAY, BUTTON_NONE},
- {ACTION_YESNO_ACCEPT, BUTTON_SELECT, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_SELECT, BUTTON_NONE},
{ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE},
{ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE},
{ACTION_STD_CANCEL, BUTTON_RIGHT, BUTTON_NONE},
@@ -182,12 +214,43 @@ static const struct button_mapping button_context_yesnoscreen[] = {
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_yesnoscreen */
+static const struct button_mapping button_context_recscreen[] = {
+ {ACTION_REC_PAUSE, BUTTON_SELECT, BUTTON_NONE},
+ {ACTION_REC_PAUSE, BUTTON_PLAY, BUTTON_NONE},
+ {ACTION_REC_NEWFILE, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT},
+ {ACTION_REC_NEWFILE, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY},
+ {ACTION_STD_MENU, BUTTON_MENU, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE},
+ {ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE},
+ {ACTION_STD_PREV, BUTTON_UP, BUTTON_NONE},
+ {ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE},
+ {ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_STD_PREV, BUTTON_SCROLL_BACK, BUTTON_NONE},
+ {ACTION_STD_PREVREPEAT, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_STD_NEXT, BUTTON_SCROLL_FWD, BUTTON_NONE},
+ {ACTION_STD_NEXTREPEAT, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_SETTINGS_INC, BUTTON_VOL_UP, BUTTON_NONE},
+ {ACTION_SETTINGS_INCREPEAT, BUTTON_VOL_UP|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_SETTINGS_DEC, BUTTON_VOL_DOWN, BUTTON_NONE},
+ {ACTION_SETTINGS_DECREPEAT, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_SETTINGS_INC, BUTTON_RIGHT, BUTTON_NONE},
+ {ACTION_SETTINGS_INCREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE},
+ {ACTION_SETTINGS_DECREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
+ LAST_ITEM_IN_LIST
+}; /* button_context_recscreen */
+
static const struct button_mapping button_context_keyboard[] = {
{ACTION_KBD_UP, BUTTON_UP, BUTTON_NONE},
{ACTION_KBD_DOWN, BUTTON_DOWN, BUTTON_NONE},
{ACTION_KBD_LEFT, BUTTON_LEFT, BUTTON_NONE},
{ACTION_KBD_RIGHT, BUTTON_RIGHT, BUTTON_NONE},
{ACTION_KBD_UP, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_KBD_UP, BUTTON_SCROLL_BACK, BUTTON_NONE},
+ {ACTION_KBD_UP, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE},
+ {ACTION_KBD_DOWN, BUTTON_SCROLL_FWD, BUTTON_NONE},
+ {ACTION_KBD_DOWN, BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_KBD_DOWN, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_KBD_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE},
{ACTION_KBD_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE},
@@ -261,24 +324,21 @@ static const struct button_mapping button_context_usb_hid_mode_browser[] = {
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
- {
- case CONTEXT_WPS|CONTEXT_LOCKED:
- return button_context_wps_locked;
- default:
- context &= ~CONTEXT_LOCKED;
- break;
- }
-
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
default:
case CONTEXT_STD:
return button_context_standard;
case CONTEXT_WPS:
+ if (context & CONTEXT_LOCKED)
+ return button_context_wps_locked;
return button_context_wps;
case CONTEXT_TREE:
case CONTEXT_MAINMENU:
+ if (global_settings.hold_lr_for_scroll_in_list)
+ return button_context_tree_scroll_lr;
+ /* else fall through to CUSTOM|CONTEXT_TREE */
+ case CONTEXT_CUSTOM|CONTEXT_TREE:
return button_context_tree;
case CONTEXT_BOOKMARKSCREEN:
return button_context_bmark;
@@ -286,8 +346,9 @@ const struct button_mapping* get_context_mapping(int context)
return button_context_list;
case CONTEXT_SETTINGS:
case CONTEXT_SETTINGS_TIME:
- case CONTEXT_SETTINGS_RECTRIGGER:
return button_context_settings;
+ case CONTEXT_SETTINGS_RECTRIGGER:
+ return button_context_settings_rectrigger;
case CONTEXT_SETTINGS_EQ:
case CONTEXT_SETTINGS_COLOURCHOOSER:
return button_context_settings_eq;
@@ -297,6 +358,8 @@ const struct button_mapping* get_context_mapping(int context)
return button_context_pitchscreen;
case CONTEXT_YESNOSCREEN:
return button_context_yesnoscreen;
+ case CONTEXT_RECSCREEN:
+ return button_context_recscreen;
case CONTEXT_KEYBOARD:
return button_context_keyboard;
case CONTEXT_USB_HID:
diff --git a/apps/keymaps/keymap-fiiom3klinux.c b/apps/keymaps/keymap-fiiom3klinux.c
index 7769e2da04..79a7687501 100644
--- a/apps/keymaps/keymap-fiiom3klinux.c
+++ b/apps/keymaps/keymap-fiiom3klinux.c
@@ -150,7 +150,6 @@ static const struct button_mapping button_context_quickscreen[] = {
/** Settings - General Mappings **/
static const struct button_mapping button_context_settings[] = {
- { ACTION_SETTINGS_RESET, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
{ ACTION_STD_PREV, BUTTON_PREV, BUTTON_NONE },
{ ACTION_STD_PREVREPEAT, BUTTON_PREV|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_NEXT, BUTTON_NONE },
@@ -193,7 +192,7 @@ static const struct button_mapping button_context_yesnoscreen[] = {
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_LIST:
return button_context_list;
diff --git a/apps/keymaps/keymap-fuze.c b/apps/keymaps/keymap-fuze.c
index c5538a6c49..ef0bed1099 100644
--- a/apps/keymaps/keymap-fuze.c
+++ b/apps/keymaps/keymap-fuze.c
@@ -99,7 +99,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_UP },
{ ACTION_STD_NEXT, BUTTON_DOWN|BUTTON_REL, BUTTON_DOWN },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_DOWN },
- { ACTION_SETTINGS_RESET, BUTTON_SELECT, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
}; /* button_context_settings */
diff --git a/apps/keymaps/keymap-fuzeplus.c b/apps/keymaps/keymap-fuzeplus.c
index 0933916b4a..052f11085e 100644
--- a/apps/keymaps/keymap-fuzeplus.c
+++ b/apps/keymaps/keymap-fuzeplus.c
@@ -128,7 +128,8 @@ static const struct button_mapping button_context_keyboard[] = {
}; /* button_context_keyboard */
static const struct button_mapping button_context_quickscreen[] = {
- { ACTION_STD_CANCEL, BUTTON_SELECT, BUTTON_NONE },
+ { ACTION_STD_CONTEXT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT },
+ { ACTION_STD_CANCEL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT },
{ ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE },
{ ACTION_STD_CANCEL, BUTTON_PLAYPAUSE, BUTTON_NONE },
{ ACTION_STD_CANCEL, BUTTON_BOTTOMRIGHT, BUTTON_NONE },
@@ -225,7 +226,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_SETTINGS_DECBIGSTEP, BUTTON_BOTTOMLEFT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_OK, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT },
- { ACTION_SETTINGS_RESET, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE },
@@ -407,7 +407,7 @@ static const struct button_mapping button_context_usb_hid_mode_mouse[] = {
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_STD:
return button_context_standard;
diff --git a/apps/keymaps/keymap-gigabeat-s.c b/apps/keymaps/keymap-gigabeat-s.c
index 4cd76184ff..35cecb7476 100644
--- a/apps/keymaps/keymap-gigabeat-s.c
+++ b/apps/keymaps/keymap-gigabeat-s.c
@@ -167,7 +167,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_BACK, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -181,7 +180,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_BACK, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settingsgraphical */
diff --git a/apps/keymaps/keymap-gigabeat.c b/apps/keymaps/keymap-gigabeat.c
index 31fd0eaf0d..913763af18 100644
--- a/apps/keymaps/keymap-gigabeat.c
+++ b/apps/keymaps/keymap-gigabeat.c
@@ -160,7 +160,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_A, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -174,7 +173,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_A, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settingsgraphical */
diff --git a/apps/keymaps/keymap-h10.c b/apps/keymaps/keymap-h10.c
index 825590e6f4..7df2b61d05 100644
--- a/apps/keymaps/keymap-h10.c
+++ b/apps/keymaps/keymap-h10.c
@@ -124,7 +124,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_FF|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_REW, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_REW|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD),
}; /* button_context_settings */
diff --git a/apps/keymaps/keymap-h1x0_h3x0.c b/apps/keymaps/keymap-h1x0_h3x0.c
index d4f098ce1e..422af7502c 100644
--- a/apps/keymaps/keymap-h1x0_h3x0.c
+++ b/apps/keymaps/keymap-h1x0_h3x0.c
@@ -145,7 +145,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_ON, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -159,7 +158,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_ON, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settingsgraphical */
diff --git a/apps/keymaps/keymap-hdd1630.c b/apps/keymaps/keymap-hdd1630.c
index ca55f7fc26..7afcaeec6d 100644
--- a/apps/keymaps/keymap-hdd1630.c
+++ b/apps/keymaps/keymap-hdd1630.c
@@ -160,7 +160,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_VIEW, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -174,7 +173,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_VIEW, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settingsgraphical */
diff --git a/apps/keymaps/keymap-hdd6330.c b/apps/keymaps/keymap-hdd6330.c
index ed197af41c..18ef2b7c8f 100644
--- a/apps/keymaps/keymap-hdd6330.c
+++ b/apps/keymaps/keymap-hdd6330.c
@@ -142,7 +142,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_VIEW, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -156,7 +155,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_VIEW, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settingsgraphical */
diff --git a/apps/keymaps/keymap-hm60x.c b/apps/keymaps/keymap-hm60x.c
index 2e1f3dd516..fa8783de6d 100644
--- a/apps/keymaps/keymap-hm60x.c
+++ b/apps/keymaps/keymap-hm60x.c
@@ -128,7 +128,6 @@ static const struct button_mapping button_context_quickscreen[] = {
/** Settings - General Mappings **/
static const struct button_mapping button_context_settings[] = {
- { ACTION_SETTINGS_RESET, BUTTON_SELECT, BUTTON_NONE },
{ ACTION_SETTINGS_INC, BUTTON_UP, BUTTON_NONE },
{ ACTION_SETTINGS_INCREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE },
diff --git a/apps/keymaps/keymap-hm801.c b/apps/keymaps/keymap-hm801.c
index 1f0a49c90c..210f521178 100644
--- a/apps/keymaps/keymap-hm801.c
+++ b/apps/keymaps/keymap-hm801.c
@@ -154,7 +154,6 @@ static const struct button_mapping button_context_quickscreen[] = {
/** Settings - General Mappings **/
static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_CANCEL, BUTTON_POWER|BUTTON_REL, BUTTON_POWER},
- { ACTION_SETTINGS_RESET, BUTTON_SELECT, BUTTON_NONE },
{ ACTION_SETTINGS_INC, BUTTON_UP, BUTTON_NONE },
{ ACTION_SETTINGS_INCREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE },
diff --git a/apps/keymaps/keymap-ihifi.c b/apps/keymaps/keymap-ihifi.c
index 147c2f5f62..0c28f812f1 100644
--- a/apps/keymaps/keymap-ihifi.c
+++ b/apps/keymaps/keymap-ihifi.c
@@ -127,7 +127,6 @@ static const struct button_mapping button_context_quickscreen[] = {
/** Settings - General Mappings **/
static const struct button_mapping button_context_settings[] = {
- { ACTION_SETTINGS_RESET, BUTTON_PLAY, BUTTON_NONE },
{ ACTION_SETTINGS_INC, BUTTON_BWD, BUTTON_NONE },
{ ACTION_SETTINGS_INCREPEAT, BUTTON_BWD|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_SETTINGS_DEC, BUTTON_FWD, BUTTON_NONE },
diff --git a/apps/keymaps/keymap-ihifi770.c b/apps/keymaps/keymap-ihifi770.c
index c5671bd650..a5f37cdb7d 100644
--- a/apps/keymaps/keymap-ihifi770.c
+++ b/apps/keymaps/keymap-ihifi770.c
@@ -139,7 +139,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_NEXT, BUTTON_NEXT, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_NEXT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_OK, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
diff --git a/apps/keymaps/keymap-ihifi800.c b/apps/keymaps/keymap-ihifi800.c
index b56bd018eb..4dfceff965 100644
--- a/apps/keymaps/keymap-ihifi800.c
+++ b/apps/keymaps/keymap-ihifi800.c
@@ -143,7 +143,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_NEXTREPEAT, BUTTON_NEXT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_OK, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
{ ACTION_STD_OK, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
diff --git a/apps/keymaps/keymap-ipod.c b/apps/keymaps/keymap-ipod.c
index e3a17fffba..6d06bd0244 100644
--- a/apps/keymaps/keymap-ipod.c
+++ b/apps/keymaps/keymap-ipod.c
@@ -132,7 +132,7 @@ static const struct button_mapping button_context_quickscreen[] = {
{ ACTION_QS_LEFT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_QS_RIGHT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_QS_RIGHT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_STD_CANCEL, BUTTON_SELECT, BUTTON_NONE },
+ { ACTION_STD_CANCEL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT },
{ ACTION_QS_VOLDOWN, BUTTON_SCROLL_BACK, BUTTON_NONE },
{ ACTION_QS_VOLDOWN, BUTTON_SCROLL_BACK|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_QS_VOLUP, BUTTON_SCROLL_FWD, BUTTON_NONE },
diff --git a/apps/keymaps/keymap-m200.c b/apps/keymaps/keymap-m200.c
index f055d648ef..be202d21e6 100644
--- a/apps/keymaps/keymap-m200.c
+++ b/apps/keymaps/keymap-m200.c
@@ -89,7 +89,6 @@ static const struct button_mapping button_context_wps[] = {
static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_SELECT, BUTTON_NONE },
{ ACTION_SETTINGS_INC, BUTTON_UP, BUTTON_NONE },
{ ACTION_SETTINGS_INCREPEAT,BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
diff --git a/apps/keymaps/keymap-ma.c b/apps/keymaps/keymap-ma.c
index 28220d9f50..aca006d071 100644
--- a/apps/keymaps/keymap-ma.c
+++ b/apps/keymaps/keymap-ma.c
@@ -135,7 +135,6 @@ static const struct button_mapping button_context_quickscreen[] = {
/** Settings - General Mappings **/
static const struct button_mapping button_context_settings[] = {
- { ACTION_SETTINGS_RESET, BUTTON_PLAY, BUTTON_NONE },
{ ACTION_SETTINGS_INC, BUTTON_UP, BUTTON_NONE },
{ ACTION_SETTINGS_INCREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_SETTINGS_DEC, BUTTON_DOWN, BUTTON_NONE },
@@ -189,7 +188,7 @@ static const struct button_mapping button_context_yesnoscreen[] = {
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
/* anything that uses button_context_standard */
case CONTEXT_LIST:
diff --git a/apps/keymaps/keymap-meizu-m6sl.c b/apps/keymaps/keymap-meizu-m6sl.c
index 35e44da905..31dbc88432 100644
--- a/apps/keymaps/keymap-meizu-m6sl.c
+++ b/apps/keymaps/keymap-meizu-m6sl.c
@@ -147,7 +147,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -161,7 +160,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settingsgraphical */
diff --git a/apps/keymaps/keymap-mini2440.c b/apps/keymaps/keymap-mini2440.c
index 70f63aef72..3fe0698fa0 100644
--- a/apps/keymaps/keymap-mini2440.c
+++ b/apps/keymaps/keymap-mini2440.c
@@ -162,7 +162,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_A, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -176,7 +175,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_A, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settingsgraphical */
diff --git a/apps/keymaps/keymap-mr100.c b/apps/keymaps/keymap-mr100.c
index d551d434be..0a677efc00 100644
--- a/apps/keymaps/keymap-mr100.c
+++ b/apps/keymaps/keymap-mr100.c
@@ -153,7 +153,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_DISPLAY, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -167,7 +166,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_DOWN, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_DISPLAY, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settingsgraphical */
diff --git a/apps/keymaps/keymap-mr500.c b/apps/keymaps/keymap-mr500.c
index b35c9c1dfc..41e6d21827 100644
--- a/apps/keymaps/keymap-mr500.c
+++ b/apps/keymaps/keymap-mr500.c
@@ -118,7 +118,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_RC_REW|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_RC_FF, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RC_FF|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_RC_MODE, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -132,7 +131,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_STD_PREVREPEAT, BUTTON_RC_PLAY|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_RC_DOWN, BUTTON_NONE },
{ ACTION_STD_NEXTREPEAT, BUTTON_RC_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_RC_MODE, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settingsgraphical */
diff --git a/apps/keymaps/keymap-nwz.c b/apps/keymaps/keymap-nwz.c
index 66bdd1b0db..36675566d3 100644
--- a/apps/keymaps/keymap-nwz.c
+++ b/apps/keymaps/keymap-nwz.c
@@ -112,7 +112,8 @@ static const struct button_mapping button_context_keyboard[] = {
}; /* button_context_keyboard */
static const struct button_mapping button_context_quickscreen[] = {
- { ACTION_STD_CANCEL, BUTTON_PLAY, BUTTON_NONE },
+ { ACTION_STD_CONTEXT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY },
+ { ACTION_STD_CANCEL, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY },
{ ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE },
{ ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE },
{ ACTION_QS_TOP, BUTTON_UP, BUTTON_NONE },
@@ -199,7 +200,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_OK, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
@@ -357,7 +357,7 @@ static const struct button_mapping button_context_usb_hid_mode_mouse[] = {
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_STD:
return button_context_standard;
diff --git a/apps/keymaps/keymap-nwza860.c b/apps/keymaps/keymap-nwza860.c
index f1a3bb6f85..899796552e 100644
--- a/apps/keymaps/keymap-nwza860.c
+++ b/apps/keymaps/keymap-nwza860.c
@@ -74,7 +74,8 @@ static const struct button_mapping button_context_keyboard[] = {
}; /* button_context_keyboard */
static const struct button_mapping button_context_quickscreen[] = {
- { ACTION_STD_CANCEL, BUTTON_PLAY, BUTTON_NONE },
+ { ACTION_STD_CONTEXT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY },
+ { ACTION_STD_CANCEL, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY },
{ ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE },
LAST_ITEM_IN_LIST
@@ -125,8 +126,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_SETTINGS_DEC, BUTTON_VOL_DOWN, BUTTON_NONE },
{ ACTION_SETTINGS_DECREPEAT, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE },
-
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
diff --git a/apps/keymaps/keymap-ondavx777.c b/apps/keymaps/keymap-ondavx777.c
index ed23350666..c4b68f1ef2 100644
--- a/apps/keymaps/keymap-ondavx777.c
+++ b/apps/keymaps/keymap-ondavx777.c
@@ -127,7 +127,7 @@ static const struct button_mapping button_context_usb_hid[] = {
const struct button_mapping* target_get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_STD:
return button_context_standard;
diff --git a/apps/keymaps/keymap-rk27xx-generic.c b/apps/keymaps/keymap-rk27xx-generic.c
index d837c608fc..4c07384810 100644
--- a/apps/keymaps/keymap-rk27xx-generic.c
+++ b/apps/keymaps/keymap-rk27xx-generic.c
@@ -164,7 +164,7 @@ static const struct button_mapping button_context_usb_hid_mode_mouse[] = {
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_STD:
return button_context_standard;
diff --git a/apps/keymaps/keymap-sa9200.c b/apps/keymaps/keymap-sa9200.c
index d29557e222..2dcf301f0f 100644
--- a/apps/keymaps/keymap-sa9200.c
+++ b/apps/keymaps/keymap-sa9200.c
@@ -155,7 +155,6 @@ static const struct button_mapping button_context_listtree_scroll_without_combo[
static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_CANCEL, BUTTON_POWER, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY, BUTTON_NONE },
{ ACTION_SETTINGS_INC, BUTTON_UP, BUTTON_NONE },
{ ACTION_SETTINGS_INCREPEAT,BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
diff --git a/apps/keymaps/keymap-shanlingq1.c b/apps/keymaps/keymap-shanlingq1.c
index 4caaa36fd2..f8fefe5ff3 100644
--- a/apps/keymaps/keymap-shanlingq1.c
+++ b/apps/keymaps/keymap-shanlingq1.c
@@ -69,7 +69,7 @@ static const struct button_mapping button_context_yesno[] = {
const struct button_mapping* target_get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
default:
case CONTEXT_STD:
diff --git a/apps/keymaps/keymap-touchscreen.c b/apps/keymaps/keymap-touchscreen.c
index c70aea2651..07710be78d 100644
--- a/apps/keymaps/keymap-touchscreen.c
+++ b/apps/keymaps/keymap-touchscreen.c
@@ -146,7 +146,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_SETTINGS_INCREPEAT, BUTTON_TOPMIDDLE|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_SETTINGS_DEC, BUTTON_BOTTOMMIDDLE, BUTTON_NONE },
{ ACTION_SETTINGS_DECREPEAT, BUTTON_BOTTOMMIDDLE|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_CENTER, BUTTON_NONE },
{ ACTION_STD_PREV, BUTTON_MIDLEFT, BUTTON_NONE },
{ ACTION_STD_PREVREPEAT, BUTTON_MIDLEFT|BUTTON_REPEAT, BUTTON_NONE },
@@ -164,7 +163,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_SETTINGS_INCREPEAT, BUTTON_MIDRIGHT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_SETTINGS_DEC, BUTTON_MIDLEFT, BUTTON_NONE },
{ ACTION_SETTINGS_DECREPEAT, BUTTON_MIDLEFT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_CENTER, BUTTON_NONE },
{ ACTION_STD_CANCEL, BUTTON_TOPLEFT, BUTTON_NONE },
@@ -385,7 +383,7 @@ const struct button_mapping* get_context_mapping(int context)
return target_get_context_mapping(context & ~CONTEXT_CUSTOM2);
}
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_STD:
return button_context_standard;
diff --git a/apps/keymaps/keymap-xduoox20.c b/apps/keymaps/keymap-xduoox20.c
index c49410cd03..fa4076e27d 100644
--- a/apps/keymaps/keymap-xduoox20.c
+++ b/apps/keymaps/keymap-xduoox20.c
@@ -145,7 +145,6 @@ static const struct button_mapping button_context_quickscreen[] = {
/** Settings - General Mappings **/
static const struct button_mapping button_context_settings[] = {
- { ACTION_SETTINGS_RESET, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
{ ACTION_STD_PREV, BUTTON_NEXT, BUTTON_NONE },
{ ACTION_STD_PREVREPEAT, BUTTON_NEXT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_PREV, BUTTON_NONE },
@@ -185,7 +184,7 @@ static const struct button_mapping button_context_yesnoscreen[] = {
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_LIST:
return button_context_list;
diff --git a/apps/keymaps/keymap-xduoox3.c b/apps/keymaps/keymap-xduoox3.c
index 124ca06c9d..bf588411eb 100644
--- a/apps/keymaps/keymap-xduoox3.c
+++ b/apps/keymaps/keymap-xduoox3.c
@@ -86,10 +86,12 @@ static const struct button_mapping button_context_wps[] = {
{ ACTION_WPS_VOLDOWN, BUTTON_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_WPS_BROWSE, BUTTON_HOME|BUTTON_REL, BUTTON_HOME },
{ ACTION_WPS_CONTEXT, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_PLAY },
- { ACTION_WPS_MENU, BUTTON_OPTION|BUTTON_REL, BUTTON_OPTION },
- { ACTION_WPS_QUICKSCREEN, BUTTON_OPTION|BUTTON_REPEAT, BUTTON_OPTION },
{ ACTION_WPS_HOTKEY, BUTTON_HOME|BUTTON_REPEAT, BUTTON_HOME },
+ { ACTION_WPS_MENU, BUTTON_OPTION|BUTTON_REL, BUTTON_OPTION },
+ { ACTION_WPS_QUICKSCREEN, BUTTON_OPTION|BUTTON_REPEAT, BUTTON_OPTION },
+ { ACTION_WPS_PITCHSCREEN, BUTTON_OPTION|BUTTON_HOME|BUTTON_REPEAT, BUTTON_NONE },
+
{ ACTION_WPS_ABSETB_NEXTDIR, BUTTON_PWRALT|BUTTON_NEXT, BUTTON_POWER },
{ ACTION_WPS_ABSETA_PREVDIR, BUTTON_PWRALT|BUTTON_PREV, BUTTON_POWER },
{ ACTION_WPS_ABRESET, BUTTON_PWRALT|BUTTON_PLAY, BUTTON_POWER },
@@ -172,7 +174,6 @@ static const struct button_mapping button_context_quickscreen[] = {
/** Settings - General Mappings **/
static const struct button_mapping button_context_settings[] = {
- { ACTION_SETTINGS_RESET, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
{ ACTION_STD_PREV, BUTTON_PREV, BUTTON_NONE },
{ ACTION_STD_PREVREPEAT, BUTTON_PREV|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_NEXT, BUTTON_NONE },
diff --git a/apps/keymaps/keymap-xduoox3ii.c b/apps/keymaps/keymap-xduoox3ii.c
index c8be8ce13e..c8724ec1f0 100644
--- a/apps/keymaps/keymap-xduoox3ii.c
+++ b/apps/keymaps/keymap-xduoox3ii.c
@@ -145,7 +145,6 @@ static const struct button_mapping button_context_quickscreen[] = {
/** Settings - General Mappings **/
static const struct button_mapping button_context_settings[] = {
- { ACTION_SETTINGS_RESET, BUTTON_POWER|BUTTON_REL, BUTTON_POWER },
{ ACTION_STD_PREV, BUTTON_NEXT, BUTTON_NONE },
{ ACTION_STD_PREVREPEAT, BUTTON_NEXT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_NEXT, BUTTON_PREV, BUTTON_NONE },
@@ -185,7 +184,7 @@ static const struct button_mapping button_context_yesnoscreen[] = {
/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_LIST:
return button_context_list;
diff --git a/apps/keymaps/keymap-yh8xx_yh9xx.c b/apps/keymaps/keymap-yh8xx_yh9xx.c
index 32623e1a72..9332c9fe98 100644
--- a/apps/keymaps/keymap-yh8xx_yh9xx.c
+++ b/apps/keymaps/keymap-yh8xx_yh9xx.c
@@ -201,7 +201,6 @@ static const struct button_mapping button_context_settings_right_is_inc[] = {
{ ACTION_SETTINGS_INCREPEAT,BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_SETTINGS_DEC, BUTTON_LEFT, BUTTON_NONE },
{ ACTION_SETTINGS_DECREPEAT,BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
- { ACTION_SETTINGS_RESET, BUTTON_REW|BUTTON_REL, BUTTON_REW },
{ ACTION_STD_PREV, BUTTON_UP, BUTTON_NONE },
{ ACTION_STD_PREVREPEAT, BUTTON_UP|BUTTON_REPEAT, BUTTON_NONE },
diff --git a/apps/keymaps/keymap-ypr0.c b/apps/keymaps/keymap-ypr0.c
index 2d6be5b7ec..6e493ddf61 100644
--- a/apps/keymaps/keymap-ypr0.c
+++ b/apps/keymaps/keymap-ypr0.c
@@ -255,7 +255,7 @@ static const struct button_mapping button_context_radio[] = {
const struct button_mapping* get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_STD:
return button_context_standard;
diff --git a/apps/keymaps/keymap-ypr1.c b/apps/keymaps/keymap-ypr1.c
index d47047912b..67f42f07c6 100644
--- a/apps/keymaps/keymap-ypr1.c
+++ b/apps/keymaps/keymap-ypr1.c
@@ -132,7 +132,7 @@ static const struct button_mapping button_context_radio[] = {
const struct button_mapping* target_get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_STD:
return button_context_standard;
diff --git a/apps/keymaps/keymap-zen.c b/apps/keymaps/keymap-zen.c
index ab0f32edb4..04b65b3980 100644
--- a/apps/keymaps/keymap-zen.c
+++ b/apps/keymaps/keymap-zen.c
@@ -145,7 +145,8 @@ static const struct button_mapping button_context_keyboard[] = {
}; /* button_context_keyboard */
static const struct button_mapping button_context_quickscreen[] = {
- { ACTION_STD_CANCEL, BUTTON_SELECT, BUTTON_NONE },
+ { ACTION_STD_CONTEXT, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_SELECT },
+ { ACTION_STD_CANCEL, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT },
{ ACTION_STD_CANCEL, BUTTON_BACK, BUTTON_NONE },
{ ACTION_STD_CANCEL, BUTTON_PLAYPAUSE, BUTTON_NONE },
{ ACTION_QS_TOP, BUTTON_UP, BUTTON_NONE },
@@ -235,7 +236,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_OK, BUTTON_SELECT|BUTTON_REL, BUTTON_SELECT },
- { ACTION_SETTINGS_RESET, BUTTON_SELECT|BUTTON_REPEAT, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
diff --git a/apps/keymaps/keymap-zenxfi2.c b/apps/keymaps/keymap-zenxfi2.c
index c98a4a8405..ba25592246 100644
--- a/apps/keymaps/keymap-zenxfi2.c
+++ b/apps/keymaps/keymap-zenxfi2.c
@@ -137,7 +137,7 @@ static const struct button_mapping button_context_radio[] = {
const struct button_mapping* target_get_context_mapping(int context)
{
- switch (context)
+ switch (context & ~CONTEXT_LOCKED)
{
case CONTEXT_STD:
return button_context_standard;
diff --git a/apps/keymaps/keymap-zenxfi3.c b/apps/keymaps/keymap-zenxfi3.c
index 191b36a1ca..d19a407b78 100644
--- a/apps/keymaps/keymap-zenxfi3.c
+++ b/apps/keymaps/keymap-zenxfi3.c
@@ -163,7 +163,6 @@ static const struct button_mapping button_context_settings[] = {
{ ACTION_STD_NEXTREPEAT, BUTTON_DOWN|BUTTON_REPEAT, BUTTON_NONE },
{ ACTION_STD_OK, BUTTON_PLAY|BUTTON_REL, BUTTON_PLAY },
- { ACTION_SETTINGS_RESET, BUTTON_PLAY|BUTTON_REPEAT, BUTTON_NONE },
LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
}; /* button_context_settings */
diff --git a/apps/lang/arabic.lang b/apps/lang/arabic.lang
index ecf8f8fb1f..c9b295956b 100644
--- a/apps/lang/arabic.lang
+++ b/apps/lang/arabic.lang
@@ -14,6 +14,8 @@
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
+# LANGUAGE_IS_RTL
+#
# Arabic language file, translated by:
# - Mohamed Tarek
# - Raafat Akkad
@@ -764,20 +766,17 @@
</voice>
</phrase>
<phrase>
- id: LANG_RECORDING_FORMAT
- desc: audio format item in recording menu
+ id: LANG_FORMAT
+ desc: audio format
user: core
<source>
- *: none
- recording: "Format"
+ *: "Format"
</source>
<dest>
- *: none
- recording: "الصيغة"
+ *: "الصيغة"
</dest>
<voice>
- *: none
- recording: "Format"
+ *: "Format"
</voice>
</phrase>
<phrase>
@@ -4043,15 +4042,15 @@
user: core
<source>
*: none
- gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
</source>
<dest>
*: none
- gigabeatfx,sansafuzeplus: "حساسية اللمس"
+ fiiom3k,gigabeatfx,sansafuzeplus: "حساسية اللمس"
</dest>
<voice>
*: none
- gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
</voice>
</phrase>
<phrase>
diff --git a/apps/lang/basque.lang b/apps/lang/basque.lang
index 59ab84b04e..05fae692e8 100644
--- a/apps/lang/basque.lang
+++ b/apps/lang/basque.lang
@@ -5263,20 +5263,17 @@
</voice>
</phrase>
<phrase>
- id: LANG_RECORDING_FORMAT
- desc: audio format item in recording menu
+ id: LANG_FORMAT
+ desc: audio format
user: core
<source>
- *: none
- recording: "Format"
+ *: "Format"
</source>
<dest>
- *: none
- recording: "Formatua"
+ *: "Formatua"
</dest>
<voice>
- *: none
- recording: "Formatua"
+ *: "Formatua"
</voice>
</phrase>
<phrase>
@@ -10311,15 +10308,15 @@
user: core
<source>
*: none
- gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
</source>
<dest>
*: none
- gigabeatfx,sansafuzeplus: "Taktilaren Sentikortasuna"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Taktilaren Sentikortasuna"
</dest>
<voice>
*: none
- gigabeatfx,sansafuzeplus: "Taktilaren Sentikortasuna"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Taktilaren Sentikortasuna"
</voice>
</phrase>
<phrase>
diff --git a/apps/lang/bulgarian.lang b/apps/lang/bulgarian.lang
index a66df1ba51..77f2d58361 100644
--- a/apps/lang/bulgarian.lang
+++ b/apps/lang/bulgarian.lang
@@ -252,7 +252,7 @@
*: "PLAY = Yes"
archosplayer: "(PLAY/STOP)"
cowond2*: "MENU, or top-right = Yes"
- creativezen*: "Select = Yes"
+ creativezen*: "SELECT = Yes"
gigabeat*,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh10_5gb,mrobe100,sansac200*,sansaclip*,sansaconnect,sansae200*,sansafuze*: "SELECT = Yes"
iriverh100,iriverh120,iriverh300: "NAVI = Yes"
mrobe500: "PLAY, POWER, or top-right = Yes"
@@ -262,7 +262,7 @@
*: "PLAY = Да"
archosplayer: "(PLAY/STOP)"
cowond2*: "MENU или горе ляво = Да"
- creativezen*: "Select = Да"
+ creativezen*: "SELECT = Да"
gigabeat*,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh10_5gb,mrobe100,sansac200*,sansaclip*,sansaconnect,sansae200*,sansafuze*: "SELECT = Да"
iriverh100,iriverh120,iriverh300: "NAVI = Да"
mrobe500: "PLAY, POWER или горе дясно = Да"
@@ -5268,20 +5268,17 @@
</voice>
</phrase>
<phrase>
- id: LANG_RECORDING_FORMAT
- desc: audio format item in recording menu
+ id: LANG_FORMAT
+ desc: audio format
user: core
<source>
- *: none
- recording: "Format"
+ *: "Format"
</source>
<dest>
- *: none
- recording: "Формат"
+ *: "Формат"
</dest>
<voice>
- *: none
- recording: "Формат"
+ *: "Формат"
</voice>
</phrase>
<phrase>
@@ -10316,15 +10313,15 @@
user: core
<source>
*: none
- gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
</source>
<dest>
*: none
- gigabeatfx,sansafuzeplus: "Чувствителност на тъчпада"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Чувствителност на тъчпада"
</dest>
<voice>
*: none
- gigabeatfx,sansafuzeplus: "Чувствителност на тъчпада"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Чувствителност на тъчпада"
</voice>
</phrase>
<phrase>
diff --git a/apps/lang/catala.lang b/apps/lang/catala.lang
index 9c29513ca5..38fd6d0644 100644
--- a/apps/lang/catala.lang
+++ b/apps/lang/catala.lang
@@ -5257,20 +5257,17 @@
</voice>
</phrase>
<phrase>
- id: LANG_RECORDING_FORMAT
- desc: audio format item in recording menu
+ id: LANG_FORMAT
+ desc: audio format
user: core
<source>
- *: none
- recording: "Format"
+ *: "Format"
</source>
<dest>
- *: none
- recording: "Format"
+ *: "Format"
</dest>
<voice>
- *: none
- recording: "Format"
+ *: "Format"
</voice>
</phrase>
<phrase>
@@ -10305,15 +10302,15 @@
user: core
<source>
*: none
- gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Touchpad Sensitivity"
</source>
<dest>
*: none
- gigabeatfx,sansafuzeplus: "Sensibilitat del touchpad"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Sensibilitat del touchpad"
</dest>
<voice>
*: none
- gigabeatfx,sansafuzeplus: "Sensibilitat del Touchpad"
+ fiiom3k,gigabeatfx,sansafuzeplus: "Sensibilitat del Touchpad"
</voice>
</phrase>
<phrase>
diff --git a/apps/lang/chinese-simp.lang b/apps/lang/chinese-simp.lang
index c1829298be..3d1d0ecaa3 100644
--- a/apps/lang/chinese-simp.lang
+++ b/apps/lang/chinese-simp.lang
@@ -19,6 +19,35 @@
# - Harry Tu
# - Jun Gu
# - Purling Nayuki
+#------
+<phrase>
+ id: LANG_LIST_SEPARATOR
+ desc: line between lines in lists
+ user: core
+ <source>
+ *: "Line Separator"
+ </source>
+ <dest>
+ *: "行分隔线"
+ </dest>
+ <voice>
+ *: "行分隔线"
+ </voice>
+</phrase>
+<phrase>
+ id: LANG_LIST_SEPARATOR_COLOR
+ desc: line between lines in lists
+ user: core
+ <source>
+ *: "Line Separator Colour"
+ </source>
+ <dest>
+ *: "行分隔线颜色"
+ </dest>
+ <voice>
+ *: "Color of Line Separator"
+ </voice>
+</phrase>
<phrase>
id: LANG_SET_BOOL_YES
desc: bool true representation
@@ -27,7 +56,7 @@
*: "Yes"
</source>
<dest>
- *: "√"
+ *: "是"
</dest>
<voice>
*: "是"
@@ -41,7 +70,7 @@
*: "No"
</source>
<dest>
- *: "×"
+ *: "否"
</dest>
<voice>
*: "否"
@@ -104,23 +133,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_CONFIRM_SHUTDOWN
- desc: in shutdown screen
- user: core
- <source>
- *: none
- soft_shutdown: "Press OFF to shut down"
- </source>
- <dest>
- *: none
- soft_shutdown: "按下OFF关机"
- </dest>
- <voice>
- *: none
- soft_shutdown: ""
- </voice>
-</phrase>
-<phrase>
id: LANG_SHUTTINGDOWN
desc: in main menu
user: core
@@ -128,27 +140,10 @@
*: "Shutting down..."
</source>
<dest>
- *: "关机中..."
- </dest>
- <voice>
- *: "关机中"
- </voice>
-</phrase>
-<phrase>
- id: LANG_REMOVE_MMC
- desc: before acknowledging usb in case an MMC is inserted (Ondio)
- user: core
- <source>
- *: none
- archosondio*: "Please remove inserted MMC"
- </source>
- <dest>
- *: none
- archosondio*: "请取出MMC卡"
+ *: "关闭中..."
</dest>
<voice>
- *: none
- archosondio*: "请取出MMC卡"
+ *: "关闭中"
</voice>
</phrase>
<phrase>
@@ -201,7 +196,7 @@
*: "General Settings"
</source>
<dest>
- *: "一般设置"
+ *: "常规设置"
</dest>
<voice>
*: "一般设置"
@@ -262,11 +257,11 @@
</source>
<dest>
*: none
- recording: "录音界面"
+ recording: "录音"
</dest>
<voice>
*: none
- recording: "录音界面"
+ recording: "录音"
</voice>
</phrase>
<phrase>
@@ -284,23 +279,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_SHUTDOWN
- desc: in main menu
- user: core
- <source>
- *: none
- soft_shutdown: "Shut down"
- </source>
- <dest>
- *: none
- soft_shutdown: "关机"
- </dest>
- <voice>
- *: none
- soft_shutdown: "关机"
- </voice>
-</phrase>
-<phrase>
id: LANG_VOLUME
desc: in sound_settings
user: core
@@ -455,159 +433,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_LOUDNESS
- desc: in sound_settings
- user: core
- <source>
- *: none
- masf: "Loudness"
- </source>
- <dest>
- *: none
- masf: "响度"
- </dest>
- <voice>
- *: none
- masf: "响度"
- </voice>
-</phrase>
-<phrase>
- id: LANG_AUTOVOL
- desc: in sound_settings
- user: core
- <source>
- *: none
- masf: "Auto Volume"
- </source>
- <dest>
- *: none
- masf: "自动音量调整"
- </dest>
- <voice>
- *: none
- masf: "自动音量调整"
- </voice>
-</phrase>
-<phrase>
- id: LANG_DECAY
- desc: in sound_settings
- user: core
- <source>
- *: none
- masf: "AV Decay Time"
- </source>
- <dest>
- *: none
- masf: "自动音量调整衰減时间"
- </dest>
- <voice>
- *: none
- masf: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_SUPERBASS
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "Super Bass"
- </source>
- <dest>
- *: none
- masf: "超低音"
- </dest>
- <voice>
- *: none
- masf: "超低音"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MDB_ENABLE
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "MDB Enable"
- </source>
- <dest>
- *: none
- masf: "启用MDB"
- </dest>
- <voice>
- *: none
- masf: "启用MDB"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MDB_STRENGTH
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "MDB Strength"
- </source>
- <dest>
- *: none
- masf: "MDB强度"
- </dest>
- <voice>
- *: none
- masf: "MDB的强度"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MDB_HARMONICS
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "MDB Harmonics"
- </source>
- <dest>
- *: none
- masf: "MDB泛音"
- </dest>
- <voice>
- *: none
- masf: "MDB的泛音"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MDB_CENTER
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "MDB Centre Frequency"
- </source>
- <dest>
- *: none
- masf: "MDB中心频率"
- </dest>
- <voice>
- *: none
- masf: "MDB的中心频率"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MDB_SHAPE
- desc: in sound settings
- user: core
- <source>
- *: none
- masf: "MDB Shape"
- </source>
- <dest>
- *: none
- masf: "MDB形状"
- </dest>
- <voice>
- *: none
- masf: "MDB的形状"
- </voice>
-</phrase>
-<phrase>
id: LANG_CROSSFEED
desc: in sound settings
user: core
@@ -929,7 +754,7 @@
*: "%dHz频段增益"
</dest>
<voice>
- *: "赫兹频段增益"
+ *: "%d赫兹频段增益"
</voice>
</phrase>
<phrase>
@@ -957,7 +782,7 @@
*: "带通滤波器%d"
</dest>
<voice>
- *: "带通滤波器"
+ *: "带通滤波器%d"
</voice>
</phrase>
<phrase>
@@ -1726,15 +1551,12 @@
user: core
<source>
*: "Peak Meter"
- masd: none
</source>
<dest>
*: "峰值电平表"
- masd: none
</dest>
<voice>
*: "峰值电平表"
- masd: none
</voice>
</phrase>
<phrase>
@@ -2142,20 +1964,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_BOOKMARK_SETTINGS_UNIQUE_ONLY
- desc: Save only on bookmark for each playlist in recent bookmarks
- user: core
- <source>
- *: "Unique only"
- </source>
- <dest>
- *: "只保存唯一一份"
- </dest>
- <voice>
- *: "只保存唯一一份"
- </voice>
-</phrase>
-<phrase>
id: LANG_VOICE_MENU
desc: item of voice menu, enable/disable the voice UI
user: core
@@ -2240,23 +2048,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_RECORDING_QUALITY
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording_hwcodec: "Quality"
- </source>
- <dest>
- *: none
- recording_hwcodec: "品质"
- </dest>
- <voice>
- *: none
- recording_hwcodec: "品质"
- </voice>
-</phrase>
-<phrase>
id: LANG_FREQUENCY
desc: in recording and playback settings
user: core
@@ -2328,23 +2119,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_RECORDING_EDITABLE
- desc: Editable recordings setting
- user: core
- <source>
- *: none
- recording_hwcodec: "Independent Frames"
- </source>
- <dest>
- *: none
- recording_hwcodec: "独立框架"
- </dest>
- <voice>
- *: none
- recording_hwcodec: "独立框架"
- </voice>
-</phrase>
-<phrase>
id: LANG_RECORD_TIMESPLIT
desc: Record split menu
user: core
@@ -3182,23 +2956,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_BUTTON_BAR
- desc: in settings menu
- user: core
- <source>
- *: none
- recorder_pad: "Button Bar"
- </source>
- <dest>
- *: none
- recorder_pad: "按键条"
- </dest>
- <voice>
- *: none
- recorder_pad: "按键条"
- </voice>
-</phrase>
-<phrase>
id: LANG_VOLUME_DISPLAY
desc: Volume type title
user: core
@@ -3260,15 +3017,12 @@
user: core
<source>
*: "Peak Release"
- masd: none
</source>
<dest>
*: "峰值释放速度"
- masd: none
</dest>
<voice>
*: "峰值释放速度"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3277,15 +3031,12 @@
user: core
<source>
*: "Peak Hold Time"
- masd: none
</source>
<dest>
*: "峰值保持时长"
- masd: none
</dest>
<voice>
*: "峰值保持时长"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3294,15 +3045,12 @@
user: core
<source>
*: "Clip Hold Time"
- masd: none
</source>
<dest>
*: "削波保持时长"
- masd: none
</dest>
<voice>
*: "削波保持时长"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3311,15 +3059,12 @@
user: core
<source>
*: "Eternal"
- masd: none
</source>
<dest>
*: "外部"
- masd: none
</dest>
<voice>
*: "外部"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3328,15 +3073,12 @@
user: core
<source>
*: "Scale"
- masd: none
</source>
<dest>
*: "标尺类型"
- masd: none
</dest>
<voice>
*: "标尺类型"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3345,15 +3087,12 @@
user: core
<source>
*: "Logarithmic (dB)"
- masd: none
</source>
<dest>
*: "对数(dB)坐标"
- masd: none
</dest>
<voice>
*: "对数坐标"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3362,15 +3101,12 @@
user: core
<source>
*: "Linear (%)"
- masd: none
</source>
<dest>
*: "线性(%)坐标"
- masd: none
</dest>
<voice>
*: "线性坐标"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3379,15 +3115,12 @@
user: core
<source>
*: "Minimum Of Range"
- masd: none
</source>
<dest>
*: "量程最小值"
- masd: none
</dest>
<voice>
*: "量程最小值"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3396,15 +3129,12 @@
user: core
<source>
*: "Maximum Of Range"
- masd: none
</source>
<dest>
*: "量程最大值"
- masd: none
</dest>
<voice>
*: "量程最大值"
- masd: none
</voice>
</phrase>
<phrase>
@@ -3999,7 +3729,7 @@
*: "搜索中...已找到%d个(%s)"
</dest>
<voice>
- *: ""
+ *: "搜索中...已找到%d个(%s)"
</voice>
</phrase>
<phrase>
@@ -4062,23 +3792,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_BATTERY_TOPOFF_CHARGE
- desc: in info display, shows that top off charge is running Only for V1 archosrecorder
- user: core
- <source>
- *: none
- archosrecorder: "Battery: Top-Off Chg"
- </source>
- <dest>
- *: none
- archosrecorder: "电池:恒流快速充电"
- </dest>
- <voice>
- *: none
- archosrecorder: "电池 恒流快速充电"
- </voice>
-</phrase>
-<phrase>
id: LANG_BATTERY_TRICKLE_CHARGE
desc: in info display, shows that trickle charge is running
user: core
@@ -4102,12 +3815,10 @@
<source>
*: "Battery: %d%% %dh %dm"
ipodmini1g,ipodmini2g,iriverh10: "Batt: %d%% %dh %dm"
- iriverifp7xx: "%d%% %dh %dm"
</source>
<dest>
*: "剩余电量:%d%% %dh %dm"
ipodmini1g,ipodmini2g,iriverh10: "电量:%d%% %dh %dm"
- iriverifp7xx: "%d%% %dh %dm"
</dest>
<voice>
*: "剩余电量"
@@ -4147,38 +3858,38 @@
user: core
<source>
*: "Int:"
+ hibylinux: "mSD:"
xduoox3: "mSD1:"
</source>
<dest>
*: "内部:"
+ hibylinux: "mSD:"
xduoox3: "mSD1:"
</dest>
<voice>
*: "内部大小为"
+ hibylinux: "micro S D"
xduoox3: "mSD卡1"
</voice>
</phrase>
<phrase>
id: LANG_DISK_NAME_MMC
- desc: in info menu; name for external disk with multivolume (Ondio; keep short!)
+ desc: in info menu; name for external disk with multivolume (keep short!)
user: core
<source>
*: none
- archosondio*: "MMC:"
multivolume: "HD1"
sansac200*,sansaclipplus,sansae200*,sansafuze*: "mSD:"
xduoox3: "mSD2:"
</source>
<dest>
*: none
- archosondio*: "MMC:"
multivolume: "磁盘1"
sansac200*,sansaclipplus,sansae200*,sansafuze*: "mSD:"
xduoox3: "mSD2:"
</dest>
<voice>
*: none
- archosondio*: "MMC卡"
multivolume: "磁盘1"
sansac200*,sansaclipplus,sansae200*,sansafuze*: "mSD卡"
xduoox3: "mSD卡2"
@@ -4339,7 +4050,8 @@
vibe500: "CANCEL:取消"
</dest>
<voice>
- *: none
+ *: ""
+ gigabeat*,gogearsa9200,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh100,iriverh10_5gb,iriverh120,iriverh300,mrobe100,samsungyh*,sansac200*,sansae200*: ""
</voice>
</phrase>
<phrase>
@@ -4398,6 +4110,7 @@
</dest>
<voice>
*: none
+ iaudiom5,iaudiox5,iriverh100,iriverh120,iriverh300,recording,samsungyh*,sansac200*,sansae200*,vibe500: ""
</voice>
</phrase>
<phrase>
@@ -4516,7 +4229,7 @@
</dest>
<voice>
*: none
- alarm: "离闹钟响起还有"
+ alarm: "离闹钟响起还有%d:%02d"
</voice>
</phrase>
<phrase>
@@ -4579,7 +4292,7 @@
</dest>
<voice>
*: none
- alarm,gigabeats,ipod*,iriverh10,iriverh10_5gb: ""
+ alarm,ipod*: ""
</voice>
</phrase>
<phrase>
@@ -4787,7 +4500,7 @@
*: "(VBR)"
</dest>
<voice>
- *: "VBR"
+ *: "(VBR)"
</voice>
</phrase>
<phrase>
@@ -4857,7 +4570,7 @@
*: "<无信息>"
</dest>
<voice>
- *: "无信息"
+ *: "<无信息>"
</voice>
</phrase>
<phrase>
@@ -5834,48 +5547,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_KILOBYTE
- desc: a unit postfix, also voiced
- user: core
- <source>
- *: "KB"
- </source>
- <dest>
- *: "KB"
- </dest>
- <voice>
- *: "B"
- </voice>
-</phrase>
-<phrase>
- id: LANG_MEGABYTE
- desc: a unit postfix, also voiced
- user: core
- <source>
- *: "MB"
- </source>
- <dest>
- *: "MB"
- </dest>
- <voice>
- *: "MB"
- </voice>
-</phrase>
-<phrase>
- id: LANG_GIGABYTE
- desc: a unit postfix, also voiced
- user: core
- <source>
- *: "GB"
- </source>
- <dest>
- *: "GB"
- </dest>
- <voice>
- *: "GB"
- </voice>
-</phrase>
-<phrase>
id: LANG_POINT
desc: decimal separator for composing numbers
user: core
@@ -6477,7 +6148,7 @@
*: "插入了%d首曲目(%s)"
</dest>
<voice>
- *: "首曲目 插入了"
+ *: "插入了%d首曲目%s"
</voice>
</phrase>
<phrase>
@@ -6491,7 +6162,7 @@
*: "列入了%d首曲目(%s)"
</dest>
<voice>
- *: "首曲目 列入了"
+ *: "列入了%d首曲目%s"
</voice>
</phrase>
<phrase>
@@ -6505,7 +6176,7 @@
*: "保存了%d首曲目(%s)"
</dest>
<voice>
- *: "首曲目 保存了"
+ *: "保存了%d首曲目%s"
</voice>
</phrase>
<phrase>
@@ -6723,91 +6394,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_BUTTONBAR_MENU
- desc: in button bar
- user: core
- <source>
- *: none
- radio_screen_button_bar: "Menu"
- </source>
- <dest>
- *: none
- radio_screen_button_bar: "选单"
- </dest>
- <voice>
- *: none
- radio_screen_button_bar: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_FM_BUTTONBAR_EXIT
- desc: in radio screen
- user: core
- <source>
- *: none
- radio_screen_button_bar: "Exit"
- </source>
- <dest>
- *: none
- radio_screen_button_bar: "退出"
- </dest>
- <voice>
- *: none
- radio_screen_button_bar: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_FM_BUTTONBAR_ACTION
- desc: in radio screen
- user: core
- <source>
- *: none
- radio_screen_button_bar: "Action"
- </source>
- <dest>
- *: none
- radio_screen_button_bar: "动作"
- </dest>
- <voice>
- *: none
- radio_screen_button_bar: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_FM_BUTTONBAR_ADD
- desc: in radio screen
- user: core
- <source>
- *: none
- radio_screen_button_bar: "Add"
- </source>
- <dest>
- *: none
- radio_screen_button_bar: "增加"
- </dest>
- <voice>
- *: none
- radio_screen_button_bar: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_FM_BUTTONBAR_RECORD
- desc: in radio screen
- user: core
- <source>
- *: none
- radio_screen_button_bar: "Record"
- </source>
- <dest>
- *: none
- radio_screen_button_bar: "录音"
- </dest>
- <voice>
- *: none
- radio_screen_button_bar: ""
- </voice>
-</phrase>
-<phrase>
id: LANG_FM_MONO_MODE
desc: in radio screen
user: core
@@ -7012,7 +6598,7 @@
</phrase>
<phrase>
id: LANG_OFF_ABORT
- desc: Used on archosrecorder models
+ desc: Used on many models
user: core
<source>
*: "OFF to abort"
@@ -7031,6 +6617,7 @@
ipod*: "按PLAY/PAUSE键取消"
iriverh10,iriverh10_5gb,sansac200*,sansae200*,vibe500: "按PREV键取消"
iriverh100,iriverh120,iriverh300: "按STOP键取消"
+ sansafuzeplus: "按BACK键取消"
</dest>
<voice>
*: ""
@@ -7178,7 +6765,7 @@
</phrase>
<phrase>
id: LANG_PLUGIN_WRONG_MODEL
- desc: The plugin is not compatible with the archos model trying to run it
+ desc: The plugin is not compatible with the player model trying to run it
user: core
<source>
*: "Incompatible model"
@@ -7187,7 +6774,7 @@
*: "不兼容型号的插件"
</dest>
<voice>
- *: ""
+ *: "不兼容型号的插件"
</voice>
</phrase>
<phrase>
@@ -7201,7 +6788,7 @@
*: "不兼容版本的插件"
</dest>
<voice>
- *: ""
+ *: "不兼容版本的插件"
</voice>
</phrase>
<phrase>
@@ -7215,7 +6802,7 @@
*: "插件返回错误"
</dest>
<voice>
- *: ""
+ *: "插件返回错误"
</voice>
</phrase>
<phrase>
@@ -7475,159 +7062,6 @@
</voice>
</phrase>
<phrase>
- id: LANG_SYSFONT_CHANNEL_STEREO
- desc: in sound_settings
- user: core
- <source>
- *: none
- recording: "Stereo"
- </source>
- <dest>
- *: none
- recording: "Stereo"
- </dest>
- <voice>
- *: none
- recording: "Stereo"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_CHANNEL_MONO
- desc: in sound_settings
- user: core
- <source>
- *: none
- recording: "Mono"
- </source>
- <dest>
- *: none
- recording: "Mono"
- </dest>
- <voice>
- *: none
- recording: "Mono"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_RECORDING_SOURCE
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording: "Source"
- </source>
- <dest>
- *: none
- recording: "来源"
- </dest>
- <voice>
- *: none
- recording: "来源"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_RECORDING_SRC_MIC
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording: "Int. Mic"
- </source>
- <dest>
- *: none
- recording: "内部麦克风"
- </dest>
- <voice>
- *: none
- recording: "内部麦克风"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_RECORDING_SRC_DIGITAL
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording: "Digital"
- </source>
- <dest>
- *: none
- recording: "数码"
- </dest>
- <voice>
- *: none
- recording: "数码"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_RECORD_TRIGGER
- desc: in recording settings_menu
- user: core
- <source>
- *: none
- recording: "Trigger"
- </source>
- <dest>
- *: none
- recording: "触发"
- </dest>
- <voice>
- *: none
- recording: "触发"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_DIRBROWSE_F1
- desc: in dir browser, F1 button bar text
- user: core
- <source>
- *: none
- recorder_pad: "Menu"
- </source>
- <dest>
- *: none
- recorder_pad: "选单"
- </dest>
- <voice>
- *: none
- recorder_pad: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_DIRBROWSE_F2
- desc: in dir browser, F2 button bar text
- user: core
- <source>
- *: none
- recorder_pad: "Option"
- </source>
- <dest>
- *: none
- recorder_pad: "选项"
- </dest>
- <voice>
- *: none
- recorder_pad: ""
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_DIRBROWSE_F3
- desc: in dir browser, F3 button bar text
- user: core
- <source>
- *: none
- recorder_pad: "LCD"
- </source>
- <dest>
- *: none
- recorder_pad: "屏幕"
- </dest>
- <voice>
- *: none
- recorder_pad: ""
- </voice>
-</phrase>
-<phrase>
id: LANG_AFMT_PCM_WAV
desc: audio format description
user: core
@@ -7641,7 +7075,7 @@
</dest>
<voice>
*: none
- recording: "PCM Wave"
+ recording: "PCM Wave(.wav)"
</voice>
</phrase>
<phrase>
@@ -7677,33 +7111,13 @@
desc: in lcd settings
user: core
<source>
- *: none
- lcd_sleep: "Never"
+ *: "Never"
</source>
<dest>
- *: none
- lcd_sleep: "从不"
+ *: "从不"
</dest>
<voice>
- *: none
- lcd_sleep: "从不"
- </voice>
-</phrase>
-<phrase>
- id: LANG_SYSFONT_LINE_IN
- desc: in the recording settings
- user: core
- <source>
- *: none
- recording: "Line In"
- </source>
- <dest>
- *: none
- recording: "线路输入"
- </dest>
- <voice>
- *: none
- recording: "线路输入"
+ *: "从不"
</voice>
</phrase>
<phrase>
@@ -7712,7 +7126,6 @@
user: core
<source>
*: "Building database... %d found (OFF to return)"
- archosplayer: "Building DB %d found"
gigabeat*,iaudiom5,iaudiox5,mrobe100,samsungyh*: "Building database... %d found (LEFT to return)"
gogearsa9200: "Building database... %d found (REW to return)"
ipod*,iriverh10,iriverh10_5gb,sansac200*,sansae200*,sansafuze*,vibe500: "Building database... %d found (PREV to return)"
@@ -7720,7 +7133,6 @@
</source>
<dest>
*: "数据库更新中...已找到%d个(按OFF键返回)"
- archosplayer: "数据库更新中...已找到%d个"
gigabeat*,iaudiom5,iaudiox5,mrobe100,samsungyh*: "数据库更新中...已找到%d个(按LEFT键返回)"
gogearsa9200: "数据库更新中...已找到%d个(按REW键返回)"
ipod*,iriverh10,iriverh10_5gb,sansac200*,sansae200*,sansafuze*,vibe500: "数据库更新中...已找到%d个(按PREV键返回)"
@@ -8075,20 +7487,17 @@
</voice>
</phrase>
<phrase>
- id: LANG_RECORDING_FORMAT
- desc: audio format item in recording menu
+ id: LANG_FORMAT
+ desc: audio format
user: core
<source>
- *: none
- recording: "Format"
+ *: "Format"
</source>
<dest>
- *: none
- recording: "格式"
+ *: "格式"
</dest>
<voice>
- *: none
- recording: "格式"
+ *: "格式"
</voice>
</phrase>
<phrase>
@@ -8142,11 +7551,9 @@
user: core
<source>
*: "Buffer:"
- archosplayer: "Buf:"
</source>
<dest>
*: "缓冲区:"
- archosplayer: "Buf:"
</dest>
<voice>
*: "缓冲区大小为"
@@ -8206,8 +7613,8 @@
user: core
<source>
*: "PLAY = Yes"
- archosplayer: "(PLAY/STOP)"
cowond2*: "MENU, or top-right = Yes"
+ creativezen*: "SELECT = Yes"
gigabeat*,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh10_5gb,mrobe100,sansac200*,sansaclip*,sansaconnect,sansae200*,sansafuze*: "SELECT = Yes"
iriverh100,iriverh120,iriverh300: "NAVI = Yes"
mrobe500: "PLAY, POWER, or top-right = Yes"
@@ -8215,9 +7622,8 @@
</source>
<dest>
*: "PLAY:是"
- archosplayer: "(PLAY/STOP)"
cowond2*: "MENU或TOP-RIGHT:是"
- gigabeat*,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh10_5gb,mrobe100,sansac200*,sansaclip*,sansaconnect,sansae200*,sansafuze*: "SELECT:是"
+ creativezen*,gigabeat*,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh10_5gb,mrobe100,sansac200*,sansaclip*,sansaconnect,sansae200*,sansafuze*: "SELECT:是"
iriverh100,iriverh120,iriverh300: "NAVI=是"
mrobe500: "PLAY,POWER或TOP-RIGHT:是"
vibe500: "OK:是"
@@ -8252,6 +7658,7 @@
</dest>
<voice>
*: none
+ gigabeat*,gogearsa9200,iaudiom5,iaudiox5,ipod*,iriverh10,iriverh100,iriverh10_5gb,iriverh120,iriverh300,mrobe100,samsungyh*,sansac200*,sansae200*: ""
</voice>
</phrase>
<phrase>
@@ -8260,11 +7667,9 @@
user: core
<source>
*: "Any Other = No"
- archosplayer: none
</source>
<dest>
*: "Any Other=否"
- archosplayer: none
</dest>
<voice>
*: ""
@@ -8427,7 +7832,7 @@
*: "Main Menu"
</source>
<dest>
- *: "主选单"
+ *: "主菜单"
</dest>
<voice>
*: "主选单"
@@ -8453,15 +7858,12 @@
user: core
<source>
*: "End of Song List"
- archosplayer: "End of List"
</source>
<dest>
*: "曲目列表结束"
- archosplayer: "列表结束"
</dest>