settings: configuration file processing rewrite

This commit is contained in:
Andrzej Rybczak
2014-08-28 18:57:16 +02:00
parent 8a1e4a48dd
commit 4b933b29e1
35 changed files with 1881 additions and 1446 deletions

View File

@@ -12,7 +12,7 @@
## file which defines that while launching ncmpcpp. ## file which defines that while launching ncmpcpp.
## ##
# #
#ncmpcpp_directory = "~/.ncmpcpp" #ncmpcpp_directory = ~/.ncmpcpp
# #
## ##
## Directory for storing downloaded lyrics. It ## Directory for storing downloaded lyrics. It
@@ -20,21 +20,21 @@
## (eg. ncmpc) also use that location. ## (eg. ncmpc) also use that location.
## ##
# #
#lyrics_directory = "~/.lyrics" #lyrics_directory = ~/.lyrics
# #
##### connection settings ##### ##### connection settings #####
# #
## set it in order to make tag editor and renaming files work properly #mpd_host = localhost
# #
#mpd_host = "localhost" #mpd_port = 6600
# #
#mpd_port = "6600" #mpd_connection_timeout = 5
# #
#mpd_music_dir = "" ## Needed for tag editor and file operations to work.
##
#mpd_music_dir = ~/music
# #
#mpd_connection_timeout = "5" #mpd_crossfade_time = 5
#
#mpd_crossfade_time = "5"
# #
##### music visualizer ##### ##### music visualizer #####
## ##
@@ -46,19 +46,13 @@
## ##
## audio_output { ## audio_output {
## type "fifo" ## type "fifo"
## name "My FIFO" ## name "Visualizer feed"
## path "/tmp/mpd.fifo" ## path "/tmp/mpd.fifo"
## format "44100:16:2" ## format "44100:16:2"
## } ## }
## ##
# #
## #visualizer_fifo_path = /tmp/mpd.fifo
## If you set format to 44100:16:2, make it 'yes'.
##
#
#visualizer_in_stereo = "no"
#
#visualizer_fifo_path = ""
# #
## ##
## Note: Below parameter is needed for ncmpcpp ## Note: Below parameter is needed for ncmpcpp
@@ -68,7 +62,12 @@
## are some problems with it. ## are some problems with it.
## ##
# #
#visualizer_output_name = "" #visualizer_output_name = Visualizer feed
#
##
## If you set format to 44100:16:2, make it 'yes'.
##
#visualizer_in_stereo = yes
# #
## ##
## Note: Below parameter defines how often ncmpcpp ## Note: Below parameter defines how often ncmpcpp
@@ -78,14 +77,16 @@
## Keep in mind that sane values start with >=10. ## Keep in mind that sane values start with >=10.
## ##
# #
#visualizer_sync_interval = "30" #visualizer_sync_interval = 30
# #
## ##
## Note: To enable spectrum frequency visualization ## Note: To enable spectrum frequency visualization
## you need to compile ncmpcpp with fftw3 support. ## you need to compile ncmpcpp with fftw3 support.
## ##
# #
#visualizer_type = "wave" (spectrum/wave) ## Available values: spectrum, wave.
##
#visualizer_type = wave
# #
#visualizer_look = "◆│" #visualizer_look = "◆│"
# #
@@ -99,7 +100,7 @@
## supports charset detection by checking output ## supports charset detection by checking output
## of `ncmpcpp --version`. ## of `ncmpcpp --version`.
## ##
## Note: Since MPD uses utf8 by default, setting ## Note: Since MPD uses UTF-8 by default, setting
## this option makes sense only if your encoding ## this option makes sense only if your encoding
## is different. ## is different.
## ##
@@ -108,13 +109,14 @@
# #
##### delays ##### ##### delays #####
# #
## delay after playlist highlighting will be disabled (0 = don't disable) ## Time of inactivity (in seconds) after playlist
## highlighting will be disabled (0 = always on).
##
#playlist_disable_highlight_delay = 5
# #
#playlist_disable_highlight_delay = "5" ## Defines how long messages are supposed to be visible.
# ##
## defines how long various messages are supposed to be visible #message_delay_time = 5
#
#message_delay_time = "4"
# #
##### song format ##### ##### song format #####
## ##
@@ -151,9 +153,9 @@
## you'll get nothing. ## you'll get nothing.
## ##
## text can also have different color than the main window has, ## text can also have different color than the main window has,
## eg. if you want length to be green, write $3%l$9 ## eg. if you want length to be green, write "$3%l$9".
## ##
## available values: ## Available values:
## ##
## - 0 - default window color (discards all other colors) ## - 0 - default window color (discards all other colors)
## - 1 - black ## - 1 - black
@@ -169,24 +171,24 @@
## Note: colors can be nested. ## Note: colors can be nested.
## ##
# #
#song_list_format = "{%a - }{%t}|{$8%f$9}$R{$3(%l)$9}" #song_list_format = {%a - }{%t}|{$8%f$9}$R{$3(%l)$9}
# #
#song_status_format = "{{%a{ \"%b\"{ (%y)}} - }{%t}}|{%f}" #song_status_format = {{%a{ \"%b\"{ (%y)}} - }{%t}}|{%f}
# #
#song_library_format = "{%n - }{%t}|{%f}" #song_library_format = {%n - }{%t}|{%f}
# #
#tag_editor_album_format = "{(%y) }%b" #tag_editor_album_format = {(%y) }%b
# #
## ##
## Note: Below variables are used for sorting songs in browser. ## Note: Below variables are used for sorting songs in browser.
## The sort mode determines how songs are sorted, and can be used ## The sort mode determines how songs are sorted, and can be used
## in combination with a sort format to specify a custom sorting format. ## in combination with a sort format to specify a custom sorting format.
## Possible values for browser_sort_mode are "name", "mtime" and "format". ## Available values for browser_sort_mode are "name", "mtime" and "format".
## ##
# #
#browser_sort_mode = "name" #browser_sort_mode = name
# #
#browser_sort_format = "{%a - }{%t}|{%f} {(%l)}" #browser_sort_format = {%a - }{%t}|{%f} {(%l)}
# #
## ##
## Note: Below variables are for alternative version of user's interface. ## Note: Below variables are for alternative version of user's interface.
@@ -205,30 +207,29 @@
## with reversed colors. ## with reversed colors.
## ##
# #
#alternative_header_first_line_format = "$b$1$aqqu$/a$9 {%t}|{%f} $1$atqq$/a$9$/b" #alternative_header_first_line_format = $b$1$aqqu$/a$9 {%t}|{%f} $1$atqq$/a$9$/b
# #
#alternative_header_second_line_format = "{{$4$b%a$/b$9}{ - $7%b$9}{ ($4%y$9)}}|{%D}" #alternative_header_second_line_format = {{$4$b%a$/b$9}{ - $7%b$9}{ ($4%y$9)}}|{%D}
# #
## ##
## Note: Below variables also supports ## Note: below variables also support text attributes listed above.
## text attributes listed above.
## ##
# #
#now_playing_prefix = "$b" #now_playing_prefix = $b
# #
#now_playing_suffix = "$/b" #now_playing_suffix = $/b
# #
#browser_playlist_prefix = "$2playlist$9 " #browser_playlist_prefix = "$2playlist$9 "
# #
#selected_item_prefix = "$6" #selected_item_prefix = $6
# #
#selected_item_suffix = "$9" #selected_item_suffix = $9
# #
#modified_item_prefix = "$3> $9" #modified_item_prefix = $3> $9
# #
## colors are not supported for below variable ## Note: colors are not supported for below variable.
# ##
#song_window_title_format = "{%a - }{%t}|{%f}" #song_window_title_format = {%a - }{%t}|{%f}
# #
##### columns settings ##### ##### columns settings #####
## ##
@@ -266,7 +267,7 @@
## not available. ## not available.
## ##
# #
#song_columns_list_format = "(7f)[green]{l} (25)[cyan]{a} (40)[]{t|f} (30)[red]{b}" #song_columns_list_format = (7f)[green]{l} (25)[cyan]{a} (40)[]{t|f} (30)[red]{b}
# #
##### various settings ##### ##### various settings #####
# #
@@ -279,75 +280,86 @@
## ##
#execute_on_song_change = "" #execute_on_song_change = ""
# #
#playlist_show_remaining_time = "no" #playlist_show_remaining_time = no
# #
#playlist_shorten_total_times = "no" #playlist_shorten_total_times = no
# #
#playlist_separate_albums = "no" #playlist_separate_albums = no
# #
#playlist_display_mode = "classic" (classic/columns) ##
## Note: Possible display modes: classic, columns.
##
#playlist_display_mode = classic
# #
#browser_display_mode = "classic" (classic/columns) #browser_display_mode = classic
# #
#search_engine_display_mode = "classic" (classic/columns) #search_engine_display_mode = classic
# #
#playlist_editor_display_mode = "classic" (classic/columns) #playlist_editor_display_mode = classic
# #
#discard_colors_if_item_is_selected = "yes" #discard_colors_if_item_is_selected = yes
# #
#incremental_seeking = "yes" #incremental_seeking = yes
# #
#seek_time = "1" #seek_time = 1
# #
#volume_change_step = "1" #volume_change_step = 1
# #
#autocenter_mode = "no" #autocenter_mode = no
# #
#centered_cursor = "no" #centered_cursor = no
# #
## ##
## Note: You can specify third character which will ## Note: You can specify third character which will
## be used to build 'empty' part of progressbar. ## be used to build 'empty' part of progressbar.
## ##
#progressbar_look = "=>" #progressbar_look = =>
# #
#progressbar_boldness = "yes" #progressbar_boldness = yes
# #
#default_place_to_search_in = "database" (database/playlist) ## Available values: database, playlist.
##
#default_place_to_search_in = database
# #
#user_interface = "classic" (classic/alternative) ## Available values: classic, alternative.
##
#user_interface = classic
# #
#media_library_left_column = "a" (possible values: a,y,g,c,p, legend above) ## Available values: artist, date, genre, composer, performer.
##
#media_library_primary_tag = artist
# #
#default_find_mode = "wrapped" (wrapped/normal) ## Available values: wrapped, normal.
##
#default_find_mode = wrapped
# #
#default_space_mode = "add" (add/select) ## Available values: add, select.
##
#default_space_mode = add
# #
#default_tag_editor_pattern = "%n - %t" #default_tag_editor_pattern = %n - %t
# #
#header_visibility = "yes" #header_visibility = yes
# #
#statusbar_visibility = "yes" #statusbar_visibility = yes
# #
#titles_visibility = "yes" #titles_visibility = yes
# #
#header_text_scrolling = "yes" #header_text_scrolling = yes
# #
#fancy_scrolling = "yes" #cyclic_scrolling = no
# #
#cyclic_scrolling = "no" #lines_scrolled = 2
# #
#lines_scrolled = "2" #follow_now_playing_lyrics = no
# #
#follow_now_playing_lyrics = "no" #fetch_lyrics_for_current_song_in_background = no
# #
#fetch_lyrics_for_current_song_in_background = "no" #store_lyrics_in_song_dir = no
# #
#store_lyrics_in_song_dir = "no" #generate_win32_compatible_filenames = yes
# #
#generate_win32_compatible_filenames = "yes" #allow_for_physical_item_deletion = no
#
#allow_for_physical_item_deletion = "no"
# #
## ##
## Note: If you set this variable, ncmpcpp will try to ## Note: If you set this variable, ncmpcpp will try to
@@ -357,13 +369,13 @@
## ##
## Note: Language has to be expressed as an ISO 639 alpha-2 code. ## Note: Language has to be expressed as an ISO 639 alpha-2 code.
## ##
#lastfm_preferred_language = "" #lastfm_preferred_language = en
# #
#ncmpc_like_songs_adding = "no" (enabled - add/remove, disabled - always add) ## Available values: add_remove, always_add.
##
#space_add_mode = always_add
# #
#show_hidden_files_in_local_browser = "no" #show_hidden_files_in_local_browser = no
#
#display_screens_numbers_on_start = "yes"
# #
## ##
## How shall screen switcher work? ## How shall screen switcher work?
@@ -374,59 +386,61 @@
## Screens available for use: help, playlist, browser, search_engine, ## Screens available for use: help, playlist, browser, search_engine,
## media_library, playlist_editor, tag_editor, outputs, visualizer, clock. ## media_library, playlist_editor, tag_editor, outputs, visualizer, clock.
## ##
#screen_switcher_mode = "playlist, browser" #screen_switcher_mode = playlist, browser
# #
## ##
## Note: You can define startup screen for ncmpcpp ## Note: You can define startup screen for ncmpcpp
## by choosing screen from the list above. ## by choosing screen from the list above.
## ##
#startup_screen = "playlist" #startup_screen = playlist
# #
## ##
## Default width of locked screen (in %). ## Default width of locked screen (in %).
## Acceptable values are from 20 to 80. ## Acceptable values are from 20 to 80.
## ##
# #
#locked_screen_width_part = "50" #locked_screen_width_part = 50
# #
#ask_for_locked_screen_width_part = "yes" #ask_for_locked_screen_width_part = yes
# #
#jump_to_now_playing_song_at_start = "yes" #jump_to_now_playing_song_at_start = yes
# #
#ask_before_clearing_main_playlist = "no" #ask_before_clearing_playlists = yes
# #
#clock_display_seconds = "no" #clock_display_seconds = no
# #
#display_volume_level = "yes" #display_volume_level = yes
# #
#display_bitrate = "no" #display_bitrate = no
# #
#display_remaining_time = "no" #display_remaining_time = no
# #
#regular_expressions = "none" (none/basic/extended) ## Available values: none, basic, extended.
##
#regular_expressions = none
# #
## ##
## Note: If below is enabled, ncmpcpp will ignore leading ## Note: If below is enabled, ncmpcpp will ignore leading
## "The" word while sorting items in browser, tags in ## "The" word while sorting items in browser, tags in
## media library, etc. ## media library, etc.
## ##
#ignore_leading_the = "no" #ignore_leading_the = no
# #
#block_search_constraints_change_if_items_found = "yes" #block_search_constraints_change_if_items_found = yes
# #
#mouse_support = "yes" #mouse_support = yes
# #
#mouse_list_scroll_whole_page = "yes" #mouse_list_scroll_whole_page = yes
# #
#empty_tag_marker = "<empty>" #empty_tag_marker = <empty>
# #
#tags_separator = " | " #tags_separator = " | "
# #
#tag_editor_extended_numeration = "no" #tag_editor_extended_numeration = no
# #
#media_library_sort_by_mtime = "no" #media_library_sort_by_mtime = no
# #
#enable_window_title = "yes" #enable_window_title = yes
# #
## ##
## Note: You can choose default search mode for search ## Note: You can choose default search mode for search
@@ -440,47 +454,49 @@
## in database and local one for searching in current playlist) ## in database and local one for searching in current playlist)
## ##
# #
#search_engine_default_search_mode = "1" #search_engine_default_search_mode = 1
# #
#external_editor = "" #external_editor = nano
# #
#use_console_editor = "no" (set to yes, if your editor is console app) ## Note: set to yes if external editor is a console application.
##
#use_console_editor = yes
# #
##### colors definitions ##### ##### colors definitions #####
# #
#colors_enabled = "yes" #colors_enabled = yes
# #
#empty_tag_color = "cyan" #empty_tag_color = cyan
# #
#header_window_color = "default" #header_window_color = default
# #
#volume_color = "default" #volume_color = default
# #
#state_line_color = "default" #state_line_color = default
# #
#state_flags_color = "default" #state_flags_color = default
# #
#main_window_color = "yellow" #main_window_color = yellow
# #
#color1 = "white" #color1 = white
# #
#color2 = "green" #color2 = green
# #
#main_window_highlight_color = "yellow" #main_window_highlight_color = yellow
# #
#progressbar_color = "default" #progressbar_color = default
# #
#progressbar_elapsed_color = "default" #progressbar_elapsed_color = default
# #
#statusbar_color = "default" #statusbar_color = default
# #
#alternative_ui_separator_color = "black" #alternative_ui_separator_color = black
# #
#active_column_color = "red" #active_column_color = red
# #
#visualizer_color = "yellow" #visualizer_color = yellow
# #
#window_border_color = "green" #window_border_color = green
# #
#active_window_border = "red" #active_window_border = red
# #

