Gtk2-Ex-Geo

 view release on metacpan or  search on metacpan

ChangeLog  view on Meta::CPAN

The changes are logged onto the SVN, which is at
http://trac.osgeo.org/geoinformatica/

Moved to svn.osgeo.org

Date: 23:45:18, 21. elokuuta 2008
overlay's parameters can be set at glue's constructor

Date: 23:44:01, 21. elokuuta 2008
default single color can be set from outside

Date: 22:37:18, 21. elokuuta 2008
layer treeview tooltips and "v" instead of "?"

Date: 13:14:45, 21. elokuuta 2008
default single color is black now

ChangeLog  view on Meta::CPAN

Date: 17:24:44, 1. elokuuta 2007
handle the case where ctrl is down and selection is null

Date: 10:59:43, 1. elokuuta 2007
update features dialog in concert with selection

Date: 22:57:54, 31. heinäkuuta 2007
reselect = send signal new_selection

Date: 16:43:36, 31. heinäkuuta 2007
do not maintain selected layer in overlay; new signal new_selection (preferred over features_selected)

Date: 22:01:28, 20. heinäkuuta 2007
use Gtk2::Gdk::Color->new and not new Gtk2::Gdk::Color

Date: 19:52:08, 19. heinäkuuta 2007
delete rubberband attribute in button_release_event if measure path, prevents erasing the path in motion_notify (maybe this is not fixing in the right place)

Date: 19:50:24, 19. heinäkuuta 2007
fixed a typo in Layer.defaults; initialize COLOR_TABLE attribute in color_table method if setting from GDAL color_table; use Gtk2::Gdk::Color->new and not new Gtk2::Gdk::Color

ChangeLog  view on Meta::CPAN

Date: 21:49:04, 15. heinäkuuta 2007
update_image in delete_rubberband but not in add_to_selection; in rubberband_value use Geo::OGC methods

Date: 19:20:52, 14. heinäkuuta 2007
rubberband_mode and rubberband_geometry; call update image after reselect; new image menu item "select containing"

Date: 19:18:51, 14. heinäkuuta 2007
selected_features gets or sets (doesn't add); after unselect all call update_image

Date: 19:17:33, 14. heinäkuuta 2007
divide overlay's rubberbanding into rubberband_mode and rubberband_geometry; remove backup pixmap; new methods: add_to_selection, reset_image and reset_pixmap; be more careful with creating selection

Date: 19:13:38, 14. heinäkuuta 2007
divide overlay's rubberbanding into rubberband_mode and rubberband_geometry

Date: 0:15:26, 14. heinäkuuta 2007
code to allow user create geometry collections

Date: 19:56:18, 12. heinäkuuta 2007
now uses Geo::OGC::Geometry 

Date: 19:55:21, 12. heinäkuuta 2007
new methods in Layer: features_selected (also an attribute), selected_features, and features

ChangeLog  view on Meta::CPAN

Date: 1:39:57, 10. heinäkuuta 2007
show toolbar button, change cursor when popup menu on layer list

Date: 1:38:35, 10. heinäkuuta 2007
test registering commands

Date: 23:37:45, 9. heinäkuuta 2007
simple named params for register_function 

Date: 23:08:33, 9. heinäkuuta 2007
simpler overlay menu

Date: 23:07:11, 9. heinäkuuta 2007
new methods: inspect_data, schema

Date: 23:04:15, 9. heinäkuuta 2007
simpler overlay menu

Date: 23:02:09, 9. heinäkuuta 2007
test layer class

Date: 18:07:02, 9. heinäkuuta 2007
removed draw_on and event_handler code mostly (should use signals)

Date: 17:16:03, 9. heinäkuuta 2007
moved p and plot to IPC::Gnuplot

README  view on Meta::CPAN

}

# visible layer list
my $list = Gtk2::ScrolledWindow->new();
$list->set_policy("never", "automatic");
$list->add($app->{tree_view});
    
# a panel with the layer list and the map
my $hbox = Gtk2::HPaned->new();
$hbox->add1($list);
$hbox->add2($app->{overlay});
    
# stack all GUI elements vertically
my $vbox = Gtk2::VBox->new(FALSE, 0);
$vbox->pack_start($app->{toolbar}, FALSE, FALSE, 0);
$vbox->pack_start($hbox, TRUE, TRUE, 0);
$vbox->pack_start($app->{entry}, FALSE, FALSE, 0);
$vbox->pack_start($app->{statusbar}, FALSE, FALSE, 0);

$window->add($vbox);
$window->signal_connect("destroy", \&my_destroy);

index.dox  view on Meta::CPAN

The Gtk2::Ex::Geo modules provide a plaform for developing geospatial
applications. The idea is to provide a canvas for geospatial data,
a set of dialogs, and glue code.

The tools build the abstract geospatial data layer defined by the
Geo::Layer module.

\section index_geg_glue Gtk2::Ex::Geo::Glue

A glue object manages the GUI. The dialog boxes of the registered
layer classes can be obtained from it. It maintains an overlay.

\section index_cli The CLI in an entry

The entry widget that is managed by a glue object is used for getting
commands from the user. The glue object maintains a history of the
objects. Old commands can be browsed with the arrow up and arrow down
keys. The user command is givent to Perl's eval function.

1) the variable names are inspected and found layer names are replaced
with pointers to real layers

index.dox  view on Meta::CPAN


\section index_geg_dialogs Gtk2::Ex::Geo::Layer

The root class of all layer classes.

Layer classes should be registered with the glue object. The
registration information comprises a dialogs object (an instance of
DialogMaster or its subclass), and class methods it offers (typically
a subset of 'new', 'open', 'save', etc.).

\section index_geg_overlay Gtk2::Ex::Geo::Overlay

