App-InvestSim

 view release on metacpan or  search on metacpan

lib/App/InvestSim/GUI.pm  view on Meta::CPAN

    $root->g_bind('<Control-s>', \&save_values);
    $file->m_add_command(-label => "Enregistrer sous...", -accelerator => 'Ctrl+Alt+S',  -underline => 12,-command => \&save_values_as);
    $root->g_bind('<Control-Alt-s>', \&save_values_as);
    $file->add_separator();
    $file->m_add_command(-label => "Quitter", -accelerator => 'Alt+F4',  -underline => 0,-command => sub { $root->g_destroy() });
    # The binding for Alt-F4 is automatically supplied by Windows and can't be
    # overriden. It will destroy the window. We catch it as well as the menu entry
    # using the following bind command.
    # If we bind to $root, then the event triggers for all contained widget.
    $root->g_bind('<Destroy>', [sub { autosave() if $_[0] eq '.' }, Tkx::Ev('%W')]);

    my $options = $menu->new_menu;
    $menu->m_add_cascade(-menu => $options, -label => "Options", -underline => 0);
    my $automatic_duration = \$values{automatic_duration};
    $options->m_add_checkbutton(-label => "Durée automatique", -variable => $automatic_duration, -onvalue => 1, -offvalue => 0, -accelerator => 'Ctrl+D');
    $root->g_bind('<Control-d>', sub { $$automatic_duration = 1 - $$automatic_duration });

    my $taxes = $menu->new_menu;
    $menu->m_add_cascade(-menu => $taxes, -label => "Fiscalité", -underline => 1);
    my $pinel_menu = $taxes->new_menu;
    my @pinel_zone = ('Zone A bis', 'Zone A', 'Zone B1', 'Zone B2');
    my $disable_pinel_zone = sub {  
      for my $z (@pinel_zone) {
        $pinel_menu->m_entryconfigure($z, -state => 'disabled');
      }
    };
    my $enable_pinel_zone = sub {
      for my $z (@pinel_zone) {
        $pinel_menu->m_entryconfigure($z, -state => 'normal');
      }
    };
    $taxes->m_add_cascade(-menu => $pinel_menu, -label => "Loi Pinel", -underline => 4);
    my $pinel_duration = \$values{pinel_duration};
    # TODO: test if loading a file with pinel duration 0 results in having the zone disabled correctly.
    $pinel_menu->add_radiobutton(-label => "Non", -variable => $pinel_duration, -value => 0, -command => sub { $disable_pinel_zone->(); calculate_all() });
    $pinel_menu->add_radiobutton(-label => "6 ans", -variable => $pinel_duration, -value => 6, -command => sub { $enable_pinel_zone->(); calculate_all() });
    $pinel_menu->add_radiobutton(-label => "9 ans", -variable => $pinel_duration, -value => 9, -command => sub { $enable_pinel_zone->(); calculate_all() });
    $pinel_menu->add_radiobutton(-label => "12 ans", -variable => $pinel_duration, -value => 12, -command => sub { $enable_pinel_zone->(); calculate_all() });
    $pinel_menu->add_separator();
    
    my $pinel_zone = \$values{pinel_zone};
    for my $i (0..$#pinel_zone) {
      $pinel_menu->add_radiobutton(-label => $pinel_zone[$i], -variable => $pinel_zone,
                                   -value => $i, -command => \&calculate_all);
    }
  }

  # When Return is pressed, we first move the focus, to force a re-computation of
  # the variables holding behind the currently edited field, if any.
  $root->g_bind('<Return>', sub {
      Tkx::focus('.');
      calculate_all();
    });

  # We're done, we can show the UI.
  $root->g_wm_deiconify();
}

# Update the values displayed in the core value table.
my @computed_values; # The output of compute_all()
sub update_displayed_mode {
  my $current_mode = $modes_combobox->m_current();
  $modes_combobox->m_selection('clear');
  my $format = $modes_format[$current_mode];
  for my $i (0..NUM_LOAN_DURATION-1) {
    for my $j (0..NUM_LOAN_AMOUNT-1) {
      $core_display_values[$i][$j] = $format->($computed_values[$i][$j][$current_mode]);
    }
  }
}

sub clear_displayed_table {
  $display_table->m_delete($display_table->m_children(''));
}

# Update the values displayed in the by-year secondary table.
my (@last_update_to_table);
sub update_displayed_table {
  # loan_duration, $loan_amount
  my ($d, $a) = (@_, @last_update_to_table);
  @last_update_to_table = (@_, @last_update_to_table);
  return if @last_update_to_table == 0;  # automatic call before any selection.
  if ($values{automatic_duration} && $values{loan_durations}[$d] != $values{duration}) {
    $values{duration} = $values{loan_durations}[$d];
    refresh_all_fields();
    return; # This method is called back by refresh_all_fields() through calculate_all().
  }
  clear_displayed_table();
  # We don't configure the height of the table unconditionnally because doing so
  # will slightly change the width of the widget for some weird reason. Forcing
  # the width does not work well (and yield some ugly redraw), so we don't do it.
  # All this is unused anyway now that we have verticall scrolling and a set size
  # for the enclosing frame.
  my $current_height = (Tkx::SplitList($display_table->m_configure('-height')))[-1];
  $display_table->m_configure(-height => $values{duration} || 1) if $values{duration} != $current_height;
  my $table = $computed_values[$d][$a][TABLE_DATA];
  for my $i (0..$#$table) {
    my $text = $i ? $i : 'Achat';
    $display_table->m_insert('', 'end', -text => $text, -values => [ map { format_euro($_) } @{$table->[$i]}]);
  }
  $display_table->m_insert('', 'end', -text => 'Total', -tags => 'total',
                           -values => [ (map { format_euro($_) } @{$computed_values[$d][$a][TABLE_TOTAL]}), '']);
}

sub calculate_all {
  if ($values{pinel_duration}) {
    my $rent_cap = App::InvestSim::Finance::pinel_rent_cap();
    $rent_cap_entry->m_configure(-style => ($rent_cap >= $values{base_rent}) ? 'TEntry' : 'Invalid.TEntry');
    $rent_cap_text = format_euro($rent_cap);
    $pinel_worth_text = format_euro(App::InvestSim::Finance::pinel_investment_value());
  } else {
    $rent_cap_text = 'N/A';
    $pinel_worth_text = 'N/A';
  }

  $total_rent_text = format_euro(App::InvestSim::Finance::total_rent());
  $notary_fees_text = format_euro(App::InvestSim::Finance::notary_fees());
  $total_invested_text = format_euro(App::InvestSim::Finance::total_invested());

  my $current_mode = $modes_combobox->m_current();
  $modes_combobox->m_selection('clear');
  for my $i (0..NUM_LOAN_DURATION-1) {
    for my $j (0..NUM_LOAN_AMOUNT-1) {
      $computed_values[$i][$j] = [ App::InvestSim::Finance::calculate($values{loan_amounts}[$j], $values{loan_durations}[$i], $values{loan_rates}[$i]) ];
    }
  }
  update_displayed_table();
  update_displayed_mode();
}

1;



( run in 1.046 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )