diff --git a/bin/ui/wndOverlays.ui b/bin/ui/wndOverlays.ui
index c40e0363e..d0b10fb42 100644
--- a/bin/ui/wndOverlays.ui
+++ b/bin/ui/wndOverlays.ui
@@ -90,7 +90,7 @@
- True
+ False
True
2
@@ -121,13 +121,13 @@
diff --git a/lib/Biodiverse/GUI/GUIManager.pm b/lib/Biodiverse/GUI/GUIManager.pm
index 872fa67ad..e393ec6b5 100644
--- a/lib/Biodiverse/GUI/GUIManager.pm
+++ b/lib/Biodiverse/GUI/GUIManager.pm
@@ -61,6 +61,7 @@ BEGIN {
gladexml => undef, # Main window widgets
tabs => [], # Stores refs to Tabs objects. In order of page index.
progress_bars => undef,
+ overlay_components => undef,
test_val => ''
};
bless $singleton, 'Biodiverse::GUI::GUIManager';
@@ -331,6 +332,16 @@ sub show_progress {
}
}
+sub get_overlay_components {
+ my ($self) = @_;
+ return $self->{overlay_components};
+}
+
+sub set_overlay_components {
+ my ($self, $components) = @_;
+ $self->{overlay_components} = $components;
+}
+
##########################################################
# Initialisation
##########################################################
diff --git a/lib/Biodiverse/GUI/Grid.pm b/lib/Biodiverse/GUI/Grid.pm
index aabe68071..f15cf7d8f 100644
--- a/lib/Biodiverse/GUI/Grid.pm
+++ b/lib/Biodiverse/GUI/Grid.pm
@@ -616,9 +616,8 @@ sub get_base_struct {
# Draws a polygonal shapefile
sub set_overlay {
- my $self = shift;
- my $shapefile = shift;
- my $colour = shift || OVERLAY_COLOUR;
+ my ($self, %args) = @_;
+
# Delete any existing
if ($self->{shapefile_group}) {
@@ -626,9 +625,12 @@ sub set_overlay {
delete $self->{shapefile_group};
}
- if ($shapefile) {
- my @args = @{ $self->{dataset_info} };
- $self->load_shapefile(@args, $shapefile, $colour);
+ if (defined $args{shapefile}) {
+ $self->load_shapefile(
+ colour => OVERLAY_COLOUR, # default
+ dataset_info => $self->{dataset_info},
+ %args,
+ );
}
return;
@@ -649,7 +651,13 @@ EOL
}
sub load_shapefile {
- my ($self, $min_x, $min_y, $max_x, $max_y, $cell_x, $cell_y, $shapefile, $colour) = @_;
+ my ($self, %args) = @_;
+
+ my $info = $args{info} // $self->{dataset_info};
+ my ($min_x, $min_y, $max_x, $max_y, $cell_x, $cell_y) = @$info;
+ my $shapefile = $args{shapefile};
+ my $colour = $args{colour};
+ my $plot_as_poly = $args{plot_as_poly};
my @rect = (
$min_x - $cell_x,
@@ -691,7 +699,16 @@ sub load_shapefile {
y => 0,
);
- $shapefile_group->raise_to_top();
+ my $is_polygon = $shapefile->shape_type_text =~ m/polygon/i;
+
+ my $canvas_shape_type = 'Gnome2::Canvas::Line';
+ if ($is_polygon && $plot_as_poly) {
+ $canvas_shape_type = 'Gnome2::Canvas::Polygon';
+ $shapefile_group->lower_to_bottom();
+ }
+ else {
+ $shapefile_group->raise_to_top();
+ }
$self->{shapefile_group} = $shapefile_group;
# Add all shapes
@@ -735,7 +752,7 @@ sub load_shapefile {
if (@plot_points > 2) { # must have more than one point (two coords)
my $poly = Gnome2::Canvas::Item->new (
$shapefile_group,
- 'Gnome2::Canvas::Line',
+ $canvas_shape_type,
points => \@plot_points,
fill_color_gdk => $colour,
);
diff --git a/lib/Biodiverse/GUI/Overlays.pm b/lib/Biodiverse/GUI/Overlays.pm
index 1046d2c5a..4f592405d 100644
--- a/lib/Biodiverse/GUI/Overlays.pm
+++ b/lib/Biodiverse/GUI/Overlays.pm
@@ -1,10 +1,12 @@
package Biodiverse::GUI::Overlays;
+use 5.010;
use strict;
use warnings;
use Gtk2;
#use Data::Dumper;
use Geo::ShapeFile;
+use Ref::Util qw/is_hashref/;
our $VERSION = '4.99_002';
@@ -14,54 +16,114 @@ use Biodiverse::GUI::Project;
my $default_colour = Gtk2::Gdk::Color->parse('#001169');
my $last_selected_colour = $default_colour;
+use constant COL_FNAME => 0;
+use constant COL_PLOT_POLY => 1;
+use constant COL_PLOT_COLOUR => 2;
+use constant COL_PLOT_COLOUR_BK => 3;
+
sub show_dialog {
my $grid = shift;
# Create dialog
my $gui = Biodiverse::GUI::GUIManager->instance;
+ my $overlay_components = $gui->get_overlay_components;
+ my $project = $gui->get_project;
+
+ if ($overlay_components) {
+ my $dlg = $overlay_components->{dialog};
+ my $colour_button = $overlay_components->{colour_button};
+ $colour_button->set_color($last_selected_colour);
+
+ set_button_actions (
+ project => $project,
+ grid => $grid,
+ %$overlay_components,
+ );
+
+ $dlg->show_all;
+ return;
+ }
+
my $dlgxml = Gtk2::Builder->new();
$dlgxml->add_from_file($gui->get_gtk_ui_file('wndOverlays.ui'));
my $dlg = $dlgxml->get_object('wndOverlays');
my $colour_button = $dlgxml->get_object('colorbutton_overlays');
- $dlg->set_transient_for( $gui->get_object('wndMain') );
+ $dlg->set_transient_for($gui->get_object('wndMain'));
$colour_button->set_color($last_selected_colour);
- my $project = $gui->get_project;
my $model = make_overlay_model($project);
my $list = init_overlay_list($dlgxml, $model);
+ my %buttons = map {$_ => $dlgxml->get_object($_)}
+ (qw /btnAdd btnDelete btnClear btnSet btnOverlayCancel btn_overlay_set_default_colour/);
+ my %components = (
+ dialog => $dlg,
+ colour_button => $colour_button,
+ list => $list,
+ buttons => \%buttons,
+ );
+
+ my $signals = set_button_actions (
+ %components,
+ project => $project,
+ grid => $grid,
+ );
+
+ # store some but not all components we set actions for
+ $gui->set_overlay_components ({
+ %components,
+ signals => $signals,
+ });
+
+ $dlg->set_modal(1);
+ $dlg->show_all();
+
+ return;
+}
+
+sub set_button_actions {
+ my %args = @_;
+ my ($list, $project, $grid, $dlg, $colour_button)
+ = @args{qw /list project grid dialog colour_button/};
+
+ my $buttons = $args{buttons};
+ my $signals = $args{signals} // {};
# Connect buttons
- $dlgxml->get_object('btnAdd')->signal_connect(
+
+ # these are always the same
+ $signals->{btnAdd} //= $buttons->{btnAdd}->signal_connect(
clicked => \&on_add,
[$list, $project],
);
- $dlgxml->get_object('btnDelete')->signal_connect(
+ $signals->{btnDelete} //= $buttons->{btnDelete}->signal_connect(
clicked => \&on_delete,
[$list, $project],
);
- $dlgxml->get_object('btnClear')->signal_connect(
- clicked => \&on_clear,
- [$list, $project, $grid, $dlg],
- );
- $dlgxml->get_object('btnSet')->signal_connect(
- clicked => \&on_set,
- [$list, $project, $grid, $dlg, $colour_button],
- );
- $dlgxml->get_object('btnOverlayCancel')->signal_connect(
+ $signals->{btnOverlayCancel} //= $buttons->{btnOverlayCancel}->signal_connect(
clicked => \&on_cancel,
$dlg,
);
- $dlgxml->get_object('btn_overlay_set_default_colour')->signal_connect(
+ $signals->{btn_overlay_set_default_colour}
+ //= $buttons->{btn_overlay_set_default_colour}->signal_connect(
clicked => \&on_set_default_colour,
$colour_button,
);
-
- $dlg->set_modal(1);
- $dlg->show_all();
-
- return;
+ # these vary by grid so need to be disconnected first or we mess up other plots
+ foreach my $btn (qw/btnClear btnSet/) {
+ my $id = $signals->{$btn} // next;
+ $buttons->{$btn}->signal_handler_disconnect($id);
+ }
+ $signals->{btnClear} = $buttons->{btnClear}->signal_connect(
+ clicked => \&on_clear,
+ [$list, $project, $grid, $dlg],
+ );
+ $signals->{btnSet} = $buttons->{btnSet}->signal_connect(
+ clicked => \&on_set,
+ [$list, $project, $grid, $dlg, $colour_button],
+ );
+ return $signals;
}
sub init_overlay_list {
@@ -70,42 +132,135 @@ sub init_overlay_list {
my $tree = $dlgxml->get_object('treeOverlays');
my $col_name = Gtk2::TreeViewColumn->new();
- my $name_renderer = Gtk2::CellRendererText->new();
- $col_name->set_title('Filename');
+ my $name_renderer = Gtk2::CellRendererText->new ();
+ #$name_renderer->signal_connect('toggled' => \&_update_colour_for_selection, $model);
+ $col_name->set_title('File name');
$col_name->pack_start($name_renderer, 1);
- $col_name->add_attribute($name_renderer, text => 0);
+ $col_name->add_attribute($name_renderer, text => COL_FNAME);
$tree->insert_column($col_name, -1);
- # fiddling around with colour selection
- #my $colColour = Gtk2::TreeViewColumn->new();
- #my $colour_button = Gtk2::CellRendererPixbuf->new();
- #$colColour->set_title('Colour');
- #$colColour->pack_start($colour_button, 1);
- #$colColour->add_attribute($colour_button, text => 0);
- #$tree->insert_column($colColour, -1);
-
- $tree->set_headers_visible(0);
+ my $col_plot_poly = Gtk2::TreeViewColumn->new();
+ $col_plot_poly->set_title('Plot as polygon');
+ my $poly_renderer = Gtk2::CellRendererToggle->new();
+ $col_plot_poly->pack_start($poly_renderer, 0);
+ $poly_renderer->signal_connect('toggled' => \&_plot_poly_toggled, $model);
+ $col_plot_poly->set_attributes($poly_renderer,
+ 'active' => 1,
+ );
+ $tree->insert_column($col_plot_poly, -1);
+
+ # my $col_colour = Gtk2::TreeViewColumn->new();
+ # my $colour_renderer_toggle = Gtk2::CellRendererToggle->new();
+ # my $colour_renderer_text = Gtk2::CellRendererText->new();
+ # $col_colour->set_title('Colour');
+ # $col_colour->pack_start($colour_renderer_toggle, 0);
+ # $col_colour->pack_start($colour_renderer_text, 0);
+ # $col_colour->add_attribute($colour_renderer_toggle, active => COL_PLOT_COLOUR);
+ # $col_colour->set_attributes($colour_renderer_toggle, active => 1);
+ # $col_colour->add_attribute($colour_renderer_text,
+ # 'cell-background' => COL_PLOT_COLOUR_BK,
+ # );
+ # $col_colour->set_attributes($colour_renderer_text,
+ # 'cell-background' => COL_PLOT_COLOUR_BK,
+ # );
+ # $colour_renderer_toggle->signal_connect(
+ # 'toggled' => \&_update_colour_for_selection, $model
+ # );
+ # $tree->insert_column($col_colour, -1);
+
+ $tree->set_headers_visible(1);
$tree->set_model($model);
return $tree;
}
+sub _plot_poly_toggled {
+ my ($cell, $path_str, $model) = @_;
+
+ my $path = Gtk2::TreePath->new_from_string ($path_str);
+
+ # get toggled iter
+ my $iter = $model->get_iter ($path);
+ my ($bool) = $model->get ($iter, COL_PLOT_POLY);
+
+ # toggle the value
+ $model->set ($iter, COL_PLOT_POLY, !$bool);
+}
+
+sub _update_colour_for_selection {
+ my ($cell, $path_str, $model) = @_;
+
+ my $path = Gtk2::TreePath->new_from_string ($path_str);
+
+ # get toggled iter
+ my $iter = $model->get_iter ($path);
+ my ($bool) = $model->get ($iter, COL_PLOT_COLOUR);
+
+ my $gui = Biodiverse::GUI::GUIManager->instance;
+ my $overlay_components = $gui->get_overlay_components;
+ my $colour_button = $overlay_components->{colour_button};
+
+ my $colour = $model->get ($iter, COL_PLOT_COLOUR_BK);
+ if (!defined $colour or $colour eq 'undef') {
+ $colour = $colour_button->get_colour; #$self->get_last_colour;
+ }
+
+ if (!Scalar::Util::blessed $colour) {
+ $colour = Gtk2::Gdk::Color->parse($colour);
+ }
+ $colour_button->set_color($colour);
+
+ $colour_button->clicked;
+ $colour = $colour_button->get_color;
+
+ say STDERR $bool, ' ', $colour->to_string;
+
+ # toggle the value
+ $model->set ($iter,
+ COL_PLOT_COLOUR, !$bool,
+ );
+ $model->set ($iter,
+ COL_PLOT_COLOUR_BK, $colour->to_string,
+ # 'cell-background' => $colour->to_string,
+ );
+ say '--- ' . $model->get ($iter, COL_PLOT_COLOUR);
+ say '--- ' . $model->get ($iter, COL_PLOT_COLOUR_BK);
+}
+
# Make the object tree that appears on the left
sub make_overlay_model {
+ my $project = shift;
+
my $model = Gtk2::ListStore->new(
'Glib::String',
- #'Glib::Boolean', # fiddling around with colour selection
+ 'Glib::Boolean',
+ # 'Glib::Boolean', # next two are colour stuff
+ # 'Glib::String',
);
- my $project = shift;
my $overlays = $project->get_overlay_list();
- foreach my $name (@{$overlays}) {
+ foreach my $entry (@{$overlays}) {
my $iter = $model->append;
- $model->set($iter, 0, $name);
+ if (!is_hashref $entry) { # previous versions did not store these
+ $entry = {
+ name => $entry,
+ plot_as_poly => 0,
+ # has_colour => undef,
+ # colour => undef,
+ };
+ }
+ # use DDP;
+ # p $entry;
+ $model->set(
+ $iter,
+ COL_FNAME, $entry->{name},
+ COL_PLOT_POLY, $entry->{plot_as_poly},
+ # COL_PLOT_COLOUR, !!$entry->{colour},
+ # COL_PLOT_COLOUR_BK, ($entry->{colour} // 'white'),
+ );
}
-
return $model;
}
@@ -120,9 +275,13 @@ sub get_selection {
return if not $path;
my $iter = $model->get_iter($path);
- my $name = $model->get($iter, 0);
+ my $name = $model->get($iter, COL_FNAME);
+ my $plot_as_poly = $model->get($iter, COL_PLOT_POLY);
+ my $array_iter = $path->to_string; # only works for a simple tree
- return wantarray ? ($name, $iter) : $name;
+ return wantarray
+ ? (iter => $iter, filename => $name, plot_as_poly => $plot_as_poly, array_iter => $array_iter)
+ : $name;
}
@@ -164,11 +323,11 @@ sub on_add {
if (!_shp_type_is_point($filename)) {
my $iter = $list->get_model->append;
- $list->get_model->set($iter, 0, $filename);
+ $list->get_model->set($iter, COL_FNAME, $filename, COL_PLOT_POLY, 0);
my $sel = $list->get_selection;
$sel->select_iter($iter);
- $project->add_overlay($filename);
+ $project->add_overlay({name => $filename});
}
else { # warn about points - one day we will fix this
my $error = "Selected shapefile is a point type.";
@@ -193,14 +352,25 @@ sub _shp_type_is_point {
return $type =~/point/i;
}
+sub _shp_type_is_polygon {
+ my $name = shift;
+
+ my $shpfile = Geo::ShapeFile->new ($name);
+ my $type = $shpfile->shape_type_text;
+
+ return $type =~/polygon/i;
+}
+
sub on_delete {
my $button = shift;
my $args = shift;
my ($list, $project) = @$args;
- my ($filename, $iter) = get_selection($list);
- return if not $filename;
- $project->delete_overlay($filename);
+ # my ($iter, $filename, undef, $array_iter) = get_selection($list);
+ my %results = get_selection($list);
+ my ($iter, $filename, $array_iter) = @results{qw/iter filename array_iter/};
+ return if not defined $filename;
+ $project->delete_overlay($filename, $array_iter);
$list->get_model->remove($iter);
return;
@@ -212,8 +382,8 @@ sub on_clear {
my $args = shift;
my ($list, $project, $grid, $dlg) = @$args;
- $grid->set_overlay(undef);
- $dlg->destroy();
+ $grid->set_overlay();
+ $dlg->hide();
return;
}
@@ -223,16 +393,23 @@ sub on_set {
my $args = shift;
my ($list, $project, $grid, $dlg, $colour_button) = @$args;
- my $filename = get_selection($list);
+ # my ($iter, $filename, $plot_as_poly, $array_iter) = get_selection($list);
+ my %results = get_selection($list);
+ my ($iter, $filename, $plot_as_poly, $array_iter)
+ = @results{qw /iter filename plot_as_poly array_iter/};
my $colour = $colour_button->get_color;
- $dlg->destroy;
+ $dlg->hide;
return if not $filename;
print "[Overlay] Setting overlay to $filename\n";
- $grid->set_overlay( $project->get_overlay($filename), $colour );
+ $grid->set_overlay(
+ shapefile => $project->get_overlay_shape_object($filename),
+ colour => $colour,
+ plot_as_poly => $plot_as_poly,
+ );
#$dlg->destroy();
$last_selected_colour = $colour;
@@ -244,7 +421,7 @@ sub on_cancel {
my $button = shift;
my $dlg = shift;
- $dlg->destroy;
+ $dlg->hide;
return;
}
diff --git a/lib/Biodiverse/GUI/Project.pm b/lib/Biodiverse/GUI/Project.pm
index 898ac4607..124563862 100644
--- a/lib/Biodiverse/GUI/Project.pm
+++ b/lib/Biodiverse/GUI/Project.pm
@@ -1477,7 +1477,7 @@ sub get_overlay_list {
return $self->{OVERLAYS};
}
-sub get_overlay {
+sub get_overlay_shape_object {
my $self = shift;
my $name = shift;
@@ -1499,27 +1499,30 @@ sub get_overlay {
sub delete_overlay {
my $self = shift;
my $name = shift;
+ my $array_iter = shift;
- # Remove from list
- foreach my $i ( 0 .. $#{ $self->{OVERLAYS} } ) {
- if ( $self->{OVERLAYS}[$i] eq $name ) {
- splice( @{ $self->{OVERLAYS} }, $i, 1 );
- last;
- }
- }
+ my $overlays = $self->{OVERLAYS};
- # remove from hash
- delete $self->{overlay_objects}{$name};
+ # Remove from list unless not found or possible
+ $array_iter //= List::Util::first {$_ eq $name} @$overlays;
+ return if $array_iter < 0 || $array_iter > $#$overlays;
+
+ splice( @$overlays, $array_iter, 1 );
+
+ # remove from hash if no longer needed
+ if (!grep {$_ eq $name} @$overlays) {
+ delete $self->{overlay_objects}{$name};
+ }
return;
}
sub add_overlay {
my $self = shift;
- my $name = shift;
+ my $entry = shift;
- $self->{overlay_objects}{$name} = undef;
- push @{ $self->{OVERLAYS} }, $name;
+ $self->{overlay_objects}{$entry->{name}} = undef;
+ push @{ $self->{OVERLAYS} }, $entry;
return;
}
@@ -1531,13 +1534,14 @@ sub init_overlay_hash {
my $existing_overlays = [];
my @missing_overlays;
- foreach my $name ( @{ $self->{OVERLAYS} } ) {
+ foreach my $entry ( @{ $self->{OVERLAYS} } ) {
+ my $name = is_hashref $entry ? $entry->{name} : $entry;
if ( Biodiverse::Common->file_is_readable (file_name => $name) ) {
# Set hash entry to undef - will load on demand
$self->{overlay_objects}{$name} = undef;
- push @$existing_overlays, $name;
+ push @$existing_overlays, $entry;
}
else {
print "[Project] Missing overlay: $name\n";
@@ -1551,7 +1555,7 @@ sub init_overlay_hash {
# Tell user if any missing
if ( scalar @missing_overlays > 0 ) {
my $text =
-"The following overlays are missing and have been deleted from the project:\n";
+"The following overlays are missing and have been removed from the project:\n";
foreach my $name (@missing_overlays) {
$text .= " $name\n";
}