An overlay is a widget, subclassed from Gtk2::ScrolledWindow. An
overlay contains a list of layers, which it renders on a canvas, which
it puts into its window.

Rubberbanding and keyboard zoom-in (with + key), zoom-out (with -
key), and panning (with arrow keys) is built-in.

\section index_geg_dialogs Gtk2::Ex::Geo::Dialogs

*/	

lib/Gtk2/Ex/Geo/Dialogs/Colors.pm  view on Meta::CPAN

# button callbacks

##@ignore
sub apply_colors {
    my($self, $gui, $close) = @{$_[1]};
    my @color = split(/ /, $self->{colors_dialog}->get_widget('border_color_label')->get_text);
    my $has_border = $self->{colors_dialog}->get_widget('border_color_checkbutton')->get_active();
    @color = () unless $has_border;
    $self->border_color(@color);
    $self->hide_dialog('colors_dialog') if $close;
    $gui->{overlay}->render;
}

##@ignore
sub cancel_colors {
    my($self, $gui);
    for (@_) {
	next unless ref eq 'ARRAY';
	($self, $gui) = @{$_};
    }
    $self->palette_type($self->{backup}->{palette_type});

lib/Gtk2/Ex/Geo/Dialogs/Colors.pm  view on Meta::CPAN


    $self->hue_range(@{$self->{backup}->{hue_range}});

    $self->grayscale_subtype($self->{backup}->{grayscale_subtype});
    $self->invert_scale($self->{backup}->{invert_scale});
    $self->grayscale_color(@{$self->{backup}->{grayscale_color}});

    $self->border_color(@{$self->{backup}->{border_color}});

    $self->hide_dialog('colors_dialog');
    $gui->{overlay}->render;
    1;
}