View File

@@ -156,9 +156,6 @@ No need to describe it, huh?
.B header_text_scrolling = yes/no .B header_text_scrolling = yes/no
If enabled, text in header window will scroll if its length is longer then actual screen width, otherwise it won't. If enabled, text in header window will scroll if its length is longer then actual screen width, otherwise it won't.
.TP .TP
.B fancy_scrolling = yes/no
If enabled, content of other columns will be updated immediately while scrolling, otherwise only after you stop scrolling.
.TP
.B cyclic_scrolling = yes/no .B cyclic_scrolling = yes/no
If enabled, cyclic scrolling is used (e.g. if you press down arrow being at the end of list, it'll take you to the beginning) If enabled, cyclic scrolling is used (e.g. if you press down arrow being at the end of list, it'll take you to the beginning)
.TP .TP
@@ -243,8 +240,8 @@ If set to yes, it will be possible to physically delete files and directories fr
.B lastfm_preferred_language = ISO 639 alpha-2 language code .B lastfm_preferred_language = ISO 639 alpha-2 language code
If set, ncmpcpp will try to get info from last.fm in language you set and if it fails, it will fall back to english. Otherwise it will use english the first time. If set, ncmpcpp will try to get info from last.fm in language you set and if it fails, it will fall back to english. Otherwise it will use english the first time.
.TP .TP
.B ncmpc_like_songs_adding = yes/no .B space_add_mode = add_remove/always_add
If enabled, pressing space on item, which is already in playlist will remove it, otherwise add it again. If set to add_remove, pressing space on item which is already in playlist will remove it, otherwise add it again.
.TP .TP
.B show_hidden_files_in_local_browser = yes/no .B show_hidden_files_in_local_browser = yes/no
Trigger for displaying in local browser files and directories that begin with '.' Trigger for displaying in local browser files and directories that begin with '.'
@@ -309,8 +306,8 @@ Type of currently used regular expressions.
.B user_interface = classic/alternative .B user_interface = classic/alternative
Default user interface used by ncmpcpp at start. Default user interface used by ncmpcpp at start.
.TP .TP
.B media_library_left_column = a/y/g/c/p .B media_library_primary_tag = artist/date/genre/composer/performer
Default tag type for left column in media library. Legend for possible letters is in SONG FORMAT section. Default tag type for leftmost column in media library.
.TP .TP
.B empty_tag_marker = TEXT .B empty_tag_marker = TEXT
Text that will be displayed, if requested tag is not set. Text that will be displayed, if requested tag is not set.

View File

@@ -2,6 +2,7 @@ bin_PROGRAMS = ncmpcpp
ncmpcpp_SOURCES = \ ncmpcpp_SOURCES = \
utility/comparators.cpp \ utility/comparators.cpp \
utility/html.cpp \ utility/html.cpp \
utility/option_parser.cpp \
utility/string.cpp \ utility/string.cpp \
utility/type_conversions.cpp \ utility/type_conversions.cpp \
utility/wide_string.cpp \ utility/wide_string.cpp \
@@ -10,9 +11,10 @@ ncmpcpp_SOURCES = \
browser.cpp \ browser.cpp \
charset.cpp \ charset.cpp \
clock.cpp \ clock.cpp \
cmdargs.cpp \ configuration.cpp \
curl_handle.cpp \ curl_handle.cpp \
display.cpp \ display.cpp \
enums.cpp \
error.cpp \ error.cpp \
global.cpp \ global.cpp \
help.cpp \ help.cpp \
@@ -56,7 +58,9 @@ ncmpcpp_LDFLAGS = $(all_libraries)
noinst_HEADERS = \ noinst_HEADERS = \
utility/comparators.h \ utility/comparators.h \
utility/conversion.h \ utility/conversion.h \
utility/functional.h \
utility/html.h \ utility/html.h \
utility/option_parser.h \
utility/string.h \ utility/string.h \
utility/type_conversions.h \ utility/type_conversions.h \
utility/wide_string.h \ utility/wide_string.h \
@@ -64,9 +68,10 @@ noinst_HEADERS = \
browser.h \ browser.h \
charset.h \ charset.h \
clock.h \ clock.h \
cmdargs.h \ configuration.h \
curl_handle.h \ curl_handle.h \
display.h \ display.h \
enums.h \
error.h \ error.h \
exec_item.h \ exec_item.h \
global.h \ global.h \

View File

