App-Music-ChordPro

 view release on metacpan or  search on metacpan

lib/ChordPro/Wx/Config.pm  view on Meta::CPAN

#! perl

use v5.26;
use Object::Pad;

class ChordPro::Wx::Config;

our %state;
our %preferences;

use Ref::Util qw( is_hashref is_arrayref );
use List::Util qw( uniq any first );

use Exporter 'import';
our @EXPORT = qw( %state %preferences );

my $cb;

use Wx qw(:everything);
use Wx::Locale gettext => '_T';
use ChordPro::Files;
use ChordPro::Paths;
use ChordPro::Utils qw( plural json_load is_true );

use constant FONTSIZE => 12;
use constant SETTINGS_VERSION => 3;

use Encode qw( decode_utf8 );

# Legacy font numbers.
my @fonts =
  ( # Monospace
    Wx::Font->new( FONTSIZE, wxFONTFAMILY_TELETYPE,
		   wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL ),
    # Serif
    Wx::Font->new( FONTSIZE, wxFONTFAMILY_ROMAN,
		   wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL ),

    # Sans serif
    Wx::Font->new( FONTSIZE, wxFONTFAMILY_SWISS,
		   wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL ),
    # Modern
    Wx::Font->new( FONTSIZE, wxFONTFAMILY_MODERN,
		   wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL ),
  );

my %prefs =
  (
   # (Old) config version.
   settings_version => SETTINGS_VERSION - 1,

   # Skip default (system, user, song) configs.
   skipstdcfg  => 1,
   # Skip legacy (un-classified) configs.
   skipoldcfg  => 0,

   # Presets.
   # Title as defined by or derived from the JSON file.
   # When multiple presets are possible, a list of titles separated by TABs
   # (which are imported as a []).
   # Note it is always a [] even when there's only one.
   # Every preset_xxx is a list of entries from $state{preset}{xxx}.
   preset_instruments => [],	# single
   preset_styles      => [],	# single
   preset_stylemods   => [],
   preset_notations   => [],	# single
   preset_tasks       => [],	# not used

   # This one is slightly different, since it does not have configs associated.
   preset_xcodes      => [],	# single

   # Custom config file.
   enable_configfile => 0,
   configfile        => "",

   # Custom library.
   enable_customlib => 0,	# defined($ENV{CHORDPRO_LIB}),
   customlib        => "",	# $ENV{CHORDPRO_LIB},

   # New song template.
   enable_tmplfile => 0,
   tmplfile        => "",

   # Editor.
   editfont	   => 0,	# inital, later "Monospace 10" etc.
   editsize	   => FONTSIZE,
   editortheme	   => "auto",

   # Mostly for STC. TextCtrl fallback uses fg and bg only.
   editcolour_light_fg	   => "#000000",
   editcolour_light_bg	   => "#ffffff",
   editcolour_light_s1	   => "#b1b1b1",
   editcolour_light_s2	   => "#b1b1b1",
   editcolour_light_s3	   => "#b1b1b1",
   editcolour_light_s4	   => "#ff3c31",
   editcolour_light_s5	   => "#0068d0",
   editcolour_light_s6	   => "#ef6c2a",
   editcolour_light_annfg  => "#ff0000",
   editcolour_light_annbg  => "#ffffa0",
   editcolour_light_numfg  => "#303030",
   editcolour_light_numbg  => "#e8e8e8",
   editcolour_dark_fg	   => "#ffffff",
   editcolour_dark_bg	   => "#000000",
   editcolour_dark_s1	   => "#b1b1b1",
   editcolour_dark_s2	   => "#b1b1b1",
   editcolour_dark_s3	   => "#b1b1b1",
   editcolour_dark_s4	   => "#ff3c31",
   editcolour_dark_s5	   => "#0068d0",
   editcolour_dark_s6	   => "#ef6c2a",
   editcolour_dark_annfg   => "#ff0000",
   editcolour_dark_annbg   => "#ffffa0",
   editcolour_dark_numfg   => "#e8e8e8",
   editcolour_dark_numbg   => "#303030",

   editorwrap       => 1,
   editorwrapindent => 2,

   # Messages.
   msgsfont	   => 0,	# inital, later "Monospace 10" etc.

   # Transcode.
   enable_xcode	   => 0,

   # PDF Viewer.
   enable_pdfviewer   => undef,
   pdfviewer   => "",

   # HTML Viewer.
   enable_htmlviewer => undef,

   # Insert spec chars.
   enable_insert_symbols => 0,

   # Preferences w/o UI.
   chordproext	=> ".chordpro",	# for Nick
   dumpstate	=> 0,
   expert	=> 0,
   advanced	=> 0,
  );

use constant MAXRECENTS => 10;
my $config_root = "/";

# Establish a connection with the persistent data store.