##@ignore
sub copy_colors {
    my($self, $gui) = @{$_[1]};
    my $table = copy_colors_dialog($self, $gui);
    if ($table) {
	my $palette_type = $self->palette_type;
	if ($palette_type eq 'Color table') {

lib/Gtk2/Ex/Geo/Dialogs/Colors.pm  view on Meta::CPAN


    my $i = 0;
    for my $column ('Layer') {
	my $cell = Gtk2::CellRendererText->new;
	my $col = Gtk2::TreeViewColumn->new_with_attributes($column, $cell, text => $i++);
	$treeview->append_column($col);
    }

    $model->clear;
    my @names;
    for my $layer (@{$gui->{overlay}->{layers}}) {
	next if $layer->name() eq $self->name();
	push @names, $layer->name();
	$model->set ($model->append(undef), 0, $layer->name());
    }

    #$dialog->move(@{$self->{colors_from_position}}) if $self->{colors_from_position};
    $dialog->get_widget('colors_from_dialog')->show_all;
    $dialog->get_widget('colors_from_dialog')->present;

    my $response = $dialog->get_widget('colors_from_dialog')->run;

    my $table;

    if ($response eq 'ok') {

	my @sel = $treeview->get_selection->get_selected_rows;
	if (@sel) {
	    my $i = $sel[0]->to_string if @sel;
	    my $from_layer = $gui->{overlay}->get_layer_by_name($names[$i]);

	    if ($palette_type eq 'Color table') {
		$table = $from_layer->color_table();
	    } elsif ($palette_type eq 'Color bins') {
		$table = $from_layer->color_bins();
	    }
	}
	
    }

lib/Gtk2/Ex/Geo/Dialogs/Labeling.pm  view on Meta::CPAN

    $labeling->{min_size} = $dialog->get_widget('labels_min_size_entry')->get_text;
    $labeling->{font} = $dialog->get_widget('labels_font_label')->get_text;
    @{$labeling->{color}} = split(/ /, $dialog->get_widget('labels_color_label')->get_text);
    $labeling->{min_size} = $dialog->get_widget('labels_min_size_entry')->get_text;
    $labeling->{incremental} = $dialog->get_widget('labels_incremental_checkbutton')->get_active();

    $self->labeling($labeling);

    $self->hide_dialog('labels_dialog') if $close;
    $gui->set_layer($self);
    $gui->{overlay}->render;
}

##@ignore
sub cancel_labels {
    my($self, $gui);
    for (@_) {
	next unless ref eq 'ARRAY';
	($self, $gui) = @{$_};
    }

    $self->labeling($self->{labeling_backup});
    $self->hide_dialog('labels_dialog');
    $gui->set_layer($self);
    $gui->{overlay}->render;
    1;
}

##@ignore
sub labels_font {
    my($self, $gui) = @{$_[1]};
    my $font_chooser = Gtk2::FontSelectionDialog->new ("Select font for the labels");
    my $font_name = $self->{labels_dialog}->get_widget('labels_font_label')->get_text;
    $font_chooser->set_font_name($font_name);
    if ($font_chooser->run eq 'ok') {

lib/Gtk2/Ex/Geo/Dialogs/Symbols.pm  view on Meta::CPAN

    $self->symbol_field($field) if defined $field;
    my $scale_min = $dialog->get_widget('symbols_scale_min_entry');
    my $scale_max = $dialog->get_widget('symbols_scale_max_entry');
    $self->symbol_scale($scale_min->get_text(), $scale_max->get_text());
    my $size_spin = $dialog->get_widget('symbols_size_spinbutton');
    my $size = $size_spin->get_value();
    $self->symbol_size($size);

    $self->hide_dialog('symbols_dialog') if $close;
    $gui->set_layer($self);
    $gui->{overlay}->render;
}

##@ignore
sub cancel_symbols {
    my($self, $gui);
    for (@_) {
	next unless ref CORE::eq 'ARRAY';
	($self, $gui) = @{$_};
    }
    
    $self->symbol_type($self->{backup}->{symbol_type});
    $self->symbol_field($self->{backup}->{symbol_field}) if $self->{backup}->{symbol_field};
    $self->symbol_scale(@{$self->{backup}->{symbol_scale}});
    $self->symbol_size($self->{backup}->{symbol_size});

    $self->hide_dialog('symbols_dialog');
    $gui->set_layer($self);
    $gui->{overlay}->render;
    1;
}

##@ignore
sub fill_symbol_type_combo {
    my($self, $symbol_type) = @_;
    $symbol_type = '' unless defined $symbol_type;
    my $combo = $self->{symbols_dialog}->get_widget('symbols_type_combobox');
    my $model = $combo->get_model;
    $model->clear;

lib/Gtk2/Ex/Geo/Dialogs/Symbols.pm  view on Meta::CPAN

    my $combo = $self->{symbols_dialog}->get_widget('symbols_field_combobox');
    ($self->{index2symbol_field}{$combo->get_active()} or '');
}

##@ignore
sub fill_symbol_scale_fields {
    my($self, $gui) = @{$_[1]};
    my @range;
    my $field = get_selected_symbol_field($self);
    return if $field eq 'Fixed size';
    my @r = $gui->{overlay}->get_viewport_of_selection;
    @r = $gui->{overlay}->get_viewport unless @r;
    eval {
	@range = $self->value_range(field_name => $field, filter_rect => \@r);
    };
    if ($@) {
	$gui->message("$@");
	return;
    }
    $self->{symbols_dialog}->get_widget('symbols_scale_min_entry')->set_text($range[0]);
    $self->{symbols_dialog}->get_widget('symbols_scale_max_entry')->set_text($range[1]);
}

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN

	$self->create_layer_tree_view;
    
    ($self->{toolbar}, $self->{mode_button}, $self->{geometry_button}) = 
	$self->create_toolbar;

    $self->{statusbar} = Gtk2::Statusbar->new();

    $self->{entry} = Gtk2::Entry->new();
    $self->{entry}->signal_connect( key_press_event => \&eval_entry, $self );

    $self->{overlay} = $self->create_overlay(@_);

    $self->set_interaction_mode('Zoom');

    ($self->{history}, $self->{history_file}) = $self->open_history($params{history});
    ($self->{resources}, $self->{resources_file}) = $self->open_resources($params{resources});

    my @buffer = <Gtk2::Ex::Geo::History::DATA>;
    pop @buffer unless $buffer[$#buffer] =~ /^\</; # remove the extra content
    shift @buffer if $buffer[0] =~ /^\s*$/;
    register_dialogs($self, Gtk2::Ex::Geo::DialogMaster->new(buffer => \@buffer));  

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN

	      $self->{focused} = $layer;
	  }, $self);
    $view->signal_connect
	( motion_notify_event => 
	  sub {
	      my($self, $event, $gis) = @_;
	      $self->set_has_tooltip(0);
	      my @res = $self->get_path_at_pos($event->x, $event->y);
	      return unless $res[0] and defined $res[0]->to_string;
	      return unless $res[1];
	      my $layer = $gis->{overlay}->get_layer_by_index($res[0]->to_string);
	      my $column = $res[1]->get_title;
	      my $tooltip = $tooltips{$column}.': ';
	      for ($column) {
		  $tooltip .= $layer->name if /^name/;
		  $tooltip .= $layer->type('long') if /^type/;
		  $tooltip .= $layer->visible ? 'visible' : 'hidden' if /^v/;
		  $tooltip .= $layer->alpha if /^a/;
	      }
	      $self->set_tooltip_text($tooltip);
	      $self->set_has_tooltip(1);

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN

	      $self->set_has_tooltip(0);
	  }) if Gtk2->CHECK_VERSION(2,12,0);
    $view->signal_connect
	( button_press_event => \&layer_menu, $self );
    return ($view, $model);
}

sub layer_list_edit {
    my($cell, $path, $new_value, $data) = @_;
    my($self, $column) = @$data;
    my $layer = $self->{overlay}->get_layer_by_index($path);
    return unless $layer;
    if ($column eq 'name') {
	$layer->name($new_value) unless $self->{overlay}->get_layer_by_name($new_value);
    } else {
	$layer->alpha($new_value);
	$self->update;
	$self->{overlay}->render;
    }
}

sub create_toolbar {
    my($self) = @_;
    my $toolbar = Gtk2::Toolbar->new();

    my $button1 = Gtk2::ComboBox->new;
    my $renderer = Gtk2::CellRendererText->new;
    $button1->pack_start($renderer, TRUE);

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN

    $item->add($button1);
    $toolbar->insert($item, 0);

    my $button = Gtk2::ToolButton->new_from_stock('gtk-zoom-in');
    my $tooltips = Gtk2::Tooltips->new;
    my $tip = 'Zoom in one tenth.';
    $button->set_tooltip($tooltips, $tip, '');
    $tooltips->set_tip($button, $tip);
    $tooltips->enable;
    $toolbar->insert($button, -1);
    $button->signal_connect('clicked', sub {$_[1]->{overlay}->zoom_in}, $self);
    $button->show_all;

    $button = Gtk2::ToolButton->new_from_stock('gtk-zoom-out');
    $tooltips = Gtk2::Tooltips->new;
    $tip = 'Zoom out one tenth.';
    $button->set_tooltip($tooltips, $tip, '');
    $tooltips->set_tip($button, $tip);
    $tooltips->enable;
    $toolbar->insert($button, -1);
    $button->signal_connect('clicked', sub {$_[1]->{overlay}->zoom_out}, $self);
    $button->show_all;

    $button = Gtk2::ToolButton->new_from_stock('gtk-zoom-fit');
    $tooltips = Gtk2::Tooltips->new;
    $tip = 'Zoom to all.';
    $button->set_tooltip($tooltips, $tip, '');
    $tooltips->set_tip($button, $tip);
    $tooltips->enable;
    $toolbar->insert($button, -1);
    $button->signal_connect('clicked', sub {$_[1]->{overlay}->zoom_to_all}, $self);
    $button->show_all;

    return ($toolbar, $button1, $button2);
}

sub _set_interaction_mode {
    my($combo, $self) = @_;
    my $model = $combo->get_model;
    my $a = $combo->get_active();
    my $iter = $model->get_iter_from_string($a);

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN

	$self->{geometry_button}->set_sensitive(1);
    } elsif ($mode eq 'Draw') {
	$self->set_interaction_geometry('Rectangle');
	$self->{geometry_button}->set_sensitive(1);
    } elsif ($mode eq 'Edit') {
	$self->set_interaction_geometry('Line');
	$self->{geometry_button}->set_sensitive(0);
    } else {
	$self->{geometry_button}->set_sensitive(1);
    }
    $self->{overlay}->{rubberband_mode} = lc($mode);
}