@@ -198,7 +198,7 @@ void resizeScreen(bool reload_main_window)
} }
# endif # endif
MainHeight = LINES-(Config.new_design ? 7 : 4); MainHeight = LINES-(Config.design == Design::Alternative ? 7 : 4);
validateScreenSize(); validateScreenSize();
@@ -211,7 +211,7 @@ void resizeScreen(bool reload_main_window)
applyToVisibleWindows(&BaseScreen::resize); applyToVisibleWindows(&BaseScreen::resize);
if (Config.header_visibility || Config.new_design) if (Config.header_visibility || Config.design == Design::Alternative)
wHeader->resize(COLS, HeaderHeight); wHeader->resize(COLS, HeaderHeight);
FooterStartY = LINES-(Config.statusbar_visibility ? 2 : 1); FooterStartY = LINES-(Config.statusbar_visibility ? 2 : 1);
@@ -236,8 +236,8 @@ void setWindowsDimensions()
using Global::MainStartY; using Global::MainStartY;
using Global::MainHeight; using Global::MainHeight;
MainStartY = Config.new_design ? 5 : 2; MainStartY = Config.design == Design::Alternative ? 5 : 2;
MainHeight = LINES-(Config.new_design ? 7 : 4); MainHeight = LINES-(Config.design == Design::Alternative ? 7 : 4);
if (!Config.header_visibility) if (!Config.header_visibility)
{ {
@@ -247,7 +247,7 @@ void setWindowsDimensions()
if (!Config.statusbar_visibility) if (!Config.statusbar_visibility)
++MainHeight; ++MainHeight;
HeaderHeight = Config.new_design ? (Config.header_visibility ? 5 : 3) : 1; HeaderHeight = Config.design == Design::Alternative ? (Config.header_visibility ? 5 : 3) : 1;
FooterStartY = LINES-(Config.statusbar_visibility ? 2 : 1); FooterStartY = LINES-(Config.statusbar_visibility ? 2 : 1);
FooterHeight = Config.statusbar_visibility ? 2 : 1; FooterHeight = Config.statusbar_visibility ? 2 : 1;
} }
@@ -337,15 +337,16 @@ void MouseEvent::run()
myPlaylist->currentSongLength()*m_mouse_event.x/double(COLS)); myPlaylist->currentSongLength()*m_mouse_event.x/double(COLS));
} }
else if (m_mouse_event.bstate & BUTTON1_PRESSED else if (m_mouse_event.bstate & BUTTON1_PRESSED
&& (Config.statusbar_visibility || Config.new_design) && (Config.statusbar_visibility || Config.design == Design::Alternative)
&& Status::State::player() != MPD::psStop && Status::State::player() != MPD::psStop
&& m_mouse_event.y == (Config.new_design ? 1 : LINES-1) && m_mouse_event.x < 9 && m_mouse_event.y == (Config.design == Design::Alternative ? 1 : LINES-1)
&& m_mouse_event.x < 9
) // playing/paused ) // playing/paused
{ {
Mpd.Toggle(); Mpd.Toggle();
} }
else if ((m_mouse_event.bstate & BUTTON2_PRESSED || m_mouse_event.bstate & BUTTON4_PRESSED) else if ((m_mouse_event.bstate & BUTTON2_PRESSED || m_mouse_event.bstate & BUTTON4_PRESSED)
&& (Config.header_visibility || Config.new_design) && (Config.header_visibility || Config.design == Design::Alternative)
&& m_mouse_event.y == 0 && size_t(m_mouse_event.x) > COLS-VolumeState.length() && m_mouse_event.y == 0 && size_t(m_mouse_event.x) > COLS-VolumeState.length()
) // volume ) // volume
{ {
@@ -488,15 +489,24 @@ void MoveEnd::run()
void ToggleInterface::run() void ToggleInterface::run()
{ {
Config.new_design = !Config.new_design; switch (Config.design)
Config.statusbar_visibility = Config.new_design ? 0 : OriginalStatusbarVisibility; {
case Design::Classic:
Config.design = Design::Alternative;
Config.statusbar_visibility = false;
break;
case Design::Alternative:
Config.design = Design::Classic;
Config.statusbar_visibility = OriginalStatusbarVisibility;
break;
}
setWindowsDimensions(); setWindowsDimensions();
Progressbar::unlock(); Progressbar::unlock();
Statusbar::unlock(); Statusbar::unlock();
resizeScreen(false); resizeScreen(false);
Status::Changes::mixer(); Status::Changes::mixer();
Status::Changes::elapsedTime(false); Status::Changes::elapsedTime(false);
Statusbar::printf("User interface: %1%", Config.new_design ? "Alternative" : "Classic"); Statusbar::printf("User interface: %1%", Config.design);
} }
bool JumpToParentDirectory::canBeRun() const bool JumpToParentDirectory::canBeRun() const
@@ -606,13 +616,13 @@ void SlaveScreen::run()
void VolumeUp::run() void VolumeUp::run()
{ {
int volume = std::min(Status::State::volume()+Config.volume_change_step, 100); int volume = std::min(Status::State::volume()+Config.volume_change_step, 100u);
Mpd.SetVolume(volume); Mpd.SetVolume(volume);
} }
void VolumeDown::run() void VolumeDown::run()
{ {
int volume = std::max(Status::State::volume()-Config.volume_change_step, 0); int volume = std::max(int(Status::State::volume()-Config.volume_change_step), 0);
Mpd.SetVolume(volume); Mpd.SetVolume(volume);
} }
@@ -999,52 +1009,83 @@ void ToggleDisplayMode::run()
{ {
if (myScreen == myPlaylist) if (myScreen == myPlaylist)
{ {
Config.columns_in_playlist = !Config.columns_in_playlist; switch (Config.playlist_display_mode)
Statusbar::printf("Playlist display mode: %1%",
Config.columns_in_playlist ? "Columns" : "Classic"
);
if (Config.columns_in_playlist)
{ {
myPlaylist->main().setItemDisplayer(boost::bind(Display::SongsInColumns, _1, myPlaylist->proxySongList())); case DisplayMode::Classic:
if (Config.titles_visibility) Config.playlist_display_mode = DisplayMode::Columns;
myPlaylist->main().setTitle(Display::Columns(myPlaylist->main().getWidth())); myPlaylist->main().setItemDisplayer(boost::bind(
else Display::SongsInColumns, _1, myPlaylist->proxySongList()
));
if (Config.titles_visibility)
myPlaylist->main().setTitle(Display::Columns(myPlaylist->main().getWidth()));
else
myPlaylist->main().setTitle("");
break;
case DisplayMode::Columns:
Config.playlist_display_mode = DisplayMode::Classic;
myPlaylist->main().setItemDisplayer(boost::bind(
Display::Songs, _1, myPlaylist->proxySongList(), Config.song_list_format
));
myPlaylist->main().setTitle(""); myPlaylist->main().setTitle("");
} }
else Statusbar::printf("Playlist display mode: %1%", Config.playlist_display_mode);
{
myPlaylist->main().setItemDisplayer(boost::bind(Display::Songs, _1, myPlaylist->proxySongList(), Config.song_list_format));
myPlaylist->main().setTitle("");
}
} }
else if (myScreen == myBrowser) else if (myScreen == myBrowser)
{ {
Config.columns_in_browser = !Config.columns_in_browser; switch (Config.browser_display_mode)
Statusbar::printf("Browser display mode: %1%", {
Config.columns_in_browser ? "Columns" : "Classic" case DisplayMode::Classic:
); Config.browser_display_mode = DisplayMode::Columns;
myBrowser->main().setTitle(Config.columns_in_browser && Config.titles_visibility ? Display::Columns(myBrowser->main().getWidth()) : ""); if (Config.titles_visibility)
myBrowser->main().setTitle(Display::Columns(myBrowser->main().getWidth()));
else
myBrowser->main().setTitle("");
break;
case DisplayMode::Columns:
Config.browser_display_mode = DisplayMode::Classic;
myBrowser->main().setTitle("");
break;
}
Statusbar::printf("Browser display mode: %1%", Config.browser_display_mode);
} }
else if (myScreen == mySearcher) else if (myScreen == mySearcher)
{ {
Config.columns_in_search_engine = !Config.columns_in_search_engine; switch (Config.search_engine_display_mode)
Statusbar::printf("Search engine display mode: %1%", {
Config.columns_in_search_engine ? "Columns" : "Classic" case DisplayMode::Classic:
); Config.search_engine_display_mode = DisplayMode::Columns;
break;
case DisplayMode::Columns:
Config.search_engine_display_mode = DisplayMode::Classic;
break;
}
Statusbar::printf("Search engine display mode: %1%", Config.search_engine_display_mode);
if (mySearcher->main().size() > SearchEngine::StaticOptions) if (mySearcher->main().size() > SearchEngine::StaticOptions)
mySearcher->main().setTitle(Config.columns_in_search_engine && Config.titles_visibility ? Display::Columns(mySearcher->main().getWidth()) : ""); mySearcher->main().setTitle(
Config.search_engine_display_mode == DisplayMode::Columns
&& Config.titles_visibility
? Display::Columns(mySearcher->main().getWidth())
: ""
);
} }
else if (myScreen->isActiveWindow(myPlaylistEditor->Content)) else if (myScreen->isActiveWindow(myPlaylistEditor->Content))
{ {
Config.columns_in_playlist_editor = !Config.columns_in_playlist_editor; switch (Config.playlist_editor_display_mode)
Statusbar::printf("Playlist editor display mode: %1%", {
Config.columns_in_playlist_editor ? "Columns" : "Classic" case DisplayMode::Classic:
); Config.playlist_editor_display_mode = DisplayMode::Columns;
if (Config.columns_in_playlist_editor) myPlaylistEditor->Content.setItemDisplayer(boost::bind(
myPlaylistEditor->Content.setItemDisplayer(boost::bind(Display::SongsInColumns, _1, myPlaylistEditor->contentProxyList())); Display::SongsInColumns, _1, myPlaylistEditor->contentProxyList()
else ));
myPlaylistEditor->Content.setItemDisplayer(boost::bind(Display::Songs, _1, myPlaylistEditor->contentProxyList(), Config.song_list_format)); break;
case DisplayMode::Columns:
Config.playlist_editor_display_mode = DisplayMode::Classic;
myPlaylistEditor->Content.setItemDisplayer(boost::bind(
Display::Songs, _1, myPlaylistEditor->contentProxyList(), Config.song_list_format
));
break;
}
Statusbar::printf("Playlist editor display mode: %1%", Config.playlist_editor_display_mode);
} }
} }
@@ -1688,7 +1729,7 @@ void AddSelectedItems::run()
void CropMainPlaylist::run() void CropMainPlaylist::run()
{ {
bool yes = true; bool yes = true;
if (Config.ask_before_clearing_main_playlist) if (Config.ask_before_clearing_playlists)
yes = askYesNoQuestion("Do you really want to crop main playlist?", Status::trace); yes = askYesNoQuestion("Do you really want to crop main playlist?", Status::trace);
if (yes) if (yes)
{ {
@@ -1707,7 +1748,7 @@ void CropPlaylist::run()
assert(!myPlaylistEditor->Playlists.empty()); assert(!myPlaylistEditor->Playlists.empty());
std::string playlist = myPlaylistEditor->Playlists.current().value(); std::string playlist = myPlaylistEditor->Playlists.current().value();
bool yes = true; bool yes = true;
if (Config.ask_before_clearing_main_playlist) if (Config.ask_before_clearing_playlists)
yes = askYesNoQuestion( yes = askYesNoQuestion(
boost::format("Do you really want to crop playlist \"%1%\"?") % playlist, boost::format("Do you really want to crop playlist \"%1%\"?") % playlist,
Status::trace Status::trace
@@ -1724,7 +1765,7 @@ void CropPlaylist::run()
void ClearMainPlaylist::run() void ClearMainPlaylist::run()
{ {
bool yes = true; bool yes = true;
if (Config.ask_before_clearing_main_playlist) if (Config.ask_before_clearing_playlists)
yes = askYesNoQuestion("Do you really want to clear main playlist?", Status::trace); yes = askYesNoQuestion("Do you really want to clear main playlist?", Status::trace);
if (yes) if (yes)
{ {
@@ -1747,7 +1788,7 @@ void ClearPlaylist::run()
assert(!myPlaylistEditor->Playlists.empty()); assert(!myPlaylistEditor->Playlists.empty());
std::string playlist = myPlaylistEditor->Playlists.current().value(); std::string playlist = myPlaylistEditor->Playlists.current().value();
bool yes = true; bool yes = true;
if (Config.ask_before_clearing_main_playlist) if (Config.ask_before_clearing_playlists)
yes = askYesNoQuestion( yes = askYesNoQuestion(
boost::format("Do you really want to clear playlist \"%1%\"?") % playlist, boost::format("Do you really want to clear playlist \"%1%\"?") % playlist,
Status::trace Status::trace
@@ -1937,10 +1978,19 @@ void ToggleSpaceMode::run()
void ToggleAddMode::run() void ToggleAddMode::run()
{ {
Config.ncmpc_like_songs_adding = !Config.ncmpc_like_songs_adding; std::string mode_desc;
Statusbar::printf("Add mode: %1%", switch (Config.space_add_mode)
Config.ncmpc_like_songs_adding ? "Add item to playlist or remove if already added" : "Always add item to playlist" {
); case SpaceAddMode::AddRemove:
Config.space_add_mode = SpaceAddMode::AlwaysAdd;
mode_desc = "Always add an item to playlist";
break;
case SpaceAddMode::AlwaysAdd:
Config.space_add_mode = SpaceAddMode::AddRemove;
mode_desc = "Add an item to playlist or remove if already added";
break;
}
Statusbar::printf("Add mode: %1%", mode_desc);
} }
void ToggleMouse::run() void ToggleMouse::run()
@@ -2008,16 +2058,16 @@ void ToggleBrowserSortMode::run()
{ {
switch (Config.browser_sort_mode) switch (Config.browser_sort_mode)
{ {
case smName: case SortMode::Name:
Config.browser_sort_mode = smMTime; Config.browser_sort_mode = SortMode::ModificationTime;
Statusbar::print("Sort songs by: Modification time"); Statusbar::print("Sort songs by: Modification time");
break; break;
case smMTime: case SortMode::ModificationTime:
Config.browser_sort_mode = smCustomFormat; Config.browser_sort_mode = SortMode::CustomFormat;
Statusbar::print("Sort songs by: Custom format"); Statusbar::print("Sort songs by: Custom format");
break; break;
case smCustomFormat: case SortMode::CustomFormat:
Config.browser_sort_mode = smName; Config.browser_sort_mode = SortMode::Name;
Statusbar::print("Sort songs by: Name"); Statusbar::print("Sort songs by: Name");
break; break;
} }
@@ -2211,13 +2261,12 @@ void NextScreen::run()
if (auto tababble = dynamic_cast<Tabbable *>(myScreen)) if (auto tababble = dynamic_cast<Tabbable *>(myScreen))
tababble->switchToPreviousScreen(); tababble->switchToPreviousScreen();
} }
else if (!Config.screens_seq.empty()) else if (!Config.screen_sequence.empty())
{ {
auto screen_type = std::find(Config.screens_seq.begin(), Config.screens_seq.end(), const auto &seq = Config.screen_sequence;
myScreen->type() auto screen_type = std::find(seq.begin(), seq.end(), myScreen->type());
); if (++screen_type == seq.end())
if (++screen_type == Config.screens_seq.end()) toScreen(seq.front())->switchTo();
toScreen(Config.screens_seq.front())->switchTo();
else else
toScreen(*screen_type)->switchTo(); toScreen(*screen_type)->switchTo();
} }
@@ -2230,13 +2279,12 @@ void PreviousScreen::run()
if (auto tababble = dynamic_cast<Tabbable *>(myScreen)) if (auto tababble = dynamic_cast<Tabbable *>(myScreen))
tababble->switchToPreviousScreen(); tababble->switchToPreviousScreen();
} }
else if (!Config.screens_seq.empty()) else if (!Config.screen_sequence.empty())
{ {
auto screen_type = std::find(Config.screens_seq.begin(), Config.screens_seq.end(), const auto &seq = Config.screen_sequence;
myScreen->type() auto screen_type = std::find(seq.begin(), seq.end(), myScreen->type());
); if (screen_type == seq.begin())
if (screen_type == Config.screens_seq.begin()) toScreen(seq.back())->switchTo();
toScreen(Config.screens_seq.back())->switchTo();
else else
toScreen(*--screen_type)->switchTo(); toScreen(*--screen_type)->switchTo();
} }
@@ -2635,34 +2683,35 @@ void seek()
*wFooter << NC::Format::Bold; *wFooter << NC::Format::Bold;
std::string tracklength; std::string tracklength;
if (Config.new_design) switch (Config.design)
{ {
if (Config.display_remaining_time) case Design::Classic:
{ tracklength = " [";
tracklength = "-"; if (Config.display_remaining_time)
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength()-songpos); {
} tracklength += "-";
else tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength()-songpos);
tracklength = MPD::Song::ShowTime(songpos); }
tracklength += "/"; else
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength()); tracklength += MPD::Song::ShowTime(songpos);
*wHeader << NC::XY(0, 0) << tracklength << " "; tracklength += "/";
wHeader->refresh(); tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength());
} tracklength += "]";
else *wFooter << NC::XY(wFooter->getWidth()-tracklength.length(), 1) << tracklength;
{ break;
tracklength = " ["; case Design::Alternative:
if (Config.display_remaining_time) if (Config.display_remaining_time)
{ {
tracklength += "-"; tracklength = "-";
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength()-songpos); tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength()-songpos);
} }
else else
tracklength += MPD::Song::ShowTime(songpos); tracklength = MPD::Song::ShowTime(songpos);
tracklength += "/"; tracklength += "/";
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength()); tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength());
tracklength += "]"; *wHeader << NC::XY(0, 0) << tracklength << " ";
*wFooter << NC::XY(wFooter->getWidth()-tracklength.length(), 1) << tracklength; wHeader->refresh();
break;
} }
*wFooter << NC::Format::NoBold; *wFooter << NC::Format::NoBold;
Progressbar::draw(songpos, myPlaylist->currentSongLength()); Progressbar::draw(songpos, myPlaylist->currentSongLength());

View File

@@ -99,10 +99,6 @@ struct Binding
return m_actions[0]; return m_actions[0];
} }
const ActionChain &actions() const {
return m_actions;
}
private: private:
ActionChain m_actions; ActionChain m_actions;
}; };

View File

@@ -40,6 +40,7 @@
#include "tags.h" #include "tags.h"
#include "utility/comparators.h" #include "utility/comparators.h"
#include "utility/string.h" #include "utility/string.h"
#include "configuration.h"
using Global::MainHeight; using Global::MainHeight;
using Global::MainStartY; using Global::MainStartY;
@@ -49,6 +50,8 @@ using MPD::itDirectory;
using MPD::itSong; using MPD::itSong;
using MPD::itPlaylist; using MPD::itPlaylist;
namespace fs = boost::filesystem;
Browser *myBrowser; Browser *myBrowser;
namespace {// namespace {//
@@ -63,7 +66,7 @@ bool BrowserEntryMatcher(const boost::regex &rx, const MPD::Item &item, bool fil
Browser::Browser() : itsBrowseLocally(0), itsScrollBeginning(0), itsBrowsedDir("/") Browser::Browser() : itsBrowseLocally(0), itsScrollBeginning(0), itsBrowsedDir("/")
{ {
w = NC::Menu<MPD::Item>(0, MainStartY, COLS, MainHeight, Config.columns_in_browser && Config.titles_visibility ? Display::Columns(COLS) : "", Config.main_color, NC::Border::None); w = NC::Menu<MPD::Item>(0, MainStartY, COLS, MainHeight, Config.browser_display_mode == DisplayMode::Columns && Config.titles_visibility ? Display::Columns(COLS) : "", Config.main_color, NC::Border::None);
w.setHighlightColor(Config.main_highlight_color); w.setHighlightColor(Config.main_highlight_color);
w.cyclicScrolling(Config.use_cyclic_scrolling); w.cyclicScrolling(Config.use_cyclic_scrolling);
w.centeredCursor(Config.centered_cursor); w.centeredCursor(Config.centered_cursor);
@@ -78,7 +81,18 @@ void Browser::resize()
getWindowResizeParams(x_offset, width); getWindowResizeParams(x_offset, width);
w.resize(width, MainHeight); w.resize(width, MainHeight);
w.moveTo(x_offset, MainStartY); w.moveTo(x_offset, MainStartY);
w.setTitle(Config.columns_in_browser && Config.titles_visibility ? Display::Columns(w.getWidth()) : ""); switch (Config.browser_display_mode)
{
case DisplayMode::Columns:
if (Config.titles_visibility)
{
w.setTitle(Display::Columns(w.getWidth()));
break;
}
case DisplayMode::Classic:
w.setTitle("");
break;
}
hasToBeResized = 0; hasToBeResized = 0;
} }
@@ -97,7 +111,7 @@ void Browser::switchTo()
std::wstring Browser::title() std::wstring Browser::title()
{ {
std::wstring result = L"Browse: "; std::wstring result = L"Browse: ";
result += Scroller(ToWString(itsBrowsedDir), itsScrollBeginning, COLS-result.length()-(Config.new_design ? 2 : Global::VolumeState.length())); result += Scroller(ToWString(itsBrowsedDir), itsScrollBeginning, COLS-result.length()-(Config.design == Design::Alternative ? 2 : Global::VolumeState.length()));
return result; return result;
} }
@@ -466,8 +480,6 @@ void Browser::GetDirectory(std::string dir, std::string subdir)
#ifndef WIN32 #ifndef WIN32
void Browser::GetLocalDirectory(MPD::ItemList &v, const std::string &directory, bool recursively) const void Browser::GetLocalDirectory(MPD::ItemList &v, const std::string &directory, bool recursively) const
{ {
namespace fs = boost::filesystem;
size_t start_size = v.size(); size_t start_size = v.size();
fs::path dir(directory); fs::path dir(directory);
std::for_each(fs::directory_iterator(dir), fs::directory_iterator(), [&](fs::directory_entry &e) { std::for_each(fs::directory_iterator(dir), fs::directory_iterator(), [&](fs::directory_entry &e) {
@@ -511,8 +523,6 @@ void Browser::GetLocalDirectory(MPD::ItemList &v, const std::string &directory,
void Browser::ClearDirectory(const std::string &path) const void Browser::ClearDirectory(const std::string &path) const
{ {
namespace fs = boost::filesystem;
fs::path dir(path); fs::path dir(path);
std::for_each(fs::directory_iterator(dir), fs::directory_iterator(), [&](fs::directory_entry &e) { std::for_each(fs::directory_iterator(dir), fs::directory_iterator(), [&](fs::directory_entry &e) {
if (!fs::is_symlink(e) && fs::is_directory(e)) if (!fs::is_symlink(e) && fs::is_directory(e))
@@ -535,9 +545,15 @@ void Browser::ChangeBrowseMode()
Statusbar::printf("Browse mode: %1%", Statusbar::printf("Browse mode: %1%",
itsBrowseLocally ? "Local filesystem" : "MPD database" itsBrowseLocally ? "Local filesystem" : "MPD database"
); );
itsBrowsedDir = itsBrowseLocally ? Config.GetHomeDirectory() : "/"; if (itsBrowseLocally)
if (itsBrowseLocally && *itsBrowsedDir.rbegin() == '/') {
itsBrowsedDir.resize(itsBrowsedDir.length()-1); itsBrowsedDir = "~";
expand_home(itsBrowsedDir);
if (*itsBrowsedDir.rbegin() == '/')
itsBrowsedDir.resize(itsBrowsedDir.length()-1);
}
else
itsBrowsedDir = "/";
w.reset(); w.reset();
GetDirectory(itsBrowsedDir); GetDirectory(itsBrowsedDir);
drawHeader(); drawHeader();
@@ -605,10 +621,15 @@ std::string ItemToString(const MPD::Item &item)
result = "[" + getBasename(item.name) + "]"; result = "[" + getBasename(item.name) + "]";
break; break;
case MPD::itSong: case MPD::itSong:
if (Config.columns_in_browser) switch (Config.browser_display_mode)
result = item.song->toString(Config.song_in_columns_to_string_format, Config.tags_separator); {
else case DisplayMode::Classic:
result = item.song->toString(Config.song_list_format_dollar_free, Config.tags_separator); result = item.song->toString(Config.song_list_format_dollar_free, Config.tags_separator);
break;
case DisplayMode::Columns:
result = item.song->toString(Config.song_in_columns_to_string_format, Config.tags_separator);
break;
}
break; break;
case MPD::itPlaylist: case MPD::itPlaylist:
result = Config.browser_playlist_prefix.str() + getBasename(item.name); result = Config.browser_playlist_prefix.str() + getBasename(item.name);

View File

@@ -18,11 +18,12 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/ ***************************************************************************/
#include <boost/filesystem/operations.hpp>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <iostream> #include <iostream>
#include "bindings.h" #include "bindings.h"
#include "cmdargs.h" #include "configuration.h"
#include "config.h" #include "config.h"
#include "mpdpp.h" #include "mpdpp.h"
#include "settings.h" #include "settings.h"
@@ -36,25 +37,25 @@ namespace {
const char *env_home; const char *env_home;
void replace_tilda_with_home(std::string &s) }
void expand_home(std::string &path)
{ {
if (!s.empty() && s[0] == '~') if (!path.empty() && path[0] == '~')
s.replace(0, 1, env_home); path.replace(0, 1, env_home);
} }
} bool configure(int argc, char **argv)
bool ParseArguments(int argc, char **argv)
{ {
std::string bindings_path, config_path; std::string bindings_path, config_path;
po::options_description desc("Options"); po::options_description options("Options");
desc.add_options() options.add_options()
("host,h", po::value<std::string>()->default_value("localhost"), "connect to server at host") ("host,h", po::value<std::string>()->default_value("localhost"), "connect to server at host")
("port,p", po::value<int>()->default_value(6600), "connect to server at port") ("port,p", po::value<int>()->default_value(6600), "connect to server at port")
("config,c", po::value<std::string>(&config_path)->default_value("~/.ncmpcpp/config"), "specify configuration file") ("config,c", po::value<std::string>(&config_path)->default_value("~/.ncmpcpp/config"), "specify configuration file")
("bindigs,b", po::value<std::string>(&bindings_path)->default_value("~/.ncmpcpp/bindings"), "specify bindings file") ("bindigs,b", po::value<std::string>(&bindings_path)->default_value("~/.ncmpcpp/bindings"), "specify bindings file")
("screen,s", po::value<std::string>(), "specify the startup screen") ("screen,s", po::value<std::string>(), "specify initial screen")
("help,?", "show help message") ("help,?", "show help message")
("version,v", "display version information") ("version,v", "display version information")
; ;
@@ -62,11 +63,11 @@ bool ParseArguments(int argc, char **argv)
po::variables_map vm; po::variables_map vm;
try try
{ {
po::store(po::parse_command_line(argc, argv, desc), vm); po::store(po::parse_command_line(argc, argv, options), vm);
if (vm.count("help")) if (vm.count("help"))
{ {
cout << "Usage: " << argv[0] << " [options]...\n" << desc << "\n"; cout << "Usage: " << argv[0] << " [options]...\n" << options << "\n";
return false; return false;
} }
if (vm.count("version")) if (vm.count("version"))
@@ -119,30 +120,33 @@ bool ParseArguments(int argc, char **argv)
po::notify(vm); po::notify(vm);
// get home directory
env_home = getenv("HOME"); env_home = getenv("HOME");
if (env_home == nullptr) if (env_home == nullptr)
{ {
cerr << "Fatal error: HOME environment variable is not defined\n"; cerr << "Fatal error: HOME environment variable is not defined\n";
return false; return false;
} }
replace_tilda_with_home(config_path); expand_home(config_path);
replace_tilda_with_home(bindings_path); expand_home(bindings_path);
// read configuration // read configuration
Config.SetDefaults(); if (Config.read(config_path) == false)
Config.Read(config_path); exit(1);
Config.GenerateColumns();
// read bindings // read bindings
if (Bindings.read(bindings_path) == false) if (Bindings.read(bindings_path) == false)
return false; exit(1);
Bindings.generateDefaults(); Bindings.generateDefaults();
// create directories
boost::filesystem::create_directory(Config.ncmpcpp_directory);
boost::filesystem::create_directory(Config.lyrics_directory);
// try to get MPD connection details from environment variables // try to get MPD connection details from environment variables
// as they take precedence over these from the configuration. // as they take precedence over these from the configuration.
auto env_host = getenv("MPD_HOST"); auto env_host = getenv("MPD_HOST");
auto env_port = getenv("MPD_PORT"); auto env_port = getenv("MPD_PORT");
if (env_host != nullptr) if (env_host != nullptr)
Mpd.SetHostname(env_host); Mpd.SetHostname(env_host);
if (env_port != nullptr) if (env_port != nullptr)
@@ -150,10 +154,11 @@ bool ParseArguments(int argc, char **argv)
// if MPD connection details are provided as command line // if MPD connection details are provided as command line
// parameters, use them as their priority is the highest. // parameters, use them as their priority is the highest.
if (vm.count("host")) if (!vm["host"].defaulted())
Mpd.SetHostname(vm["host"].as<std::string>()); Mpd.SetHostname(vm["host"].as<std::string>());
if (vm.count("port")) if (!vm["port"].defaulted())
Mpd.SetPort(vm["port"].as<int>()); Mpd.SetPort(vm["port"].as<int>());
Mpd.SetTimeout(Config.mpd_connection_timeout);
// custom startup screen // custom startup screen
if (vm.count("screen")) if (vm.count("screen"))
@@ -162,15 +167,15 @@ bool ParseArguments(int argc, char **argv)
Config.startup_screen_type = stringtoStartupScreenType(screen); Config.startup_screen_type = stringtoStartupScreenType(screen);
if (Config.startup_screen_type == ScreenType::Unknown) if (Config.startup_screen_type == ScreenType::Unknown)
{ {
std::cerr << "Invalid screen: " << screen << "\n"; std::cerr << "Unknown screen: " << screen << "\n";
return false; exit(1);
} }
} }
} }
catch (std::exception &e) catch (std::exception &e)
{ {
cerr << "Error while parsing command line options: " << e.what() << "\n"; cerr << "Error while processing configuration: " << e.what() << "\n";
return false; exit(1);
} }
return true; return true;
} }

View File

@@ -18,9 +18,11 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/ ***************************************************************************/
#ifndef NCMPCPP_CMDARGS_H #ifndef NCMPCPP_CONFIGURATION_H
#define NCMPCPP_CMDARGS_H #define NCMPCPP_CONFIGURATION_H
bool ParseArguments(int argc, char **argv); void expand_home(std::string &path);
#endif // NCMPCPP_CMDARGS_H bool configure(int argc, char **argv);
#endif // NCMPCPP_CONFIGURATION_H

View File

@@ -392,10 +392,15 @@ void Display::Items(NC::Menu<MPD::Item> &menu, const ProxySongList &pl)
<< "]"; << "]";
break; break;
case MPD::itSong: case MPD::itSong:
if (!Config.columns_in_browser) switch (Config.browser_display_mode)
showSongs(menu, *item.song, pl, Config.song_list_format); {
else case DisplayMode::Classic:
showSongsInColumns(menu, *item.song, pl); showSongs(menu, *item.song, pl, Config.song_list_format);
break;
case DisplayMode::Columns:
showSongsInColumns(menu, *item.song, pl);
break;
}
break; break;
case MPD::itPlaylist: case MPD::itPlaylist:
menu << Config.browser_playlist_prefix menu << Config.browser_playlist_prefix
@@ -409,10 +414,15 @@ void Display::SEItems(NC::Menu<SEItem> &menu, const ProxySongList &pl)
const SEItem &si = menu.drawn()->value(); const SEItem &si = menu.drawn()->value();
if (si.isSong()) if (si.isSong())
{ {
if (!Config.columns_in_search_engine) switch (Config.search_engine_display_mode)
showSongs(menu, si.song(), pl, Config.song_list_format); {
else case DisplayMode::Classic:
showSongsInColumns(menu, si.song(), pl); showSongs(menu, si.song(), pl, Config.song_list_format);
break;
case DisplayMode::Columns:
showSongsInColumns(menu, si.song(), pl);
break;
}
} }
else else
menu << si.buffer(); menu << si.buffer();

134
src/enums.cpp Normal file
View File

@@ -0,0 +1,134 @@
/***************************************************************************
* Copyright (C) 2008-2014 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* 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 program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "enums.h"
std::ostream &operator<<(std::ostream &os, SpaceAddMode sam)
{
switch (sam)
{
case SpaceAddMode::AddRemove:
os << "add_remove";
break;
case SpaceAddMode::AlwaysAdd:
os << "always_add";
break;
}
return os;
}
std::istream &operator>>(std::istream &is, SpaceAddMode &sam)
{
std::string ssam;
is >> ssam;
if (ssam == "add_remove")
sam = SpaceAddMode::AddRemove;
else if (ssam == "always_add")
sam = SpaceAddMode::AlwaysAdd;
else
is.setstate(std::ios::failbit);
return is;
}
std::ostream &operator<<(std::ostream &os, SortMode sm)
{
switch (sm)
{
case SortMode::Name:
os << "name";
break;
case SortMode::ModificationTime:
os << "mtime";
break;
case SortMode::CustomFormat:
os << "format";
break;
}
return os;
}
std::istream &operator>>(std::istream &is, SortMode &sm)
{
std::string ssm;
is >> ssm;
if (ssm == "name")
sm = SortMode::Name;
else if (ssm == "mtime")
sm = SortMode::ModificationTime;
else if (ssm == "format")
sm = SortMode::CustomFormat;
else
is.setstate(std::ios::failbit);
return is;
}
std::ostream &operator<<(std::ostream &os, DisplayMode dm)
{
switch (dm)
{
case DisplayMode::Classic:
os << "classic";
break;
case DisplayMode::Columns:
os << "columns";
break;
}
return os;
}
std::istream &operator>>(std::istream &is, DisplayMode &dm)
{
std::string sdm;
is >> sdm;
if (sdm == "classic")
dm = DisplayMode::Classic;
else if (sdm == "columns")
dm = DisplayMode::Columns;
else
is.setstate(std::ios::failbit);
return is;
}
std::ostream &operator<<(std::ostream &os, Design ui)
{
switch (ui)
{
case Design::Classic:
os << "classic";
break;
case Design::Alternative:
os << "alternative";
break;
}
return os;
}
std::istream &operator>>(std::istream &is, Design &ui)
{
std::string sui;
is >> sui;
if (sui == "classic")
ui = Design::Classic;
else if (sui == "alternative")
ui = Design::Alternative;
else
is.setstate(std::ios::failbit);
return is;
}

42
src/enums.h Normal file
View File

@@ -0,0 +1,42 @@
/***************************************************************************
* Copyright (C) 2008-2014 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* 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 program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NCMPCPP_ENUMS_H
#define NCMPCPP_ENUMS_H
#include <iostream>
enum class SpaceAddMode { AddRemove, AlwaysAdd };
std::ostream &operator<<(std::ostream &os, SpaceAddMode sam);
std::istream &operator>>(std::istream &is, SpaceAddMode &sam);
enum class SortMode { Name, ModificationTime, CustomFormat };
std::ostream &operator<<(std::ostream &os, SortMode sm);
std::istream &operator>>(std::istream &is, SortMode &sm);
enum class DisplayMode { Classic, Columns };
std::ostream &operator<<(std::ostream &os, DisplayMode dm);
std::istream &operator>>(std::istream &is, DisplayMode &dm);
enum class Design { Classic, Alternative };
std::ostream &operator<<(std::ostream &os, Design ui);
std::istream &operator>>(std::istream &is, Design &ui);
#endif // NCMPCPP_ENUMS_H

View File

@@ -27,7 +27,7 @@
bool addSongToPlaylist(const MPD::Song &s, bool play, int position) bool addSongToPlaylist(const MPD::Song &s, bool play, int position)
{ {
bool result = false; bool result = false;
if (Config.ncmpc_like_songs_adding && myPlaylist->checkForSong(s)) if (Config.space_add_mode == SpaceAddMode::AddRemove && myPlaylist->checkForSong(s))
{ {
auto &w = myPlaylist->main(); auto &w = myPlaylist->main();
if (play) if (play)

View File

@@ -434,6 +434,14 @@ void stringToBuffer(const std::basic_string<CharT> &s, NC::BasicBuffer<CharT> &b
stringToBuffer(s.begin(), s.end(), buf); stringToBuffer(s.begin(), s.end(), buf);
} }
template <typename CharT>
NC::BasicBuffer<CharT> stringToBuffer(const std::basic_string<CharT> &s)
{
NC::BasicBuffer<CharT> result;
stringToBuffer(s, result);
return result;
}
template <typename T> void ShowTime(T &buf, size_t length, bool short_names) template <typename T> void ShowTime(T &buf, size_t length, bool short_names)
{ {
const unsigned MINUTE = 60; const unsigned MINUTE = 60;

View File

@@ -133,7 +133,7 @@ void Lyrics::switchTo()
std::wstring Lyrics::title() std::wstring Lyrics::title()
{ {
std::wstring result = L"Lyrics: "; std::wstring result = L"Lyrics: ";
result += Scroller(ToWString(itsSong.toString("{%a - %t}", ", ")), itsScrollBegin, COLS-result.length()-(Config.new_design ? 2 : Global::VolumeState.length())); result += Scroller(ToWString(itsSong.toString("{%a - %t}", ", ")), itsScrollBegin, COLS-result.length()-(Config.design == Design::Alternative ? 2 : Global::VolumeState.length()));
return result; return result;
} }
@@ -314,8 +314,6 @@ void Lyrics::Load()
itsFilename = GenerateFilename(itsSong); itsFilename = GenerateFilename(itsSong);
CreateDir(Config.lyrics_directory);
w.clear(); w.clear();
w.reset(); w.reset();

View File

@@ -34,7 +34,7 @@
#include "bindings.h" #include "bindings.h"
#include "browser.h" #include "browser.h"
#include "charset.h" #include "charset.h"
#include "cmdargs.h" #include "configuration.h"
#include "global.h" #include "global.h"
#include "error.h" #include "error.h"
#include "helpers.h" #include "helpers.h"
@@ -101,12 +101,9 @@ int main(int argc, char **argv)
std::setlocale(LC_ALL, ""); std::setlocale(LC_ALL, "");
std::locale::global(Charset::internalLocale()); std::locale::global(Charset::internalLocale());
if (!ParseArguments(argc, argv)) if (!configure(argc, argv))
return 0; return 0;
Mpd.SetTimeout(Config.mpd_connection_timeout);
CreateDir(Config.ncmpcpp_directory);
// always execute these commands, even if ncmpcpp use exit function // always execute these commands, even if ncmpcpp use exit function
atexit(do_at_exit); atexit(do_at_exit);
@@ -122,7 +119,7 @@ int main(int argc, char **argv)
if (!Config.titles_visibility) if (!Config.titles_visibility)
wattron(stdscr, COLOR_PAIR(int(Config.main_color))); wattron(stdscr, COLOR_PAIR(int(Config.main_color)));
if (Config.new_design) if (Config.design == Design::Alternative)
Config.statusbar_visibility = 0; Config.statusbar_visibility = 0;
Actions::setWindowsDimensions(); Actions::setWindowsDimensions();
@@ -130,7 +127,7 @@ int main(int argc, char **argv)
Actions::initializeScreens(); Actions::initializeScreens();
wHeader = new NC::Window(0, 0, COLS, Actions::HeaderHeight, "", Config.header_color, NC::Border::None); wHeader = new NC::Window(0, 0, COLS, Actions::HeaderHeight, "", Config.header_color, NC::Border::None);
if (Config.header_visibility || Config.new_design) if (Config.header_visibility || Config.design == Design::Alternative)
wHeader->display(); wHeader->display();
wFooter = new NC::Window(0, Actions::FooterStartY, COLS, Actions::FooterHeight, "", Config.statusbar_color, NC::Border::None); wFooter = new NC::Window(0, Actions::FooterStartY, COLS, Actions::FooterHeight, "", Config.statusbar_color, NC::Border::None);
@@ -140,14 +137,14 @@ int main(int argc, char **argv)
// initialize global timer // initialize global timer
Timer = boost::posix_time::microsec_clock::local_time(); Timer = boost::posix_time::microsec_clock::local_time();
// go to playlist // initialize playlist
myPlaylist->switchTo(); myPlaylist->switchTo();
// local variables // local variables
Key input(0, Key::Standard); Key input(0, Key::Standard);
boost::posix_time::ptime past = boost::posix_time::from_time_t(0); auto past = boost::posix_time::from_time_t(0);
// local variables end
/// enable mouse
mouseinterval(0); mouseinterval(0);
if (Config.mouse_support) if (Config.mouse_support)
mousemask(ALL_MOUSE_EVENTS, 0); mousemask(ALL_MOUSE_EVENTS, 0);
@@ -240,7 +237,7 @@ int main(int argc, char **argv)
} }
catch (OutOfBounds &e) catch (OutOfBounds &e)
{ {
Statusbar::print(e.errorMessage()); Statusbar::printf("Error: %1%", e.errorMessage());
} }
if (myScreen == myPlaylist) if (myScreen == myPlaylist)

View File

@@ -53,16 +53,21 @@ bool playlistEntryMatcher(const boost::regex &rx, const MPD::Song &s);
Playlist::Playlist() Playlist::Playlist()
: itsTotalLength(0), itsRemainingTime(0), itsScrollBegin(0), m_old_playlist_version(0) : itsTotalLength(0), itsRemainingTime(0), itsScrollBegin(0), m_old_playlist_version(0)
{ {
w = NC::Menu<MPD::Song>(0, MainStartY, COLS, MainHeight, Config.columns_in_playlist && Config.titles_visibility ? Display::Columns(COLS) : "", Config.main_color, NC::Border::None); w = NC::Menu<MPD::Song>(0, MainStartY, COLS, MainHeight, Config.playlist_display_mode == DisplayMode::Columns && Config.titles_visibility ? Display::Columns(COLS) : "", Config.main_color, NC::Border::None);
w.cyclicScrolling(Config.use_cyclic_scrolling); w.cyclicScrolling(Config.use_cyclic_scrolling);
w.centeredCursor(Config.centered_cursor); w.centeredCursor(Config.centered_cursor);
w.setHighlightColor(Config.main_highlight_color); w.setHighlightColor(Config.main_highlight_color);
w.setSelectedPrefix(Config.selected_item_prefix); w.setSelectedPrefix(Config.selected_item_prefix);
w.setSelectedSuffix(Config.selected_item_suffix); w.setSelectedSuffix(Config.selected_item_suffix);
if (Config.columns_in_playlist) switch (Config.playlist_display_mode)
w.setItemDisplayer(boost::bind(Display::SongsInColumns, _1, proxySongList())); {
else case DisplayMode::Classic:
w.setItemDisplayer(boost::bind(Display::Songs, _1, proxySongList(), Config.song_list_format)); w.setItemDisplayer(boost::bind(Display::Songs, _1, proxySongList(), Config.song_list_format));
break;
case DisplayMode::Columns:
w.setItemDisplayer(boost::bind(Display::SongsInColumns, _1, proxySongList()));
break;
}
} }
void Playlist::switchTo() void Playlist::switchTo()
@@ -80,10 +85,17 @@ void Playlist::resize()
w.resize(width, MainHeight); w.resize(width, MainHeight);
w.moveTo(x_offset, MainStartY); w.moveTo(x_offset, MainStartY);
if (Config.columns_in_playlist && Config.titles_visibility) switch (Config.playlist_display_mode)
w.setTitle(Display::Columns(w.getWidth())); {
else case DisplayMode::Columns:
w.setTitle(""); if (Config.titles_visibility)
{
w.setTitle(Display::Columns(w.getWidth()));
break;
}
case DisplayMode::Classic:
w.setTitle("");
}
hasToBeResized = 0; hasToBeResized = 0;
} }
@@ -93,7 +105,7 @@ std::wstring Playlist::title()
std::wstring result = L"Playlist "; std::wstring result = L"Playlist ";
if (ReloadTotalLength || ReloadRemaining) if (ReloadTotalLength || ReloadRemaining)
itsBufferedStats = TotalLength(); itsBufferedStats = TotalLength();
result += Scroller(ToWString(itsBufferedStats), itsScrollBegin, COLS-result.length()-(Config.new_design ? 2 : Global::VolumeState.length())); result += Scroller(ToWString(itsBufferedStats), itsScrollBegin, COLS-result.length()-(Config.design == Design::Alternative ? 2 : Global::VolumeState.length()));
return result; return result;
} }
@@ -373,10 +385,14 @@ namespace {//
std::string songToString(const MPD::Song &s) std::string songToString(const MPD::Song &s)
{ {
std::string result; std::string result;
if (Config.columns_in_playlist) switch (Config.playlist_display_mode)
result = s.toString(Config.song_in_columns_to_string_format, Config.tags_separator); {
else case DisplayMode::Classic:
result = s.toString(Config.song_list_format_dollar_free, Config.tags_separator); result = s.toString(Config.song_list_format_dollar_free, Config.tags_separator);
break;
case DisplayMode::Columns:
result = s.toString(Config.song_in_columns_to_string_format, Config.tags_separator);
}
return result; return result;
} }

View File

@@ -77,10 +77,15 @@ PlaylistEditor::PlaylistEditor()
Content.centeredCursor(Config.centered_cursor); Content.centeredCursor(Config.centered_cursor);
Content.setSelectedPrefix(Config.selected_item_prefix); Content.setSelectedPrefix(Config.selected_item_prefix);
Content.setSelectedSuffix(Config.selected_item_suffix); Content.setSelectedSuffix(Config.selected_item_suffix);
if (Config.columns_in_playlist_editor) switch (Config.playlist_editor_display_mode)
Content.setItemDisplayer(boost::bind(Display::SongsInColumns, _1, contentProxyList())); {
else case DisplayMode::Classic:
Content.setItemDisplayer(boost::bind(Display::Songs, _1, contentProxyList(), Config.song_list_format)); Content.setItemDisplayer(boost::bind(Display::Songs, _1, contentProxyList(), Config.song_list_format));
break;
case DisplayMode::Columns:
Content.setItemDisplayer(boost::bind(Display::SongsInColumns, _1, contentProxyList()));
break;
}
w = &Playlists; w = &Playlists;
} }
@@ -550,10 +555,15 @@ namespace {//
std::string SongToString(const MPD::Song &s) std::string SongToString(const MPD::Song &s)
{ {
std::string result; std::string result;
if (Config.columns_in_playlist_editor) switch (Config.playlist_display_mode)
result = s.toString(Config.song_in_columns_to_string_format, Config.tags_separator); {
else case DisplayMode::Classic:
result = s.toString(Config.song_list_format_dollar_free, Config.tags_separator); result = s.toString(Config.song_list_format_dollar_free, Config.tags_separator);
break;
case DisplayMode::Columns:
result = s.toString(Config.song_in_columns_to_string_format, Config.tags_separator);
break;
}
return result; return result;
} }

View File

@@ -112,8 +112,10 @@ BaseScreen *toScreen(ScreenType st)
# endif // ENABLE_CLOCK # endif // ENABLE_CLOCK
case ScreenType::Help: case ScreenType::Help:
return myHelp; return myHelp;
# ifdef HAVE_CURL_CURL_H
case ScreenType::Lastfm: case ScreenType::Lastfm:
return myLastfm; return myLastfm;
# endif // HAVE_CURL_CURL_H
case ScreenType::Lyrics: case ScreenType::Lyrics:
return myLyrics; return myLyrics;
case ScreenType::MediaLibrary: case ScreenType::MediaLibrary:

View File

@@ -119,7 +119,17 @@ void SearchEngine::resize()
getWindowResizeParams(x_offset, width); getWindowResizeParams(x_offset, width);
w.resize(width, MainHeight); w.resize(width, MainHeight);
w.moveTo(x_offset, MainStartY); w.moveTo(x_offset, MainStartY);
w.setTitle(Config.columns_in_search_engine && Config.titles_visibility ? Display::Columns(w.getWidth()) : ""); switch (Config.search_engine_display_mode)
{
case DisplayMode::Columns:
if (Config.titles_visibility)
{
w.setTitle(Display::Columns(w.getWidth()));
break;
}
case DisplayMode::Classic:
w.setTitle("");
}
hasToBeResized = 0; hasToBeResized = 0;
} }
@@ -175,7 +185,7 @@ void SearchEngine::enterPressed()
Search(); Search();
if (w.back().value().isSong()) if (w.back().value().isSong())
{ {
if (Config.columns_in_search_engine) if (Config.search_engine_display_mode == DisplayMode::Columns)
w.setTitle(Config.titles_visibility ? Display::Columns(w.getWidth()) : ""); w.setTitle(Config.titles_visibility ? Display::Columns(w.getWidth()) : "");
size_t found = w.size()-SearchEngine::StaticOptions; size_t found = w.size()-SearchEngine::StaticOptions;
found += 3; // don't count options inserted below found += 3; // don't count options inserted below
@@ -616,10 +626,15 @@ std::string SEItemToString(const SEItem &ei)
std::string result; std::string result;
if (ei.isSong()) if (ei.isSong())
{ {
if (Config.columns_in_search_engine) switch (Config.search_engine_display_mode)
result = ei.song().toString(Config.song_in_columns_to_string_format, Config.tags_separator); {
else case DisplayMode::Classic:
result = ei.song().toString(Config.song_list_format_dollar_free, Config.tags_separator); result = ei.song().toString(Config.song_list_format_dollar_free, Config.tags_separator);
break;
case DisplayMode::Columns:
result = ei.song().toString(Config.song_in_columns_to_string_format, Config.tags_separator);
break;
}
} }
else else
result = ei.buffer().str(); result = ei.buffer().str();

File diff suppressed because it is too large Load Diff

View File

@@ -26,12 +26,11 @@
#include <cassert> #include <cassert>
#include <vector> #include <vector>
#include <mpd/client.h> #include <mpd/client.h>
#include "actions.h"
#include "enums.h"
#include "screen_type.h" #include "screen_type.h"
#include "strbuffer.h" #include "strbuffer.h"
enum SortMode { smName, smMTime, smCustomFormat };
struct Column struct Column
{ {
Column() : stretch_limit(-1), right_alignment(0), display_empty_tag(1) { } Column() : stretch_limit(-1), right_alignment(0), display_empty_tag(1) { }
@@ -48,25 +47,20 @@ struct Column
struct Configuration struct Configuration
{ {
Configuration(); Configuration()
: playlist_disable_highlight_delay(0), visualizer_sync_interval(0)
{ }
const std::string &GetHomeDirectory(); bool read(const std::string &config_path);
void CheckForCommandLineConfigFilePath(char **argv, int argc);
void SetDefaults();
void Read(const std::string& config_path);
void GenerateColumns();
std::string ncmpcpp_directory; std::string ncmpcpp_directory;
std::string lyrics_directory; std::string lyrics_directory;
std::string mpd_host;
std::string mpd_music_dir; std::string mpd_music_dir;
std::string visualizer_fifo_path; std::string visualizer_fifo_path;
std::string visualizer_output_name; std::string visualizer_output_name;
std::string empty_tag; std::string empty_tag;
std::string tags_separator; std::string tags_separator;
std::string song_list_columns_format;
std::string song_list_format; std::string song_list_format;
std::string song_list_format_dollar_free; std::string song_list_format_dollar_free;
std::string song_status_format; std::string song_status_format;
@@ -89,6 +83,11 @@ struct Configuration
std::vector<Column> columns; std::vector<Column> columns;
DisplayMode playlist_display_mode;
DisplayMode browser_display_mode;
DisplayMode search_engine_display_mode;
DisplayMode playlist_editor_display_mode;
NC::Buffer browser_playlist_prefix; NC::Buffer browser_playlist_prefix;
NC::Buffer selected_item_prefix; NC::Buffer selected_item_prefix;
NC::Buffer selected_item_suffix; NC::Buffer selected_item_suffix;
@@ -115,16 +114,16 @@ struct Configuration
NC::Border window_border; NC::Border window_border;
NC::Border active_window_border; NC::Border active_window_border;
Design design;
SpaceAddMode space_add_mode;
mpd_tag_type media_lib_primary_tag; mpd_tag_type media_lib_primary_tag;
bool colors_enabled; bool colors_enabled;
bool playlist_show_remaining_time; bool playlist_show_remaining_time;
bool playlist_shorten_total_times; bool playlist_shorten_total_times;
bool playlist_separate_albums; bool playlist_separate_albums;
bool columns_in_playlist;
bool columns_in_browser;
bool columns_in_search_engine;
bool columns_in_playlist_editor;
bool set_window_title; bool set_window_title;
bool header_visibility; bool header_visibility;
bool header_text_scrolling; bool header_text_scrolling;
@@ -135,7 +134,6 @@ struct Configuration
bool autocenter_mode; bool autocenter_mode;
bool wrapped_search; bool wrapped_search;
bool space_selects; bool space_selects;
bool ncmpc_like_songs_adding;
bool incremental_seeking; bool incremental_seeking;
bool now_playing_lyrics; bool now_playing_lyrics;
bool fetch_lyrics_in_background; bool fetch_lyrics_in_background;
@@ -150,10 +148,9 @@ struct Configuration
bool block_search_constraints_change; bool block_search_constraints_change;
bool use_console_editor; bool use_console_editor;
bool use_cyclic_scrolling; bool use_cyclic_scrolling;
bool ask_before_clearing_main_playlist; bool ask_before_clearing_playlists;
bool mouse_support; bool mouse_support;
bool mouse_list_scroll_whole_page; bool mouse_list_scroll_whole_page;
bool new_design;
bool visualizer_use_wave; bool visualizer_use_wave;
bool visualizer_in_stereo; bool visualizer_in_stereo;
bool media_library_sort_by_mtime; bool media_library_sort_by_mtime;
@@ -165,19 +162,17 @@ struct Configuration
bool allow_for_physical_item_deletion; bool allow_for_physical_item_deletion;
bool progressbar_boldness; bool progressbar_boldness;
int mpd_port; unsigned mpd_connection_timeout;
int mpd_connection_timeout; unsigned crossfade_time;
int crossfade_time; unsigned seek_time;
int seek_time; unsigned volume_change_step;
int volume_change_step; unsigned message_delay_time;
int message_delay_time; unsigned lyrics_db;
int lyrics_db;
boost::regex::flag_type regex_type;
unsigned lines_scrolled; unsigned lines_scrolled;
unsigned search_engine_default_search_mode; unsigned search_engine_default_search_mode;
boost::regex::flag_type regex_type;
boost::posix_time::seconds playlist_disable_highlight_delay; boost::posix_time::seconds playlist_disable_highlight_delay;
boost::posix_time::seconds visualizer_sync_interval; boost::posix_time::seconds visualizer_sync_interval;
@@ -189,19 +184,12 @@ struct Configuration
size_t now_playing_suffix_length; size_t now_playing_suffix_length;
ScreenType startup_screen_type; ScreenType startup_screen_type;
std::list<ScreenType> screens_seq; std::list<ScreenType> screen_sequence;
SortMode browser_sort_mode; SortMode browser_sort_mode;
private:
void MakeProperPath(std::string &dir);
std::string home_directory;
}; };
extern Configuration Config; extern Configuration Config;
void CreateDir(const std::string &dir);
#endif // NCMPCPP_SETTINGS_H #endif // NCMPCPP_SETTINGS_H

View File

@@ -288,7 +288,7 @@ std::string Song::ShowTime(unsigned length)
return result; return result;
} }
bool MPD::Song::isFormatOk(const std::string &type, const std::string &fmt) void MPD::Song::validateFormat(const std::string &fmt)
{ {
int braces = 0; int braces = 0;
for (std::string::const_iterator it = fmt.begin(); it != fmt.end(); ++it) for (std::string::const_iterator it = fmt.begin(); it != fmt.end(); ++it)
@@ -299,22 +299,17 @@ bool MPD::Song::isFormatOk(const std::string &type, const std::string &fmt)
--braces; --braces;
} }
if (braces) if (braces)
{ throw std::runtime_error("number of opening and closing braces is not equal");
std::cerr << type << ": number of opening and closing braces does not equal\n";
return false;
}
for (size_t i = fmt.find('%'); i != std::string::npos; i = fmt.find('%', i)) for (size_t i = fmt.find('%'); i != std::string::npos; i = fmt.find('%', i))
{ {
if (isdigit(fmt[++i])) if (isdigit(fmt[++i]))
while (isdigit(fmt[++i])) { } while (isdigit(fmt[++i])) { }
if (!charToGetFunction(fmt[i])) if (!charToGetFunction(fmt[i]))
{ throw std::runtime_error(
std::cerr << type << ": invalid character at position " << boost::lexical_cast<std::string>(i+1) << ": '" << fmt[i] << "'\n"; (boost::format("invalid character at position %1%: %2%") % (i+1) % fmt[i]).str()
return false; );
}
} }
return true;
} }
std::string Song::ParseFormat(std::string::const_iterator &it, const std::string &tags_separator, std::string Song::ParseFormat(std::string::const_iterator &it, const std::string &tags_separator,

View File

@@ -80,7 +80,7 @@ struct Song
bool operator!=(const Song &rhs) const { return m_hash != rhs.m_hash; } bool operator!=(const Song &rhs) const { return m_hash != rhs.m_hash; }
static std::string ShowTime(unsigned length); static std::string ShowTime(unsigned length);
static bool isFormatOk(const std::string &type, const std::string &fmt); static void validateFormat(const std::string &fmt);
static const char FormatEscapeCharacter = 1; static const char FormatEscapeCharacter = 1;

View File

@@ -80,19 +80,19 @@ std::string playerStateToString(MPD::PlayerState ps)
result = "[unknown]"; result = "[unknown]";
break; break;
case MPD::psPlay: case MPD::psPlay:
if (Config.new_design) if (Config.design == Design::Alternative)
result = "[playing]"; result = "[playing]";
else else
result = "Playing: "; result = "Playing: ";
break; break;
case MPD::psPause: case MPD::psPause:
if (Config.new_design) if (Config.design == Design::Alternative)
result = "[paused] "; result = "[paused] ";
else else
result = "[Paused] "; result = "[Paused] ";
break; break;
case MPD::psStop: case MPD::psStop:
if (Config.new_design) if (Config.design == Design::Alternative)
result = "[stopped]"; result = "[stopped]";
break; break;
default: default:
@@ -337,7 +337,7 @@ void Status::Changes::playerState()
if (Progressbar::isUnlocked()) if (Progressbar::isUnlocked())
Progressbar::draw(0, 0); Progressbar::draw(0, 0);
Playlist::ReloadRemaining = true; Playlist::ReloadRemaining = true;
if (Config.new_design) if (Config.design == Design::Alternative)
{ {
*wHeader << NC::XY(0, 0) << wclrtoeol << NC::XY(0, 1) << wclrtoeol; *wHeader << NC::XY(0, 0) << wclrtoeol << NC::XY(0, 1) << wclrtoeol;
mixer(); mixer();
@@ -358,7 +358,7 @@ void Status::Changes::playerState()
# endif // ENABLE_VISUALIZER # endif // ENABLE_VISUALIZER
std::string state = playerStateToString(State::player()); std::string state = playerStateToString(State::player());
if (Config.new_design) if (Config.design == Design::Alternative)
{ {
*wHeader << NC::XY(0, 1) << NC::Format::Bold << state << NC::Format::NoBold; *wHeader << NC::XY(0, 1) << NC::Format::Bold << state << NC::Format::NoBold;
wHeader->refresh(); wHeader->refresh();
@@ -428,85 +428,88 @@ void Status::Changes::elapsedTime(bool update_elapsed)
drawTitle(np); drawTitle(np);
std::string tracklength; std::string tracklength;
if (Config.new_design) switch (Config.design)
{ {
if (Config.display_remaining_time) case Design::Classic:
{ if (Statusbar::isUnlocked() && Config.statusbar_visibility)
tracklength = "-"; {
tracklength += MPD::Song::ShowTime(st.totalTime()-st.elapsedTime()); if (Config.display_bitrate && st.kbps())
} {
else tracklength += " [";
tracklength = MPD::Song::ShowTime(st.elapsedTime()); tracklength += boost::lexical_cast<std::string>(st.kbps());
if (st.totalTime()) tracklength += " kbps]";
{ }
tracklength += "/"; tracklength += " [";
tracklength += MPD::Song::ShowTime(st.totalTime()); if (st.totalTime())
} {
// bitrate here doesn't look good, but it can be moved somewhere else later if (Config.display_remaining_time)
if (Config.display_bitrate && st.kbps()) {
{ tracklength += "-";
tracklength += " "; tracklength += MPD::Song::ShowTime(st.totalTime()-st.elapsedTime());
tracklength += boost::lexical_cast<std::string>(st.kbps()); }
tracklength += " kbps"; else
} tracklength += MPD::Song::ShowTime(st.elapsedTime());
tracklength += "/";
NC::WBuffer first, second; tracklength += MPD::Song::ShowTime(st.totalTime());
stringToBuffer(ToWString(Charset::utf8ToLocale(np.toString(Config.new_header_first_line, Config.tags_separator, "$"))), first); tracklength += "]";
stringToBuffer(ToWString(Charset::utf8ToLocale(np.toString(Config.new_header_second_line, Config.tags_separator, "$"))), second); }
else
size_t first_len = wideLength(first.str()); {
size_t first_margin = (std::max(tracklength.length()+1, VolumeState.length()))*2; tracklength += MPD::Song::ShowTime(st.elapsedTime());
size_t first_start = first_len < COLS-first_margin ? (COLS-first_len)/2 : tracklength.length()+1; tracklength += "]";
}
size_t second_len = wideLength(second.str()); NC::WBuffer np_song;
size_t second_margin = (std::max(ps.length(), size_t(8))+1)*2; stringToBuffer(ToWString(Charset::utf8ToLocale(np.toString(Config.song_status_format, Config.tags_separator, "$"))), np_song);
size_t second_start = second_len < COLS-second_margin ? (COLS-second_len)/2 : ps.length()+1; *wFooter << NC::XY(0, 1) << wclrtoeol << NC::Format::Bold << ps << NC::Format::NoBold;
writeCyclicBuffer(np_song, *wFooter, playing_song_scroll_begin, wFooter->getWidth()-ps.length()-tracklength.length(), L" ** ");
if (!Global::SeekingInProgress) *wFooter << NC::Format::Bold << NC::XY(wFooter->getWidth()-tracklength.length(), 1) << tracklength << NC::Format::NoBold;
*wHeader << NC::XY(0, 0) << wclrtoeol << tracklength; }
*wHeader << NC::XY(first_start, 0); break;
writeCyclicBuffer(first, *wHeader, first_line_scroll_begin, COLS-tracklength.length()-VolumeState.length()-1, L" ** "); case Design::Alternative:
*wHeader << NC::XY(0, 1) << wclrtoeol << NC::Format::Bold << ps << NC::Format::NoBold;
*wHeader << NC::XY(second_start, 1);
writeCyclicBuffer(second, *wHeader, second_line_scroll_begin, COLS-ps.length()-8-2, L" ** ");
*wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << Config.volume_color << VolumeState << NC::Color::End;
flags();
}
else if (Statusbar::isUnlocked() && Config.statusbar_visibility)
{
if (Config.display_bitrate && st.kbps())
{
tracklength += " [";
tracklength += boost::lexical_cast<std::string>(st.kbps());
tracklength += " kbps]";
}
tracklength += " [";
if (st.totalTime())
{
if (Config.display_remaining_time) if (Config.display_remaining_time)
{ {
tracklength += "-"; tracklength = "-";
tracklength += MPD::Song::ShowTime(st.totalTime()-st.elapsedTime()); tracklength += MPD::Song::ShowTime(st.totalTime()-st.elapsedTime());
} }
else else
tracklength += MPD::Song::ShowTime(st.elapsedTime()); tracklength = MPD::Song::ShowTime(st.elapsedTime());
tracklength += "/"; if (st.totalTime())
tracklength += MPD::Song::ShowTime(st.totalTime()); {
tracklength += "]"; tracklength += "/";
} tracklength += MPD::Song::ShowTime(st.totalTime());
else }
{ // bitrate here doesn't look good, but it can be moved somewhere else later
tracklength += MPD::Song::ShowTime(st.elapsedTime()); if (Config.display_bitrate && st.kbps())
tracklength += "]"; {
} tracklength += " ";
NC::WBuffer np_song; tracklength += boost::lexical_cast<std::string>(st.kbps());
stringToBuffer(ToWString(Charset::utf8ToLocale(np.toString(Config.song_status_format, Config.tags_separator, "$"))), np_song); tracklength += " kbps";
*wFooter << NC::XY(0, 1) << wclrtoeol << NC::Format::Bold << ps << NC::Format::NoBold; }
writeCyclicBuffer(np_song, *wFooter, playing_song_scroll_begin, wFooter->getWidth()-ps.length()-tracklength.length(), L" ** ");
*wFooter << NC::Format::Bold << NC::XY(wFooter->getWidth()-tracklength.length(), 1) << tracklength << NC::Format::NoBold; NC::WBuffer first, second;
stringToBuffer(ToWString(Charset::utf8ToLocale(np.toString(Config.new_header_first_line, Config.tags_separator, "$"))), first);
stringToBuffer(ToWString(Charset::utf8ToLocale(np.toString(Config.new_header_second_line, Config.tags_separator, "$"))), second);
size_t first_len = wideLength(first.str());
size_t first_margin = (std::max(tracklength.length()+1, VolumeState.length()))*2;
size_t first_start = first_len < COLS-first_margin ? (COLS-first_len)/2 : tracklength.length()+1;
size_t second_len = wideLength(second.str());
size_t second_margin = (std::max(ps.length(), size_t(8))+1)*2;
size_t second_start = second_len < COLS-second_margin ? (COLS-second_len)/2 : ps.length()+1;
if (!Global::SeekingInProgress)
*wHeader << NC::XY(0, 0) << wclrtoeol << tracklength;
*wHeader << NC::XY(first_start, 0);
writeCyclicBuffer(first, *wHeader, first_line_scroll_begin, COLS-tracklength.length()-VolumeState.length()-1, L" ** ");
*wHeader << NC::XY(0, 1) << wclrtoeol << NC::Format::Bold << ps << NC::Format::NoBold;
*wHeader << NC::XY(second_start, 1);
writeCyclicBuffer(second, *wHeader, second_line_scroll_begin, COLS-ps.length()-8-2, L" ** ");
*wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << Config.volume_color << VolumeState << NC::Color::End;
flags();
} }
if (Progressbar::isUnlocked()) if (Progressbar::isUnlocked())
Progressbar::draw(st.elapsedTime(), st.totalTime()); Progressbar::draw(st.elapsedTime(), st.totalTime());
@@ -557,69 +560,78 @@ void Status::Changes::dbUpdateState(bool show_msg)
void Status::Changes::flags() void Status::Changes::flags()
{ {
if (!Config.header_visibility && !Config.new_design) if (!Config.header_visibility && Config.design == Design::Classic)
return; return;
std::string switch_state; std::string switch_state;
if (Config.new_design) switch (Config.design)
{ {
switch_state += '['; case Design::Classic:
switch_state += m_repeat ? m_repeat : '-'; if (m_repeat)
switch_state += m_random ? m_random : '-'; switch_state += m_repeat;
switch_state += m_single ? m_single : '-'; if (m_random)
switch_state += m_consume ? m_consume : '-'; switch_state += m_random;
switch_state += m_crossfade ? m_crossfade : '-'; if (m_single)
switch_state += m_db_updating ? m_db_updating : '-'; switch_state += m_single;
switch_state += ']'; if (m_consume)
*wHeader << NC::XY(COLS-switch_state.length(), 1) << NC::Format::Bold << Config.state_flags_color << switch_state << NC::Color::End << NC::Format::NoBold; switch_state += m_consume;
if (Config.new_design && !Config.header_visibility) // in this case also draw separator if (m_crossfade)
{ switch_state += m_crossfade;
*wHeader << NC::Format::Bold << NC::Color::Black; if (m_db_updating)
mvwhline(wHeader->raw(), 2, 0, 0, COLS); switch_state += m_db_updating;
*wHeader << NC::Color::End << NC::Format::NoBold;
}
wHeader->refresh();
}
else
{
if (m_repeat)
switch_state += m_repeat;
if (m_random)
switch_state += m_random;
if (m_single)
switch_state += m_single;
if (m_consume)
switch_state += m_consume;
if (m_crossfade)
switch_state += m_crossfade;
if (m_db_updating)
switch_state += m_db_updating;
// this is done by raw ncurses because creating another // this is done by raw ncurses because creating another
// window only for handling this is quite silly // window only for handling this is quite silly
attrset(A_BOLD|COLOR_PAIR(int(Config.state_line_color))); attrset(A_BOLD|COLOR_PAIR(int(Config.state_line_color)));
mvhline(1, 0, 0, COLS); mvhline(1, 0, 0, COLS);
if (!switch_state.empty()) if (!switch_state.empty())
{ {
mvprintw(1, COLS-switch_state.length()-3, "["); mvprintw(1, COLS-switch_state.length()-3, "[");
attroff(COLOR_PAIR(int(Config.state_line_color))); attroff(COLOR_PAIR(int(Config.state_line_color)));
attron(COLOR_PAIR(int(Config.state_flags_color))); attron(COLOR_PAIR(int(Config.state_flags_color)));
mvprintw(1, COLS-switch_state.length()-2, "%s", switch_state.c_str()); mvprintw(1, COLS-switch_state.length()-2, "%s", switch_state.c_str());
attroff(COLOR_PAIR(int(Config.state_flags_color))); attroff(COLOR_PAIR(int(Config.state_flags_color)));
attron(COLOR_PAIR(int(Config.state_line_color))); attron(COLOR_PAIR(int(Config.state_line_color)));
mvprintw(1, COLS-2, "]"); mvprintw(1, COLS-2, "]");
} }
attroff(A_BOLD|COLOR_PAIR(int(Config.state_line_color))); attroff(A_BOLD|COLOR_PAIR(int(Config.state_line_color)));
refresh(); refresh();
break;
case Design::Alternative:
switch_state += '[';
switch_state += m_repeat ? m_repeat : '-';
switch_state += m_random ? m_random : '-';
switch_state += m_single ? m_single : '-';
switch_state += m_consume ? m_consume : '-';
switch_state += m_crossfade ? m_crossfade : '-';
switch_state += m_db_updating ? m_db_updating : '-';
switch_state += ']';
*wHeader << NC::XY(COLS-switch_state.length(), 1) << NC::Format::Bold << Config.state_flags_color << switch_state << NC::Color::End << NC::Format::NoBold;
if (!Config.header_visibility) // in this case also draw separator
{
*wHeader << NC::Format::Bold << NC::Color::Black;
mvwhline(wHeader->raw(), 2, 0, 0, COLS);
*wHeader << NC::Color::End << NC::Format::NoBold;
}
wHeader->refresh();
break;
} }
} }
void Status::Changes::mixer() void Status::Changes::mixer()
{ {
if (!Config.display_volume_level || (!Config.header_visibility && !Config.new_design)) if (!Config.display_volume_level || (!Config.header_visibility && Config.design == Design::Classic))
return; return;
VolumeState = Config.new_design ? " Vol: " : " Volume: "; switch (Config.design)
{
case Design::Classic:
VolumeState = " " "Volume" ": ";
break;
case Design::Alternative:
VolumeState = " " "Vol" ": ";
break;
}
if (State::volume() < 0) if (State::volume() < 0)
VolumeState += "n/a"; VolumeState += "n/a";
else else

View File

@@ -106,10 +106,15 @@ void Statusbar::unlock()
} }
if (Status::State::player() == MPD::psStop) if (Status::State::player() == MPD::psStop)
{ {
if (Config.new_design) switch (Config.design)
Progressbar::draw(Status::State::elapsedTime(), myPlaylist->currentSongLength()); {
else case Design::Classic:
put() << wclrtoeol; put() << wclrtoeol;
break;
case Design::Alternative:
Progressbar::draw(Status::State::elapsedTime(), myPlaylist->currentSongLength());
break;
}
wFooter->refresh(); wFooter->refresh();
} }
} }
@@ -134,10 +139,15 @@ void Statusbar::tryRedraw()
if (Status::State::player() != MPD::psStop && !statusbarBlockUpdate && !progressbarBlockUpdate) if (Status::State::player() != MPD::psStop && !statusbarBlockUpdate && !progressbarBlockUpdate)
{ {
if (Config.new_design) switch (Config.design)
Progressbar::draw(Status::State::elapsedTime(), myPlaylist->currentSongLength()); {
else case Design::Classic:
Status::Changes::elapsedTime(false); Status::Changes::elapsedTime(false);
break;
case Design::Alternative:
Progressbar::draw(Status::State::elapsedTime(), myPlaylist->currentSongLength());
break;
}
wFooter->refresh(); wFooter->refresh();
} }
} }

View File

@@ -63,18 +63,19 @@ template <typename CharT> class BasicBuffer
return m_id < rhs.m_id; return m_id < rhs.m_id;
} }
friend Window &operator<<(Window &w, const Property &p) template <typename OutputStreamT>
friend OutputStreamT &operator<<(OutputStreamT &os, const Property &p)
{ {
switch (p.m_type) switch (p.m_type)
{ {
case Type::Color: case Type::Color:
w << p.m_color; os << p.m_color;
break; break;
case Type::Format: case Type::Format:
w << p.m_format; os << p.m_format;
break; break;
} }
return w; return os;
} }
private: private:
@@ -89,7 +90,11 @@ public:
typedef std::basic_string<CharT> StringType; typedef std::basic_string<CharT> StringType;
typedef std::set<Property> Properties; typedef std::set<Property> Properties;
BasicBuffer() { } template <typename... Args>
BasicBuffer(Args... args)
{
construct(std::forward<Args>(args)...);
}
const StringType &str() const { return m_string; } const StringType &str() const { return m_string; }
const Properties &properties() const { return m_properties; } const Properties &properties() const { return m_properties; }
@@ -183,6 +188,14 @@ public:
} }
private: private:
void construct() { }
template <typename ArgT, typename... Args>
void construct(ArgT &&arg, Args... args)
{
*this << std::forward<ArgT>(arg);
construct(std::forward<Args>(args)...);
}
StringType m_string; StringType m_string;
Properties m_properties; Properties m_properties;
}; };
@@ -190,11 +203,11 @@ private:
typedef BasicBuffer<char> Buffer; typedef BasicBuffer<char> Buffer;
typedef BasicBuffer<wchar_t> WBuffer; typedef BasicBuffer<wchar_t> WBuffer;
template <typename CharT> template <typename OutputStreamT, typename CharT>
Window &operator<<(Window &w, const BasicBuffer<CharT> &buffer) OutputStreamT &operator<<(OutputStreamT &os, const BasicBuffer<CharT> &buffer)
{ {
if (buffer.properties().empty()) if (buffer.properties().empty())
w << buffer.str(); os << buffer.str();
else else
{ {
auto &s = buffer.str(); auto &s = buffer.str();
@@ -203,14 +216,14 @@ Window &operator<<(Window &w, const BasicBuffer<CharT> &buffer)
for (size_t i = 0; i < s.size(); ++i) for (size_t i = 0; i < s.size(); ++i)
{ {
for (; p != ps.end() && p->position() == i; ++p) for (; p != ps.end() && p->position() == i; ++p)
w << *p; os << *p;
w << s[i]; os << s[i];
} }
// load remaining properties // load remaining properties
for (; p != ps.end(); ++p) for (; p != ps.end(); ++p)
w << *p; os << *p;
} }
return w; return os;
} }
} }

View File

@@ -26,8 +26,8 @@
#include <boost/locale/conversion.hpp> #include <boost/locale/conversion.hpp>
#include <algorithm> #include <algorithm>
#include <fstream> #include <fstream>
#include <sstream>
#include "actions.h"
#include "browser.h" #include "browser.h"
#include "charset.h" #include "charset.h"
#include "display.h" #include "display.h"

View File

@@ -44,23 +44,24 @@ void drawHeader()
if (!Config.header_visibility) if (!Config.header_visibility)
return; return;
if (Config.new_design) switch (Config.design)
{ {
std::wstring title = myScreen->title(); case Design::Classic:
*wHeader << NC::XY(0, 3) << wclrtoeol; *wHeader << NC::XY(0, 0) << wclrtoeol << NC::Format::Bold << myScreen->title() << NC::Format::NoBold;
*wHeader << NC::Format::Bold << Config.alternative_ui_separator_color; *wHeader << Config.volume_color;
mvwhline(wHeader->raw(), 2, 0, 0, COLS); *wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << VolumeState;
mvwhline(wHeader->raw(), 4, 0, 0, COLS); *wHeader << NC::Color::End;
*wHeader << NC::XY((COLS-wideLength(title))/2, 3); break;
*wHeader << Config.header_color << title << NC::Color::End; case Design::Alternative:
*wHeader << NC::Color::End << NC::Format::NoBold; std::wstring title = myScreen->title();
} *wHeader << NC::XY(0, 3) << wclrtoeol;
else *wHeader << NC::Format::Bold << Config.alternative_ui_separator_color;
{ mvwhline(wHeader->raw(), 2, 0, 0, COLS);
*wHeader << NC::XY(0, 0) << wclrtoeol << NC::Format::Bold << myScreen->title() << NC::Format::NoBold; mvwhline(wHeader->raw(), 4, 0, 0, COLS);
*wHeader << Config.volume_color; *wHeader << NC::XY((COLS-wideLength(title))/2, 3);
*wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << VolumeState; *wHeader << Config.header_color << title << NC::Color::End;
*wHeader << NC::Color::End; *wHeader << NC::Color::End << NC::Format::NoBold;
break;
} }
wHeader->refresh(); wHeader->refresh();
} }

View File

@@ -68,13 +68,13 @@ bool LocaleBasedItemSorting::operator()(const MPD::Item &a, const MPD::Item &b)
case MPD::itSong: case MPD::itSong:
switch (m_sort_mode) switch (m_sort_mode)
{ {
case smName: case SortMode::Name:
result = m_cmp(*a.song, *b.song); result = m_cmp(*a.song, *b.song);
break; break;
case smMTime: case SortMode::ModificationTime:
result = a.song->getMTime() > b.song->getMTime(); result = a.song->getMTime() > b.song->getMTime();
break; break;
case smCustomFormat: case SortMode::CustomFormat:
result = m_cmp(a.song->toString(Config.browser_sort_format, Config.tags_separator), result = m_cmp(a.song->toString(Config.browser_sort_format, Config.tags_separator),
b.song->toString(Config.browser_sort_format, Config.tags_separator)); b.song->toString(Config.browser_sort_format, Config.tags_separator));
break; break;

View File

@@ -18,10 +18,14 @@
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/ ***************************************************************************/
#ifndef NCMPCPP_UTILITY_CONVERSION_H
#define NCMPCPP_UTILITY_CONVERSION_H
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/type_traits/is_unsigned.hpp> #include <boost/type_traits/is_unsigned.hpp>
#include "config.h"
#include "gcc.h" #include "gcc.h"
struct ConversionError struct ConversionError
@@ -35,7 +39,7 @@ private:
std::string m_source_value; std::string m_source_value;
}; };
struct OutOfBounds struct OutOfBounds : std::exception
{ {
const std::string &errorMessage() { return m_error_message; } const std::string &errorMessage() { return m_error_message; }
@@ -43,23 +47,25 @@ struct OutOfBounds
GNUC_NORETURN static void raise(const Type &value, const Type &lbound, const Type &ubound) GNUC_NORETURN static void raise(const Type &value, const Type &lbound, const Type &ubound)
{ {
throw OutOfBounds((boost::format( throw OutOfBounds((boost::format(
"Value is out of bounds ([%1%, %2%] expected, %3% given)") % lbound % ubound % value).str()); "value is out of bounds ([%1%, %2%] expected, %3% given)") % lbound % ubound % value).str());
} }
template <typename Type> template <typename Type>
GNUC_NORETURN static void raiseLower(const Type &value, const Type &lbound) GNUC_NORETURN static void raiseLower(const Type &value, const Type &lbound)
{ {
throw OutOfBounds((boost::format( throw OutOfBounds((boost::format(
"Value is out of bounds ([%1%, ->) expected, %2% given)") % lbound % value).str()); "value is out of bounds ([%1%, ->) expected, %2% given)") % lbound % value).str());
} }
template <typename Type> template <typename Type>
GNUC_NORETURN static void raiseUpper(const Type &value, const Type &ubound) GNUC_NORETURN static void raiseUpper(const Type &value, const Type &ubound)
{ {
throw OutOfBounds((boost::format( throw OutOfBounds((boost::format(
"Value is out of bounds ((<-, %1%] expected, %2% given)") % ubound % value).str()); "value is out of bounds ((<-, %1%] expected, %2% given)") % ubound % value).str());
} }
virtual const char *what() const noexcept OVERRIDE { return m_error_message.c_str(); }
private: private:
OutOfBounds(std::string msg) : m_error_message(msg) { } OutOfBounds(std::string msg) : m_error_message(msg) { }
@@ -115,3 +121,5 @@ void upperBoundCheck(const Type &value, const Type &ubound)
if (value > ubound) if (value > ubound)
OutOfBounds::raiseUpper(value, ubound); OutOfBounds::raiseUpper(value, ubound);
} }
#endif // NCMPCPP_UTILITY_CONVERSION_H

37
src/utility/functional.h Normal file
View File

@@ -0,0 +1,37 @@
/***************************************************************************
* Copyright (C) 2008-2014 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* 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 program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NCMPCPP_UTILITY_FUNCTIONAL_H
#define NCMPCPP_UTILITY_FUNCTIONAL_H
#include <utility>
// identity function object
struct id_
{
template <typename ValueT>
constexpr auto operator()(ValueT &&v) const noexcept
-> decltype(std::forward<ValueT>(v))
{
return std::forward<ValueT>(v);
}
};
#endif // NCMPCPP_UTILITY_FUNCTIONAL_H

View File

@@ -0,0 +1,82 @@
/***************************************************************************
* Copyright (C) 2008-2014 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* 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 program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include <boost/regex.hpp>
#include <iostream>
#include "utility/option_parser.h"
bool option_parser::run(std::istream &is)
{
// quoted value. leftmost and rightmost quotation marks are the delimiters.
boost::regex quoted("(\\w+)\\h*=\\h*\"(.*)\"[^\"]*");
// unquoted value. whitespaces get trimmed.
boost::regex unquoted("(\\w+)\\h*=\\h*(.*?)\\h*");
boost::smatch match;
std::string line;
while (std::getline(is, line))
{
if (boost::regex_match(line, match, quoted)
|| boost::regex_match(line, match, unquoted))
{
std::string option = match[1];
auto it = m_parsers.find(option);
if (it != m_parsers.end())
{
try {
it->second.parse(match[2]);
} catch (std::exception &e) {
std::cerr << "Error while processing option \"" << option << "\": " << e.what() << "\n";
return false;
}
}
else
{
std::cerr << "Unknown option: " << option << "\n";
return false;
}
}
}
for (auto &p : m_parsers)
{
if (!p.second.defined())
{
try {
p.second.run_default();
} catch (std::exception &e) {
std::cerr << "Error while finalizing option \"" << p.first << "\": " << e.what() << "\n";
return false;
}
}
}
return true;
}
option_parser::worker yes_no(bool &arg, bool value)
{
return option_parser::worker([&arg](std::string &&v) {
if (v == "yes")
arg = true;
else if (v == "no")
arg = false;
else
throw std::runtime_error("invalid argument: " + v);
}, defaults_to(arg, value));
}

131
src/utility/option_parser.h Normal file
View File

@@ -0,0 +1,131 @@
/***************************************************************************
* Copyright (C) 2008-2014 by Andrzej Rybczak *
* electricityispower@gmail.com *
* *
* 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 program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#ifndef NCMPCPP_UTILITY_OPTION_PARSER_H
#define NCMPCPP_UTILITY_OPTION_PARSER_H
#include <boost/lexical_cast.hpp>
#include <cassert>
#include <stdexcept>
#include <unordered_map>
#include "helpers.h"
#include "strbuffer.h"
#include "utility/functional.h"
struct option_parser
{
typedef std::function<void(std::string &&)> parser_t;
typedef std::function<void()> default_t;
struct worker
{
worker() { }
template <typename ParserT, typename DefaultT>
worker(ParserT &&p, DefaultT &&d)
: m_defined(false), m_parser(std::forward<ParserT>(p))
, m_default(std::forward<DefaultT>(d)) { }
template <typename ValueT>
void parse(ValueT &&value)
{
if (m_defined)
throw std::runtime_error("option already defined");
m_parser(std::forward<ValueT>(value));
m_defined = true;
}
bool defined() const { return m_defined; }
void run_default() const { m_default(); }
private:
bool m_defined;
parser_t m_parser;
default_t m_default;
};
template <typename ParserT, typename DefaultT>
void add(const std::string &option, ParserT &&p, DefaultT &&d)
{
assert(m_parsers.count(option) == 0);
m_parsers[option] = worker(std::forward<ParserT>(p), std::forward<DefaultT>(d));
}
template <typename WorkerT>
void add(const std::string &option, WorkerT &&w)
{
assert(m_parsers.count(option) == 0);
m_parsers[option] = std::forward<WorkerT>(w);
}
bool run(std::istream &is);
private:
std::unordered_map<std::string, worker> m_parsers;
};
template <typename IntermediateT, typename ArgT, typename TransformT>
option_parser::parser_t assign(ArgT &arg, TransformT map = id_())
{
return [&arg, map](std::string &&v) {
try {
arg = map(boost::lexical_cast<IntermediateT>(v));
} catch (boost::bad_lexical_cast &) {
throw std::runtime_error("invalid value: " + v);
}
};
}
template <typename ArgT, typename ValueT>
option_parser::default_t defaults_to(ArgT &arg, ValueT &&value)
{
return [&arg, value] {
arg = std::move(value);
};
}
template <typename IntermediateT, typename ArgT, typename ValueT, typename TransformT>
option_parser::worker assign_default(ArgT &arg, ValueT &&value, TransformT map)
{
return option_parser::worker(
assign<IntermediateT>(arg, map), defaults_to(arg, map(std::forward<ValueT>(value)))
);
}
template <typename ArgT, typename ValueT>
option_parser::worker assign_default(ArgT &arg, ValueT &&value)
{
return assign_default<ArgT>(arg, std::forward<ValueT>(value), id_());
}
// workers for specific types
template <typename ValueT, typename TransformT>
option_parser::worker buffer(NC::Buffer &arg, ValueT &&value, TransformT map)
{
return option_parser::worker(assign<std::string>(arg, [&arg, map](std::string &&s) {
return map(stringToBuffer(s));
}), defaults_to(arg, map(std::forward<ValueT>(value))));
}
option_parser::worker yes_no(bool &arg, bool value);
#endif // NCMPCPP_UTILITY_OPTION_PARSER_H

View File

@@ -21,6 +21,7 @@
#include <cstring> #include <cstring>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <iostream>
#include <readline/history.h> #include <readline/history.h>
#include <readline/readline.h> #include <readline/readline.h>
@@ -158,6 +159,196 @@ int add_base()
namespace NC {// namespace NC {//
std::ostream &operator<<(std::ostream &os, Color c)
{
switch (c)
{
case Color::Default:
os << "default";
break;
case Color::Black:
os << "black";
break;
case Color::Red:
os << "red";
break;
case Color::Green:
os << "green";
break;
case Color::Yellow:
os << "yellow";
break;
case Color::Blue:
os << "blue";
break;
case Color::Magenta:
os << "magenta";
break;
case Color::Cyan:
os << "cyan";
break;
case Color::White:
os << "white";
break;
case Color::End:
os << "color_end";
break;
}
return os;
}
std::istream &operator>>(std::istream &is, Color &c)
{
std::string sc;
is >> sc;
if (sc == "default")
c = Color::Default;
else if (sc == "black")
c = Color::Black;
else if (sc == "red")
c = Color::Red;
else if (sc == "green")
c = Color::Green;
else if (sc == "yellow")
c = Color::Yellow;
else if (sc == "blue")
c = Color::Blue;
else if (sc == "magenta")
c = Color::Magenta;
else if (sc == "cyan")
c = Color::Cyan;
else if (sc == "white")
c = Color::White;
else if (sc == "color_end")
c = Color::End;
else
is.setstate(std::ios::failbit);
return is;
}
std::ostream &operator<<(std::ostream &os, Format f)
{
switch (f)
{
case Format::None:
os << "none";
break;
case Format::Bold:
os << "bold";
break;
case Format::NoBold:
os << "bold";
break;
case Format::Underline:
os << "underline";
break;
case Format::NoUnderline:
os << "no_underline";
break;
case Format::Reverse:
os << "reverse";
break;
case Format::NoReverse:
os << "no_reverse";
break;
case Format::AltCharset:
os << "alt_charset";
break;
case Format::NoAltCharset:
os << "no_alt_charset";
break;
}
return os;
}
std::ostream &operator<<(std::ostream &os, Border b)
{
switch (b)
{
case Border::None:
os << "none";
break;
case Border::Black:
os << "black";
break;
case Border::Red:
os << "red";
break;
case Border::Green:
os << "green";
break;
case Border::Yellow:
os << "yellow";
break;
case Border::Blue:
os << "blue";
break;
case Border::Magenta:
os << "magenta";
break;
case Border::Cyan:
os << "cyan";
break;
case Border::White:
os << "white";
break;
}
return os;
}
std::istream &operator>>(std::istream &is, Border &b)
{
std::string sb;
is >> sb;
if (sb == "none")
b = Border::None;
else if (sb == "black")
b = Border::Black;
else if (sb == "red")
b = Border::Red;
else if (sb == "green")
b = Border::Green;
else if (sb == "yellow")
b = Border::Yellow;
else if (sb == "blue")
b = Border::Blue;
else if (sb == "magenta")
b = Border::Magenta;
else if (sb == "cyan")
b = Border::Cyan;
else if (sb == "white")
b = Border::White;
else
is.setstate(std::ios::failbit);
return is;
}
std::ostream &operator<<(std::ostream &os, Scroll s)
{
switch (s)
{
case Scroll::Up:
os << "scroll_up";
break;
case Scroll::Down:
os << "scroll_down";
break;
case Scroll::PageUp:
os << "scroll_page_up";
break;
case Scroll::PageDown:
os << "scroll_page_down";
break;
case Scroll::Home:
os << "scroll_home";
break;
case Scroll::End:
os << "scroll_end";
break;
}
return os;
}
void initScreen(GNUC_UNUSED const char *window_title, bool enable_colors) void initScreen(GNUC_UNUSED const char *window_title, bool enable_colors)
{ {
const int ColorsTable[] = const int ColorsTable[] =

View File

@@ -114,6 +114,9 @@ namespace NC {//
/// Colors used by NCurses /// Colors used by NCurses
enum class Color { Default, Black, Red, Green, Yellow, Blue, Magenta, Cyan, White, End }; enum class Color { Default, Black, Red, Green, Yellow, Blue, Magenta, Cyan, White, End };
std::ostream &operator<<(std::ostream &os, Color c);
std::istream &operator>>(std::istream &is, Color &c);
/// Format flags used by NCurses /// Format flags used by NCurses
enum class Format { enum class Format {
None, None,
@@ -123,12 +126,19 @@ enum class Format {
AltCharset, NoAltCharset AltCharset, NoAltCharset
}; };
std::ostream &operator<<(std::ostream &os, Format f);
/// Available border colors for window /// Available border colors for window
enum class Border { None, Black, Red, Green, Yellow, Blue, Magenta, Cyan, White }; enum class Border { None, Black, Red, Green, Yellow, Blue, Magenta, Cyan, White };
std::ostream &operator<<(std::ostream &os, Border b);
std::istream &operator>>(std::istream &is, Border &b);
/// This indicates how much the window has to be scrolled /// This indicates how much the window has to be scrolled
enum class Scroll { Up, Down, PageUp, PageDown, Home, End }; enum class Scroll { Up, Down, PageUp, PageDown, Home, End };
std::ostream &operator<<(std::ostream &os, Scroll s);
/// Helper function that is invoked each time one will want /// Helper function that is invoked each time one will want
/// to obtain string from Window::getString() function /// to obtain string from Window::getString() function
/// @see Window::getString() /// @see Window::getString()