App-Music-ChordPro-Wx

 view release on metacpan or  search on metacpan

lib/App/Music/ChordPro/Wx/Main.pm  view on Meta::CPAN

#! perl

use strict;
use warnings;

# Implementation of App::Music::ChordPro::Wx::Main_wxg details.

package App::Music::ChordPro::Wx::Main;

# App::Music::ChordPro::Wx::Main_wxg is generated by wxGlade and contains
# all UI associated code.

use base qw( App::Music::ChordPro::Wx::Main_wxg );

use Wx qw[:everything];
use Wx::Locale gettext => '_T';

use App::Music::ChordPro::Wx;
use App::Music::ChordPro;
use App::Packager;
use File::Temp qw( tempfile );
use Encode qw(decode_utf8);

our $VERSION = $App::Music::ChordPro::Wx::VERSION;

sub new {
    my $self = bless $_[0]->SUPER::new(), __PACKAGE__;

    Wx::Event::EVT_IDLE($self, $self->can('OnIdle'));

    $self;
}

use constant FONTSIZE => 12;

my @fonts =
  ( { name => "Monospace",
      font => Wx::Font->new( FONTSIZE, wxFONTFAMILY_TELETYPE,
			     wxFONTSTYLE_NORMAL,
			     wxFONTWEIGHT_NORMAL ),
    },
    { name => "Serif",
      font => Wx::Font->new( FONTSIZE, wxFONTFAMILY_ROMAN,
			     wxFONTSTYLE_NORMAL,
			     wxFONTWEIGHT_NORMAL ),
    },
    { name => "Sans serif",
      font => Wx::Font->new( FONTSIZE, wxFONTFAMILY_SWISS,
			     wxFONTSTYLE_NORMAL,
			     wxFONTWEIGHT_NORMAL ),
    },
  );

my $prefctl;

# Explicit (re)initialisation of this class.
sub init {
    my ( $self, $options ) = @_;

    $prefctl ||=
      {
       cfgpreset => lc(_T("Default")),
       xcode => "",
       notation => "",
       skipstdcfg => 1,
       configfile => "",
       pdfviewer => "",
       editfont => 0,
       editsize => FONTSIZE,
      };

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

    $self->{_verbose} = $options->{verbose};
    $self->{_trace}   = $options->{trace};
    $self->{_debug}   = $options->{debug};

    $self->GetPreferences;
    my $font = $fonts[$self->{prefs_editfont}]->{font};
    $font->SetPointSize($self->{prefs_editsize});
    $self->{t_source}->SetFont($font);

    # Disable menu items if we cannot.
    $self->{main_menubar}->FindItem(wxID_UNDO)
      ->Enable($self->{t_source}->CanUndo);
    $self->{main_menubar}->FindItem(wxID_REDO)
      ->Enable($self->{t_source}->CanRedo);

    Wx::Log::SetTimestamp(' ');
    if ( @ARGV && -s $ARGV[0] ) {
	$self->openfile( shift(@ARGV) );
	return 1;
    }

    $self->opendialog;
    $self->newfile unless $self->{_currentfile};
    return 1;
}

################ Internal methods ################

# List of available config presets (styles).
my $stylelist;
sub stylelist {
    return $stylelist if $stylelist && @$stylelist;
    my $cfglib = getresource("config");
    $stylelist = [];
    if ( -d $cfglib ) {
	opendir( my $dh, $cfglib );
	foreach ( sort readdir($dh) ) {
	    $_ = decode_utf8($_);
	    next unless /^(.*)\.json$/;
	    my $base = $1;
	    unshift( @$stylelist, $base ), next
	      if $base eq "chordpro"; # default
	    push( @$stylelist, $base );
	}
    }
    push( @$stylelist, "custom" );
    return $stylelist;
}

# List of available notation systems.
my $notationlist;
sub notationlist {
    return $notationlist if $notationlist && @$notationlist;
    my $cfglib = getresource("notes");
    $notationlist = [ undef ];
    if ( -d $cfglib ) {
	opendir( my $dh, $cfglib );
	foreach ( sort readdir($dh) ) {
	    $_ = decode_utf8($_);
	    next unless /^(.*)\.json$/;
	    my $base = $1;
	    $notationlist->[0] = "common", next
	      if $base eq "common";
	    push( @$notationlist, $base )
	}
    }
    return $notationlist;
}

sub fonts { \@fonts }

sub opendialog {
    my ($self) = @_;
    my $fd = Wx::FileDialog->new
      ($self, _T("Choose ChordPro file"),
       "", "",
       "ChordPro files (*.cho,*.crd,*.chopro,*.chord,*.chordpro,*.pro)|*.cho;*.crd;*.chopro;*.chord;*.chordpro;*.pro|All files|*.*",
       0|wxFD_OPEN|wxFD_FILE_MUST_EXIST,
       wxDefaultPosition);
    my $ret = $fd->ShowModal;
    if ( $ret == wxID_OK ) {
	$self->openfile( $fd->GetPath );
    }
    $fd->Destroy;
}

sub openfile {
    my ( $self, $file ) = @_;
    unless ( $self->{t_source}->LoadFile($file) ) {
	my $md = Wx::MessageDialog->new
	  ( $self,
	    "Error opening $file: $!",
	    "File open error",
	    wxOK | wxICON_ERROR );
	$md->ShowModal;
	$md->Destroy;
	return;
    }
    #### TODO: Get rid of selection on Windows
    $self->{_currentfile} = $file;
    if ( $self->{t_source}->GetValue =~ /^\{\s*t(?:itle)[: ]+([^\}]*)\}/m ) {
	my $n = $self->{t_source}->GetNumberOfLines;
	Wx::LogStatus("Loaded: $1 ($n line" .
		      ( $n == 1 ? "" : "s" ) .
		      ")");
	$self->{sz_source}->GetStaticBox->SetLabel($1);
    }
    $self->SetTitle( $self->{_windowtitle} = $file);

    $self->{prefs_xpose} = 0;
    $self->{prefs_xposesharp} = 0;
}

sub newfile {
    my ( $self ) = @_;
    undef $self->{_currentfile};
    $self->{t_source}->SetValue( <<EOD );
{title: New Song}

EOD
    Wx::LogStatus("New file");
    $self->{prefs_xpose} = 0;
    $self->{prefs_xposesharp} = 0;
}

my ( $preview_cho, $preview_pdf );
my ( $msgs, $fatal, $died );

sub _warn {
    Wx::LogWarning(@_);



( run in 1.027 second using v1.01-cache-2.11-cpan-5b529ec07f3 )