sub set_interaction_mode {
    my($self, $mode) = @_;
    my $model = $self->{mode_button}->get_model;
    $model->foreach(\&set_combo_to, [$self->{mode_button}, $mode]);
}

sub _set_interaction_geometry {
    my($combo, $self) = @_;
    my $model = $combo->get_model;
    my $a = $combo->get_active();
    my $iter = $model->get_iter_from_string($a);
    my $geometry = $model->get_value($iter);
    $self->{overlay}->{rubberband_geometry} = lc($geometry);
}


sub set_interaction_geometry {
    my($self, $geometry) = @_;
    my $model = $self->{geometry_button}->get_model;
    $model->foreach(\&set_combo_to, [$self->{geometry_button}, $geometry]);
}

sub create_overlay {
    my($self, %params) = @_;

    my $overlay = Gtk2::Ex::Geo::Overlay->new();

    my($menu, $menu_item_setup) = overlay_menu();

    my %overlay_params = ( menu => $menu,
			   menu_item_setup => $menu_item_setup,
			   rubberband_mode => 'zoom',
			   rubberband_geometry => 'rect',
			   selecting => 'that_intersect',
	);
    
    for my $key (keys %params) {
	if ($key =~ /^overlay:(\w+)/) {
	    $overlay_params{$1} = $params{$key};
	}
    }
    
    $overlay->my_inits( %overlay_params );  
    
    $overlay->signal_connect
	( pixmap_ready => sub {
	    my($overlay, $gis) = @_;
	    my $layer = $self->get_selected_layer();
	    if ($layer) {
		my $gc = Gtk2::Gdk::GC->new($overlay->{pixmap});
		$gc->set_rgb_fg_color(Gtk2::Gdk::Color->new(65535,0,0));
		$layer->render_selection($gc, $overlay);
	    }
	  }, $self);
    
    $overlay->signal_connect
	( new_selection => 
	  sub {
	      my(undef, $gis) = @_;
	      my $overlay = $gis->{overlay};
	      my $layer = $gis->get_selected_layer();
	      if ($layer) {
		  if ($overlay->{selection}) {
		      $layer->select($overlay->{selecting} => $overlay->{selection});
		  } else {
		      $layer->select();
		  }
		  $overlay->update_image;
		  $layer->open_features_dialog($self, 1);
	      }
	  }, $self);

    $overlay->signal_connect
	( motion_notify => \&show_information, $self );

    return $overlay;
}

sub open_history {
    my($self, $filename) = @_;
    my $history;
    if ($filename) {
	my $mode = 0600;
	chmod $mode, $filename if -e $filename;
	if (open TMP, $filename) {
	    my @history = <TMP>;

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN

	    }
	    close TMP;
	} else {
	    croak "$!: $self->{resources_file}";
	}
    }
    while ($self->delete_selected(1)) {};
    delete $self->{dialogs};
    delete $self->{commands};
    delete $self->{functions};
    $self->{overlay}->close;
    delete $self->{overlay};
    delete $self->{model};
    for my $key ('mode_button', 'geometry_button', 'toolbar', 'tree_view', 'entry', 'statusbar') {
	$self->{$key}->destroy;
	delete $self->{$key};
    }
    while (my($key, $widget) = each %$self) {
	next if $key eq 'treedumper';
	$widget->destroy if blessed($widget) and $widget->isa("Gtk2::Widget");
	delete $self->{$key};
    }

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN

    my($self, $message) = @_;
    my $dialog = Gtk2::MessageDialog->new(undef,
					  'destroy-with-parent',
					  'info',
					  'close',
					  $message);
    $dialog->signal_connect(response => sub {$_[0]->destroy});
    $dialog->show_all;
}

