settings: configuration file processing rewrite
This commit is contained in:
272
doc/config
272
doc/config
@@ -12,7 +12,7 @@
|
||||
## file which defines that while launching ncmpcpp.
|
||||
##
|
||||
#
|
||||
#ncmpcpp_directory = "~/.ncmpcpp"
|
||||
#ncmpcpp_directory = ~/.ncmpcpp
|
||||
#
|
||||
##
|
||||
## Directory for storing downloaded lyrics. It
|
||||
@@ -20,21 +20,21 @@
|
||||
## (eg. ncmpc) also use that location.
|
||||
##
|
||||
#
|
||||
#lyrics_directory = "~/.lyrics"
|
||||
#lyrics_directory = ~/.lyrics
|
||||
#
|
||||
##### 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 #####
|
||||
##
|
||||
@@ -46,19 +46,13 @@
|
||||
##
|
||||
## audio_output {
|
||||
## type "fifo"
|
||||
## name "My FIFO"
|
||||
## name "Visualizer feed"
|
||||
## path "/tmp/mpd.fifo"
|
||||
## format "44100:16:2"
|
||||
## }
|
||||
##
|
||||
#
|
||||
##
|
||||
## If you set format to 44100:16:2, make it 'yes'.
|
||||
##
|
||||
#
|
||||
#visualizer_in_stereo = "no"
|
||||
#
|
||||
#visualizer_fifo_path = ""
|
||||
#visualizer_fifo_path = /tmp/mpd.fifo
|
||||
#
|
||||
##
|
||||
## Note: Below parameter is needed for ncmpcpp
|
||||
@@ -68,7 +62,12 @@
|
||||
## 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
|
||||
@@ -78,14 +77,16 @@
|
||||
## Keep in mind that sane values start with >=10.
|
||||
##
|
||||
#
|
||||
#visualizer_sync_interval = "30"
|
||||
#visualizer_sync_interval = 30
|
||||
#
|
||||
##
|
||||
## Note: To enable spectrum frequency visualization
|
||||
## you need to compile ncmpcpp with fftw3 support.
|
||||
##
|
||||
#
|
||||
#visualizer_type = "wave" (spectrum/wave)
|
||||
## Available values: spectrum, wave.
|
||||
##
|
||||
#visualizer_type = wave
|
||||
#
|
||||
#visualizer_look = "◆│"
|
||||
#
|
||||
@@ -99,7 +100,7 @@
|
||||
## supports charset detection by checking output
|
||||
## 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
|
||||
## is different.
|
||||
##
|
||||
@@ -108,13 +109,14 @@
|
||||
#
|
||||
##### 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 various messages are supposed to be visible
|
||||
#
|
||||
#message_delay_time = "4"
|
||||
## Defines how long messages are supposed to be visible.
|
||||
##
|
||||
#message_delay_time = 5
|
||||
#
|
||||
##### song format #####
|
||||
##
|
||||
@@ -151,9 +153,9 @@
|
||||
## you'll get nothing.
|
||||
##
|
||||
## 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)
|
||||
## - 1 - black
|
||||
@@ -169,24 +171,24 @@
|
||||
## 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.
|
||||
## The sort mode determines how songs are sorted, and can be used
|
||||
## 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.
|
||||
@@ -205,30 +207,29 @@
|
||||
## 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
|
||||
## text attributes listed above.
|
||||
## Note: below variables also support 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 "
|
||||
#
|
||||
#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
|
||||
#
|
||||
#song_window_title_format = "{%a - }{%t}|{%f}"
|
||||
## Note: colors are not supported for below variable.
|
||||
##
|
||||
#song_window_title_format = {%a - }{%t}|{%f}
|
||||
#
|
||||
##### columns settings #####
|
||||
##
|
||||
@@ -266,7 +267,7 @@
|
||||
## 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 #####
|
||||
#
|
||||
@@ -279,75 +280,86 @@
|
||||
##
|
||||
#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
|
||||
## 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
|
||||
@@ -357,13 +369,13 @@
|
||||
##
|
||||
## 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"
|
||||
#
|
||||
#display_screens_numbers_on_start = "yes"
|
||||
#show_hidden_files_in_local_browser = no
|
||||
#
|
||||
##
|
||||
## How shall screen switcher work?
|
||||
@@ -374,59 +386,61 @@
|
||||
## Screens available for use: help, playlist, browser, search_engine,
|
||||
## 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
|
||||
## by choosing screen from the list above.
|
||||
##
|
||||
#startup_screen = "playlist"
|
||||
#startup_screen = playlist
|
||||
#
|
||||
##
|
||||
## Default width of locked screen (in %).
|
||||
## 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
|
||||
## "The" word while sorting items in browser, tags in
|
||||
## 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 = " | "
|
||||
#
|
||||
#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
|
||||
@@ -440,47 +454,49 @@
|
||||
## 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_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
|
||||
#
|
||||
|
||||
@@ -156,9 +156,6 @@ No need to describe it, huh?
|
||||
.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.
|
||||
.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
|
||||
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
|
||||
@@ -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
|
||||
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
|
||||
.B ncmpc_like_songs_adding = yes/no
|
||||
If enabled, pressing space on item, which is already in playlist will remove it, otherwise add it again.
|
||||
.B space_add_mode = add_remove/always_add
|
||||
If set to add_remove, pressing space on item which is already in playlist will remove it, otherwise add it again.
|
||||
.TP
|
||||
.B show_hidden_files_in_local_browser = yes/no
|
||||
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
|
||||
Default user interface used by ncmpcpp at start.
|
||||
.TP
|
||||
.B media_library_left_column = a/y/g/c/p
|
||||
Default tag type for left column in media library. Legend for possible letters is in SONG FORMAT section.
|
||||
.B media_library_primary_tag = artist/date/genre/composer/performer
|
||||
Default tag type for leftmost column in media library.
|
||||
.TP
|
||||
.B empty_tag_marker = TEXT
|
||||
Text that will be displayed, if requested tag is not set.
|
||||
|
||||
@@ -2,6 +2,7 @@ bin_PROGRAMS = ncmpcpp
|
||||
ncmpcpp_SOURCES = \
|
||||
utility/comparators.cpp \
|
||||
utility/html.cpp \
|
||||
utility/option_parser.cpp \
|
||||
utility/string.cpp \
|
||||
utility/type_conversions.cpp \
|
||||
utility/wide_string.cpp \
|
||||
@@ -10,9 +11,10 @@ ncmpcpp_SOURCES = \
|
||||
browser.cpp \
|
||||
charset.cpp \
|
||||
clock.cpp \
|
||||
cmdargs.cpp \
|
||||
configuration.cpp \
|
||||
curl_handle.cpp \
|
||||
display.cpp \
|
||||
enums.cpp \
|
||||
error.cpp \
|
||||
global.cpp \
|
||||
help.cpp \
|
||||
@@ -56,7 +58,9 @@ ncmpcpp_LDFLAGS = $(all_libraries)
|
||||
noinst_HEADERS = \
|
||||
utility/comparators.h \
|
||||
utility/conversion.h \
|
||||
utility/functional.h \
|
||||
utility/html.h \
|
||||
utility/option_parser.h \
|
||||
utility/string.h \
|
||||
utility/type_conversions.h \
|
||||
utility/wide_string.h \
|
||||
@@ -64,9 +68,10 @@ noinst_HEADERS = \
|
||||
browser.h \
|
||||
charset.h \
|
||||
clock.h \
|
||||
cmdargs.h \
|
||||
configuration.h \
|
||||
curl_handle.h \
|
||||
display.h \
|
||||
enums.h \
|
||||
error.h \
|
||||
exec_item.h \
|
||||
global.h \
|
||||
|
||||
249
src/actions.cpp
249
src/actions.cpp
@@ -198,7 +198,7 @@ void resizeScreen(bool reload_main_window)
|
||||
}
|
||||
# endif
|
||||
|
||||
MainHeight = LINES-(Config.new_design ? 7 : 4);
|
||||
MainHeight = LINES-(Config.design == Design::Alternative ? 7 : 4);
|
||||
|
||||
validateScreenSize();
|
||||
|
||||
@@ -211,7 +211,7 @@ void resizeScreen(bool reload_main_window)
|
||||
|
||||
applyToVisibleWindows(&BaseScreen::resize);
|
||||
|
||||
if (Config.header_visibility || Config.new_design)
|
||||
if (Config.header_visibility || Config.design == Design::Alternative)
|
||||
wHeader->resize(COLS, HeaderHeight);
|
||||
|
||||
FooterStartY = LINES-(Config.statusbar_visibility ? 2 : 1);
|
||||
@@ -236,8 +236,8 @@ void setWindowsDimensions()
|
||||
using Global::MainStartY;
|
||||
using Global::MainHeight;
|
||||
|
||||
MainStartY = Config.new_design ? 5 : 2;
|
||||
MainHeight = LINES-(Config.new_design ? 7 : 4);
|
||||
MainStartY = Config.design == Design::Alternative ? 5 : 2;
|
||||
MainHeight = LINES-(Config.design == Design::Alternative ? 7 : 4);
|
||||
|
||||
if (!Config.header_visibility)
|
||||
{
|
||||
@@ -247,7 +247,7 @@ void setWindowsDimensions()
|
||||
if (!Config.statusbar_visibility)
|
||||
++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);
|
||||
FooterHeight = Config.statusbar_visibility ? 2 : 1;
|
||||
}
|
||||
@@ -337,15 +337,16 @@ void MouseEvent::run()
|
||||
myPlaylist->currentSongLength()*m_mouse_event.x/double(COLS));
|
||||
}
|
||||
else if (m_mouse_event.bstate & BUTTON1_PRESSED
|
||||
&& (Config.statusbar_visibility || Config.new_design)
|
||||
&& Status::State::player() != MPD::psStop
|
||||
&& m_mouse_event.y == (Config.new_design ? 1 : LINES-1) && m_mouse_event.x < 9
|
||||
&& (Config.statusbar_visibility || Config.design == Design::Alternative)
|
||||
&& Status::State::player() != MPD::psStop
|
||||
&& m_mouse_event.y == (Config.design == Design::Alternative ? 1 : LINES-1)
|
||||
&& m_mouse_event.x < 9
|
||||
) // playing/paused
|
||||
{
|
||||
Mpd.Toggle();
|
||||
}
|
||||
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()
|
||||
) // volume
|
||||
{
|
||||
@@ -488,15 +489,24 @@ void MoveEnd::run()
|
||||
|
||||
void ToggleInterface::run()
|
||||
{
|
||||
Config.new_design = !Config.new_design;
|
||||
Config.statusbar_visibility = Config.new_design ? 0 : OriginalStatusbarVisibility;
|
||||
switch (Config.design)
|
||||
{
|
||||
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();
|
||||
Progressbar::unlock();
|
||||
Statusbar::unlock();
|
||||
resizeScreen(false);
|
||||
Status::Changes::mixer();
|
||||
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
|
||||
@@ -606,13 +616,13 @@ void SlaveScreen::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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -999,52 +1009,83 @@ void ToggleDisplayMode::run()
|
||||
{
|
||||
if (myScreen == myPlaylist)
|
||||
{
|
||||
Config.columns_in_playlist = !Config.columns_in_playlist;
|
||||
Statusbar::printf("Playlist display mode: %1%",
|
||||
Config.columns_in_playlist ? "Columns" : "Classic"
|
||||
);
|
||||
|
||||
if (Config.columns_in_playlist)
|
||||
switch (Config.playlist_display_mode)
|
||||
{
|
||||
myPlaylist->main().setItemDisplayer(boost::bind(Display::SongsInColumns, _1, myPlaylist->proxySongList()));
|
||||
if (Config.titles_visibility)
|
||||
myPlaylist->main().setTitle(Display::Columns(myPlaylist->main().getWidth()));
|
||||
else
|
||||
case DisplayMode::Classic:
|
||||
Config.playlist_display_mode = DisplayMode::Columns;
|
||||
myPlaylist->main().setItemDisplayer(boost::bind(
|
||||
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("");
|
||||
}
|
||||
else
|
||||
{
|
||||
myPlaylist->main().setItemDisplayer(boost::bind(Display::Songs, _1, myPlaylist->proxySongList(), Config.song_list_format));
|
||||
myPlaylist->main().setTitle("");
|
||||
}
|
||||
Statusbar::printf("Playlist display mode: %1%", Config.playlist_display_mode);
|
||||
}
|
||||
else if (myScreen == myBrowser)
|
||||
{
|
||||
Config.columns_in_browser = !Config.columns_in_browser;
|
||||
Statusbar::printf("Browser display mode: %1%",
|
||||
Config.columns_in_browser ? "Columns" : "Classic"
|
||||
);
|
||||
myBrowser->main().setTitle(Config.columns_in_browser && Config.titles_visibility ? Display::Columns(myBrowser->main().getWidth()) : "");
|
||||
switch (Config.browser_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
Config.browser_display_mode = DisplayMode::Columns;
|
||||
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)
|
||||
{
|
||||
Config.columns_in_search_engine = !Config.columns_in_search_engine;
|
||||
Statusbar::printf("Search engine display mode: %1%",
|
||||
Config.columns_in_search_engine ? "Columns" : "Classic"
|
||||
);
|
||||
switch (Config.search_engine_display_mode)
|
||||
{
|
||||
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)
|
||||
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))
|
||||
{
|
||||
Config.columns_in_playlist_editor = !Config.columns_in_playlist_editor;
|
||||
Statusbar::printf("Playlist editor display mode: %1%",
|
||||
Config.columns_in_playlist_editor ? "Columns" : "Classic"
|
||||
);
|
||||
if (Config.columns_in_playlist_editor)
|
||||
myPlaylistEditor->Content.setItemDisplayer(boost::bind(Display::SongsInColumns, _1, myPlaylistEditor->contentProxyList()));
|
||||
else
|
||||
myPlaylistEditor->Content.setItemDisplayer(boost::bind(Display::Songs, _1, myPlaylistEditor->contentProxyList(), Config.song_list_format));
|
||||
switch (Config.playlist_editor_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
Config.playlist_editor_display_mode = DisplayMode::Columns;
|
||||
myPlaylistEditor->Content.setItemDisplayer(boost::bind(
|
||||
Display::SongsInColumns, _1, myPlaylistEditor->contentProxyList()
|
||||
));
|
||||
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()
|
||||
{
|
||||
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);
|
||||
if (yes)
|
||||
{
|
||||
@@ -1707,7 +1748,7 @@ void CropPlaylist::run()
|
||||
assert(!myPlaylistEditor->Playlists.empty());
|
||||
std::string playlist = myPlaylistEditor->Playlists.current().value();
|
||||
bool yes = true;
|
||||
if (Config.ask_before_clearing_main_playlist)
|
||||
if (Config.ask_before_clearing_playlists)
|
||||
yes = askYesNoQuestion(
|
||||
boost::format("Do you really want to crop playlist \"%1%\"?") % playlist,
|
||||
Status::trace
|
||||
@@ -1724,7 +1765,7 @@ void CropPlaylist::run()
|
||||
void ClearMainPlaylist::run()
|
||||
{
|
||||
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);
|
||||
if (yes)
|
||||
{
|
||||
@@ -1747,7 +1788,7 @@ void ClearPlaylist::run()
|
||||
assert(!myPlaylistEditor->Playlists.empty());
|
||||
std::string playlist = myPlaylistEditor->Playlists.current().value();
|
||||
bool yes = true;
|
||||
if (Config.ask_before_clearing_main_playlist)
|
||||
if (Config.ask_before_clearing_playlists)
|
||||
yes = askYesNoQuestion(
|
||||
boost::format("Do you really want to clear playlist \"%1%\"?") % playlist,
|
||||
Status::trace
|
||||
@@ -1937,10 +1978,19 @@ void ToggleSpaceMode::run()
|
||||
|
||||
void ToggleAddMode::run()
|
||||
{
|
||||
Config.ncmpc_like_songs_adding = !Config.ncmpc_like_songs_adding;
|
||||
Statusbar::printf("Add mode: %1%",
|
||||
Config.ncmpc_like_songs_adding ? "Add item to playlist or remove if already added" : "Always add item to playlist"
|
||||
);
|
||||
std::string mode_desc;
|
||||
switch (Config.space_add_mode)
|
||||
{
|
||||
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()
|
||||
@@ -2008,16 +2058,16 @@ void ToggleBrowserSortMode::run()
|
||||
{
|
||||
switch (Config.browser_sort_mode)
|
||||
{
|
||||
case smName:
|
||||
Config.browser_sort_mode = smMTime;
|
||||
case SortMode::Name:
|
||||
Config.browser_sort_mode = SortMode::ModificationTime;
|
||||
Statusbar::print("Sort songs by: Modification time");
|
||||
break;
|
||||
case smMTime:
|
||||
Config.browser_sort_mode = smCustomFormat;
|
||||
case SortMode::ModificationTime:
|
||||
Config.browser_sort_mode = SortMode::CustomFormat;
|
||||
Statusbar::print("Sort songs by: Custom format");
|
||||
break;
|
||||
case smCustomFormat:
|
||||
Config.browser_sort_mode = smName;
|
||||
case SortMode::CustomFormat:
|
||||
Config.browser_sort_mode = SortMode::Name;
|
||||
Statusbar::print("Sort songs by: Name");
|
||||
break;
|
||||
}
|
||||
@@ -2211,13 +2261,12 @@ void NextScreen::run()
|
||||
if (auto tababble = dynamic_cast<Tabbable *>(myScreen))
|
||||
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(),
|
||||
myScreen->type()
|
||||
);
|
||||
if (++screen_type == Config.screens_seq.end())
|
||||
toScreen(Config.screens_seq.front())->switchTo();
|
||||
const auto &seq = Config.screen_sequence;
|
||||
auto screen_type = std::find(seq.begin(), seq.end(), myScreen->type());
|
||||
if (++screen_type == seq.end())
|
||||
toScreen(seq.front())->switchTo();
|
||||
else
|
||||
toScreen(*screen_type)->switchTo();
|
||||
}
|
||||
@@ -2230,13 +2279,12 @@ void PreviousScreen::run()
|
||||
if (auto tababble = dynamic_cast<Tabbable *>(myScreen))
|
||||
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(),
|
||||
myScreen->type()
|
||||
);
|
||||
if (screen_type == Config.screens_seq.begin())
|
||||
toScreen(Config.screens_seq.back())->switchTo();
|
||||
const auto &seq = Config.screen_sequence;
|
||||
auto screen_type = std::find(seq.begin(), seq.end(), myScreen->type());
|
||||
if (screen_type == seq.begin())
|
||||
toScreen(seq.back())->switchTo();
|
||||
else
|
||||
toScreen(*--screen_type)->switchTo();
|
||||
}
|
||||
@@ -2635,34 +2683,35 @@ void seek()
|
||||
|
||||
*wFooter << NC::Format::Bold;
|
||||
std::string tracklength;
|
||||
if (Config.new_design)
|
||||
switch (Config.design)
|
||||
{
|
||||
if (Config.display_remaining_time)
|
||||
{
|
||||
tracklength = "-";
|
||||
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength()-songpos);
|
||||
}
|
||||
else
|
||||
tracklength = MPD::Song::ShowTime(songpos);
|
||||
tracklength += "/";
|
||||
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength());
|
||||
*wHeader << NC::XY(0, 0) << tracklength << " ";
|
||||
wHeader->refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
tracklength = " [";
|
||||
if (Config.display_remaining_time)
|
||||
{
|
||||
tracklength += "-";
|
||||
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength()-songpos);
|
||||
}
|
||||
else
|
||||
tracklength += MPD::Song::ShowTime(songpos);
|
||||
tracklength += "/";
|
||||
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength());
|
||||
tracklength += "]";
|
||||
*wFooter << NC::XY(wFooter->getWidth()-tracklength.length(), 1) << tracklength;
|
||||
case Design::Classic:
|
||||
tracklength = " [";
|
||||
if (Config.display_remaining_time)
|
||||
{
|
||||
tracklength += "-";
|
||||
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength()-songpos);
|
||||
}
|
||||
else
|
||||
tracklength += MPD::Song::ShowTime(songpos);
|
||||
tracklength += "/";
|
||||
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength());
|
||||
tracklength += "]";
|
||||
*wFooter << NC::XY(wFooter->getWidth()-tracklength.length(), 1) << tracklength;
|
||||
break;
|
||||
case Design::Alternative:
|
||||
if (Config.display_remaining_time)
|
||||
{
|
||||
tracklength = "-";
|
||||
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength()-songpos);
|
||||
}
|
||||
else
|
||||
tracklength = MPD::Song::ShowTime(songpos);
|
||||
tracklength += "/";
|
||||
tracklength += MPD::Song::ShowTime(myPlaylist->currentSongLength());
|
||||
*wHeader << NC::XY(0, 0) << tracklength << " ";
|
||||
wHeader->refresh();
|
||||
break;
|
||||
}
|
||||
*wFooter << NC::Format::NoBold;
|
||||
Progressbar::draw(songpos, myPlaylist->currentSongLength());
|
||||
|
||||
@@ -99,10 +99,6 @@ struct Binding
|
||||
return m_actions[0];
|
||||
}
|
||||
|
||||
const ActionChain &actions() const {
|
||||
return m_actions;
|
||||
}
|
||||
|
||||
private:
|
||||
ActionChain m_actions;
|
||||
};
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "tags.h"
|
||||
#include "utility/comparators.h"
|
||||
#include "utility/string.h"
|
||||
#include "configuration.h"
|
||||
|
||||
using Global::MainHeight;
|
||||
using Global::MainStartY;
|
||||
@@ -49,6 +50,8 @@ using MPD::itDirectory;
|
||||
using MPD::itSong;
|
||||
using MPD::itPlaylist;
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
Browser *myBrowser;
|
||||
|
||||
namespace {//
|
||||
@@ -63,7 +66,7 @@ bool BrowserEntryMatcher(const boost::regex &rx, const MPD::Item &item, bool fil
|
||||
|
||||
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.cyclicScrolling(Config.use_cyclic_scrolling);
|
||||
w.centeredCursor(Config.centered_cursor);
|
||||
@@ -78,7 +81,18 @@ void Browser::resize()
|
||||
getWindowResizeParams(x_offset, width);
|
||||
w.resize(width, MainHeight);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -97,7 +111,7 @@ void Browser::switchTo()
|
||||
std::wstring Browser::title()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -466,8 +480,6 @@ void Browser::GetDirectory(std::string dir, std::string subdir)
|
||||
#ifndef WIN32
|
||||
void Browser::GetLocalDirectory(MPD::ItemList &v, const std::string &directory, bool recursively) const
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
size_t start_size = v.size();
|
||||
fs::path dir(directory);
|
||||
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
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
fs::path dir(path);
|
||||
std::for_each(fs::directory_iterator(dir), fs::directory_iterator(), [&](fs::directory_entry &e) {
|
||||
if (!fs::is_symlink(e) && fs::is_directory(e))
|
||||
@@ -535,9 +545,15 @@ void Browser::ChangeBrowseMode()
|
||||
Statusbar::printf("Browse mode: %1%",
|
||||
itsBrowseLocally ? "Local filesystem" : "MPD database"
|
||||
);
|
||||
itsBrowsedDir = itsBrowseLocally ? Config.GetHomeDirectory() : "/";
|
||||
if (itsBrowseLocally && *itsBrowsedDir.rbegin() == '/')
|
||||
itsBrowsedDir.resize(itsBrowsedDir.length()-1);
|
||||
if (itsBrowseLocally)
|
||||
{
|
||||
itsBrowsedDir = "~";
|
||||
expand_home(itsBrowsedDir);
|
||||
if (*itsBrowsedDir.rbegin() == '/')
|
||||
itsBrowsedDir.resize(itsBrowsedDir.length()-1);
|
||||
}
|
||||
else
|
||||
itsBrowsedDir = "/";
|
||||
w.reset();
|
||||
GetDirectory(itsBrowsedDir);
|
||||
drawHeader();
|
||||
@@ -605,10 +621,15 @@ std::string ItemToString(const MPD::Item &item)
|
||||
result = "[" + getBasename(item.name) + "]";
|
||||
break;
|
||||
case MPD::itSong:
|
||||
if (Config.columns_in_browser)
|
||||
result = item.song->toString(Config.song_in_columns_to_string_format, Config.tags_separator);
|
||||
else
|
||||
result = item.song->toString(Config.song_list_format_dollar_free, Config.tags_separator);
|
||||
switch (Config.browser_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
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;
|
||||
case MPD::itPlaylist:
|
||||
result = Config.browser_playlist_prefix.str() + getBasename(item.name);
|
||||
|
||||
@@ -18,11 +18,12 @@
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include "bindings.h"
|
||||
#include "cmdargs.h"
|
||||
#include "configuration.h"
|
||||
#include "config.h"
|
||||
#include "mpdpp.h"
|
||||
#include "settings.h"
|
||||
@@ -36,25 +37,25 @@ namespace {
|
||||
|
||||
const char *env_home;
|
||||
|
||||
void replace_tilda_with_home(std::string &s)
|
||||
}
|
||||
|
||||
void expand_home(std::string &path)
|
||||
{
|
||||
if (!s.empty() && s[0] == '~')
|
||||
s.replace(0, 1, env_home);
|
||||
if (!path.empty() && path[0] == '~')
|
||||
path.replace(0, 1, env_home);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool ParseArguments(int argc, char **argv)
|
||||
bool configure(int argc, char **argv)
|
||||
{
|
||||
std::string bindings_path, config_path;
|
||||
|
||||
po::options_description desc("Options");
|
||||
desc.add_options()
|
||||
po::options_description options("Options");
|
||||
options.add_options()
|
||||
("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")
|
||||
("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")
|
||||
("screen,s", po::value<std::string>(), "specify the startup screen")
|
||||
("screen,s", po::value<std::string>(), "specify initial screen")
|
||||
("help,?", "show help message")
|
||||
("version,v", "display version information")
|
||||
;
|
||||
@@ -62,11 +63,11 @@ bool ParseArguments(int argc, char **argv)
|
||||
po::variables_map vm;
|
||||
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"))
|
||||
{
|
||||
cout << "Usage: " << argv[0] << " [options]...\n" << desc << "\n";
|
||||
cout << "Usage: " << argv[0] << " [options]...\n" << options << "\n";
|
||||
return false;
|
||||
}
|
||||
if (vm.count("version"))
|
||||
@@ -119,30 +120,33 @@ bool ParseArguments(int argc, char **argv)
|
||||
|
||||
po::notify(vm);
|
||||
|
||||
// get home directory
|
||||
env_home = getenv("HOME");
|
||||
if (env_home == nullptr)
|
||||
{
|
||||
cerr << "Fatal error: HOME environment variable is not defined\n";
|
||||
return false;
|
||||
}
|
||||
replace_tilda_with_home(config_path);
|
||||
replace_tilda_with_home(bindings_path);
|
||||
expand_home(config_path);
|
||||
expand_home(bindings_path);
|
||||
|
||||
// read configuration
|
||||
Config.SetDefaults();
|
||||
Config.Read(config_path);
|
||||
Config.GenerateColumns();
|
||||
if (Config.read(config_path) == false)
|
||||
exit(1);
|
||||
|
||||
// read bindings
|
||||
if (Bindings.read(bindings_path) == false)
|
||||
return false;
|
||||
exit(1);
|
||||
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
|
||||
// as they take precedence over these from the configuration.
|
||||
auto env_host = getenv("MPD_HOST");
|
||||
auto env_port = getenv("MPD_PORT");
|
||||
|
||||
if (env_host != nullptr)
|
||||
Mpd.SetHostname(env_host);
|
||||
if (env_port != nullptr)
|
||||
@@ -150,10 +154,11 @@ bool ParseArguments(int argc, char **argv)
|
||||
|
||||
// if MPD connection details are provided as command line
|
||||
// parameters, use them as their priority is the highest.
|
||||
if (vm.count("host"))
|
||||
if (!vm["host"].defaulted())
|
||||
Mpd.SetHostname(vm["host"].as<std::string>());
|
||||
if (vm.count("port"))
|
||||
if (!vm["port"].defaulted())
|
||||
Mpd.SetPort(vm["port"].as<int>());
|
||||
Mpd.SetTimeout(Config.mpd_connection_timeout);
|
||||
|
||||
// custom startup screen
|
||||
if (vm.count("screen"))
|
||||
@@ -162,15 +167,15 @@ bool ParseArguments(int argc, char **argv)
|
||||
Config.startup_screen_type = stringtoStartupScreenType(screen);
|
||||
if (Config.startup_screen_type == ScreenType::Unknown)
|
||||
{
|
||||
std::cerr << "Invalid screen: " << screen << "\n";
|
||||
return false;
|
||||
std::cerr << "Unknown screen: " << screen << "\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
cerr << "Error while parsing command line options: " << e.what() << "\n";
|
||||
return false;
|
||||
cerr << "Error while processing configuration: " << e.what() << "\n";
|
||||
exit(1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -18,9 +18,11 @@
|
||||
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef NCMPCPP_CMDARGS_H
|
||||
#define NCMPCPP_CMDARGS_H
|
||||
#ifndef NCMPCPP_CONFIGURATION_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
|
||||
@@ -392,10 +392,15 @@ void Display::Items(NC::Menu<MPD::Item> &menu, const ProxySongList &pl)
|
||||
<< "]";
|
||||
break;
|
||||
case MPD::itSong:
|
||||
if (!Config.columns_in_browser)
|
||||
showSongs(menu, *item.song, pl, Config.song_list_format);
|
||||
else
|
||||
showSongsInColumns(menu, *item.song, pl);
|
||||
switch (Config.browser_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
showSongs(menu, *item.song, pl, Config.song_list_format);
|
||||
break;
|
||||
case DisplayMode::Columns:
|
||||
showSongsInColumns(menu, *item.song, pl);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MPD::itPlaylist:
|
||||
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();
|
||||
if (si.isSong())
|
||||
{
|
||||
if (!Config.columns_in_search_engine)
|
||||
showSongs(menu, si.song(), pl, Config.song_list_format);
|
||||
else
|
||||
showSongsInColumns(menu, si.song(), pl);
|
||||
switch (Config.search_engine_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
showSongs(menu, si.song(), pl, Config.song_list_format);
|
||||
break;
|
||||
case DisplayMode::Columns:
|
||||
showSongsInColumns(menu, si.song(), pl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
menu << si.buffer();
|
||||
|
||||
134
src/enums.cpp
Normal file
134
src/enums.cpp
Normal 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
42
src/enums.h
Normal 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
|
||||
@@ -27,7 +27,7 @@
|
||||
bool addSongToPlaylist(const MPD::Song &s, bool play, int position)
|
||||
{
|
||||
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();
|
||||
if (play)
|
||||
|
||||
@@ -434,6 +434,14 @@ void stringToBuffer(const std::basic_string<CharT> &s, NC::BasicBuffer<CharT> &b
|
||||
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)
|
||||
{
|
||||
const unsigned MINUTE = 60;
|
||||
|
||||
@@ -133,7 +133,7 @@ void Lyrics::switchTo()
|
||||
std::wstring Lyrics::title()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -314,8 +314,6 @@ void Lyrics::Load()
|
||||
|
||||
itsFilename = GenerateFilename(itsSong);
|
||||
|
||||
CreateDir(Config.lyrics_directory);
|
||||
|
||||
w.clear();
|
||||
w.reset();
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "bindings.h"
|
||||
#include "browser.h"
|
||||
#include "charset.h"
|
||||
#include "cmdargs.h"
|
||||
#include "configuration.h"
|
||||
#include "global.h"
|
||||
#include "error.h"
|
||||
#include "helpers.h"
|
||||
@@ -101,12 +101,9 @@ int main(int argc, char **argv)
|
||||
std::setlocale(LC_ALL, "");
|
||||
std::locale::global(Charset::internalLocale());
|
||||
|
||||
if (!ParseArguments(argc, argv))
|
||||
if (!configure(argc, argv))
|
||||
return 0;
|
||||
|
||||
Mpd.SetTimeout(Config.mpd_connection_timeout);
|
||||
CreateDir(Config.ncmpcpp_directory);
|
||||
|
||||
// always execute these commands, even if ncmpcpp use exit function
|
||||
atexit(do_at_exit);
|
||||
|
||||
@@ -122,7 +119,7 @@ int main(int argc, char **argv)
|
||||
if (!Config.titles_visibility)
|
||||
wattron(stdscr, COLOR_PAIR(int(Config.main_color)));
|
||||
|
||||
if (Config.new_design)
|
||||
if (Config.design == Design::Alternative)
|
||||
Config.statusbar_visibility = 0;
|
||||
|
||||
Actions::setWindowsDimensions();
|
||||
@@ -130,7 +127,7 @@ int main(int argc, char **argv)
|
||||
Actions::initializeScreens();
|
||||
|
||||
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();
|
||||
|
||||
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
|
||||
Timer = boost::posix_time::microsec_clock::local_time();
|
||||
|
||||
// go to playlist
|
||||
// initialize playlist
|
||||
myPlaylist->switchTo();
|
||||
|
||||
// local variables
|
||||
Key input(0, Key::Standard);
|
||||
boost::posix_time::ptime past = boost::posix_time::from_time_t(0);
|
||||
// local variables end
|
||||
auto past = boost::posix_time::from_time_t(0);
|
||||
|
||||
/// enable mouse
|
||||
mouseinterval(0);
|
||||
if (Config.mouse_support)
|
||||
mousemask(ALL_MOUSE_EVENTS, 0);
|
||||
@@ -240,7 +237,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
catch (OutOfBounds &e)
|
||||
{
|
||||
Statusbar::print(e.errorMessage());
|
||||
Statusbar::printf("Error: %1%", e.errorMessage());
|
||||
}
|
||||
|
||||
if (myScreen == myPlaylist)
|
||||
|
||||
@@ -53,16 +53,21 @@ bool playlistEntryMatcher(const boost::regex &rx, const MPD::Song &s);
|
||||
Playlist::Playlist()
|
||||
: 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.centeredCursor(Config.centered_cursor);
|
||||
w.setHighlightColor(Config.main_highlight_color);
|
||||
w.setSelectedPrefix(Config.selected_item_prefix);
|
||||
w.setSelectedSuffix(Config.selected_item_suffix);
|
||||
if (Config.columns_in_playlist)
|
||||
w.setItemDisplayer(boost::bind(Display::SongsInColumns, _1, proxySongList()));
|
||||
else
|
||||
w.setItemDisplayer(boost::bind(Display::Songs, _1, proxySongList(), Config.song_list_format));
|
||||
switch (Config.playlist_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
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()
|
||||
@@ -80,11 +85,18 @@ void Playlist::resize()
|
||||
w.resize(width, MainHeight);
|
||||
w.moveTo(x_offset, MainStartY);
|
||||
|
||||
if (Config.columns_in_playlist && Config.titles_visibility)
|
||||
w.setTitle(Display::Columns(w.getWidth()));
|
||||
else
|
||||
w.setTitle("");
|
||||
|
||||
switch (Config.playlist_display_mode)
|
||||
{
|
||||
case DisplayMode::Columns:
|
||||
if (Config.titles_visibility)
|
||||
{
|
||||
w.setTitle(Display::Columns(w.getWidth()));
|
||||
break;
|
||||
}
|
||||
case DisplayMode::Classic:
|
||||
w.setTitle("");
|
||||
}
|
||||
|
||||
hasToBeResized = 0;
|
||||
}
|
||||
|
||||
@@ -93,7 +105,7 @@ std::wstring Playlist::title()
|
||||
std::wstring result = L"Playlist ";
|
||||
if (ReloadTotalLength || ReloadRemaining)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -373,10 +385,14 @@ namespace {//
|
||||
std::string songToString(const MPD::Song &s)
|
||||
{
|
||||
std::string result;
|
||||
if (Config.columns_in_playlist)
|
||||
result = s.toString(Config.song_in_columns_to_string_format, Config.tags_separator);
|
||||
else
|
||||
result = s.toString(Config.song_list_format_dollar_free, Config.tags_separator);
|
||||
switch (Config.playlist_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -77,10 +77,15 @@ PlaylistEditor::PlaylistEditor()
|
||||
Content.centeredCursor(Config.centered_cursor);
|
||||
Content.setSelectedPrefix(Config.selected_item_prefix);
|
||||
Content.setSelectedSuffix(Config.selected_item_suffix);
|
||||
if (Config.columns_in_playlist_editor)
|
||||
Content.setItemDisplayer(boost::bind(Display::SongsInColumns, _1, contentProxyList()));
|
||||
else
|
||||
Content.setItemDisplayer(boost::bind(Display::Songs, _1, contentProxyList(), Config.song_list_format));
|
||||
switch (Config.playlist_editor_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
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;
|
||||
}
|
||||
@@ -550,10 +555,15 @@ namespace {//
|
||||
std::string SongToString(const MPD::Song &s)
|
||||
{
|
||||
std::string result;
|
||||
if (Config.columns_in_playlist_editor)
|
||||
result = s.toString(Config.song_in_columns_to_string_format, Config.tags_separator);
|
||||
else
|
||||
result = s.toString(Config.song_list_format_dollar_free, Config.tags_separator);
|
||||
switch (Config.playlist_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,8 +112,10 @@ BaseScreen *toScreen(ScreenType st)
|
||||
# endif // ENABLE_CLOCK
|
||||
case ScreenType::Help:
|
||||
return myHelp;
|
||||
# ifdef HAVE_CURL_CURL_H
|
||||
case ScreenType::Lastfm:
|
||||
return myLastfm;
|
||||
# endif // HAVE_CURL_CURL_H
|
||||
case ScreenType::Lyrics:
|
||||
return myLyrics;
|
||||
case ScreenType::MediaLibrary:
|
||||
|
||||
@@ -119,7 +119,17 @@ void SearchEngine::resize()
|
||||
getWindowResizeParams(x_offset, width);
|
||||
w.resize(width, MainHeight);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -175,7 +185,7 @@ void SearchEngine::enterPressed()
|
||||
Search();
|
||||
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()) : "");
|
||||
size_t found = w.size()-SearchEngine::StaticOptions;
|
||||
found += 3; // don't count options inserted below
|
||||
@@ -616,10 +626,15 @@ std::string SEItemToString(const SEItem &ei)
|
||||
std::string result;
|
||||
if (ei.isSong())
|
||||
{
|
||||
if (Config.columns_in_search_engine)
|
||||
result = ei.song().toString(Config.song_in_columns_to_string_format, Config.tags_separator);
|
||||
else
|
||||
result = ei.song().toString(Config.song_list_format_dollar_free, Config.tags_separator);
|
||||
switch (Config.search_engine_display_mode)
|
||||
{
|
||||
case DisplayMode::Classic:
|
||||
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
|
||||
result = ei.buffer().str();
|
||||
|
||||
1404
src/settings.cpp
1404
src/settings.cpp
File diff suppressed because it is too large
Load Diff
@@ -26,12 +26,11 @@
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <mpd/client.h>
|
||||
#include "actions.h"
|
||||
|
||||
#include "enums.h"
|
||||
#include "screen_type.h"
|
||||
#include "strbuffer.h"
|
||||
|
||||
enum SortMode { smName, smMTime, smCustomFormat };
|
||||
|
||||
struct Column
|
||||
{
|
||||
Column() : stretch_limit(-1), right_alignment(0), display_empty_tag(1) { }
|
||||
@@ -48,25 +47,20 @@ struct Column
|
||||
|
||||
struct Configuration
|
||||
{
|
||||
Configuration();
|
||||
Configuration()
|
||||
: playlist_disable_highlight_delay(0), visualizer_sync_interval(0)
|
||||
{ }
|
||||
|
||||
const std::string &GetHomeDirectory();
|
||||
void CheckForCommandLineConfigFilePath(char **argv, int argc);
|
||||
|
||||
void SetDefaults();
|
||||
void Read(const std::string& config_path);
|
||||
void GenerateColumns();
|
||||
bool read(const std::string &config_path);
|
||||
|
||||
std::string ncmpcpp_directory;
|
||||
std::string lyrics_directory;
|
||||
|
||||
std::string mpd_host;
|
||||
std::string mpd_music_dir;
|
||||
std::string visualizer_fifo_path;
|
||||
std::string visualizer_output_name;
|
||||
std::string empty_tag;
|
||||
std::string tags_separator;
|
||||
std::string song_list_columns_format;
|
||||
std::string song_list_format;
|
||||
std::string song_list_format_dollar_free;
|
||||
std::string song_status_format;
|
||||
@@ -86,9 +80,14 @@ struct Configuration
|
||||
std::wstring visualizer_chars;
|
||||
|
||||
std::string pattern;
|
||||
|
||||
|
||||
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 selected_item_prefix;
|
||||
NC::Buffer selected_item_suffix;
|
||||
@@ -115,16 +114,16 @@ struct Configuration
|
||||
NC::Border window_border;
|
||||
NC::Border active_window_border;
|
||||
|
||||
Design design;
|
||||
|
||||
SpaceAddMode space_add_mode;
|
||||
|
||||
mpd_tag_type media_lib_primary_tag;
|
||||
|
||||
bool colors_enabled;
|
||||
bool playlist_show_remaining_time;
|
||||
bool playlist_shorten_total_times;
|
||||
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 header_visibility;
|
||||
bool header_text_scrolling;
|
||||
@@ -135,7 +134,6 @@ struct Configuration
|
||||
bool autocenter_mode;
|
||||
bool wrapped_search;
|
||||
bool space_selects;
|
||||
bool ncmpc_like_songs_adding;
|
||||
bool incremental_seeking;
|
||||
bool now_playing_lyrics;
|
||||
bool fetch_lyrics_in_background;
|
||||
@@ -150,10 +148,9 @@ struct Configuration
|
||||
bool block_search_constraints_change;
|
||||
bool use_console_editor;
|
||||
bool use_cyclic_scrolling;
|
||||
bool ask_before_clearing_main_playlist;
|
||||
bool ask_before_clearing_playlists;
|
||||
bool mouse_support;
|
||||
bool mouse_list_scroll_whole_page;
|
||||
bool new_design;
|
||||
bool visualizer_use_wave;
|
||||
bool visualizer_in_stereo;
|
||||
bool media_library_sort_by_mtime;
|
||||
@@ -165,18 +162,16 @@ struct Configuration
|
||||
bool allow_for_physical_item_deletion;
|
||||
bool progressbar_boldness;
|
||||
|
||||
int mpd_port;
|
||||
int mpd_connection_timeout;
|
||||
int crossfade_time;
|
||||
int seek_time;
|
||||
int volume_change_step;
|
||||
int message_delay_time;
|
||||
int lyrics_db;
|
||||
|
||||
boost::regex::flag_type regex_type;
|
||||
|
||||
unsigned mpd_connection_timeout;
|
||||
unsigned crossfade_time;
|
||||
unsigned seek_time;
|
||||
unsigned volume_change_step;
|
||||
unsigned message_delay_time;
|
||||
unsigned lyrics_db;
|
||||
unsigned lines_scrolled;
|
||||
unsigned search_engine_default_search_mode;
|
||||
|
||||
boost::regex::flag_type regex_type;
|
||||
|
||||
boost::posix_time::seconds playlist_disable_highlight_delay;
|
||||
boost::posix_time::seconds visualizer_sync_interval;
|
||||
@@ -189,19 +184,12 @@ struct Configuration
|
||||
size_t now_playing_suffix_length;
|
||||
|
||||
ScreenType startup_screen_type;
|
||||
std::list<ScreenType> screens_seq;
|
||||
std::list<ScreenType> screen_sequence;
|
||||
|
||||
SortMode browser_sort_mode;
|
||||
|
||||
private:
|
||||
void MakeProperPath(std::string &dir);
|
||||
|
||||
std::string home_directory;
|
||||
};
|
||||
|
||||
extern Configuration Config;
|
||||
|
||||
void CreateDir(const std::string &dir);
|
||||
|
||||
#endif // NCMPCPP_SETTINGS_H
|
||||
|
||||
|
||||
15
src/song.cpp
15
src/song.cpp
@@ -288,7 +288,7 @@ std::string Song::ShowTime(unsigned length)
|
||||
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;
|
||||
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;
|
||||
}
|
||||
if (braces)
|
||||
{
|
||||
std::cerr << type << ": number of opening and closing braces does not equal\n";
|
||||
return false;
|
||||
}
|
||||
throw std::runtime_error("number of opening and closing braces is not equal");
|
||||
|
||||
for (size_t i = fmt.find('%'); i != std::string::npos; i = fmt.find('%', i))
|
||||
{
|
||||
if (isdigit(fmt[++i]))
|
||||
while (isdigit(fmt[++i])) { }
|
||||
if (!charToGetFunction(fmt[i]))
|
||||
{
|
||||
std::cerr << type << ": invalid character at position " << boost::lexical_cast<std::string>(i+1) << ": '" << fmt[i] << "'\n";
|
||||
return false;
|
||||
}
|
||||
throw std::runtime_error(
|
||||
(boost::format("invalid character at position %1%: %2%") % (i+1) % fmt[i]).str()
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Song::ParseFormat(std::string::const_iterator &it, const std::string &tags_separator,
|
||||
|
||||
@@ -80,7 +80,7 @@ struct Song
|
||||
bool operator!=(const Song &rhs) const { return m_hash != rhs.m_hash; }
|
||||
|
||||
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;
|
||||
|
||||
|
||||
272
src/status.cpp
272
src/status.cpp
@@ -80,19 +80,19 @@ std::string playerStateToString(MPD::PlayerState ps)
|
||||
result = "[unknown]";
|
||||
break;
|
||||
case MPD::psPlay:
|
||||
if (Config.new_design)
|
||||
if (Config.design == Design::Alternative)
|
||||
result = "[playing]";
|
||||
else
|
||||
result = "Playing: ";
|
||||
break;
|
||||
case MPD::psPause:
|
||||
if (Config.new_design)
|
||||
if (Config.design == Design::Alternative)
|
||||
result = "[paused] ";
|
||||
else
|
||||
result = "[Paused] ";
|
||||
break;
|
||||
case MPD::psStop:
|
||||
if (Config.new_design)
|
||||
if (Config.design == Design::Alternative)
|
||||
result = "[stopped]";
|
||||
break;
|
||||
default:
|
||||
@@ -337,7 +337,7 @@ void Status::Changes::playerState()
|
||||
if (Progressbar::isUnlocked())
|
||||
Progressbar::draw(0, 0);
|
||||
Playlist::ReloadRemaining = true;
|
||||
if (Config.new_design)
|
||||
if (Config.design == Design::Alternative)
|
||||
{
|
||||
*wHeader << NC::XY(0, 0) << wclrtoeol << NC::XY(0, 1) << wclrtoeol;
|
||||
mixer();
|
||||
@@ -358,7 +358,7 @@ void Status::Changes::playerState()
|
||||
# endif // ENABLE_VISUALIZER
|
||||
|
||||
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->refresh();
|
||||
@@ -428,85 +428,88 @@ void Status::Changes::elapsedTime(bool update_elapsed)
|
||||
drawTitle(np);
|
||||
|
||||
std::string tracklength;
|
||||
if (Config.new_design)
|
||||
switch (Config.design)
|
||||
{
|
||||
if (Config.display_remaining_time)
|
||||
{
|
||||
tracklength = "-";
|
||||
tracklength += MPD::Song::ShowTime(st.totalTime()-st.elapsedTime());
|
||||
}
|
||||
else
|
||||
tracklength = MPD::Song::ShowTime(st.elapsedTime());
|
||||
if (st.totalTime())
|
||||
{
|
||||
tracklength += "/";
|
||||
tracklength += MPD::Song::ShowTime(st.totalTime());
|
||||
}
|
||||
// bitrate here doesn't look good, but it can be moved somewhere else later
|
||||
if (Config.display_bitrate && st.kbps())
|
||||
{
|
||||
tracklength += " ";
|
||||
tracklength += boost::lexical_cast<std::string>(st.kbps());
|
||||
tracklength += " kbps";
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
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())
|
||||
{
|
||||
case Design::Classic:
|
||||
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)
|
||||
{
|
||||
tracklength += "-";
|
||||
tracklength += MPD::Song::ShowTime(st.totalTime()-st.elapsedTime());
|
||||
}
|
||||
else
|
||||
tracklength += MPD::Song::ShowTime(st.elapsedTime());
|
||||
tracklength += "/";
|
||||
tracklength += MPD::Song::ShowTime(st.totalTime());
|
||||
tracklength += "]";
|
||||
}
|
||||
else
|
||||
{
|
||||
tracklength += MPD::Song::ShowTime(st.elapsedTime());
|
||||
tracklength += "]";
|
||||
}
|
||||
NC::WBuffer np_song;
|
||||
stringToBuffer(ToWString(Charset::utf8ToLocale(np.toString(Config.song_status_format, Config.tags_separator, "$"))), np_song);
|
||||
*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;
|
||||
}
|
||||
break;
|
||||
case Design::Alternative:
|
||||
if (Config.display_remaining_time)
|
||||
{
|
||||
tracklength += "-";
|
||||
tracklength = "-";
|
||||
tracklength += MPD::Song::ShowTime(st.totalTime()-st.elapsedTime());
|
||||
}
|
||||
else
|
||||
tracklength += MPD::Song::ShowTime(st.elapsedTime());
|
||||
tracklength += "/";
|
||||
tracklength += MPD::Song::ShowTime(st.totalTime());
|
||||
tracklength += "]";
|
||||
}
|
||||
else
|
||||
{
|
||||
tracklength += MPD::Song::ShowTime(st.elapsedTime());
|
||||
tracklength += "]";
|
||||
}
|
||||
NC::WBuffer np_song;
|
||||
stringToBuffer(ToWString(Charset::utf8ToLocale(np.toString(Config.song_status_format, Config.tags_separator, "$"))), np_song);
|
||||
*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;
|
||||
tracklength = MPD::Song::ShowTime(st.elapsedTime());
|
||||
if (st.totalTime())
|
||||
{
|
||||
tracklength += "/";
|
||||
tracklength += MPD::Song::ShowTime(st.totalTime());
|
||||
}
|
||||
// bitrate here doesn't look good, but it can be moved somewhere else later
|
||||
if (Config.display_bitrate && st.kbps())
|
||||
{
|
||||
tracklength += " ";
|
||||
tracklength += boost::lexical_cast<std::string>(st.kbps());
|
||||
tracklength += " kbps";
|
||||
}
|
||||
|
||||
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())
|
||||
Progressbar::draw(st.elapsedTime(), st.totalTime());
|
||||
@@ -557,69 +560,78 @@ void Status::Changes::dbUpdateState(bool show_msg)
|
||||
|
||||
void Status::Changes::flags()
|
||||
{
|
||||
if (!Config.header_visibility && !Config.new_design)
|
||||
if (!Config.header_visibility && Config.design == Design::Classic)
|
||||
return;
|
||||
|
||||
std::string switch_state;
|
||||
if (Config.new_design)
|
||||
switch (Config.design)
|
||||
{
|
||||
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.new_design && !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();
|
||||
}
|
||||
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
|
||||
// window only for handling this is quite silly
|
||||
attrset(A_BOLD|COLOR_PAIR(int(Config.state_line_color)));
|
||||
mvhline(1, 0, 0, COLS);
|
||||
if (!switch_state.empty())
|
||||
{
|
||||
mvprintw(1, COLS-switch_state.length()-3, "[");
|
||||
attroff(COLOR_PAIR(int(Config.state_line_color)));
|
||||
attron(COLOR_PAIR(int(Config.state_flags_color)));
|
||||
mvprintw(1, COLS-switch_state.length()-2, "%s", switch_state.c_str());
|
||||
attroff(COLOR_PAIR(int(Config.state_flags_color)));
|
||||
attron(COLOR_PAIR(int(Config.state_line_color)));
|
||||
mvprintw(1, COLS-2, "]");
|
||||
}
|
||||
attroff(A_BOLD|COLOR_PAIR(int(Config.state_line_color)));
|
||||
refresh();
|
||||
case Design::Classic:
|
||||
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
|
||||
// window only for handling this is quite silly
|
||||
attrset(A_BOLD|COLOR_PAIR(int(Config.state_line_color)));
|
||||
mvhline(1, 0, 0, COLS);
|
||||
if (!switch_state.empty())
|
||||
{
|
||||
mvprintw(1, COLS-switch_state.length()-3, "[");
|
||||
attroff(COLOR_PAIR(int(Config.state_line_color)));
|
||||
attron(COLOR_PAIR(int(Config.state_flags_color)));
|
||||
mvprintw(1, COLS-switch_state.length()-2, "%s", switch_state.c_str());
|
||||
attroff(COLOR_PAIR(int(Config.state_flags_color)));
|
||||
attron(COLOR_PAIR(int(Config.state_line_color)));
|
||||
mvprintw(1, COLS-2, "]");
|
||||
}
|
||||
attroff(A_BOLD|COLOR_PAIR(int(Config.state_line_color)));
|
||||
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()
|
||||
{
|
||||
if (!Config.display_volume_level || (!Config.header_visibility && !Config.new_design))
|
||||
if (!Config.display_volume_level || (!Config.header_visibility && Config.design == Design::Classic))
|
||||
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)
|
||||
VolumeState += "n/a";
|
||||
else
|
||||
|
||||
@@ -106,10 +106,15 @@ void Statusbar::unlock()
|
||||
}
|
||||
if (Status::State::player() == MPD::psStop)
|
||||
{
|
||||
if (Config.new_design)
|
||||
Progressbar::draw(Status::State::elapsedTime(), myPlaylist->currentSongLength());
|
||||
else
|
||||
put() << wclrtoeol;
|
||||
switch (Config.design)
|
||||
{
|
||||
case Design::Classic:
|
||||
put() << wclrtoeol;
|
||||
break;
|
||||
case Design::Alternative:
|
||||
Progressbar::draw(Status::State::elapsedTime(), myPlaylist->currentSongLength());
|
||||
break;
|
||||
}
|
||||
wFooter->refresh();
|
||||
}
|
||||
}
|
||||
@@ -134,10 +139,15 @@ void Statusbar::tryRedraw()
|
||||
|
||||
if (Status::State::player() != MPD::psStop && !statusbarBlockUpdate && !progressbarBlockUpdate)
|
||||
{
|
||||
if (Config.new_design)
|
||||
Progressbar::draw(Status::State::elapsedTime(), myPlaylist->currentSongLength());
|
||||
else
|
||||
Status::Changes::elapsedTime(false);
|
||||
switch (Config.design)
|
||||
{
|
||||
case Design::Classic:
|
||||
Status::Changes::elapsedTime(false);
|
||||
break;
|
||||
case Design::Alternative:
|
||||
Progressbar::draw(Status::State::elapsedTime(), myPlaylist->currentSongLength());
|
||||
break;
|
||||
}
|
||||
wFooter->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,18 +63,19 @@ template <typename CharT> class BasicBuffer
|
||||
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)
|
||||
{
|
||||
case Type::Color:
|
||||
w << p.m_color;
|
||||
os << p.m_color;
|
||||
break;
|
||||
case Type::Format:
|
||||
w << p.m_format;
|
||||
os << p.m_format;
|
||||
break;
|
||||
}
|
||||
return w;
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -89,8 +90,12 @@ public:
|
||||
typedef std::basic_string<CharT> StringType;
|
||||
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 Properties &properties() const { return m_properties; }
|
||||
|
||||
@@ -183,6 +188,14 @@ public:
|
||||
}
|
||||
|
||||
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;
|
||||
Properties m_properties;
|
||||
};
|
||||
@@ -190,11 +203,11 @@ private:
|
||||
typedef BasicBuffer<char> Buffer;
|
||||
typedef BasicBuffer<wchar_t> WBuffer;
|
||||
|
||||
template <typename CharT>
|
||||
Window &operator<<(Window &w, const BasicBuffer<CharT> &buffer)
|
||||
template <typename OutputStreamT, typename CharT>
|
||||
OutputStreamT &operator<<(OutputStreamT &os, const BasicBuffer<CharT> &buffer)
|
||||
{
|
||||
if (buffer.properties().empty())
|
||||
w << buffer.str();
|
||||
os << buffer.str();
|
||||
else
|
||||
{
|
||||
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 (; p != ps.end() && p->position() == i; ++p)
|
||||
w << *p;
|
||||
w << s[i];
|
||||
os << *p;
|
||||
os << s[i];
|
||||
}
|
||||
// load remaining properties
|
||||
for (; p != ps.end(); ++p)
|
||||
w << *p;
|
||||
os << *p;
|
||||
}
|
||||
return w;
|
||||
return os;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
#include <boost/locale/conversion.hpp>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
#include "actions.h"
|
||||
#include "browser.h"
|
||||
#include "charset.h"
|
||||
#include "display.h"
|
||||
|
||||
@@ -44,23 +44,24 @@ void drawHeader()
|
||||
|
||||
if (!Config.header_visibility)
|
||||
return;
|
||||
if (Config.new_design)
|
||||
switch (Config.design)
|
||||
{
|
||||
std::wstring title = myScreen->title();
|
||||
*wHeader << NC::XY(0, 3) << wclrtoeol;
|
||||
*wHeader << NC::Format::Bold << Config.alternative_ui_separator_color;
|
||||
mvwhline(wHeader->raw(), 2, 0, 0, COLS);
|
||||
mvwhline(wHeader->raw(), 4, 0, 0, COLS);
|
||||
*wHeader << NC::XY((COLS-wideLength(title))/2, 3);
|
||||
*wHeader << Config.header_color << title << NC::Color::End;
|
||||
*wHeader << NC::Color::End << NC::Format::NoBold;
|
||||
}
|
||||
else
|
||||
{
|
||||
*wHeader << NC::XY(0, 0) << wclrtoeol << NC::Format::Bold << myScreen->title() << NC::Format::NoBold;
|
||||
*wHeader << Config.volume_color;
|
||||
*wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << VolumeState;
|
||||
*wHeader << NC::Color::End;
|
||||
case Design::Classic:
|
||||
*wHeader << NC::XY(0, 0) << wclrtoeol << NC::Format::Bold << myScreen->title() << NC::Format::NoBold;
|
||||
*wHeader << Config.volume_color;
|
||||
*wHeader << NC::XY(wHeader->getWidth()-VolumeState.length(), 0) << VolumeState;
|
||||
*wHeader << NC::Color::End;
|
||||
break;
|
||||
case Design::Alternative:
|
||||
std::wstring title = myScreen->title();
|
||||
*wHeader << NC::XY(0, 3) << wclrtoeol;
|
||||
*wHeader << NC::Format::Bold << Config.alternative_ui_separator_color;
|
||||
mvwhline(wHeader->raw(), 2, 0, 0, COLS);
|
||||
mvwhline(wHeader->raw(), 4, 0, 0, COLS);
|
||||
*wHeader << NC::XY((COLS-wideLength(title))/2, 3);
|
||||
*wHeader << Config.header_color << title << NC::Color::End;
|
||||
*wHeader << NC::Color::End << NC::Format::NoBold;
|
||||
break;
|
||||
}
|
||||
wHeader->refresh();
|
||||
}
|
||||
|
||||
@@ -68,13 +68,13 @@ bool LocaleBasedItemSorting::operator()(const MPD::Item &a, const MPD::Item &b)
|
||||
case MPD::itSong:
|
||||
switch (m_sort_mode)
|
||||
{
|
||||
case smName:
|
||||
case SortMode::Name:
|
||||
result = m_cmp(*a.song, *b.song);
|
||||
break;
|
||||
case smMTime:
|
||||
case SortMode::ModificationTime:
|
||||
result = a.song->getMTime() > b.song->getMTime();
|
||||
break;
|
||||
case smCustomFormat:
|
||||
case SortMode::CustomFormat:
|
||||
result = m_cmp(a.song->toString(Config.browser_sort_format, Config.tags_separator),
|
||||
b.song->toString(Config.browser_sort_format, Config.tags_separator));
|
||||
break;
|
||||
|
||||
@@ -18,10 +18,14 @@
|
||||
* 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/lexical_cast.hpp>
|
||||
#include <boost/type_traits/is_unsigned.hpp>
|
||||
|
||||
#include "config.h"
|
||||
#include "gcc.h"
|
||||
|
||||
struct ConversionError
|
||||
@@ -35,7 +39,7 @@ private:
|
||||
std::string m_source_value;
|
||||
};
|
||||
|
||||
struct OutOfBounds
|
||||
struct OutOfBounds : std::exception
|
||||
{
|
||||
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)
|
||||
{
|
||||
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>
|
||||
GNUC_NORETURN static void raiseLower(const Type &value, const Type &lbound)
|
||||
{
|
||||
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>
|
||||
GNUC_NORETURN static void raiseUpper(const Type &value, const Type &ubound)
|
||||
{
|
||||
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:
|
||||
OutOfBounds(std::string msg) : m_error_message(msg) { }
|
||||
|
||||
@@ -115,3 +121,5 @@ void upperBoundCheck(const Type &value, const Type &ubound)
|
||||
if (value > ubound)
|
||||
OutOfBounds::raiseUpper(value, ubound);
|
||||
}
|
||||
|
||||
#endif // NCMPCPP_UTILITY_CONVERSION_H
|
||||
|
||||
37
src/utility/functional.h
Normal file
37
src/utility/functional.h
Normal 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
|
||||
82
src/utility/option_parser.cpp
Normal file
82
src/utility/option_parser.cpp
Normal 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
131
src/utility/option_parser.h
Normal 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
|
||||
191
src/window.cpp
191
src/window.cpp
@@ -21,6 +21,7 @@
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
|
||||
@@ -158,6 +159,196 @@ int add_base()
|
||||
|
||||
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)
|
||||
{
|
||||
const int ColorsTable[] =
|
||||
|
||||
10
src/window.h
10
src/window.h
@@ -114,6 +114,9 @@ namespace NC {//
|
||||
/// Colors used by NCurses
|
||||
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
|
||||
enum class Format {
|
||||
None,
|
||||
@@ -123,12 +126,19 @@ enum class Format {
|
||||
AltCharset, NoAltCharset
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, Format f);
|
||||
|
||||
/// Available border colors for window
|
||||
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
|
||||
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
|
||||
/// to obtain string from Window::getString() function
|
||||
/// @see Window::getString()
|
||||
|
||||
Reference in New Issue
Block a user