#method Setup :common ($options) {
sub Setup( $class, $options ) {

    if ( $options->{config} ) {
	Wx::ConfigBase::Set
	    ( $cb = Wx::FileConfig->new
	     ( "WxChordPro",
	       "ChordPro_ORG",
	       $options->{config},
	       '',
	       wxCONFIG_USE_LOCAL_FILE,
	     ));
    }
    elsif ( $^O =~ /^mswin/i ) {
	$cb = Wx::ConfigBase::Get;
	$config_root = "/wxchordpro";
	$cb->SetPath($config_root);
    }
    else {
	my $file;
	if ( $ENV{XDG_CONFIG_HOME} && fs_test( d => $ENV{XDG_CONFIG_HOME} ) ) {
	    $file =
	      $ENV{XDG_CONFIG_HOME} . "/wxchordpro/wxchordpro";
	}
	elsif ( -d "$ENV{HOME}/.config" ) {
	    $file = "$ENV{HOME}/.config/wxchordpro/wxchordpro";
	    mkdir("$ENV{HOME}/.config/wxchordpro");
	}
	else {
	    $file = "$ENV{HOME}/.wxchordpro";
	}
	unless ( fs_test( f => $file ) ) {
	    my $fd = fs_open( $file, '>' );
	}

lib/ChordPro/Wx/Config.pm  view on Meta::CPAN

		}
		else {
		    warn("Preferences: unknown key: $entry");
		    $cb->DeleteEntry($entry);
		    next;
		}

		# These are always returned as lists of hashes.
		if ( $entry =~ m/^preset_(instruments|styles|stylemods|notations|tasks|xcodes)/ ) {
		    $preferences{$entry} =
		      [ map { +{ title => lc($_) } } split( /\t+/, $value ) ];
		}

		elsif ( $entry eq "editcolours" ) {
		    my @c = split( /,\s*/, $value );
		    if ( @c <= 1 ) {
			...;
		    }
		    else {
			$preferences{editcolour}{light}{fg} = $c[0];
			$preferences{editcolour}{light}{bg} = $c[1];
			$preferences{editcolour}{light}{s1} = $c[2];
			$preferences{editcolour}{light}{s2} = $c[3];
			$preferences{editcolour}{light}{s3} = $c[4];
			$preferences{editcolour}{light}{s4} = $c[5];
			$preferences{editcolour}{light}{s5} = $c[6];
			$preferences{editcolour}{light}{annbg} = $c[7];
			$preferences{editcolour}{light}{annfg} = "#ff0000";
			$preferences{editcolour}{light}{numbg} =
			  $preferences{editcolour}{dark}{numfg} = "#e8e8e8";
			$preferences{editcolour}{light}{numfg} =
			  $preferences{editcolour}{dark}{numbg} = "#303030";
		    }
		}
		elsif ( $entry =~ /^(editcolour)_(\w+)_(\w+)$/ ) {
		    $cb->DeleteEntry($entry), next if $2 eq "auto";
		    $preferences{$1}{$2}{$3} = $value;
		}
		else {
		    $preferences{$entry} = $value;
		}
	    }
	    elsif ( $group eq "recents" ) {
		push( @{$state{$group}}, $value )
		  if fs_test( 's', $value );
	    }
	    else {
		$state{$group}->{$entry} = $value;
	    }
	}
	continue {
	    ( $goon, $entry, $index ) = $cb->GetNextEntry($index);
	}
	$cb->SetPath($cp);
	( $ggoon, $group, $gindex ) = $cb->GetNextGroup($gindex);
    }

    # Catch mistakes and abuse.
    lock_keys(%preferences);

    # Legacy font number -> font desc.
    for ( qw( editfont msgsfont ) ) {
	next unless $preferences{$_} =~ /^\d+$/;
	$preferences{$_} = $fonts[$preferences{$_}]->GetNativeFontInfoDesc;
    }
    delete $ENV{CHORDPRO_LIB};

    if ( $preferences{settings_version} < SETTINGS_VERSION ) {
	for ( qw( windows sash ) ) {
	    delete $state{$_};
	    $cb->DeleteGroup($_);
	}
    }

    $preferences{enable_pdfviewer} //= 0;
    $preferences{enable_htmlviewer} //= 0;
    $cb->Flush;

    # Collect from the environment.
    CP->setup_resdirs;
    setup_styles();

    # For convenience.
    setup_filters();

    if ( $preferences{dumpstate} ) {
	use DDP; p %state;
    }
}

# Store the preferences and other persistent state.

method Store :common {

    my $cp = $config_root;
    $preferences{settings_version} = SETTINGS_VERSION;
    $cb->DeleteAll;
    $cb->SetPath($cp);

    # We sort all the keys, so we can compare configs (for testing).
    for my $group ( sort keys %state ) {
	my $v = $state{$group};

	next unless $group =~ m{ ^(?:
				     preferences | messages | recents |
				     sash | songbookexport | windows
				 )$ }x;
	$cb->SetPath($cp);

	# Re-write the recents. Array.
	if ( $group eq "recents" && is_arrayref($v) ) {
	    # $cb->DeleteGroup($group);
	    $cb->SetPath($group);
	    for ( my $i = 0; $i < @$v; $i++ ) {
		last if $i >= MAXRECENTS;
		$cb->Write( "$i", $v->[$i] );
	    }
	    next;
	}

	# Everything else are hash refs.
	next unless is_hashref($v);

	$cb->SetPath($group);



( run in 1.255 second using v1.01-cache-2.11-cpan-5735350b133 )