## @fn overlay_menu()
# @brief Construct a menu for an overlay object.
sub overlay_menu {
    my @menu = 
	('Zoom to pre_vious' => sub {
	     my ($item, $self) = @_;
	     my $zoom = pop @{$self->{zoom_stack}};
	     $self->zoom(@$zoom, 0, 1) if $zoom;
	 },
	 1 => 0,
	 'Reselect' => sub { 
	     my ($item, $self) = @_;
	     $self->signal_emit('new_selection');

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN


    my $selection = $tree_view->get_selection;
    my @rows = $selection->get_selected_rows;
    my @res = $tree_view->get_path_at_pos($event->x, $event->y);
    return unless defined $res[0];
    my $index = $res[0] ? $res[0]->to_string : '';
    my $column = $res[1] ? $res[1]->get_title : '';
    my $path = Gtk2::TreePath->new($index);

    if (@rows < 2) {
	$layer = $self->{overlay}->get_layer_by_index($index);
	return unless $layer;
    } else {
	for my $r (@rows) {
	    $layer = $self->{overlay}->get_layer_by_index($r->to_string);
	    push @layers, $layer;
	}
    }
    
    if ($event->button == 3) {

	$tree_view->set_cursor($path);

	my $hide = $layer->visible() ? '_Hide' : '_Show';
	
	my @items = @layers ?
	    ( '_Hide' => sub {
		my($layers, $self) = @{$_[1]};
		for my $layer (@$layers) {
		    $layer->visible(0);
		}
		$self->update;
		$self->{overlay}->render;
	      },
	      '_Show' => sub {
		  my($layers, $self) = @{$_[1]};
		  for my $layer (@$layers) {
		      $layer->visible(1);
		  }
		  $self->update;
		  $self->{overlay}->render;
	      },
	      '_Remove' => sub {
		  my($layers, $self) = @{$_[1]};
		  for my $layer (@$layers) {
		      $self->{model}->remove($layer->{_tree_index});
		      $self->{overlay}->remove_layer_by_name($layer->name);
		  }
		  $self->{overlay}->render;
	      }
	    ) 
	    :
	    ( 
	      '_Zoom to' => sub {
		  my($layer, $self) = @{$_[1]};
		  $self->{overlay}->zoom_to($layer);
	      },
	      '_Up' => sub {
		  my($layer, $self) = @{$_[1]};
		  $self->move_up();
	      },
	      '_Down' => sub {
		  my($layer, $self) = @{$_[1]};
		  $self->move_down();
	      },
	      $hide => sub {
		  my($layer, $self) = @{$_[1]};
		  $layer->visible(!$layer->visible());
		  $self->update;
		  $self->{overlay}->render;
	      },
	      '_Remove' => sub {
		  my($layer, $self) = @{$_[1]};
		  $self->delete_selected(); 
	      }
	    );

	# add items from the layer classes
	unless (@layers) {
	    push @items, ( 1 => 0 );

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN

	    $item->show;
	    $menu->append($item);
	}
	$menu->popup(undef, undef, undef, undef, $event->button, $event->time);
	return 1;

    } elsif ($column =~ /^v/) {

	$layer->visible(!$layer->visible());
	$self->update;
	$self->{overlay}->render;

    } elsif ($column =~ /^t/) {

	$tree_view->columns_autosize();

    }

    return 0;
}

## @ignore
sub show_information {
    my($overlay, $self) = @_;
    my($x, $y) = $overlay->event_pixel2point;

    my $layer = $self->get_selected_layer();

    my $location = sprintf("(x,y) = (%.4f, %.4f)", $x, $y);
    my $value = '';
    if ($layer and $layer->isa('Geo::Raster')) {
	my @ij = $layer->w2g($x, $y);
	$location .= sprintf(", (i,j) = (%i, %i)",@ij);
	$value = $layer->point($x, $y);
	if (defined $value and $value ne 'nodata' and $layer->{INFO}) {
	    $value = $layer->{TABLE}->{DATA}->[$value]->[$layer->{INFO}-1];
	}
    }

    $self->{statusbar}->pop(0);

    $value = '' unless defined $value;

    # additional info, based on mode
    my($dim, $val) = $self->{overlay}->rubberband_value();
    if (defined $dim) {
	$dim = $dim == 1 ? 'length' : 'area';
	if (defined $val) {
	    my $d = '';
	    if ($val > 1000000) {
		$val /= 1000000;
		$d = 'M';
	    } elsif ($val > 1000) {
		$val /= 1000;
		$d = 'k';
	    }
	    $val = sprintf(" $dim = %.2f$d", $val);
	} else {
	    $val = " $dim not computed";
	}
    } else {
	$val = '';
    }

    my $mode = $self->{overlay}->rubberband_mode();
 
    $self->{statusbar}->push(0, "$mode $location $value$val");
}

## @ignore
sub inspect {
    my($self, $data, $name) = @_;

    $name = 'unknown variable' unless $name;

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN


    $self->{model}->set ($layer->{_tree_index},
			 0, $layer->name(),
			 1, $type,
			 2, $visible,
			 3, $alpha,
			 );
}

## @method Gtk2::Ex::Geo::Layer add_layer($object, $name, $do_not_zoom_to)
# @brief Add a layer to the overlay and the tree store
#
# The default behavior is to zoom to the new layer. The layer is
# upgraded using the upgrade method of the registered layer classes.
#
# @param object A geospatial data object. Must be either an object of
# a subclass of Gtk2::Ex::Geo::Layer or a data object that is
# recognized by such. It is the responsibility of the upgrade method
# of the layer class to upgrade the data object to a layer object.
# @param name (optional) Name for the new layer.
# @param do_not_zoom_to (optional) Whether to not to zoom the overlay
# to this layer. Forwarded to Gtk2::Ex::Geo::Overlay::add_layer.
# @return
sub add_layer {
    my($self, $object, $name, $do_not_zoom_to) = @_;
    return unless $object;

    my $layer;
    for $upgrade (@{$self->{upgrades}}) {
	$layer = $upgrade->($object);
	last if $layer;
    }
    if ($layer) {
	$layer = $object if $layer == 1; # backwards compatibility
    } else {
	$layer = $object;
    }

    return unless $layer->isa('Gtk2::Ex::Geo::Layer');

    my $i = $self->{overlay}->index_of_layer($name) if defined $name;
    croak "layer with name $name already exists" if defined $i;

    $layer->name($name);
    $layer->{_tree_index} = $self->{model}->insert (undef, 0);
 
    $self->set_layer($layer);
    $self->{overlay}->add_layer($layer, $do_not_zoom_to);
    return $layer;
}

## @method Gtk2::Ex::Geo::Layer layer($name)
# @param name
# @return
sub layer {
    my($self, $name) = @_;
    return $self->{overlay}->get_layer_by_name($name);
}

## @method layers
# @return a list of all layers (not the internal list but a copy)
sub layers {
    my($self) = @_;
    my @a = @{$self->{overlay}->{layers}};
    return @a;
}

## @method get_focal($name)
# @brief Returns a selected (or visible) part of a raster layer by its name.
# @deprecated Selected and clip are implemented elsewhere.
sub get_focal {
    my($self, $name) = @_;
    my $gd = $self->{overlay}->get_layer_by_name($name);
    if ($gd and $gd->isa('Geo::Raster')) {
	my @clip = $self->{overlay}->get_focus;
	@clip = $gd->wa2ga(@clip);
	# do not expand the view
	$clip[2]--; 
	$clip[3]--;
	return $gd->clip(@clip);
    }
}

## @method update
# @brief Updates the whole layer list.
sub update {
    my($self) = @_;
    for my $layer (@{$self->{overlay}->{layers}}) {
	$self->set_layer($layer);
    }
}

## @ignore
sub swap {
    my($array,$i1,$i2) = @_;
    my $e1 = $array->[$i1];
    my $e2 = $array->[$i2];
    $array->[$i1] = $e2;

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN

}

## @method move_down
# @brief Moves the selected layer down in the list.
sub move_down {
    my($self) = @_;

    my ($path, $focus_column) = $self->{tree_view}->get_cursor;
    return unless $path;
    my $index = $path->to_string;
    my $n = $#{$self->{overlay}->{layers}};
    if ($index < $n) {
	my($layer1,$layer2) = swap($self->{overlay}->{layers},$n-$index,$n-$index-1);
	$self->{model}->move_after($layer1->{_tree_index},$layer2->{_tree_index});
	$self->{overlay}->render;
    }

}

## @method move_up
# @brief Moves the selected layer up in the list.
sub move_up {
    my($self) = @_;

    my ($path, $focus_column) = $self->{tree_view}->get_cursor;
    return unless $path;
    my $index = $path->to_string;
    my $n = $#{$self->{overlay}->{layers}};
    if ($index > 0) {
	my($layer1,$layer2) = swap($self->{overlay}->{layers},$n-$index,$n-$index+1);
	$self->{model}->move_before($layer1->{_tree_index},$layer2->{_tree_index});
	$self->{overlay}->render;
    }

}

## @method remove_layer
# @brief Removes the selected layer.
# @return Success or failure
sub remove_layer {
    my($self, $name, $do_not_render) = @_;
    my $layer = $self->{overlay}->get_layer_by_name($name);
    return unless $layer;
    $self->{model}->remove($layer->{_tree_index});
    $self->{overlay}->remove_layer_by_name($name);
    delete($self->{focused}) if $self->{focused} and $self->{focused}->name eq $layer->name;
    $layer->close($self);
    $self->{overlay}->render unless $do_not_render;
    return 1;
}

## @method delete_selected
# @brief Removes the selected layer and destroys it.
# @return Success or failure
sub delete_selected {
    my($self, $do_not_render) = @_;
    my $n = $#{$self->{overlay}->{layers}};
    return if $n < 0;
    my ($path, $focus_column) = $self->{tree_view}->get_cursor;
    return unless $path;
    my $index = $path->to_string;
    return if $index < 0 or $index > $n;
    my($layer) = splice(@{$self->{overlay}->{layers}}, $n-$index, 1);
    $self->{model}->remove($layer->{_tree_index});
    delete($self->{focused}) if $self->{focused} and $self->{focused}->name eq $layer->name;
    $layer->close($self);
    if ($n > 0) {
	$index-- if $index == $n;
	$self->{tree_view}->set_cursor(Gtk2::TreePath->new($index));
    }    
    $self->{overlay}->render unless $do_not_render;
    return 1;
}

## @method get_selected
# @brief Returns the selected layer.
sub get_selected_layer {
    my($self) = @_;
    my($path, $focus_column) = $self->{tree_view}->get_cursor;
    return unless $path;
    my $index = $path->to_string;
    return $self->{overlay}->get_layer_by_index($index);
}

## @method select_layer($name)
# @brief Selects a layer.
sub select_layer {
    my($self, $name) = @_;
    my $index = $self->{overlay}->index_of_layer($name);
    if (defined $index) {
	$self->{tree_view}->set_cursor(Gtk2::TreePath->new($index));
    }
}

## @ignore
# explain this in some dox file
sub eval_entry {
    my($entry, $event, $self) = @_;
    my $key = $event->keyval;

lib/Gtk2/Ex/Geo/Glue.pm.in  view on Meta::CPAN

	if ($function and $self->{functions}{$function}) {
	    if ($self->{functions}{$function}{sub}) {
		$text =~ s/^$function/$self->{functions}{$function}{sub}/;
	    } else { # object
		$text =~ s/^$function/\$self->{functions}{$function}{object}-\>$function/;
	    }
	}
	my @g = $text =~ /\$(\w+)/g;
	my @_gd;
	for my $i (0..$#g) {
	    $_gd[$i] = $focal ? $self->get_focal($g[$i]) : $self->{overlay}->get_layer_by_name($g[$i]);
	    next unless $_gd[$i];
	    $text =~ s/\$$g[$i]\b/\$_gd[$i]/;
	}
	{
	    no strict;
	    eval $text;
	    croak "$text\n$@" if $@;
	}
	for my $i (0..$#g) {
	    if ($self->{overlay}->get_layer_by_name($g[$i])) {
		$_gd[$i]->value_range() if $_gd[$i]->isa('Geo::Raster');
	    } else {
		eval "\$self->add_layer(\$$g[$i],'$g[$i]',1);" if $g[$i] and $g[$i] ne 'self';
	    }
	}
	undef @_gd;
	$self->update();
	$self->{overlay}->render;
	return 1;
    } elsif ($key == $Gtk2::Gdk::Keysyms{Up}) {
	$entry->set_text($self->{history}->arrow_up);
	return 1;
    } elsif ($key == $Gtk2::Gdk::Keysyms{Down}) {
	$entry->set_text($self->{history}->arrow_down);
	return 1;
    }
}

sub render {
    $_[0]->{overlay}->render;
}

sub simulate {
    my($self, $sub) = @_;
    $self->stop;
    $self->{_event_source} = Glib::Idle->add($sub);
}

sub stop {
    my($self) = @_;

lib/Gtk2/Ex/Geo/Layer.pm  view on Meta::CPAN

# @todo add machinery for multiselection.
#
# @return a reference to the items array.
sub menu_items {
    my($self) = @_;
    my @items;
    push @items, (
	'_Unselect all' => sub {
	    my($self, $gui) = @{$_[1]};
	    $self->select;
	    $gui->{overlay}->update_image;
	    $self->open_features_dialog($gui, 1);
	},
	'_Symbol...' => sub {
	    my($self, $gui) = @{$_[1]};
	    $self->open_symbols_dialog($gui);
	},
	'_Colors...' => sub {
	    my($self, $gui) = @{$_[1]};
	    $self->open_colors_dialog($gui);
	},

lib/Gtk2/Ex/Geo/Layer.pm  view on Meta::CPAN


sub value_range {
    return (0, 0);
}

## @method @world()
#
# @brief A callback function. Return the bounding box.
# @return (minx, miny, maxx, maxy)

## @method render($pb, $cr, $overlay, $viewport)
#
# @brief A callback function. Render the layer.
# @param pb Gtk2::Gdk::Pixbuf object
# @param cr Cairo context
# @param overlay Gtk2::Ex::Geo::Overlay object
# @param viewport The pixbuf / cairo surface area in map coordinates
# [minx, miny, maxx, maxy]

## @method render_selection($gc)
#
# @brief Render the selection using the given graphics context
# @param $gc Gtk2::Gdk::GC
sub render_selection {
}

## @method void render($pb, $cr, $overlay, $viewport)
#
# @brief A request to render the data of the layer onto a surface.
#
# @param[in,out] pb A (XS wrapped) pointer to a gtk2_ex_geo_pixbuf.
# @param[in,out] cr A Cairo::Context object for the surface to draw on.
# @param[in] overlay A Gtk2::Ex::Geo::Overlay object which manages the surface.
# @param[in] viewport A reference to the bounding box [min_x, min_y,
# max_x, max_y] of the surface in world coordinates.
sub render {
    my($self, $pb, $cr, $overlay, $viewport) = @_;
}

## @method $bootstrap_dialog($gui, $dialog, $title, $connects)
#
# @brief Bootstrap the requested dialog.
#
# The requested dialog is asked from a Glue object, stored into the
# layer, and presented. 
#
# @param gui A Gtk2::Ex::Geo::Glue object

lib/Gtk2/Ex/Geo/Overlay.pm  view on Meta::CPAN

use Geo::OGC::Geometry;

use vars qw / $EDIT_SNAP_DISTANCE /;

our $VERSION = '0.62'; # same as Geo.pm

=pod

=head1 NAME

Gtk2::Ex::Geo::Overlay - A Gtk2 widget for a visual overlay of geospatial data

The <a href="http://geoinformatics.aalto.fi/doc/Geoinformatica/html/">
documentation of Gtk2::Ex::Geo</a> is written in doxygen format.

=cut

$EDIT_SNAP_DISTANCE = 5;

use Glib::Object::Subclass
    Gtk2::ScrolledWindow::,

lib/Gtk2/Ex/Geo/Overlay.pm  view on Meta::CPAN

	return (round(($p[0] - $self->{minX})/$self->{pixel_size} - 0.5),
		round(($self->{maxY} - $p[1])/$self->{pixel_size} - 0.5));
    }
    package Gtk2::Ex::Geo::Canvas;
    our @ISA = qw(Gtk2::Gdk::Pixbuf);
 
    sub new {
	my($class, $layers, 
	   $minX, $maxY, $pixel_size, $w_offset, $h_offset,
	   $width, $height,
	   $bg_r, $bg_g, $bg_b, $bg_a, $overlay) = @_;
	
	return unless defined $minX;

	$overlay = Gtk2::Ex::Geo::PseudoOverlay->new($minX, $maxY, $pixel_size) unless $overlay;
	
	my @viewport = ($minX+$pixel_size*$w_offset, 0, 0, $maxY-$pixel_size*$h_offset);
	$viewport[2] = $viewport[0]+$pixel_size*$width;
	$viewport[1] = $viewport[3]-$pixel_size*$height;
	
	my $pb = &Gtk2::Ex::Geo::gtk2_ex_geo_pixbuf_create($width, $height,
							   $viewport[0], $viewport[3],
							   $pixel_size, 
							   $bg_r, $bg_g, $bg_b, $bg_a);
	
	my $surface = &Gtk2::Ex::Geo::gtk2_ex_geo_pixbuf_get_cairo_surface($pb);
	my $cr = Cairo::Context->create($surface);
	
	for my $layer (@$layers) {
	    $layer->render($pb, $cr, $overlay, \@viewport);
	}
	
	undef $cr;
	undef $surface;
	my $self = &Gtk2::Ex::Geo::gtk2_ex_geo_pixbuf_get_pixbuf($pb);
	&Gtk2::Ex::Geo::gtk2_ex_geo_pixbuf_destroy($pb); # does not delete the real pixbuf
	
	bless($self, $class); 
    }
}

lib/Gtk2/Ex/Geo/Overlay.pm  view on Meta::CPAN

    $self->{old_vadj} = $self->get_vscrollbar->get_adjustment; # prevents a warning
    $self->get_vscrollbar->set_adjustment
	(Gtk2::Adjustment->new($self->{offset}[1], 0, $self->{canvas_size}[1], $size->[1]/20,
			       $size->[1], $size->[1]));

    $self->signal_emit ('map-updated');

}

## @method render_geometry($gc, $geom)
# @brief Render a geometry on the overlay.
#
# @note this should be called annotate or made detect the context (gdk vs cairo)
# Call update_image after you are finished with drawing on the pixmap.
# @param gc A gdk graphics context (Gtk2::Gdk::GC object)
# @param geom A Geo::OGC::Geometry object.
sub render_geometry {
    my($self, $gc, $geom, %param) = @_;
    if ($geom->isa('Geo::OGC::GeometryCollection')) 
    {
	for my $g ($geom->NumGeometries) {

lib/Gtk2/Ex/Geo/Overlay.pm  view on Meta::CPAN

    {
	$self->render_geometry($gc, $geom->ExteriorRing, %param);
	for my $i (0..$geom->NumInteriorRing-1) {
	    $self->render_geometry($gc, $geom->InteriorRingN($i), %param);
	}
    }
}

## @method update_image($annotations, $user_param)
# @param annotations A subroutine for user annotations. Called like
# this: $annotations->($overlay, $pixmap, $gc, $user_param).
# @param user_param User parameter for the annotations.
# @brief Updates the image on the screen to show the changes in pixmap.
sub update_image {
    my($self, $annotations, $user_param) = @_;
    return unless $self->{pixbuf};
    $self->{image}->set_from_pixbuf(undef);
    $self->{pixmap} = $self->{pixbuf}->render_pixmap_and_mask(0);
    my $gc = Gtk2::Gdk::GC->new($self->{pixmap});
    $self->{pixmap}->draw_line($gc, 0, 0, 0, 0); # strange bug, the first line is not drawn
    $self->signal_emit('pixmap_ready');

t/01.t  view on Meta::CPAN

	my $self = Gtk2::Ex::Geo::Layer::new($package);
	return $self;
    }
    sub name {
	'test';
    }
    sub world {
	return (0, 0, 100, 100);
    }
    sub render {
	my($self, $pb, $cr, $overlay, $viewport) = @_;
    }
}

ok(1);

if (0) {
    my($window, $gis) = Gtk2::Ex::Geo::simple(classes => [qw/My::Test::Layer/]);
    ok(1);
    
    if ($have_gnuplot) {

t/02.t  view on Meta::CPAN

    package Gtk2::Ex::Geo::Test1;
    our @ISA = qw(Gtk2::Ex::Geo::Layer);
    sub new {
	my $self = Gtk2::Ex::Geo::Layer::new(@_);
	return $self;
    }
    sub world {
	return (0, 0, 100, 100);
    }
    sub render {
	my($self, $pb, $cr, $overlay, $viewport) = @_;
    }
    sub got_focus {
	my($self, $gui) = @_;
	print STDERR $self->name," got focus\n";
	$self->{_tag} = $gui->{overlay}->signal_connect(drawing_changed => \&drawing_changed, $self);
    }
    sub lost_focus {
	my($self, $gui) = @_;
	print STDERR $self->name," lost focus\n";
	$gui->{overlay}->signal_handler_disconnect($self->{_tag}) if $self->{_tag};
    }
    sub drawing_changed {
	my(undef, $self) = @_;
	print STDERR $self->name," was notified of a change in drawing\n";
    }
    sub select {
	my($self, %params) = @_;
	for my $k (keys %params) {
	    print STDERR $self->name," was notified of a change in selection: $k=>$params{$k}\n";
	}

t/02.t  view on Meta::CPAN

    package Gtk2::Ex::Geo::Test2;
    our @ISA = qw(Gtk2::Ex::Geo::Layer);
    sub new {
	my $self = Gtk2::Ex::Geo::Layer::new(@_);
	return $self;
    }
    sub world {
	return (0, 0, 100, 100);
    }
    sub render {
	my($self, $pb, $cr, $overlay, $viewport) = @_;
    }
    sub got_focus {
	my($self) = @_;
	print STDERR $self->name," got focus\n";
    }
    sub lost_focus {
	my($self, $gui) = @_;
	print STDERR $self->name," lost focus\n";
    }
    sub select {

t/02.t  view on Meta::CPAN

    $gis->register_function( name => 'plot', object => $gnuplot );
    $gis->register_function( name => 'p', object => $gnuplot );
}

my $layer = Gtk2::Ex::Geo::Test1->new(name => 'test 1');
$gis->add_layer($layer);

$layer = Gtk2::Ex::Geo::Test2->new(name => 'test 2');
$gis->add_layer($layer);

$gis->{overlay}->signal_connect(update_layers => 
	sub {
	#print STDERR "in callback: @_\n";
	});

$gis->register_commands(
    [ 
      tag => 'test popup',
      label => 'Menu',
      tip => 'Press to get a menu',
      {

t/02.t  view on Meta::CPAN

    }

    # layer list
    my $list = Gtk2::ScrolledWindow->new();
    $list->set_policy("never", "automatic");
    $list->add($gis->{tree_view});
    
    # layer list and the map
    my $hbox = Gtk2::HBox->new(FALSE, 0);
    $hbox->pack_start($list, FALSE, FALSE, 0);
    $hbox->pack_start($gis->{overlay}, TRUE, TRUE, 0);
    
    # the stack
    my $vbox = Gtk2::VBox->new(FALSE, 0);
    $vbox->pack_start($gis->{toolbar}, FALSE, FALSE, 0);
    #$vbox->add($hbox);
    $vbox->pack_start($hbox, TRUE, TRUE, 0);
    $vbox->pack_start($gis->{entry}, FALSE, FALSE, 0);
    $vbox->pack_start($gis->{statusbar}, FALSE, FALSE, 0);

    $window->add($vbox);



( run in 0.686 second using v1.01-cache-2.11-cpan-49f99fa48dc )