diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/lang/english.lang | 17 | ||||
-rw-r--r-- | apps/playlist.c | 171 | ||||
-rw-r--r-- | apps/playlist.h | 18 | ||||
-rw-r--r-- | apps/playlist_menu.c | 8 | ||||
-rw-r--r-- | apps/playlist_viewer.c | 848 | ||||
-rw-r--r-- | apps/playlist_viewer.h | 26 | ||||
-rw-r--r-- | apps/wps.c | 29 |
7 files changed, 1075 insertions, 42 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 0a1cfaeb51..ce2b300d8c 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -1660,7 +1660,7 @@ new: | |||
1660 | 1660 | ||
1661 | id: LANG_SAVE_DYNAMIC_PLAYLIST | 1661 | id: LANG_SAVE_DYNAMIC_PLAYLIST |
1662 | desc: in playlist menu. | 1662 | desc: in playlist menu. |
1663 | eng: "Save Dynamic Playlist" | 1663 | eng: "Save Current Playlist" |
1664 | new: | 1664 | new: |
1665 | 1665 | ||
1666 | id: LANG_PLAYLIST_MENU | 1666 | id: LANG_PLAYLIST_MENU |
@@ -1827,3 +1827,18 @@ id: LANG_FM_BUTTONBAR_RECORD | |||
1827 | desc: in main menu | 1827 | desc: in main menu |
1828 | eng: "Record" | 1828 | eng: "Record" |
1829 | new: | 1829 | new: |
1830 | |||
1831 | id: LANG_VIEW_DYNAMIC_PLAYLIST | ||
1832 | desc: in playlist menu. | ||
1833 | eng: "View Current Playlist" | ||
1834 | new: | ||
1835 | |||
1836 | id: LANG_MOVE | ||
1837 | desc: The verb/action Move | ||
1838 | eng: "Move" | ||
1839 | new: | ||
1840 | |||
1841 | id: LANG_MOVE_FAILED | ||
1842 | desc: Error message displayed in playlist viewer | ||
1843 | eng: "Move failed" | ||
1844 | new: | ||
diff --git a/apps/playlist.c b/apps/playlist.c index f834a3d5e7..1ededb2ba9 100644 --- a/apps/playlist.c +++ b/apps/playlist.c | |||
@@ -146,6 +146,7 @@ static int format_track_path(char *dest, char *src, int buf_length, int max, | |||
146 | static void display_playlist_count(int count, char *fmt); | 146 | static void display_playlist_count(int count, char *fmt); |
147 | static void display_buffer_full(void); | 147 | static void display_buffer_full(void); |
148 | static int flush_pending_control(void); | 148 | static int flush_pending_control(void); |
149 | static int rotate_index(int index); | ||
149 | 150 | ||
150 | /* | 151 | /* |
151 | * remove any files and indices associated with the playlist | 152 | * remove any files and indices associated with the playlist |
@@ -679,11 +680,7 @@ static int get_next_index(int steps) | |||
679 | { | 680 | { |
680 | case REPEAT_OFF: | 681 | case REPEAT_OFF: |
681 | { | 682 | { |
682 | /* Rotate indices such that first_index is considered index 0 to | 683 | current_index = rotate_index(current_index); |
683 | simplify next calculation */ | ||
684 | current_index -= playlist.first_index; | ||
685 | if (current_index < 0) | ||
686 | current_index += playlist.amount; | ||
687 | 684 | ||
688 | next_index = current_index+steps; | 685 | next_index = current_index+steps; |
689 | if ((next_index < 0) || (next_index >= playlist.amount)) | 686 | if ((next_index < 0) || (next_index >= playlist.amount)) |
@@ -993,6 +990,18 @@ static int flush_pending_control(void) | |||
993 | } | 990 | } |
994 | 991 | ||
995 | /* | 992 | /* |
993 | * Rotate indices such that first_index is index 0 | ||
994 | */ | ||
995 | static int rotate_index(int index) | ||
996 | { | ||
997 | index -= playlist.first_index; | ||
998 | if (index < 0) | ||
999 | index += playlist.amount; | ||
1000 | |||
1001 | return index; | ||
1002 | } | ||
1003 | |||
1004 | /* | ||
996 | * Initialize playlist entries at startup | 1005 | * Initialize playlist entries at startup |
997 | */ | 1006 | */ |
998 | void playlist_init(void) | 1007 | void playlist_init(void) |
@@ -1604,25 +1613,108 @@ int playlist_insert_playlist(char *filename, int position, bool queue) | |||
1604 | return result; | 1613 | return result; |
1605 | } | 1614 | } |
1606 | 1615 | ||
1607 | /* delete track at specified index */ | 1616 | /* |
1617 | * Delete track at specified index. If index is PLAYLIST_DELETE_CURRENT then | ||
1618 | * we want to delete the current playing track. | ||
1619 | */ | ||
1608 | int playlist_delete(int index) | 1620 | int playlist_delete(int index) |
1609 | { | 1621 | { |
1610 | int result; | 1622 | int result = 0; |
1611 | 1623 | ||
1612 | if (playlist.control_fd < 0) | 1624 | if (playlist.control_fd < 0) |
1613 | { | 1625 | { |
1614 | splash(HZ*2, 0, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); | 1626 | splash(HZ*2, 0, true, str(LANG_PLAYLIST_CONTROL_ACCESS_ERROR)); |
1615 | return -1; | 1627 | return -1; |
1616 | } | 1628 | } |
1617 | 1629 | ||
1618 | result = remove_track_from_playlist(index, true); | 1630 | if (index == PLAYLIST_DELETE_CURRENT) |
1631 | index = playlist.index; | ||
1619 | 1632 | ||
1633 | result = remove_track_from_playlist(index, true); | ||
1634 | |||
1620 | if (result != -1) | 1635 | if (result != -1) |
1621 | mpeg_flush_and_reload_tracks(); | 1636 | mpeg_flush_and_reload_tracks(); |
1622 | 1637 | ||
1623 | return result; | 1638 | return result; |
1624 | } | 1639 | } |
1625 | 1640 | ||
1641 | /* | ||
1642 | * Move track at index to new_index. Tracks between the two are shifted | ||
1643 | * appropriately. Returns 0 on success and -1 on failure. | ||
1644 | */ | ||
1645 | int playlist_move(int index, int new_index) | ||
1646 | { | ||
1647 | int result; | ||
1648 | int seek; | ||
1649 | bool control_file; | ||
1650 | bool queue; | ||
1651 | bool current = false; | ||
1652 | int r = rotate_index(new_index); | ||
1653 | char filename[MAX_PATH]; | ||
1654 | |||
1655 | if (index == new_index) | ||
1656 | return -1; | ||
1657 | |||
1658 | if (index == playlist.index) | ||
1659 | /* Moving the current track */ | ||
1660 | current = true; | ||
1661 | |||
1662 | control_file = playlist.indices[index] & PLAYLIST_INSERT_TYPE_MASK; | ||
1663 | queue = playlist.indices[index] & PLAYLIST_QUEUE_MASK; | ||
1664 | seek = playlist.indices[index] & PLAYLIST_SEEK_MASK; | ||
1665 | |||
1666 | if (get_filename(seek, control_file, filename, sizeof(filename)) < 0) | ||
1667 | return -1; | ||
1668 | |||
1669 | /* Delete track from original position */ | ||
1670 | result = remove_track_from_playlist(index, true); | ||
1671 | |||
1672 | if (result != -1) | ||
1673 | { | ||
1674 | /* We want to insert the track at the position that was specified by | ||
1675 | new_index. This may be different then new_index because of the | ||
1676 | shifting that occurred after the delete */ | ||
1677 | if (r == 0) | ||
1678 | /* First index */ | ||
1679 | new_index = PLAYLIST_PREPEND; | ||
1680 | else if (r == playlist.amount) | ||
1681 | /* Append */ | ||
1682 | new_index = PLAYLIST_INSERT_LAST; | ||
1683 | else | ||
1684 | /* Calculate index of desired position */ | ||
1685 | new_index = (r+playlist.first_index)%playlist.amount; | ||
1686 | |||
1687 | result = add_track_to_playlist(filename, new_index, queue, -1); | ||
1688 | |||
1689 | if (result != -1) | ||
1690 | { | ||
1691 | if (current) | ||
1692 | { | ||
1693 | /* Moved the current track */ | ||
1694 | switch (new_index) | ||
1695 | { | ||
1696 | case PLAYLIST_PREPEND: | ||
1697 | playlist.index = playlist.first_index; | ||
1698 | break; | ||
1699 | case PLAYLIST_INSERT_LAST: | ||
1700 | playlist.index = playlist.first_index - 1; | ||
1701 | if (playlist.index < 0) | ||
1702 | playlist.index += playlist.amount; | ||
1703 | break; | ||
1704 | default: | ||
1705 | playlist.index = new_index; | ||
1706 | break; | ||
1707 | } | ||
1708 | } | ||
1709 | |||
1710 | fsync(playlist.control_fd); | ||
1711 | mpeg_flush_and_reload_tracks(); | ||
1712 | } | ||
1713 | } | ||
1714 | |||
1715 | return result; | ||
1716 | } | ||
1717 | |||
1626 | /* shuffle newly created playlist using random seed. */ | 1718 | /* shuffle newly created playlist using random seed. */ |
1627 | int playlist_shuffle(int random_seed, int start_index) | 1719 | int playlist_shuffle(int random_seed, int start_index) |
1628 | { | 1720 | { |
@@ -1763,21 +1855,13 @@ int playlist_next(int steps) | |||
1763 | index = get_next_index(steps); | 1855 | index = get_next_index(steps); |
1764 | playlist.index = index; | 1856 | playlist.index = index; |
1765 | 1857 | ||
1766 | if (playlist.last_insert_pos >= 0) | 1858 | if (playlist.last_insert_pos >= 0 && steps > 0) |
1767 | { | 1859 | { |
1768 | /* check to see if we've gone beyond the last inserted track */ | 1860 | /* check to see if we've gone beyond the last inserted track */ |
1769 | int rot_index = index; | 1861 | int cur = rotate_index(index); |
1770 | int rot_last_pos = playlist.last_insert_pos; | 1862 | int last_pos = rotate_index(playlist.last_insert_pos); |
1771 | 1863 | ||
1772 | rot_index -= playlist.first_index; | 1864 | if (cur > last_pos) |
1773 | if (rot_index < 0) | ||
1774 | rot_index += playlist.amount; | ||
1775 | |||
1776 | rot_last_pos -= playlist.first_index; | ||
1777 | if (rot_last_pos < 0) | ||
1778 | rot_last_pos += playlist.amount; | ||
1779 | |||
1780 | if (rot_index > rot_last_pos) | ||
1781 | { | 1865 | { |
1782 | /* reset last inserted track */ | 1866 | /* reset last inserted track */ |
1783 | playlist.last_insert_pos = -1; | 1867 | playlist.last_insert_pos = -1; |
@@ -1826,16 +1910,18 @@ int playlist_get_resume_info(short *resume_index) | |||
1826 | index into the playlist */ | 1910 | index into the playlist */ |
1827 | int playlist_get_display_index(void) | 1911 | int playlist_get_display_index(void) |
1828 | { | 1912 | { |
1829 | int index = playlist.index; | ||
1830 | |||
1831 | /* first_index should always be index 0 for display purposes */ | 1913 | /* first_index should always be index 0 for display purposes */ |
1832 | index -= playlist.first_index; | 1914 | int index = rotate_index(playlist.index); |
1833 | if (index < 0) | ||
1834 | index += playlist.amount; | ||
1835 | 1915 | ||
1836 | return (index+1); | 1916 | return (index+1); |
1837 | } | 1917 | } |
1838 | 1918 | ||
1919 | /* returns index of first track in playlist */ | ||
1920 | int playlist_get_first_index(void) | ||
1921 | { | ||
1922 | return playlist.first_index; | ||
1923 | } | ||
1924 | |||
1839 | /* returns number of tracks in playlist (includes queued/inserted tracks) */ | 1925 | /* returns number of tracks in playlist (includes queued/inserted tracks) */ |
1840 | int playlist_amount(void) | 1926 | int playlist_amount(void) |
1841 | { | 1927 | { |
@@ -1860,6 +1946,39 @@ char *playlist_name(char *buf, int buf_size) | |||
1860 | return buf; | 1946 | return buf; |
1861 | } | 1947 | } |
1862 | 1948 | ||
1949 | /* Fills info structure with information about track at specified index. | ||
1950 | Returns 0 on success and -1 on failure */ | ||
1951 | int playlist_get_track_info(int index, struct playlist_track_info* info) | ||
1952 | { | ||
1953 | int seek; | ||
1954 | bool control_file; | ||
1955 | |||
1956 | if (index < 0 || index >= playlist.amount) | ||
1957 | return -1; | ||
1958 | |||
1959 | control_file = playlist.indices[index] & PLAYLIST_INSERT_TYPE_MASK; | ||
1960 | seek = playlist.indices[index] & PLAYLIST_SEEK_MASK; | ||
1961 | |||
1962 | if (get_filename(seek, control_file, info->filename, | ||
1963 | sizeof(info->filename)) < 0) | ||
1964 | return -1; | ||
1965 | |||
1966 | info->attr = 0; | ||
1967 | |||
1968 | if (control_file) | ||
1969 | { | ||
1970 | if (playlist.indices[index] & PLAYLIST_QUEUE_MASK) | ||
1971 | info->attr |= PLAYLIST_ATTR_QUEUED; | ||
1972 | else | ||
1973 | info->attr |= PLAYLIST_ATTR_INSERTED; | ||
1974 | } | ||
1975 | |||
1976 | info->index = index; | ||
1977 | info->display_index = rotate_index(index) + 1; | ||
1978 | |||
1979 | return 0; | ||
1980 | } | ||
1981 | |||
1863 | /* save the current dynamic playlist to specified file */ | 1982 | /* save the current dynamic playlist to specified file */ |
1864 | int playlist_save(char *filename) | 1983 | int playlist_save(char *filename) |
1865 | { | 1984 | { |
diff --git a/apps/playlist.h b/apps/playlist.h index 45ecba505c..82d67bf0bb 100644 --- a/apps/playlist.h +++ b/apps/playlist.h | |||
@@ -47,6 +47,17 @@ struct playlist_info | |||
47 | struct mutex control_mutex; /* mutex for control file access */ | 47 | struct mutex control_mutex; /* mutex for control file access */ |
48 | }; | 48 | }; |
49 | 49 | ||
50 | #define PLAYLIST_ATTR_QUEUED 0x01 | ||
51 | #define PLAYLIST_ATTR_INSERTED 0x02 | ||
52 | |||
53 | struct playlist_track_info | ||
54 | { | ||
55 | char filename[MAX_PATH]; /* path name of mp3 file */ | ||
56 | int attr; /* playlist attributes for track */ | ||
57 | int index; /* index of track in playlist */ | ||
58 | int display_index; /* index of track for display */ | ||
59 | }; | ||
60 | |||
50 | void playlist_init(void); | 61 | void playlist_init(void); |
51 | int playlist_create(char *dir, char *file); | 62 | int playlist_create(char *dir, char *file); |
52 | int playlist_resume(void); | 63 | int playlist_resume(void); |
@@ -56,6 +67,7 @@ int playlist_insert_directory(char *dirname, int position, bool queue, | |||
56 | bool recurse); | 67 | bool recurse); |
57 | int playlist_insert_playlist(char *filename, int position, bool queue); | 68 | int playlist_insert_playlist(char *filename, int position, bool queue); |
58 | int playlist_delete(int index); | 69 | int playlist_delete(int index); |
70 | int playlist_move(int index, int new_index); | ||
59 | int playlist_shuffle(int random_seed, int start_index); | 71 | int playlist_shuffle(int random_seed, int start_index); |
60 | int playlist_randomise(unsigned int seed, bool start_current); | 72 | int playlist_randomise(unsigned int seed, bool start_current); |
61 | int playlist_sort(bool start_current); | 73 | int playlist_sort(bool start_current); |
@@ -65,8 +77,10 @@ char *playlist_peek(int steps); | |||
65 | int playlist_next(int steps); | 77 | int playlist_next(int steps); |
66 | int playlist_get_resume_info(short *resume_index); | 78 | int playlist_get_resume_info(short *resume_index); |
67 | int playlist_get_display_index(void); | 79 | int playlist_get_display_index(void); |
80 | int playlist_get_first_index(void); | ||
68 | int playlist_amount(void); | 81 | int playlist_amount(void); |
69 | char *playlist_name(char *buf, int buf_size); | 82 | char *playlist_name(char *buf, int buf_size); |
83 | int playlist_get_track_info(int index, struct playlist_track_info* info); | ||
70 | int playlist_save(char *filename); | 84 | int playlist_save(char *filename); |
71 | 85 | ||
72 | enum { | 86 | enum { |
@@ -76,4 +90,8 @@ enum { | |||
76 | PLAYLIST_INSERT_FIRST = -4 | 90 | PLAYLIST_INSERT_FIRST = -4 |
77 | }; | 91 | }; |
78 | 92 | ||
93 | enum { | ||
94 | PLAYLIST_DELETE_CURRENT = -1 | ||
95 | }; | ||
96 | |||
79 | #endif /* __PLAYLIST_H__ */ | 97 | #endif /* __PLAYLIST_H__ */ |
diff --git a/apps/playlist_menu.c b/apps/playlist_menu.c index 4223e3cf72..f4e4867a92 100644 --- a/apps/playlist_menu.c +++ b/apps/playlist_menu.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "playlist.h" | 25 | #include "playlist.h" |
26 | #include "tree.h" | 26 | #include "tree.h" |
27 | #include "settings.h" | 27 | #include "settings.h" |
28 | #include "playlist_viewer.h" | ||
28 | 29 | ||
29 | #include "lang.h" | 30 | #include "lang.h" |
30 | 31 | ||
@@ -64,9 +65,10 @@ bool playlist_menu(void) | |||
64 | bool result; | 65 | bool result; |
65 | 66 | ||
66 | struct menu_items items[] = { | 67 | struct menu_items items[] = { |
67 | { str(LANG_CREATE_PLAYLIST), create_playlist }, | 68 | { str(LANG_CREATE_PLAYLIST), create_playlist }, |
68 | { str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist }, | 69 | { str(LANG_VIEW_DYNAMIC_PLAYLIST), playlist_viewer }, |
69 | { str(LANG_RECURSE_DIRECTORY), recurse_directory }, | 70 | { str(LANG_SAVE_DYNAMIC_PLAYLIST), save_playlist }, |
71 | { str(LANG_RECURSE_DIRECTORY), recurse_directory }, | ||
70 | }; | 72 | }; |
71 | 73 | ||
72 | m = menu_init( items, sizeof items / sizeof(struct menu_items) ); | 74 | m = menu_init( items, sizeof items / sizeof(struct menu_items) ); |
diff --git a/apps/playlist_viewer.c b/apps/playlist_viewer.c new file mode 100644 index 0000000000..555c9a7128 --- /dev/null +++ b/apps/playlist_viewer.c | |||
@@ -0,0 +1,848 @@ | |||
1 | /*************************************************************************** | ||
2 | * | ||
3 | * __________ __ ___. | ||
4 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
5 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
6 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
7 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
8 | * \/ \/ \/ \/ \/ | ||
9 | * $Id$ | ||
10 | * | ||
11 | * Copyright (C) 2003 Hardeep Sidhu | ||
12 | * | ||
13 | * All files in this archive are subject to the GNU General Public License. | ||
14 | * See the file COPYING in the source tree root for full license agreement. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #include <string.h> | ||
22 | #include <sprintf.h> | ||
23 | #include "playlist.h" | ||
24 | #include "mpeg.h" | ||
25 | #include "screens.h" | ||
26 | #include "status.h" | ||
27 | #include "settings.h" | ||
28 | #include "icons.h" | ||
29 | #include "menu.h" | ||
30 | #include "plugin.h" | ||
31 | |||
32 | #ifdef HAVE_LCD_BITMAP | ||
33 | #include "widgets.h" | ||
34 | #endif | ||
35 | |||
36 | #include "lang.h" | ||
37 | |||
38 | /* Defines for LCD display purposes. Taken from tree.c */ | ||
39 | #ifdef HAVE_LCD_BITMAP | ||
40 | #define CURSOR_X (global_settings.scrollbar && \ | ||
41 | viewer.num_tracks>viewer.num_display_lines?1:0) | ||
42 | #define CURSOR_Y 0 | ||
43 | #define CURSOR_WIDTH (global_settings.invert_cursor ? 0 : 4) | ||
44 | |||
45 | #define ICON_WIDTH ((viewer.char_width > 6) ? viewer.char_width : 6) | ||
46 | |||
47 | #define MARGIN_X ((global_settings.scrollbar && \ | ||
48 | viewer.num_tracks > viewer.num_display_lines ? \ | ||
49 | SCROLLBAR_WIDTH : 0) + CURSOR_WIDTH + ICON_WIDTH) | ||
50 | #define MARGIN_Y (global_settings.statusbar ? STATUSBAR_HEIGHT : 0) | ||
51 | |||
52 | #define LINE_X 0 | ||
53 | #define LINE_Y (global_settings.statusbar ? 1 : 0) | ||
54 | |||
55 | #define SCROLLBAR_X 0 | ||
56 | #define SCROLLBAR_Y lcd_getymargin() | ||
57 | #define SCROLLBAR_WIDTH 6 | ||
58 | #else | ||
59 | #define MARGIN_X 0 | ||
60 | #define MARGIN_Y 0 | ||
61 | #define LINE_X 2 | ||
62 | #define LINE_Y 0 | ||
63 | #define CURSOR_X 0 | ||
64 | #define CURSOR_Y 0 | ||
65 | #endif | ||
66 | |||
67 | /* Maximum number of tracks we can have loaded at one time */ | ||
68 | #define MAX_PLAYLIST_ENTRIES 200 | ||
69 | |||
70 | /* Index of track on display line _pos */ | ||
71 | #define INDEX(_pos) (viewer.first_display_index - viewer.first_index + (_pos)) | ||
72 | |||
73 | /* Global playlist viewer settings */ | ||
74 | struct playlist_viewer_info { | ||
75 | char *name_buffer; /* Buffer used to store track names */ | ||
76 | int buffer_size; /* Size of name buffer */ | ||
77 | |||
78 | int num_display_lines; /* Number of lines on lcd */ | ||
79 | int line_height; /* Height (in pixels) of display line */ | ||
80 | int char_width; /* Width (in pixels) of a character */ | ||
81 | |||
82 | int num_tracks; /* Number of tracks in playlist */ | ||
83 | short current_playing_track;/* Index of current playing track */ | ||
84 | |||
85 | int num_loaded; /* Number of track entries loaded in viewer */ | ||
86 | int first_index; /* Index of first loaded track */ | ||
87 | int last_index; /* Index of last loaded track */ | ||
88 | int first_display_index; /* Index of first track on display */ | ||
89 | int last_display_index; /* Index of last track on display */ | ||
90 | int cursor_pos; /* Line number of cursor */ | ||
91 | |||
92 | int move_track; /* Playlist index of track to move or -1 */ | ||
93 | }; | ||
94 | |||
95 | /* Information about a specific track */ | ||
96 | struct playlist_entry { | ||
97 | char *name; /* Formatted track name */ | ||
98 | int index; /* Playlist index */ | ||
99 | int display_index; /* Display index */ | ||
100 | bool queued; /* Is track queued? */ | ||
101 | }; | ||
102 | |||
103 | static struct playlist_viewer_info viewer; | ||
104 | static struct playlist_entry tracks[MAX_PLAYLIST_ENTRIES]; | ||
105 | |||
106 | #ifdef HAVE_LCD_BITMAP | ||
107 | extern unsigned char bitmap_icons_6x8[LastIcon][6]; | ||
108 | #endif | ||
109 | |||
110 | static bool initialize(void); | ||
111 | static void load_playlist_entries(int start_index); | ||
112 | static void load_playlist_entries_r(int end_index); | ||
113 | static int load_entry(int index, int pos, char* p, int size); | ||
114 | static void format_name(char* dest, char* src); | ||
115 | static void display_playlist(void); | ||
116 | static void update_display_line(int line, bool scroll); | ||
117 | static void scroll_display(int lines); | ||
118 | static void update_first_index(void); | ||
119 | static bool update_playlist(bool force); | ||
120 | static int onplay_menu(int index); | ||
121 | |||
122 | /* Initialize the playlist viewer */ | ||
123 | static bool initialize(void) | ||
124 | { | ||
125 | if (!(mpeg_status() & MPEG_STATUS_PLAY)) | ||
126 | /* Nothing is playing, exit */ | ||
127 | return false; | ||
128 | |||
129 | viewer.name_buffer = plugin_get_buffer(&viewer.buffer_size); | ||
130 | if (!viewer.name_buffer) | ||
131 | return false; | ||
132 | |||
133 | #ifdef HAVE_LCD_BITMAP | ||
134 | { | ||
135 | char icon_chars[] = "MQ"; /* characters used as icons */ | ||
136 | unsigned int i; | ||
137 | |||
138 | viewer.char_width = 0; | ||
139 | viewer.line_height = 0; | ||
140 | |||
141 | /* Use icon characters to calculate largest possible width/height so | ||
142 | that we set proper margins */ | ||
143 | for (i=0; i<sizeof(icon_chars); i++) | ||
144 | { | ||
145 | char str[2]; | ||
146 | int w, h; | ||
147 | |||
148 | snprintf(str, sizeof(str), "%c", icon_chars[i]); | ||
149 | lcd_getstringsize(str, &w, &h); | ||
150 | |||
151 | if (w > viewer.char_width) | ||
152 | viewer.char_width = w; | ||
153 | |||
154 | if (h > viewer.line_height) | ||
155 | { | ||
156 | viewer.line_height = h; | ||
157 | viewer.num_display_lines = (LCD_HEIGHT - MARGIN_Y)/h; | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | #else | ||
162 | viewer.num_display_lines = 2; | ||
163 | viewer.char_width = 1; | ||
164 | viewer.line_height = 1; | ||
165 | #endif | ||
166 | |||
167 | viewer.cursor_pos = 0; | ||
168 | viewer.move_track = -1; | ||
169 | |||
170 | /* Start displaying at current playing track */ | ||
171 | viewer.first_display_index = playlist_get_display_index() - 1; | ||
172 | update_first_index(); | ||
173 | |||
174 | if (!update_playlist(true)) | ||
175 | return false; | ||
176 | |||
177 | return true; | ||
178 | } | ||
179 | |||
180 | /* Load tracks starting at start_index */ | ||
181 | static void load_playlist_entries(int start_index) | ||
182 | { | ||
183 | int num_entries = viewer.num_tracks - start_index; | ||
184 | char* p = viewer.name_buffer; | ||
185 | int remaining = viewer.buffer_size; | ||
186 | int i; | ||
187 | |||
188 | viewer.first_index = start_index; | ||
189 | |||
190 | if (num_entries > MAX_PLAYLIST_ENTRIES) | ||
191 | num_entries = MAX_PLAYLIST_ENTRIES; | ||
192 | |||
193 | for(i=0; i<num_entries; i++, start_index++) | ||
194 | { | ||
195 | int len = load_entry(start_index, i, p, remaining); | ||
196 | if (len < 0) | ||
197 | { | ||
198 | /* Out of name buffer space */ | ||
199 | num_entries = i; | ||
200 | break; | ||
201 | } | ||
202 | |||
203 | p += len; | ||
204 | remaining -= len; | ||
205 | } | ||
206 | |||
207 | viewer.num_loaded = num_entries; | ||
208 | viewer.last_index = viewer.first_index + (viewer.num_loaded - 1); | ||
209 | } | ||
210 | |||
211 | /* Load tracks in reverse, ending at end_index */ | ||
212 | static void load_playlist_entries_r(int end_index) | ||
213 | { | ||
214 | int num_entries = end_index; | ||
215 | char* p = viewer.name_buffer; | ||
216 | int remaining = viewer.buffer_size; | ||
217 | int i; | ||
218 | |||
219 | viewer.last_index = end_index; | ||
220 | |||
221 | if (num_entries > MAX_PLAYLIST_ENTRIES) | ||
222 | num_entries = MAX_PLAYLIST_ENTRIES; | ||
223 | |||
224 | for(i=num_entries; i>=0; i--, end_index--) | ||
225 | { | ||
226 | int len = load_entry(end_index, i, p, remaining); | ||
227 | if (len < 0) | ||
228 | { | ||
229 | int j; | ||
230 | |||
231 | /* Out of name buffer space */ | ||
232 | num_entries -= i; | ||
233 | |||
234 | /* Shift loaded tracks up such that first track is index 0 */ | ||
235 | for (j=0; j<num_entries; j++, i++) | ||
236 | { | ||
237 | tracks[j].name = tracks[i].name; | ||
238 | tracks[j].index = tracks[i].index; | ||
239 | tracks[j].display_index = tracks[i].display_index; | ||
240 | tracks[j].queued = tracks[i].queued; | ||
241 | } | ||
242 | |||
243 | break; | ||
244 | } | ||
245 | |||
246 | p += len; | ||
247 | remaining -= len; | ||
248 | } | ||
249 | |||
250 | viewer.first_index = viewer.last_index - num_entries; | ||
251 | |||
252 | num_entries++; | ||
253 | if (!viewer.first_index && | ||
254 | num_entries < viewer.num_tracks && | ||
255 | num_entries < MAX_PLAYLIST_ENTRIES) | ||
256 | { | ||
257 | /* Lets see if we can load more data at the end of the list */ | ||
258 | int max = viewer.num_tracks; | ||
259 | if (max > MAX_PLAYLIST_ENTRIES) | ||
260 | max = MAX_PLAYLIST_ENTRIES; | ||
261 | |||
262 | for (i = num_entries; i<max; i++) | ||
263 | { | ||
264 | int len = load_entry(num_entries, num_entries, p, remaining); | ||
265 | if (len < 0) | ||
266 | /* Out of name buffer space */ | ||
267 | break; | ||
268 | |||
269 | p += len; | ||
270 | remaining -= len; | ||
271 | |||
272 | num_entries++; | ||
273 | viewer.last_index++; | ||
274 | } | ||
275 | } | ||
276 | |||
277 | viewer.num_loaded = num_entries; | ||
278 | } | ||
279 | |||
280 | /* Load track at playlist index. pos is the position in the tracks array and | ||
281 | p is a pointer to the name buffer (max size), Returns -1 if buffer is | ||
282 | full. */ | ||
283 | static int load_entry(int index, int pos, char* p, int size) | ||
284 | { | ||
285 | struct playlist_track_info info; | ||
286 | int len; | ||
287 | int result = 0; | ||
288 | char name[MAX_PATH]; | ||
289 | |||
290 | /* Playlist viewer orders songs based on display index. We need to | ||
291 | convert to real playlist index to access track */ | ||
292 | index = (index + playlist_get_first_index()) % viewer.num_tracks; | ||
293 | if (playlist_get_track_info(index, &info) < 0) | ||
294 | return -1; | ||
295 | |||
296 | format_name(name, info.filename); | ||
297 | |||
298 | len = strlen(name) + 1; | ||
299 | |||
300 | if (len <= size) | ||
301 | { | ||
302 | strcpy(p, name); | ||
303 | |||
304 | tracks[pos].name = p; | ||
305 | tracks[pos].index = info.index; | ||
306 | tracks[pos].display_index = info.display_index; | ||
307 | tracks[pos].queued = info.attr & PLAYLIST_ATTR_QUEUED; | ||
308 | |||
309 | result = len; | ||
310 | } | ||
311 | else | ||
312 | result = -1; | ||
313 | |||
314 | return result; | ||
315 | } | ||
316 | |||
317 | /* Format trackname for display purposes */ | ||
318 | static void format_name(char* dest, char* src) | ||
319 | { | ||
320 | char* p = strrchr(src, '/'); | ||
321 | int len; | ||
322 | |||
323 | /* Only display the mp3 filename */ | ||
324 | strcpy(dest, p+1); | ||
325 | len = strlen(dest); | ||
326 | |||
327 | /* Remove the extension */ | ||
328 | if (!strcasecmp(&dest[len-4], ".mp3") || | ||
329 | !strcasecmp(&dest[len-4], ".mp2") || | ||
330 | !strcasecmp(&dest[len-4], ".mpa")) | ||
331 | dest[len-4] = '\0'; | ||
332 | } | ||
333 | |||
334 | /* Display tracks on screen */ | ||
335 | static void display_playlist(void) | ||
336 | { | ||
337 | int i; | ||
338 | int num_display_tracks = | ||
339 | viewer.last_display_index - viewer.first_display_index; | ||
340 | |||
341 | lcd_clear_display(); | ||
342 | |||
343 | #ifdef HAVE_LCD_BITMAP | ||
344 | lcd_setmargins(MARGIN_X, MARGIN_Y); | ||
345 | lcd_setfont(FONT_UI); | ||
346 | #endif | ||
347 | |||
348 | for (i=0; i<=num_display_tracks; i++) | ||
349 | { | ||
350 | /* Icons */ | ||
351 | if (tracks[INDEX(i)].index == viewer.current_playing_track) | ||
352 | { | ||
353 | /* Current playing track */ | ||
354 | #ifdef HAVE_LCD_BITMAP | ||
355 | int offset=0; | ||
356 | if ( viewer.line_height > 8 ) | ||
357 | offset = (viewer.line_height - 8) / 2; | ||
358 | lcd_bitmap(bitmap_icons_6x8[File], | ||
359 | CURSOR_X * 6 + CURSOR_WIDTH, | ||
360 | MARGIN_Y+(i*viewer.line_height) + offset, | ||
361 | 6, 8, true); | ||
362 | #else | ||
363 | lcd_putc(LINE_X-1, i, File); | ||
364 | #endif | ||
365 | } | ||
366 | else if (tracks[INDEX(i)].index == viewer.move_track) | ||
367 | { | ||
368 | /* Track we are moving */ | ||
369 | #ifdef HAVE_LCD_BITMAP | ||
370 | lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH, | ||
371 | MARGIN_Y+(i*viewer.line_height), "M"); | ||
372 | #else | ||
373 | lcd_putc(LINE_X-1, i, 'M'); | ||
374 | #endif | ||
375 | } | ||
376 | else if (tracks[INDEX(i)].queued) | ||
377 | { | ||
378 | /* Queued track */ | ||
379 | #ifdef HAVE_LCD_BITMAP | ||
380 | lcd_putsxy(CURSOR_X * 6 + CURSOR_WIDTH, | ||
381 | MARGIN_Y+(i*viewer.line_height), "Q"); | ||
382 | #else | ||
383 | lcd_putc(LINE_X-1, i, 'Q'); | ||
384 | #endif | ||
385 | } | ||
386 | |||
387 | update_display_line(i, false); | ||
388 | } | ||
389 | |||
390 | #ifdef HAVE_LCD_BITMAP | ||
391 | if (global_settings.scrollbar && | ||
392 | (viewer.num_tracks > viewer.num_display_lines)) | ||
393 | scrollbar(SCROLLBAR_X, SCROLLBAR_Y, SCROLLBAR_WIDTH - 1, | ||
394 | LCD_HEIGHT - SCROLLBAR_Y, viewer.num_tracks-1, | ||
395 | viewer.first_display_index, viewer.last_display_index, | ||
396 | VERTICAL); | ||
397 | #endif | ||
398 | |||
399 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true); | ||
400 | status_draw(true); | ||
401 | } | ||
402 | |||
403 | /* Scroll cursor or display by num lines */ | ||
404 | static void scroll_display(int lines) | ||
405 | { | ||
406 | int new_index = viewer.first_display_index + viewer.cursor_pos + lines; | ||
407 | bool pagescroll = false; | ||
408 | bool wrap = false; | ||
409 | |||
410 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, false); | ||
411 | |||
412 | if (lines > 1 || lines < -1) | ||
413 | pagescroll = true; | ||
414 | |||
415 | if (new_index < 0) | ||
416 | { | ||
417 | /* Wrap around if not pageup */ | ||
418 | if (pagescroll) | ||
419 | new_index = 0; | ||
420 | else | ||
421 | { | ||
422 | new_index += viewer.num_tracks; | ||
423 | viewer.cursor_pos = viewer.num_display_lines-1; | ||
424 | wrap = true; | ||
425 | } | ||
426 | } | ||
427 | else if (new_index >= viewer.num_tracks) | ||
428 | { | ||
429 | /* Wrap around if not pagedown */ | ||
430 | if (pagescroll) | ||
431 | new_index = viewer.num_tracks - 1; | ||
432 | else | ||
433 | { | ||
434 | new_index -= viewer.num_tracks; | ||
435 | viewer.cursor_pos = 0; | ||
436 | wrap = true; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | if (new_index >= viewer.first_display_index && | ||
441 | new_index <= viewer.last_display_index) | ||
442 | { | ||
443 | /* Just update the cursor */ | ||
444 | viewer.cursor_pos = new_index - viewer.first_display_index; | ||
445 | } | ||
446 | else | ||
447 | { | ||
448 | /* New track is outside of display */ | ||
449 | if (wrap) | ||
450 | viewer.first_display_index = new_index; | ||
451 | else | ||
452 | viewer.first_display_index = viewer.first_display_index + lines; | ||
453 | |||
454 | if (viewer.first_display_index < 0) | ||
455 | viewer.first_display_index = 0; | ||
456 | |||
457 | viewer.last_display_index = | ||
458 | viewer.first_display_index + (viewer.num_display_lines - 1); | ||
459 | if (viewer.last_display_index >= viewer.num_tracks) | ||
460 | { | ||
461 | /* display as many tracks as possible on screen */ | ||
462 | if (viewer.first_display_index > 0) | ||
463 | { | ||
464 | viewer.first_display_index -= | ||
465 | (viewer.last_display_index - viewer.num_tracks + 1); | ||
466 | if (viewer.first_display_index < 0) | ||
467 | viewer.first_display_index = 0; | ||
468 | } | ||
469 | |||
470 | viewer.last_display_index = viewer.num_tracks - 1; | ||
471 | } | ||
472 | |||
473 | if (viewer.cursor_pos > | ||
474 | (viewer.last_display_index - viewer.first_display_index)) | ||
475 | viewer.cursor_pos = | ||
476 | viewer.last_display_index - viewer.first_display_index; | ||
477 | |||
478 | /* Load more data if needed */ | ||
479 | if (viewer.first_display_index < viewer.first_index) | ||
480 | load_playlist_entries_r(viewer.last_display_index); | ||
481 | else if (viewer.last_display_index > viewer.last_index) | ||
482 | load_playlist_entries(viewer.first_display_index); | ||
483 | |||
484 | display_playlist(); | ||
485 | } | ||
486 | |||
487 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true); | ||
488 | } | ||
489 | |||
490 | /* Update lcd line. Scroll line if requested */ | ||
491 | static void update_display_line(int line, bool scroll) | ||
492 | { | ||
493 | char str[MAX_PATH + 16]; | ||
494 | |||
495 | snprintf(str, sizeof(str), "%d. %s", | ||
496 | tracks[INDEX(line)].display_index, | ||
497 | tracks[INDEX(line)].name); | ||
498 | |||
499 | if (scroll) | ||
500 | { | ||
501 | #ifdef HAVE_LCD_BITMAP | ||
502 | if (global_settings.invert_cursor) | ||
503 | lcd_puts_scroll_style(LINE_X, line, str, STYLE_INVERT); | ||
504 | else | ||
505 | #endif | ||
506 | lcd_puts_scroll(LINE_X, line, str); | ||
507 | } | ||
508 | else | ||
509 | lcd_puts(LINE_X, line, str); | ||
510 | } | ||
511 | |||
512 | /* Update first index, if necessary, to put as much as possible on the | ||
513 | screen */ | ||
514 | static void update_first_index(void) | ||
515 | { | ||
516 | /* viewer.num_tracks may be invalid at this point */ | ||
517 | int num_tracks = playlist_amount(); | ||
518 | |||
519 | if ((num_tracks - viewer.first_display_index) < viewer.num_display_lines) | ||
520 | { | ||
521 | /* Try to display as much as possible */ | ||
522 | int old_index = viewer.first_display_index; | ||
523 | |||
524 | viewer.first_display_index = num_tracks - viewer.num_display_lines; | ||
525 | if (viewer.first_display_index < 0) | ||
526 | viewer.first_display_index = 0; | ||
527 | |||
528 | /* Cursor should still point at current track */ | ||
529 | viewer.cursor_pos += old_index - viewer.first_display_index; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | /* Update playlist in case something has changed or forced */ | ||
534 | static bool update_playlist(bool force) | ||
535 | { | ||
536 | playlist_get_resume_info(&viewer.current_playing_track); | ||
537 | |||
538 | if (force || playlist_amount() != viewer.num_tracks) | ||
539 | { | ||
540 | int index; | ||
541 | |||
542 | /* Reload tracks */ | ||
543 | viewer.num_tracks = playlist_amount(); | ||
544 | if (viewer.num_tracks < 0) | ||
545 | return false; | ||
546 | |||
547 | index = viewer.first_display_index; | ||
548 | |||
549 | load_playlist_entries(index); | ||
550 | |||
551 | if (viewer.num_loaded <= 0) | ||
552 | return false; | ||
553 | |||
554 | viewer.first_display_index = viewer.first_index; | ||
555 | viewer.last_display_index = | ||
556 | viewer.first_index + viewer.num_display_lines - 1; | ||
557 | if (viewer.last_display_index >= viewer.num_tracks) | ||
558 | viewer.last_display_index = viewer.num_tracks - 1; | ||
559 | } | ||
560 | |||
561 | display_playlist(); | ||
562 | |||
563 | return true; | ||
564 | } | ||
565 | |||
566 | /* Menu of playlist commands. Invoked via ON+PLAY on main viewer screen. | ||
567 | Returns -1 if USB attached, 0 if no playlist change, and 1 if playlist | ||
568 | changed. */ | ||
569 | static int onplay_menu(int index) | ||
570 | { | ||
571 | struct menu_items menu[2]; /* increase this if you add entries! */ | ||
572 | int m, i=0, result, ret = 0; | ||
573 | bool current = (tracks[index].index == viewer.current_playing_track); | ||
574 | |||
575 | menu[i].desc = str(LANG_DELETE); | ||
576 | i++; | ||
577 | |||
578 | menu[i].desc = str(LANG_MOVE); | ||
579 | i++; | ||
580 | |||
581 | m = menu_init(menu, i); | ||
582 | result = menu_show(m); | ||
583 | if (result == MENU_ATTACHED_USB) | ||
584 | ret = -1; | ||
585 | else if (result >= 0) | ||
586 | { | ||
587 | /* Abort current move */ | ||
588 | viewer.move_track = -1; | ||
589 | |||
590 | switch (result) | ||
591 | { | ||
592 | case 0: | ||
593 | /* delete track */ | ||
594 | if (current) | ||
595 | mpeg_stop(); | ||
596 | |||
597 | playlist_delete(tracks[index].index); | ||
598 | |||
599 | if (current) | ||
600 | { | ||
601 | /* Start playing new track except if it's the last track | ||
602 | in the playlist and repeat mode is disabled */ | ||
603 | if (tracks[index].display_index != viewer.num_tracks || | ||
604 | global_settings.repeat_mode == REPEAT_ALL) | ||
605 | { | ||
606 | mpeg_play(0); | ||
607 | viewer.current_playing_track = -1; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | ret = 1; | ||
612 | break; | ||
613 | case 1: | ||
614 | /* move track */ | ||
615 | viewer.move_track = tracks[index].index; | ||
616 | ret = 0; | ||
617 | break; | ||
618 | } | ||
619 | } | ||
620 | |||
621 | menu_exit(m); | ||
622 | |||
623 | return ret; | ||
624 | } | ||
625 | |||
626 | /* Main viewer function */ | ||
627 | bool playlist_viewer(void) | ||
628 | { | ||
629 | bool exit=false; /* exit viewer */ | ||
630 | bool update=true; /* update display */ | ||
631 | bool cursor_on=true; /* used for flashing cursor */ | ||
632 | int old_cursor_pos; /* last cursor position */ | ||
633 | int button; | ||
634 | |||
635 | if (!initialize()) | ||
636 | return false; | ||
637 | |||
638 | old_cursor_pos = viewer.cursor_pos; | ||
639 | |||
640 | while (!exit) | ||
641 | { | ||
642 | short track; | ||
643 | |||
644 | /* Timeout so we can determine if play status has changed */ | ||
645 | button = button_get_w_tmo(HZ/2); | ||
646 | |||
647 | if (!(mpeg_status() & MPEG_STATUS_PLAY)) | ||
648 | { | ||
649 | /* Play has stopped */ | ||
650 | #ifdef HAVE_LCD_CHARCELLS | ||
651 | splash(HZ, 0, true, str(LANG_END_PLAYLIST_PLAYER)); | ||
652 | #else | ||
653 | splash(HZ, 0, true, str(LANG_END_PLAYLIST_RECORDER)); | ||
654 | #endif | ||
655 | status_set_playmode(STATUS_STOP); | ||
656 | return false;; | ||
657 | } | ||
658 | |||
659 | if (viewer.move_track != -1 || !cursor_on) | ||
660 | { | ||
661 | /* Flash cursor to identify that we are moving a track */ | ||
662 | cursor_on = !cursor_on; | ||
663 | #ifdef HAVE_LCD_BITMAP | ||
664 | if (global_settings.invert_cursor) | ||
665 | { | ||
666 | lcd_invertrect( | ||
667 | MARGIN_X, MARGIN_Y+(viewer.cursor_pos*viewer.line_height), | ||
668 | LCD_WIDTH, viewer.line_height); | ||
669 | lcd_invertscroll(LINE_X, viewer.cursor_pos); | ||
670 | } | ||
671 | else | ||
672 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, | ||
673 | cursor_on); | ||
674 | |||
675 | lcd_update_rect( | ||
676 | 0, MARGIN_Y + (viewer.cursor_pos * viewer.line_height), | ||
677 | LCD_WIDTH, viewer.line_height); | ||
678 | #else | ||
679 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, cursor_on); | ||
680 | lcd_update(); | ||
681 | #endif | ||
682 | } | ||
683 | |||
684 | playlist_get_resume_info(&track); | ||
685 | |||
686 | if (track != viewer.current_playing_track || | ||
687 | playlist_amount() != viewer.num_tracks) | ||
688 | { | ||
689 | /* Playlist has changed (new track started?) */ | ||
690 | update_first_index(); | ||
691 | if (!update_playlist(false)) | ||
692 | exit = true; | ||
693 | else | ||
694 | update = true; | ||
695 | |||
696 | /* Abort move on playlist change */ | ||
697 | viewer.move_track = -1; | ||
698 | } | ||
699 | |||
700 | switch (button) | ||
701 | { | ||
702 | #ifdef HAVE_RECORDER_KEYPAD | ||
703 | case BUTTON_OFF: | ||
704 | case BUTTON_LEFT: | ||
705 | #else | ||
706 | case BUTTON_STOP: | ||
707 | #endif | ||
708 | exit = true; | ||
709 | break; | ||
710 | |||
711 | #ifdef HAVE_RECORDER_KEYPAD | ||
712 | case BUTTON_UP: | ||
713 | case BUTTON_UP | BUTTON_REPEAT: | ||
714 | #else | ||
715 | case BUTTON_LEFT: | ||
716 | case BUTTON_LEFT | BUTTON_REPEAT: | ||
717 | #endif | ||
718 | scroll_display(-1); | ||
719 | update = true; | ||
720 | break; | ||
721 | |||
722 | #ifdef HAVE_RECORDER_KEYPAD | ||
723 | case BUTTON_DOWN: | ||
724 | case BUTTON_DOWN | BUTTON_REPEAT: | ||
725 | #else | ||
726 | case BUTTON_RIGHT: | ||
727 | case BUTTON_RIGHT | BUTTON_REPEAT: | ||
728 | #endif | ||
729 | scroll_display(1); | ||
730 | update = true; | ||
731 | break; | ||
732 | |||
733 | #ifdef HAVE_RECORDER_KEYPAD | ||
734 | case BUTTON_ON | BUTTON_UP: | ||
735 | case BUTTON_ON | BUTTON_UP | BUTTON_REPEAT: | ||
736 | #else | ||
737 | case BUTTON_ON | BUTTON_LEFT: | ||
738 | case BUTTON_ON | BUTTON_LEFT | BUTTON_REPEAT: | ||
739 | #endif | ||
740 | /* Pageup */ | ||
741 | scroll_display(-viewer.num_display_lines); | ||
742 | update = true; | ||
743 | break; | ||
744 | |||
745 | #ifdef HAVE_RECORDER_KEYPAD | ||
746 | case BUTTON_ON | BUTTON_DOWN: | ||
747 | case BUTTON_ON | BUTTON_DOWN | BUTTON_REPEAT: | ||
748 | #else | ||
749 | case BUTTON_ON | BUTTON_RIGHT: | ||
750 | case BUTTON_ON | BUTTON_RIGHT | BUTTON_REPEAT: | ||
751 | #endif | ||
752 | /* Pagedown */ | ||
753 | scroll_display(viewer.num_display_lines); | ||
754 | update = true; | ||
755 | break; | ||
756 | |||
757 | #ifdef HAVE_RECORDER_KEYPAD | ||
758 | case BUTTON_RIGHT: | ||
759 | #endif | ||
760 | case BUTTON_PLAY: | ||
761 | if (viewer.move_track >= 0) | ||
762 | { | ||
763 | /* Move track */ | ||
764 | int ret; | ||
765 | |||
766 | ret = playlist_move(viewer.move_track, | ||
767 | tracks[INDEX(viewer.cursor_pos)].index); | ||
768 | if (ret < 0) | ||
769 | splash(HZ, 0, true, str(LANG_MOVE_FAILED)); | ||
770 | |||
771 | update_playlist(true); | ||
772 | viewer.move_track = -1; | ||
773 | } | ||
774 | else | ||
775 | { | ||
776 | /* Stop current track and play new track */ | ||
777 | mpeg_stop(); | ||
778 | playlist_start(tracks[INDEX(viewer.cursor_pos)].index, 0); | ||
779 | status_set_playmode(STATUS_PLAY); | ||
780 | update_playlist(false); | ||
781 | } | ||
782 | |||
783 | display_playlist(); | ||
784 | update = true; | ||
785 | break; | ||
786 | |||
787 | case BUTTON_ON | BUTTON_PLAY: | ||
788 | { | ||
789 | /* ON+PLAY menu */ | ||
790 | int ret; | ||
791 | |||
792 | ret = onplay_menu(INDEX(viewer.cursor_pos)); | ||
793 | |||
794 | if (ret < 0) | ||
795 | /* USB attached */ | ||
796 | return true; | ||
797 | else if (ret > 0) | ||
798 | { | ||
799 | /* Playlist changed */ | ||
800 | update_first_index(); | ||
801 | update_playlist(true); | ||
802 | if (viewer.num_tracks <= 0) | ||
803 | exit = true; | ||
804 | } | ||
805 | else | ||
806 | display_playlist(); | ||
807 | |||
808 | update = true; | ||
809 | break; | ||
810 | } | ||
811 | case SYS_USB_CONNECTED: | ||
812 | usb_screen(); | ||
813 | return true; | ||
814 | } | ||
815 | |||
816 | if (update && !exit) | ||
817 | { | ||
818 | lcd_stop_scroll(); | ||
819 | |||
820 | if (viewer.cursor_pos > | ||
821 | (viewer.last_display_index - viewer.first_display_index)) | ||
822 | { | ||
823 | /* Cursor position is invalid */ | ||
824 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, false); | ||
825 | viewer.cursor_pos = | ||
826 | viewer.last_display_index - viewer.first_display_index; | ||
827 | put_cursorxy(CURSOR_X, CURSOR_Y + viewer.cursor_pos, true); | ||
828 | } | ||
829 | |||
830 | if (viewer.cursor_pos != old_cursor_pos && | ||
831 | old_cursor_pos <= | ||
832 | (viewer.last_display_index - viewer.first_display_index)) | ||
833 | /* Stop scrolling previous line */ | ||
834 | update_display_line(old_cursor_pos, false); | ||
835 | |||
836 | /* Scroll line at new cursor position */ | ||
837 | update_display_line(viewer.cursor_pos, true); | ||
838 | |||
839 | lcd_update(); | ||
840 | |||
841 | old_cursor_pos = viewer.cursor_pos; | ||
842 | cursor_on = true; | ||
843 | update = false; | ||
844 | } | ||
845 | } | ||
846 | |||
847 | return false; | ||
848 | } | ||
diff --git a/apps/playlist_viewer.h b/apps/playlist_viewer.h new file mode 100644 index 0000000000..ecc5197566 --- /dev/null +++ b/apps/playlist_viewer.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /*************************************************************************** | ||
2 | * | ||
3 | * __________ __ ___. | ||
4 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
5 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
6 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
7 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
8 | * \/ \/ \/ \/ \/ | ||
9 | * $Id$ | ||
10 | * | ||
11 | * Copyright (C) 2003 Hardeep Sidhu | ||
12 | * | ||
13 | * All files in this archive are subject to the GNU General Public License. | ||
14 | * See the file COPYING in the source tree root for full license agreement. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
20 | |||
21 | #ifndef _PLAYLIST_VIEWER_H_ | ||
22 | #define _PLAYLIST_VIEWER_H_ | ||
23 | |||
24 | bool playlist_viewer(void); | ||
25 | |||
26 | #endif | ||
diff --git a/apps/wps.c b/apps/wps.c index 7044369ed5..a39f2ba30c 100644 --- a/apps/wps.c +++ b/apps/wps.c | |||
@@ -578,8 +578,6 @@ static bool menu(void) | |||
578 | status_set_param(false); | 578 | status_set_param(false); |
579 | #endif | 579 | #endif |
580 | 580 | ||
581 | wps_display(id3); | ||
582 | wps_refresh(id3, 0, WPS_REFRESH_ALL); | ||
583 | return false; | 581 | return false; |
584 | } | 582 | } |
585 | 583 | ||
@@ -627,6 +625,7 @@ int wps_show(void) | |||
627 | bool ignore_keyup = true; | 625 | bool ignore_keyup = true; |
628 | bool restore = false; | 626 | bool restore = false; |
629 | bool exit = false; | 627 | bool exit = false; |
628 | bool update_track = false; | ||
630 | 629 | ||
631 | id3 = NULL; | 630 | id3 = NULL; |
632 | current_track_path[0] = '\0'; | 631 | current_track_path[0] = '\0'; |
@@ -902,6 +901,7 @@ int wps_show(void) | |||
902 | if (menu()) | 901 | if (menu()) |
903 | return SYS_USB_CONNECTED; | 902 | return SYS_USB_CONNECTED; |
904 | 903 | ||
904 | update_track = true; | ||
905 | restore = true; | 905 | restore = true; |
906 | break; | 906 | break; |
907 | 907 | ||
@@ -939,18 +939,24 @@ int wps_show(void) | |||
939 | return SYS_USB_CONNECTED; | 939 | return SYS_USB_CONNECTED; |
940 | 940 | ||
941 | case BUTTON_NONE: /* Timeout */ | 941 | case BUTTON_NONE: /* Timeout */ |
942 | if (update()) | 942 | update_track = true; |
943 | { | ||
944 | /* set dir browser to current playing song */ | ||
945 | if (global_settings.browse_current && | ||
946 | current_track_path[0] != '\0') | ||
947 | set_current_file(current_track_path); | ||
948 | |||
949 | return 0; | ||
950 | } | ||
951 | break; | 943 | break; |
952 | } | 944 | } |
953 | 945 | ||
946 | if (update_track) | ||
947 | { | ||
948 | if (update()) | ||
949 | { | ||
950 | /* set dir browser to current playing song */ | ||
951 | if (global_settings.browse_current && | ||
952 | current_track_path[0] != '\0') | ||
953 | set_current_file(current_track_path); | ||
954 | |||
955 | return 0; | ||
956 | } | ||
957 | update_track = false; | ||
958 | } | ||
959 | |||
954 | if (exit) { | 960 | if (exit) { |
955 | #ifdef HAVE_LCD_CHARCELLS | 961 | #ifdef HAVE_LCD_CHARCELLS |
956 | status_set_record(false); | 962 | status_set_record(false); |
@@ -975,7 +981,6 @@ int wps_show(void) | |||
975 | return 0; | 981 | return 0; |
976 | } | 982 | } |
977 | 983 | ||
978 | |||
979 | if ( button ) | 984 | if ( button ) |
980 | ata_spin(); | 985 | ata_spin(); |
981 | 986 | ||