148
226
my $response = $self->{_dialogs}->dlg_error_message(
149
sprintf( $d->get("Error while opening image %s."), "'" . $filename . "'"),
150
$d->get( "There was an error opening the image." ),
227
sprintf( $self->{_d}->get("Error while opening image %s."), "'" . $self->{_filename} . "'"),
228
$self->{_d}->get( "There was an error opening the image." ),
151
229
undef, undef, undef,
152
230
undef, undef, undef,
156
234
$self->{_drawing_window}->destroy if $self->{_drawing_window};
240
#-------------------------------------------------
163
241
$self->{_canvas} = Goo::Canvas->new();
164
my $gray = Gtk2::Gdk::Color->parse('gray');
165
$self->{_canvas}->set( 'background-color' => sprintf( "#%04x%04x%04x", $gray->red, $gray->green, $gray->blue ) );
167
$self->{_canvas}->set_bounds( 0, 0, $self->{_drawing_pixbuf}->get_width, $self->{_drawing_pixbuf}->get_height );
168
my $root = $self->{_canvas}->get_root_item;
170
$self->{_canvas_bg} = Goo::Canvas::Image->new( $root, $self->{_drawing_pixbuf}, 0, 0 );
243
#'redraw-when-scrolled' to reduce the flicker of static items
245
#this property is not available in older versions
246
#it was added to goocanvas on Mon Nov 17 10:28:07 2008 UTC
247
#http://svn.gnome.org/viewvc/goocanvas?view=revision&revision=28
248
if($self->{_canvas}->find_property ('redraw-when-scrolled')){
249
$self->{_canvas}->set(
250
'redraw-when-scrolled' => TRUE
254
my $gray = Gtk2::Gdk::Color->parse('gray');
255
$self->{_canvas}->set(
256
'automatic-bounds' => FALSE,
257
'bounds-from-origin' => FALSE,
258
'background-color' => sprintf( "#%04x%04x%04x", $gray->red, $gray->green, $gray->blue ),
261
#and attach scroll event
262
#to imitate scroll behavior of
263
#Gtk2::ImageView widget Ctrl+Mouse Wheel
264
$self->{_canvas}->signal_connect(
267
my ( $canvas, $ev ) = @_;
269
my $alloc = $self->{_canvas}->allocation;
270
my $scale = $canvas->get_scale;
272
if ($ev->state >= 'control-mask' && ($ev->direction eq 'up' || $ev->direction eq 'left') ) {
274
$canvas->scroll_to(int($ev->x - $alloc->width / 2 ) / $scale, int($ev->y - $alloc->height / 2 ) / $scale);
276
}elsif ( $ev->state >= 'control-mask' && ($ev->direction eq 'down' || $ev->direction eq 'right') ) {
284
#create rectangle to resize the background
285
$self->{_canvas_bg_rect} = Goo::Canvas::Rect->new(
286
$self->{_canvas}->get_root_item, 0, 0, $self->{_drawing_pixbuf}->get_width, $self->{_drawing_pixbuf}->get_height,
287
'fill-pattern' => $self->create_color('gray', 1.0),
288
'line-dash' => Goo::Canvas::LineDash->new( [ 5, 5 ] ),
290
'stroke-color' => 'black',
292
$self->setup_item_signals( $self->{_canvas_bg_rect} );
294
$self->handle_bg_rects( 'create' );
295
$self->handle_bg_rects( 'update' );
297
#create canvas background (:= screenshot)
298
$self->{_canvas_bg} = Goo::Canvas::Image->new(
299
$self->{_canvas}->get_root_item,
300
$self->{_drawing_pixbuf},
171
303
$self->setup_item_signals( $self->{_canvas_bg} );
174
$self->{_scrolled_window} = Gtk2::ScrolledWindow->new;
175
$self->{_scrolled_window}->set_policy( 'automatic', 'automatic' );
176
$self->{_scrolled_window}->add( $self->{_canvas} );
305
$self->handle_bg_rects( 'raise' );
178
my $drawing_vbox = Gtk2::VBox->new( FALSE, 0 );
179
my $drawing_inner_vbox = Gtk2::VBox->new( FALSE, 0 );
180
my $drawing_hbox = Gtk2::HBox->new( FALSE, 0 );
308
#-------------------------------------------------
309
$self->{_drawing_vbox} = Gtk2::VBox->new( FALSE, 0 );
310
$self->{_drawing_inner_vbox} = Gtk2::VBox->new( FALSE, 0 );
311
$self->{_drawing_inner_vbox_c} = Gtk2::VBox->new( FALSE, 0 );
312
$self->{_drawing_hbox} = Gtk2::HBox->new( FALSE, 0 );
313
$self->{_drawing_hbox_c} = Gtk2::HBox->new( FALSE, 0 );
182
315
#disable undo/redo actions at startup
183
#~ $self->{_uimanager}->get_widget("/MenuBar/Edit/Undo")->set_sensitive(FALSE);
184
#~ $self->{_uimanager}->get_widget("/MenuBar/Edit/Redo")->set_sensitive(FALSE);
186
#do show these actions because the user would be confused
187
#to see multiple shortcuts to handle zooming
188
#controlequal is used for english keyboard layouts for example
189
$self->{_uimanager}->get_action("/MenuBar/View/ControlEqual")->set_visible(FALSE);
190
$self->{_uimanager}->get_action("/MenuBar/View/ControlKpAdd")->set_visible(FALSE);
191
$self->{_uimanager}->get_action("/MenuBar/View/ControlKpSub")->set_visible(FALSE);
193
#create a table for placing the ruler and scrolle window
194
my $table = new Gtk2::Table( 3, 2, FALSE );
196
$self->{_drawing_window}->add($drawing_vbox);
316
$self->{_uimanager}->get_widget("/MenuBar/Edit/Undo")->set_sensitive(FALSE);
317
$self->{_uimanager}->get_widget("/MenuBar/Edit/Redo")->set_sensitive(FALSE);
319
$self->{_uimanager}->get_widget("/ToolBar/Undo")->set_sensitive(FALSE);
320
$self->{_uimanager}->get_widget("/ToolBar/Redo")->set_sensitive(FALSE);
322
$self->{_drawing_window}->add($self->{_drawing_vbox});
198
324
my $menubar = $self->{_uimanager}->get_widget("/MenuBar");
199
$drawing_vbox->pack_start( $menubar, FALSE, FALSE, 0 );
325
$self->{_drawing_vbox}->pack_start( $menubar, FALSE, FALSE, 0 );
201
327
my $toolbar_drawing = $self->{_uimanager}->get_widget("/ToolBarDrawing");
202
328
$toolbar_drawing->set_orientation('vertical');
203
329
$toolbar_drawing->set_style('icons');
204
330
$toolbar_drawing->set_icon_size('menu');
205
331
$toolbar_drawing->set_show_arrow(FALSE);
206
$drawing_hbox->pack_start( $toolbar_drawing, FALSE, FALSE, 0 );
332
$self->{_drawing_hbox}->pack_start( $toolbar_drawing, FALSE, FALSE, 0 );
334
#DRAWING TOOL CONTAINER
335
#-------------------------------------------------
336
#scrolled window for the canvas
337
$self->{_scrolled_window} = Gtk2::ScrolledWindow->new;
338
$self->{_scrolled_window}->set_policy( 'automatic', 'automatic' );
339
$self->{_scrolled_window}->add( $self->{_canvas} );
340
$self->{_hscroll_hid} = $self->{_scrolled_window}->get_hscrollbar->signal_connect('value-changed' => sub { $self->adjust_rulers} );
341
$self->{_vscroll_hid} = $self->{_scrolled_window}->get_vscrollbar->signal_connect('value-changed' => sub { $self->adjust_rulers} );
209
344
$self->{_vruler} = Gtk2::VRuler->new;
210
345
$self->{_vruler}->set_metric('pixels');
250
427
sub setup_bottom_hbox {
251
428
my $self = shift;
253
my $d = $self->{_shutter_common}->get_gettext;
256
431
my $tooltips = $self->{_shutter_common}->get_tooltips;
258
433
my $drawing_bottom_hbox = Gtk2::HBox->new( FALSE, 5 );
261
my $fill_color_label = Gtk2::Label->new( $d->get("Fill color") . ":" );
262
my $fill_color = Gtk2::ColorButton->new();
263
$fill_color->set_color( $self->{_fill_color} );
264
$fill_color->set_alpha( int( $self->{_fill_color_alpha} * 65636 ) );
265
$fill_color->set_use_alpha(TRUE);
266
$fill_color->set_title( $d->get("Choose fill color") );
267
$fill_color->signal_connect(
269
$self->{_fill_color} = $fill_color->get_color;
270
$self->{_fill_color_alpha} = $fill_color->get_alpha / 65636;
436
my $fill_color_label = Gtk2::Label->new( $self->{_d}->get("Fill color") . ":" );
437
$self->{_fill_color_w} = Gtk2::ColorButton->new();
438
$self->{_fill_color_w}->set_color( $self->{_fill_color} );
439
$self->{_fill_color_w}->set_alpha( int( $self->{_fill_color_alpha} * 65636 ) );
440
$self->{_fill_color_w}->set_use_alpha(TRUE);
441
$self->{_fill_color_w}->set_title( $self->{_d}->get("Choose fill color") );
274
$tooltips->set_tip( $fill_color_label, $d->get("Adjust fill color and opacity") );
275
$tooltips->set_tip( $fill_color, $d->get("Adjust fill color and opacity") );
443
$tooltips->set_tip( $fill_color_label, $self->{_d}->get("Adjust fill color and opacity") );
444
$tooltips->set_tip( $self->{_fill_color_w}, $self->{_d}->get("Adjust fill color and opacity") );
277
446
$drawing_bottom_hbox->pack_start( $fill_color_label, FALSE, FALSE, 5 );
278
$drawing_bottom_hbox->pack_start( $fill_color, FALSE, FALSE, 5 );
447
$drawing_bottom_hbox->pack_start( $self->{_fill_color_w}, FALSE, FALSE, 5 );
281
my $stroke_color_label = Gtk2::Label->new( $d->get("Stroke color") . ":" );
282
my $stroke_color = Gtk2::ColorButton->new();
283
$stroke_color->set_color( $self->{_stroke_color} );
284
$stroke_color->set_alpha( int( $self->{_stroke_color_alpha} * 65535 ) );
285
$stroke_color->set_use_alpha(TRUE);
286
$stroke_color->set_title( $d->get("Choose stroke color") );
287
$stroke_color->signal_connect(
289
$self->{_stroke_color} = $stroke_color->get_color;
290
$self->{_stroke_color_alpha} = $stroke_color->get_alpha / 65535;
450
my $stroke_color_label = Gtk2::Label->new( $self->{_d}->get("Stroke color") . ":" );
451
$self->{_stroke_color_w} = Gtk2::ColorButton->new();
452
$self->{_stroke_color_w}->set_color( $self->{_stroke_color} );
453
$self->{_stroke_color_w}->set_alpha( int( $self->{_stroke_color_alpha} * 65535 ) );
454
$self->{_stroke_color_w}->set_use_alpha(TRUE);
455
$self->{_stroke_color_w}->set_title( $self->{_d}->get("Choose stroke color") );
294
$tooltips->set_tip( $stroke_color_label, $d->get("Adjust stroke color and opacity") );
295
$tooltips->set_tip( $stroke_color, $d->get("Adjust stroke color and opacity") );
457
$tooltips->set_tip( $stroke_color_label, $self->{_d}->get("Adjust stroke color and opacity") );
458
$tooltips->set_tip( $self->{_stroke_color_w}, $self->{_d}->get("Adjust stroke color and opacity") );
297
460
$drawing_bottom_hbox->pack_start( $stroke_color_label, FALSE, FALSE, 5 );
298
$drawing_bottom_hbox->pack_start( $stroke_color, FALSE, FALSE, 5 );
461
$drawing_bottom_hbox->pack_start( $self->{_stroke_color_w}, FALSE, FALSE, 5 );
301
my $linew_label = Gtk2::Label->new( $d->get("Line width") . ":" );
302
my $line_spin = Gtk2::SpinButton->new_with_range( 0.5, 10, 0.1 );
303
$line_spin->set_value( $self->{_line_width} );
304
$line_spin->signal_connect(
305
'value-changed' => sub {
306
$self->{_line_width} = $line_spin->get_value;
464
my $linew_label = Gtk2::Label->new( $self->{_d}->get("Line width") . ":" );
465
$self->{_line_spin_w} = Gtk2::SpinButton->new_with_range( 0.5, 20, 0.1 );
466
$self->{_line_spin_w}->set_value( $self->{_line_width} );
310
$tooltips->set_tip( $linew_label, $d->get("Adjust line width") );
311
$tooltips->set_tip( $line_spin, $d->get("Adjust line width") );
468
$tooltips->set_tip( $linew_label, $self->{_d}->get("Adjust line width") );
469
$tooltips->set_tip( $self->{_line_spin_w}, $self->{_d}->get("Adjust line width") );
313
471
$drawing_bottom_hbox->pack_start( $linew_label, FALSE, FALSE, 5 );
314
$drawing_bottom_hbox->pack_start( $line_spin, FALSE, FALSE, 5 );
472
$drawing_bottom_hbox->pack_start( $self->{_line_spin_w}, FALSE, FALSE, 5 );
317
my $font_label = Gtk2::Label->new( $d->get("Font") . ":" );
318
my $font_btn = Gtk2::FontButton->new();
319
$font_btn->set_font_name( $self->{_font} );
320
$font_btn->signal_connect(
322
my $font_descr = Gtk2::Pango::FontDescription->from_string( $font_btn->get_font_name );
323
$self->{_font} = $font_descr->to_string;
475
my $font_label = Gtk2::Label->new( $self->{_d}->get("Font") . ":" );
476
$self->{_font_btn_w} = Gtk2::FontButton->new();
477
$self->{_font_btn_w}->set_font_name( $self->{_font} );
327
$tooltips->set_tip( $font_label, $d->get("Select font family and size") );
328
$tooltips->set_tip( $font_btn, $d->get("Select font family and size") );
479
$tooltips->set_tip( $font_label, $self->{_d}->get("Select font family and size") );
480
$tooltips->set_tip( $self->{_font_btn_w}, $self->{_d}->get("Select font family and size") );
330
482
$drawing_bottom_hbox->pack_start( $font_label, FALSE, FALSE, 5 );
331
$drawing_bottom_hbox->pack_start( $font_btn, FALSE, FALSE, 5 );
483
$drawing_bottom_hbox->pack_start( $self->{_font_btn_w}, FALSE, FALSE, 5 );
334
my $image_label = Gtk2::Label->new( $d->get("Insert image") . ":" );
486
my $image_label = Gtk2::Label->new( $self->{_d}->get("Insert image") . ":" );
335
487
my $image_btn = Gtk2::MenuToolButton->new( undef, undef );
336
$image_btn->set_menu( $self->ret_objects_menu($image_btn) );
338
#~ $image_btn->signal_connect( 'show-menu' => sub { my ($widget) = @_; $self->ret_objects_menu($widget, 'noinit') } );
491
$image_btn->set_menu( $self->import_from_filesystem($image_btn) );
496
#handle property changes
497
#changes are applied directly to the current item
498
$self->{_line_spin_wh} = $self->{_line_spin_w}->signal_connect(
499
'value-changed' => sub {
500
$self->{_line_width} = $self->{_line_spin_w}->get_value;
502
if($self->{_current_item}){
503
#apply all changes directly
504
my $item = $self->{_current_item};
505
if(my $child = $self->get_child_item($item)){
508
my $parent = $self->get_parent_item($item);
509
#determine key for item hash
510
my $key = $self->get_item_key($item, $parent);
512
$self->apply_properties($item, $parent, $key, $self->{_fill_color_w},
513
$self->{_stroke_color_w}, $self->{_line_spin_w},
514
$self->{_stroke_color_w}, $self->{_font_btn_w});
521
$self->{_stroke_color_wh} = $self->{_stroke_color_w}->signal_connect(
523
$self->{_stroke_color} = $self->{_stroke_color_w}->get_color;
524
$self->{_stroke_color_alpha} = $self->{_stroke_color_w}->get_alpha / 65535;
526
if($self->{_current_item}){
527
#apply all changes directly
528
my $item = $self->{_current_item};
529
if(my $child = $self->get_child_item($item)){
532
my $parent = $self->get_parent_item($item);
533
#determine key for item hash
534
my $key = $self->get_item_key($item, $parent);
536
$self->apply_properties($item, $parent, $key, $self->{_fill_color_w},
537
$self->{_stroke_color_w}, $self->{_line_spin_w},
538
$self->{_stroke_color_w}, $self->{_font_btn_w});
545
$self->{_fill_color_wh} = $self->{_fill_color_w}->signal_connect(
547
$self->{_fill_color} = $self->{_fill_color_w}->get_color;
548
$self->{_fill_color_alpha} = $self->{_fill_color_w}->get_alpha / 65636;
550
if($self->{_current_item}){
551
#apply all changes directly
552
my $item = $self->{_current_item};
553
if(my $child = $self->get_child_item($item)){
556
my $parent = $self->get_parent_item($item);
557
#determine key for item hash
558
my $key = $self->get_item_key($item, $parent);
560
$self->apply_properties($item, $parent, $key, $self->{_fill_color_w},
561
$self->{_stroke_color_w}, $self->{_line_spin_w},
562
$self->{_stroke_color_w}, $self->{_font_btn_w});
569
$self->{_font_btn_wh} = $self->{_font_btn_w}->signal_connect(
571
my $font_descr = Gtk2::Pango::FontDescription->from_string( $self->{_font_btn_w}->get_font_name );
572
$self->{_font} = $font_descr->to_string;
574
if($self->{_current_item}){
575
#apply all changes directly
576
my $item = $self->{_current_item};
577
if(my $child = $self->get_child_item($item)){
580
my $parent = $self->get_parent_item($item);
581
#determine key for item hash
582
my $key = $self->get_item_key($item, $parent);
584
$self->apply_properties($item, $parent, $key, $self->{_fill_color_w},
585
$self->{_stroke_color_w}, $self->{_line_spin_w},
586
$self->{_stroke_color_w}, $self->{_font_btn_w});
339
593
$image_btn->signal_connect(
340
594
'clicked' => sub {
341
$self->{_canvas}->window->set_cursor($self->change_cursor_to_current_pixbuf());
595
$self->{_canvas}->window->set_cursor($self->change_cursor_to_current_pixbuf);
345
$tooltips->set_tip( $image_label, $d->get("Insert an arbitrary object or file") );
346
$tooltips->set_tip( $image_btn, $d->get("Insert an arbitrary object or file") );
599
$tooltips->set_tip( $image_label, $self->{_d}->get("Insert an arbitrary object or file") );
600
$tooltips->set_tip( $image_btn, $self->{_d}->get("Insert an arbitrary object or file") );
348
602
$drawing_bottom_hbox->pack_start( $image_label, FALSE, FALSE, 5 );
349
603
$drawing_bottom_hbox->pack_start( $image_btn, FALSE, FALSE, 5 );
351
605
return $drawing_bottom_hbox;
608
sub setup_right_vbox_c {
612
my $tooltips = $self->{_shutter_common}->get_tooltips;
614
my $cropping_bottom_vbox = Gtk2::VBox->new( FALSE, 5 );
617
my $pixbuf = $self->{_view}->get_pixbuf || $self->{_drawing_pixbuf};
620
my $xw_label = Gtk2::Label->new( $self->{_d}->get("X") . ":" );
621
$self->{_x_spin_w} = Gtk2::SpinButton->new_with_range( 0, $pixbuf->get_width, 1 );
622
$self->{_x_spin_w}->set_value( 0 );
623
$self->{_x_spin_w_handler} = $self->{_x_spin_w}->signal_connect(
624
'value-changed' => sub {
625
$self->{_selector}->set_selection(
626
Gtk2::Gdk::Rectangle->new(
627
$self->{_x_spin_w}->get_value, $self->{_y_spin_w}->get_value,
628
$self->{_width_spin_w}->get_value, $self->{_height_spin_w}->get_value
634
my $xw_hbox = Gtk2::HBox->new( FALSE, 5 );
635
$xw_hbox->pack_start( $xw_label, FALSE, FALSE, 5 );
636
$xw_hbox->pack_start( $self->{_x_spin_w}, FALSE, FALSE, 5 );
639
my $yw_label = Gtk2::Label->new( $self->{_d}->get("Y") . ":" );
640
$self->{_y_spin_w} = Gtk2::SpinButton->new_with_range( 0, $pixbuf->get_height, 1 );
641
$self->{_y_spin_w}->set_value( 0 );
642
$self->{_y_spin_w_handler} = $self->{_y_spin_w}->signal_connect(
643
'value-changed' => sub {
644
$self->{_selector}->set_selection(
645
Gtk2::Gdk::Rectangle->new(
646
$self->{_x_spin_w}->get_value, $self->{_y_spin_w}->get_value,
647
$self->{_width_spin_w}->get_value, $self->{_height_spin_w}->get_value
653
my $yw_hbox = Gtk2::HBox->new( FALSE, 5 );
654
$yw_hbox->pack_start( $yw_label, FALSE, FALSE, 5 );
655
$yw_hbox->pack_start( $self->{_y_spin_w}, FALSE, FALSE, 5 );
658
my $widthw_label = Gtk2::Label->new( $self->{_d}->get("Width") . ":" );
659
$self->{_width_spin_w} = Gtk2::SpinButton->new_with_range( 0, $pixbuf->get_width, 1 );
660
$self->{_width_spin_w}->set_value( 0 );
661
$self->{_width_spin_w_handler} = $self->{_width_spin_w}->signal_connect(
662
'value-changed' => sub {
663
$self->{_selector}->set_selection(
664
Gtk2::Gdk::Rectangle->new(
665
$self->{_x_spin_w}->get_value, $self->{_y_spin_w}->get_value,
666
$self->{_width_spin_w}->get_value, $self->{_height_spin_w}->get_value
672
my $ww_hbox = Gtk2::HBox->new( FALSE, 5 );
673
$ww_hbox->pack_start( $widthw_label, FALSE, FALSE, 5 );
674
$ww_hbox->pack_start( $self->{_width_spin_w}, FALSE, FALSE, 5 );
677
my $heightw_label = Gtk2::Label->new( $self->{_d}->get("Height") . ":" );
678
$self->{_height_spin_w} = Gtk2::SpinButton->new_with_range( 0, $pixbuf->get_height, 1 );
679
$self->{_height_spin_w}->set_value( 0 );
680
$self->{_height_spin_w_handler} = $self->{_height_spin_w}->signal_connect(
681
'value-changed' => sub {
682
$self->{_selector}->set_selection(
683
Gtk2::Gdk::Rectangle->new(
684
$self->{_x_spin_w}->get_value, $self->{_y_spin_w}->get_value,
685
$self->{_width_spin_w}->get_value, $self->{_height_spin_w}->get_value
691
my $hw_hbox = Gtk2::HBox->new( FALSE, 5 );
692
$hw_hbox->pack_start( $heightw_label, FALSE, FALSE, 5 );
693
$hw_hbox->pack_start( $self->{_height_spin_w}, FALSE, FALSE, 5 );
695
#the above values are changed when the selection is changed
696
$self->{_selector_handler} = $self->{_selector}->signal_connect(
697
'selection-changed' => sub {
698
$self->adjust_crop_values($pixbuf);
703
my $crop_c = Gtk2::Button->new_from_stock ('gtk-cancel');
704
$crop_c->signal_connect('clicked' => sub { $self->abort_current_mode} );
707
my $crop_ok = Gtk2::Button->new_with_mnemonic ($self->{_d}->get("_Crop"));
708
$crop_ok->set_image( Gtk2::Image->new_from_file($self->{_dicons}.'/transform-crop.png') );
709
$crop_ok->signal_connect('clicked' => sub {
711
my $s = $self->{_selector}->get_selection;
712
my $p = $self->{_view}->get_pixbuf;
717
$self->store_to_xdo_stack($self->{_canvas_bg}, 'modify', 'undo', $s);
720
#create temp pixbuf because selected area might be bigger than
721
#source pixbuf (screenshot) => canvas area is resizeable
722
my $temp = Gtk2::Gdk::Pixbuf->new ($self->{_drawing_pixbuf}->get_colorspace, TRUE, 8, $p->get_width, $p->get_height);
723
#whole pixbuf is transparent
724
$temp->fill(0x00000000);
726
#copy source image to temp pixbuf (temp pixbuf's size == $self->{_view}->get_pixbuf)
727
$self->{_drawing_pixbuf}->copy_area(0, 0, $self->{_drawing_pixbuf}->get_width, $self->{_drawing_pixbuf}->get_height, $temp, 0, 0);
729
#and create a new subpixbuf from the temp pixbuf
730
my $new_p = $temp->new_subpixbuf ($s->x, $s->y, $s->width, $s->height);
731
$self->{_drawing_pixbuf} = $new_p->copy;
733
#update bounds and bg_rects
734
$self->{_canvas_bg_rect}->set('width' => $s->width, 'height' => $s->height);
735
$self->handle_bg_rects( 'update' );
737
#update canvas and show the new pixbuf
738
$self->{_canvas_bg}->set('pixbuf' => $new_p);
741
#so they are in the right position
742
#~ print $s->x ." - ".$s->y."\n";
743
$self->move_all($s->x, $s->y);
746
$self->{_canvas_bg}->lower;
747
$self->{_canvas_bg_rect}->lower;
748
$self->handle_bg_rects( 'raise' );
751
#nothing here right now
754
#finally reset mode to select tool
755
$self->abort_current_mode;
760
#put buttons in a separated box
761
#all buttons = one size
762
my $sg_butt = Gtk2::SizeGroup->new('vertical');
763
$sg_butt->add_widget($crop_c);
764
$sg_butt->add_widget($crop_ok);
766
my $cropping_bottom_vbox_b = Gtk2::VBox->new( FALSE, 5 );
767
$cropping_bottom_vbox_b->pack_start( $crop_c, FALSE, FALSE, 0 );
768
$cropping_bottom_vbox_b->pack_start( $crop_ok, FALSE, FALSE, 0 );
771
#all labels = one size
772
$xw_label->set_alignment( 0, 0.5 );
773
$yw_label->set_alignment( 0, 0.5 );
774
$widthw_label->set_alignment( 0, 0.5 );
775
$heightw_label->set_alignment( 0, 0.5 );
777
my $sg_main = Gtk2::SizeGroup->new('horizontal');
778
$sg_main->add_widget($xw_label);
779
$sg_main->add_widget($yw_label);
780
$sg_main->add_widget($widthw_label);
781
$sg_main->add_widget($heightw_label);
783
$cropping_bottom_vbox->pack_start( $xw_hbox, FALSE, FALSE, 3 );
784
$cropping_bottom_vbox->pack_start( $yw_hbox, FALSE, FALSE, 3 );
785
$cropping_bottom_vbox->pack_start( $ww_hbox, FALSE, FALSE, 3 );
786
$cropping_bottom_vbox->pack_start( $hw_hbox, FALSE, FALSE, 3 );
787
$cropping_bottom_vbox->pack_start( $cropping_bottom_vbox_b, TRUE, TRUE, 3 );
790
my $crop_frame_label = Gtk2::Label->new;
791
$crop_frame_label->set_markup( "<b>" . $self->{_d}->get("Selection") . "</b>" );
793
my $crop_frame = Gtk2::Frame->new();
794
$crop_frame->set_border_width(5);
795
$crop_frame->set_label_widget($crop_frame_label);
796
$crop_frame->set_shadow_type('none');
798
$crop_frame->add($cropping_bottom_vbox);
803
sub adjust_crop_values{
807
#block 'value-change' handlers for widgets
808
#so we do not apply the changes twice
809
$self->{_x_spin_w}->signal_handler_block ($self->{_x_spin_w_handler});
810
$self->{_y_spin_w}->signal_handler_block ($self->{_y_spin_w_handler});
811
$self->{_width_spin_w}->signal_handler_block ($self->{_width_spin_w_handler});
812
$self->{_height_spin_w}->signal_handler_block ($self->{_height_spin_w_handler});
814
my $s = $self->{_selector}->get_selection;
817
$self->{_x_spin_w}->set_value( $s->x );
818
$self->{_x_spin_w}->set_range( 0, $pixbuf->get_width - $s->width );
820
$self->{_y_spin_w}->set_value( $s->y );
821
$self->{_y_spin_w}->set_range( 0, $pixbuf->get_height - $s->height );
823
$self->{_width_spin_w}->set_value( $s->width );
824
$self->{_width_spin_w}->set_range( 0, $pixbuf->get_width - $s->x );
826
$self->{_height_spin_w}->set_value( $s->height );
827
$self->{_height_spin_w}->set_range( 0, $pixbuf->get_height - $s->y );
830
#unblock 'value-change' handlers for widgets
831
$self->{_x_spin_w}->signal_handler_unblock ($self->{_x_spin_w_handler});
832
$self->{_y_spin_w}->signal_handler_unblock ($self->{_y_spin_w_handler});
833
$self->{_width_spin_w}->signal_handler_unblock ($self->{_width_spin_w_handler});
834
$self->{_height_spin_w}->signal_handler_unblock ($self->{_height_spin_w_handler});
354
840
sub push_to_statusbar {
355
841
my $self = shift;
358
844
my $action = shift || 'none';
360
my $d = $self->{_shutter_common}->get_gettext;
362
846
my $status_text = int( $x ) . " x " . int( $y );
364
848
if ( $self->{_current_mode} == 10 ) {
366
850
if($action eq 'resize'){
367
$status_text .= " ".$d->get("Click-Drag to scale (try Control to scale uniformly)");
851
$status_text .= " ".$self->{_d}->get("Click-Drag to scale (try Control to scale uniformly)");
852
}elsif($action eq 'canvas_resize'){
853
$status_text .= " ".$self->{_d}->get("Click-Drag to resize the canvas");
370
} elsif ( $self->{_current_mode} == 20 ) {
856
} elsif ( $self->{_current_mode} == 20 || $self->{_current_mode} == 30) {
372
$status_text .= " ".$d->get("Click to paint (try Control or Shift for a straight line)");
858
$status_text .= " ".$self->{_d}->get("Click to paint (try Control or Shift for a straight line)");
374
} elsif ( $self->{_current_mode} == 30 ) {
376
$status_text .= " ".$d->get("Click-Drag to create a new straight line");
378
860
} elsif ( $self->{_current_mode} == 40 ) {
380
$status_text .= " ".$d->get("Click-Drag to create a new rectangle");
862
$status_text .= " ".$self->{_d}->get("Click-Drag to create a new straight line");
382
864
} elsif ( $self->{_current_mode} == 50 ) {
384
$status_text .= " ".$d->get("Click-Drag to create a new ellipse");
866
$status_text .= " ".$self->{_d}->get("Click-Drag to create a new arrow");
386
868
} elsif ( $self->{_current_mode} == 60 ) {
388
$status_text .= " ".$d->get("Click-Drag to add a new text area");
870
$status_text .= " ".$self->{_d}->get("Click-Drag to create a new rectangle");
390
872
} elsif ( $self->{_current_mode} == 70 ) {
392
$status_text .= " ".$d->get("Click to censor (try Control or Shift for a straight line)");
874
$status_text .= " ".$self->{_d}->get("Click-Drag to create a new ellipse");
394
876
} elsif ( $self->{_current_mode} == 80 ) {
396
$status_text .= " ".$d->get("Select an object to delete it from the canvas");
878
$status_text .= " ".$self->{_d}->get("Click-Drag to add a new text area");
398
880
} elsif ( $self->{_current_mode} == 90 ) {
400
$status_text .= " ".$d->get("Delete all objects");
882
$status_text .= " ".$self->{_d}->get("Click to censor (try Control or Shift for a straight line)");
884
} elsif ( $self->{_current_mode} == 100 ) {
886
$status_text .= " ".$self->{_d}->get("Click to add an auto-increment shape");
888
} elsif ( $self->{_current_mode} == 110 ) {
890
#nothing to do here....
404
894
#update statusbar
405
895
$self->{_drawing_statusbar}->push( 0, $status_text );
918
1504
unless $item == $self->{_canvas_bg};
1508
if($item->{dragging_start}){
1509
$self->store_to_xdo_stack($item, 'modify', 'undo');
1510
$item->{dragging_start} = FALSE;
922
} elsif ( ($self->{_current_mode_descr} eq "freehand" || $self->{_current_mode_descr} eq "censor") && $ev->state >= 'button1-mask' ) {
924
my $item = $self->{_current_new_item};
1514
} elsif ( ($self->{_current_mode_descr} eq "freehand" || $self->{_current_mode_descr} eq "highlighter" ||$self->{_current_mode_descr} eq "censor") && $ev->state >= 'button1-mask' ) {
1516
#mark as active item
1518
if($self->{_current_new_item}){
1519
$item = $self->{_current_new_item};
1520
$self->{_current_new_item} = undef;
1521
$self->{_current_item} = $item;
1523
#apply item properties to widgets
1524
#line width, fill color, stroke color etc.
1525
$self->set_and_save_drawing_properties($item, FALSE);
1528
$self->store_to_xdo_stack($self->{_current_item} , 'create', 'undo');
1531
$item = $self->{_current_item};
927
1534
if($ev->state >= 'control-mask'){
928
1536
my $last_point = pop @{ $self->{_items}{$item}{'points'} };
929
$last_point = $ev->y unless $last_point;
930
push @{ $self->{_items}{$item}{'points'} }, $last_point, $ev->x, $last_point;
1537
$last_point = $ev->y_root unless $last_point;
1538
push @{ $self->{_items}{$item}{'points'} }, $last_point, $ev->x_root, $last_point;
931
1540
}elsif($ev->state >= 'shift-mask'){
932
1542
my $last_point_y = pop @{ $self->{_items}{$item}{'points'} };
933
1543
my $last_point_x = pop @{ $self->{_items}{$item}{'points'} };
934
$last_point_x = $ev->x unless $last_point_x;
935
$last_point_y = $ev->y unless $last_point_y;
936
push @{ $self->{_items}{$item}{'points'} }, $last_point_x, $last_point_y, $last_point_x, $ev->y;
1544
$last_point_x = $ev->x_root unless $last_point_x;
1545
$last_point_y = $ev->y_root unless $last_point_y;
1546
push @{ $self->{_items}{$item}{'points'} }, $last_point_x, $last_point_y, $last_point_x, $ev->y_root;
938
push @{ $self->{_items}{$item}{'points'} }, $ev->x, $ev->y;
1550
push @{ $self->{_items}{$item}{'points'} }, $ev->x_root, $ev->y_root;
940
1553
$self->{_items}{$item}->set( points => Goo::Canvas::Points->new( $self->{_items}{$item}{'points'} ) );
1555
#new item is already on the canvas with small initial size
1556
#drawing is like resizing, so set up for resizing
944
1558
( $self->{_current_mode_descr} eq "rect"
945
1559
|| $self->{_current_mode_descr} eq "line"
1560
|| $self->{_current_mode_descr} eq "arrow"
946
1561
|| $self->{_current_mode_descr} eq "ellipse"
947
1562
|| $self->{_current_mode_descr} eq "text"
948
1563
|| $self->{_current_mode_descr} eq "image"
1564
|| $self->{_current_mode_descr} eq "number"
950
1566
&& $ev->state >= 'button1-mask'
1567
&& !$item->{resizing} #if item is not in resize mode already
954
#new item is already on the canvas with small initial size
955
#drawing is like resizing, so set up tool for resizing
1571
#~ print "start resizing\n";
956
1573
my $item = $self->{_current_new_item};
957
#~ $self->{_current_new_item} = undef;
958
$self->set_drawing_action(0);
959
$self->change_drawing_tool_cb(10);
960
$self->{_current_item} = $item;
961
$self->{_items}{$item}{'bottom-right-corner'}->{res_x} = $ev->x;
962
$self->{_items}{$item}{'bottom-right-corner'}->{res_y} = $ev->y;
1575
return FALSE unless $item;
1577
$self->{_current_new_item} = undef;
1578
$self->{_last_item} = $item;
1579
$self->{_current_item} = $item;
1581
#apply item properties to widgets / or only save it
1582
#line width, fill color, stroke color etc.
1583
$self->set_and_save_drawing_properties($self->{_current_item}, TRUE);
1585
$self->{_items}{$item}{'bottom-right-corner'}->{res_x} = $ev->x_root;
1586
$self->{_items}{$item}{'bottom-right-corner'}->{res_y} = $ev->y_root;
963
1587
$self->{_items}{$item}{'bottom-right-corner'}->{resizing} = TRUE;
964
$self->{_canvas}->pointer_grab( $self->{_items}{$item}{'bottom-right-corner'}, [ 'pointer-motion-mask', 'button-release-mask' ], Gtk2::Gdk::Cursor->new('bottom-right-corner'), $ev->time );
1588
#~ $self->{_canvas}->pointer_grab( $self->{_items}{$item}{'bottom-right-corner'}, [ 'pointer-motion-mask', 'button-release-mask' ], Gtk2::Gdk::Cursor->new('bottom-right-corner'), $ev->time );
1589
$self->{_canvas}->pointer_grab( $self->{_items}{$item}{'bottom-right-corner'}, [ 'pointer-motion-mask', 'button-release-mask' ], undef, $ev->time );
1592
$self->store_to_xdo_stack($self->{_current_item} , 'create', 'undo');
1594
#item is resizing mode already
967
1595
} elsif ( $item->{resizing} && $ev->state >= 'button1-mask' ) {
1597
#~ print "resizing\n";
969
1599
$self->{_current_mode_descr} = "resize";
971
my $curr_item = $self->{_current_item};
974
#calculate aspect ratio (resizing when control is pressed)
976
$ratio = $self->{_items}{$curr_item}->get('width')/$self->{_items}{$curr_item}->get('height') if $self->{_items}{$curr_item}->get('height') != 0;
978
foreach ( keys %{ $self->{_items}{$curr_item} } ) {
980
#fancy resizing using our little resize boxes
981
if ( $item == $self->{_items}{$curr_item}{$_} ) {
988
if ( $_ eq 'top-left-corner' ) {
992
if($ev->state >= 'control-mask'){
993
$new_x = $self->{_items}{$curr_item}->get('x') + ($ev->y - $item->{res_y}) * $ratio;
994
$new_y = $self->{_items}{$curr_item}->get('y') + ($ev->y - $item->{res_y});
995
$new_width = $self->{_items}{$curr_item}->get('width') + ( $self->{_items}{$curr_item}->get('x') - $new_x );
996
$new_height = $self->{_items}{$curr_item}->get('height') + ( $self->{_items}{$curr_item}->get('y') - $new_y );
998
$new_x = $self->{_items}{$curr_item}->get('x') + $ev->x - $item->{res_x};
999
$new_y = $self->{_items}{$curr_item}->get('y') + $ev->y - $item->{res_y};
1000
$new_width = $self->{_items}{$curr_item}->get('width') + ( $self->{_items}{$curr_item}->get('x') - $new_x );
1001
$new_height = $self->{_items}{$curr_item}->get('height') + ( $self->{_items}{$curr_item}->get('y') - $new_y );
1004
} elsif ( $_ eq 'top-side' ) {
1008
$new_x = $self->{_items}{$curr_item}->get('x');
1009
$new_y = $self->{_items}{$curr_item}->get('y') + $ev->y - $item->{res_y};
1011
$new_width = $self->{_items}{$curr_item}->get('width');
1012
$new_height = $self->{_items}{$curr_item}->get('height') + ( $self->{_items}{$curr_item}->get('y') - $new_y );
1014
} elsif ( $_ eq 'top-right-corner' ) {
1018
$new_x = $self->{_items}{$curr_item}->get('x');
1019
$new_y = $self->{_items}{$curr_item}->get('y') + $ev->y - $item->{res_y};
1021
if($ev->state >= 'control-mask'){
1022
$new_width = $self->{_items}{$curr_item}->get('width') - ( $ev->y - $item->{res_y} ) * $ratio;
1023
$new_height = $self->{_items}{$curr_item}->get('height') + ( $self->{_items}{$curr_item}->get('y') - $new_y );
1025
$new_width = $self->{_items}{$curr_item}->get('width') + ( $ev->x - $item->{res_x} );
1026
$new_height = $self->{_items}{$curr_item}->get('height') + ( $self->{_items}{$curr_item}->get('y') - $new_y );
1029
} elsif ( $_ eq 'left-side' ) {
1033
$new_x = $self->{_items}{$curr_item}->get('x') + $ev->x - $item->{res_x};
1034
$new_y = $self->{_items}{$curr_item}->get('y');
1036
$new_width = $self->{_items}{$curr_item}->get('width') + ( $self->{_items}{$curr_item}->get('x') - $new_x );
1037
$new_height = $self->{_items}{$curr_item}->get('height');
1039
} elsif ( $_ eq 'right-side' ) {
1043
$new_x = $self->{_items}{$curr_item}->get('x');
1044
$new_y = $self->{_items}{$curr_item}->get('y');
1046
$new_width = $self->{_items}{$curr_item}->get('width') + ( $ev->x - $item->{res_x} );
1047
$new_height = $self->{_items}{$curr_item}->get('height');
1049
} elsif ( $_ eq 'bottom-left-corner' ) {
1053
if($ev->state >= 'control-mask'){
1054
$new_x = $self->{_items}{$curr_item}->get('x') - $ev->y + $item->{res_y};
1055
$new_y = $self->{_items}{$curr_item}->get('y');
1057
$new_width = $self->{_items}{$curr_item}->get('width') + ( $self->{_items}{$curr_item}->get('x') - $new_x );
1058
$new_height = $self->{_items}{$curr_item}->get('height') + ( $ev->y - $item->{res_y} ) / $ratio;
1060
$new_x = $self->{_items}{$curr_item}->get('x') + $ev->x - $item->{res_x};
1061
$new_y = $self->{_items}{$curr_item}->get('y');
1063
$new_width = $self->{_items}{$curr_item}->get('width') + ( $self->{_items}{$curr_item}->get('x') - $new_x );
1064
$new_height = $self->{_items}{$curr_item}->get('height') + ( $ev->y - $item->{res_y} );
1067
} elsif ( $_ eq 'bottom-side' ) {
1071
$new_x = $self->{_items}{$curr_item}->get('x');
1072
$new_y = $self->{_items}{$curr_item}->get('y');
1074
$new_width = $self->{_items}{$curr_item}->get('width');
1075
$new_height = $self->{_items}{$curr_item}->get('height') + ( $ev->y - $item->{res_y} );
1077
} elsif ( $_ eq 'bottom-right-corner' ) {
1081
$new_x = $self->{_items}{$curr_item}->get('x');
1082
$new_y = $self->{_items}{$curr_item}->get('y');
1084
if($ev->state >= 'control-mask'){
1085
$new_width = $self->{_items}{$curr_item}->get('width') + ( $ev->y - $item->{res_y} ) * $ratio;
1086
$new_height = $self->{_items}{$curr_item}->get('height') + ( $ev->y - $item->{res_y} );
1088
$new_width = $self->{_items}{$curr_item}->get('width') + ( $ev->x - $item->{res_x} );
1089
$new_height = $self->{_items}{$curr_item}->get('height') + ( $ev->y - $item->{res_y} );
1096
$self->{_canvas}->window->set_cursor( Gtk2::Gdk::Cursor->new($cursor) );
1098
$item->{res_x} = $ev->x;
1099
$item->{res_y} = $ev->y;
1101
#when width or height are too small we switch to opposite rectangle and do the resizing in this way
1102
if ( $new_width < 0 || $new_height < 0) {
1103
$self->{_canvas}->pointer_ungrab($item, $ev->time);
1104
my $oppo = $self->get_opposite_rect($item, $curr_item, $new_width, $new_height);
1105
$self->{_items}{$curr_item}{$oppo}->{res_x} = $ev->x;
1106
$self->{_items}{$curr_item}{$oppo}->{res_y} = $ev->y;
1107
$self->{_items}{$curr_item}{$oppo}->{resizing} = TRUE;
1108
$self->{_canvas}->pointer_grab( $self->{_items}{$curr_item}{$oppo}, [ 'pointer-motion-mask', 'button-release-mask' ], Gtk2::Gdk::Cursor->new($oppo), $ev->time );
1109
$self->handle_embedded( 'mirror', $curr_item );
1110
$new_width = 0 if $new_width < 0;
1111
$new_height = 0 if $new_height < 0;
1114
$self->{_items}{$curr_item}->set(
1117
'width' => $new_width,
1118
'height' => $new_height,
1121
$self->handle_rects( 'update', $curr_item );
1122
$self->handle_embedded( 'update', $curr_item );
1601
#canvas resizing shape
1602
if ( $self->{_canvas_bg_rect}{'right-side'} == $item ) {
1604
my $new_width = $self->{_canvas_bg_rect}->get('width') + ( $ev->x_root - $item->{res_x} );
1606
unless ( $new_width < 0 ) {
1608
$self->{_canvas_bg_rect}->set(
1609
'width' => $new_width,
1612
$self->handle_bg_rects('update');
1616
} elsif ( $self->{_canvas_bg_rect}{'bottom-side'} == $item ) {
1618
my $new_height = $self->{_canvas_bg_rect}->get('height') + ( $ev->y_root - $item->{res_y} );
1620
unless ( $new_height < 0 ) {
1622
$self->{_canvas_bg_rect}->set(
1623
'height' => $new_height,
1626
$self->handle_bg_rects('update');
1630
} elsif ( $self->{_canvas_bg_rect}{'bottom-right-corner'} == $item ) {
1632
my $new_width = $self->{_canvas_bg_rect}->get('width') + ( $ev->x_root - $item->{res_x} );
1633
my $new_height = $self->{_canvas_bg_rect}->get('height') + ( $ev->y_root - $item->{res_y} );
1635
unless ( $new_width < 0 || $new_height < 0) {
1637
$self->{_canvas_bg_rect}->set(
1638
'width' => $new_width,
1639
'height' => $new_height,
1642
$self->handle_bg_rects('update');
1646
#item resizing shape
1649
my $curr_item = $self->{_current_item};
1650
#~ my $cursor = undef;
1652
return FALSE unless $curr_item;
1654
#calculate aspect ratio (resizing when control is pressed)
1656
$ratio = $self->{_items}{$curr_item}->get('width')/$self->{_items}{$curr_item}->get('height') if $self->{_items}{$curr_item}->get('height') != 0;
1663
foreach ( keys %{ $self->{_items}{$curr_item} } ) {
1665
next unless $_ =~ m/(corner|side)/;
1667
#fancy resizing using our little resize boxes
1668
if ( $item == $self->{_items}{$curr_item}{$_} ) {
1672
if ( $_ eq 'bottom-side' ) {
1674
$new_x = $self->{_items}{$curr_item}->get('x');
1675
$new_y = $self->{_items}{$curr_item}->get('y');
1677
$new_width = $self->{_items}{$curr_item}->get('width');
1678
$new_height = $self->{_items}{$curr_item}->get('height') + ( $ev->y_root - $item->{res_y} );
1682
} elsif ( $_ eq 'bottom-right-corner' ) {
1684
$new_x = $self->{_items}{$curr_item}->get('x');
1685
$new_y = $self->{_items}{$curr_item}->get('y');
1687
if($ev->state >= 'control-mask'){
1688
$new_width = $self->{_items}{$curr_item}->get('width') + ( $ev->y_root - $item->{res_y} ) * $ratio;
1689
$new_height = $self->{_items}{$curr_item}->get('height') + ( $ev->y_root - $item->{res_y} );
1691
$new_width = $self->{_items}{$curr_item}->get('width') + ( $ev->x_root - $item->{res_x} );
1692
$new_height = $self->{_items}{$curr_item}->get('height') + ( $ev->y_root - $item->{res_y} );
1697
}elsif ( $_ eq 'top-left-corner' ) {
1699
if($ev->state >= 'control-mask'){
1700
$new_x = $self->{_items}{$curr_item}->get('x') + ($ev->y_root - $item->{res_y}) * $ratio;
1701
$new_y = $self->{_items}{$curr_item}->get('y') + ($ev->y_root - $item->{res_y});
1702
$new_width = $self->{_items}{$curr_item}->get('width') + ( $self->{_items}{$curr_item}->get('x') - $new_x );
1703
$new_height = $self->{_items}{$curr_item}->get('height') + ( $self->{_items}{$curr_item}->get('y') - $new_y );
1705
$new_x = $self->{_items}{$curr_item}->get('x') + $ev->x_root - $item->{res_x};
1706
$new_y = $self->{_items}{$curr_item}->get('y') + $ev->y_root - $item->{res_y};
1707
$new_width = $self->{_items}{$curr_item}->get('width') + ( $self->{_items}{$curr_item}->get('x') - $new_x );
1708
$new_height = $self->{_items}{$curr_item}->get('height') + ( $self->{_items}{$curr_item}->get('y') - $new_y );
1713
} elsif ( $_ eq 'top-side' ) {
1715
$new_x = $self->{_items}{$curr_item}->get('x');
1716
$new_y = $self->{_items}{$curr_item}->get('y') + $ev->y_root - $item->{res_y};
1718
$new_width = $self->{_items}{$curr_item}->get('width');
1719
$new_height = $self->{_items}{$curr_item}->get('height') + ( $self->{_items}{$curr_item}->get('y') - $new_y );
1723
} elsif ( $_ eq 'top-right-corner' ) {
1725
$new_x = $self->{_items}{$curr_item}->get('x');
1726
$new_y = $self->{_items}{$curr_item}->get('y') + $ev->y_root - $item->{res_y};
1728
if($ev->state >= 'control-mask'){
1729
$new_width = $self->{_items}{$curr_item}->get('width') - ( $ev->y_root - $item->{res_y} ) * $ratio;
1730
$new_height = $self->{_items}{$curr_item}->get('height') + ( $self->{_items}{$curr_item}->get('y') - $new_y );
1732
$new_width = $self->{_items}{$curr_item}->get('width') + ( $ev->x_root - $item->{res_x} );
1733
$new_height = $self->{_items}{$curr_item}->get('height') + ( $self->{_items}{$curr_item}->get('y') - $new_y );
1738
} elsif ( $_ eq 'left-side' ) {
1740
$new_x = $self->{_items}{$curr_item}->get('x') + $ev->x_root - $item->{res_x};
1741
$new_y = $self->{_items}{$curr_item}->get('y');
1743
$new_width = $self->{_items}{$curr_item}->get('width') + ( $self->{_items}{$curr_item}->get('x') - $new_x );
1744
$new_height = $self->{_items}{$curr_item}->get('height');
1748
} elsif ( $_ eq 'right-side' ) {
1750
$new_x = $self->{_items}{$curr_item}->get('x');
1751
$new_y = $self->{_items}{$curr_item}->get('y');
1753
$new_width = $self->{_items}{$curr_item}->get('width') + ( $ev->x_root - $item->{res_x} );
1754
$new_height = $self->{_items}{$curr_item}->get('height');
1758
} elsif ( $_ eq 'bottom-left-corner' ) {
1760
if($ev->state >= 'control-mask'){
1761
$new_x = $self->{_items}{$curr_item}->get('x') - $ev->y_root + $item->{res_y};
1762
$new_y = $self->{_items}{$curr_item}->get('y');
1764
$new_width = $self->{_items}{$curr_item}->get('width') + ( $self->{_items}{$curr_item}->get('x') - $new_x );
1765
$new_height = $self->{_items}{$curr_item}->get('height') + ( $ev->y_root - $item->{res_y} ) / $ratio;
1767
$new_x = $self->{_items}{$curr_item}->get('x') + $ev->x_root - $item->{res_x};
1768
$new_y = $self->{_items}{$curr_item}->get('y');
1770
$new_width = $self->{_items}{$curr_item}->get('width') + ( $self->{_items}{$curr_item}->get('x') - $new_x );
1771
$new_height = $self->{_items}{$curr_item}->get('height') + ( $ev->y_root - $item->{res_y} );
1782
#~ $self->{_canvas}->window->set_cursor( Gtk2::Gdk::Cursor->new($cursor) );
1784
#when width or height are too small we switch to opposite rectangle and do the resizing in this way
1785
if($ev->state >= 'control-mask' && $new_width < 1 && $new_height < 1){
1787
$new_x = $self->{_items}{$curr_item}->get('x');
1788
$new_y = $self->{_items}{$curr_item}->get('y');
1789
$new_width = $self->{_items}{$curr_item}->get('width');
1790
$new_height = $self->{_items}{$curr_item}->get('height');
1792
}elsif ( $new_width < 0 || $new_height < 0) {
1794
$self->{_canvas}->pointer_ungrab($item, $ev->time);
1795
my $oppo = $self->get_opposite_rect($item, $curr_item, $new_width, $new_height);
1796
$self->{_items}{$curr_item}{$oppo}->{res_x} = $ev->x_root;
1797
$self->{_items}{$curr_item}{$oppo}->{res_y} = $ev->y_root;
1798
$self->{_items}{$curr_item}{$oppo}->{resizing} = TRUE;
1800
#don'change cursor if this item was just started
1801
if($self->{_last_item} && $self->{_current_item} && $self->{_last_item} == $self->{_current_item}){
1802
$self->{_canvas}->pointer_grab( $self->{_items}{$curr_item}{$oppo}, [ 'pointer-motion-mask', 'button-release-mask' ], undef, $ev->time );
1804
$self->{_canvas}->pointer_grab( $self->{_items}{$curr_item}{$oppo}, [ 'pointer-motion-mask', 'button-release-mask' ], Gtk2::Gdk::Cursor->new($oppo), $ev->time );
1807
$self->handle_embedded( 'mirror', $curr_item, $new_width, $new_height);
1810
if ($new_width < 0){
1811
$new_x += $new_width;
1812
$new_width = abs($new_width);
1814
if ($new_height < 0){
1815
$new_y += $new_height;
1816
$new_height = abs($new_height);
1821
#apply new values...
1822
$self->{_items}{$curr_item}->set(
1825
'width' => $new_width,
1826
'height' => $new_height,
1829
#and update rectangles and embedded items
1830
$self->handle_rects( 'update', $curr_item );
1831
$self->handle_embedded( 'update', $curr_item );
1835
$item->{res_x} = $ev->x_root;
1836
$item->{res_y} = $ev->y_root;
1129
1840
if ( $item->isa('Goo::Canvas::Rect') ) {
1132
1843
my $parent = $self->get_parent_item($item);
1133
1844
$item = $parent if $parent;
1136
unless ( exists $self->{_items}{$item} ) {
1137
$self->push_to_statusbar( int( $ev->x ), int( $ev->y ), 'resize' );
1846
#shape or canvas background (resizeable rectangle)
1847
if ( exists $self->{_items}{$item} or $item == $self->{_canvas_bg_rect}) {
1848
$self->push_to_statusbar( int( $ev->x_root ), int( $ev->y_root ) );
1850
#canvas resizing shape
1851
} elsif ( $self->{_canvas_bg_rect}{'right-side'} == $item
1852
|| $self->{_canvas_bg_rect}{'bottom-side'} == $item
1853
|| $self->{_canvas_bg_rect}{'bottom-right-corner'} == $item )
1855
$self->push_to_statusbar( int( $ev->x_root ), int( $ev->y_root ), 'canvas_resize' );
1139
$self->push_to_statusbar( int( $ev->x ), int( $ev->y ) );
1860
$self->push_to_statusbar( int( $ev->x_root ), int( $ev->y_root ), 'resize' );
1142
$self->push_to_statusbar( int( $ev->x ), int( $ev->y ) );
1863
$self->push_to_statusbar( int( $ev->x_root ), int( $ev->y_root ) );
1205
1930
sub get_parent_item {
1931
my ($self, $item) = @_;
1209
1933
my $parent = undef;
1210
1934
foreach ( keys %{ $self->{_items} } ) {
1211
$parent = $self->{_items}{$_} if $self->{_items}{$_}{ellipse} == $item;
1212
$parent = $self->{_items}{$_} if $self->{_items}{$_}{text} == $item;
1213
$parent = $self->{_items}{$_} if $self->{_items}{$_}{image} == $item;
1214
$parent = $self->{_items}{$_} if $self->{_items}{$_}{line} == $item;
1935
$parent = $self->{_items}{$_} if exists $self->{_items}{$_}{ellipse} && $self->{_items}{$_}{ellipse} == $item;
1936
$parent = $self->{_items}{$_} if exists $self->{_items}{$_}{text} && $self->{_items}{$_}{text} == $item;
1937
$parent = $self->{_items}{$_} if exists $self->{_items}{$_}{image} && $self->{_items}{$_}{image} == $item;
1938
$parent = $self->{_items}{$_} if exists $self->{_items}{$_}{line} && $self->{_items}{$_}{line} == $item;
1217
1941
return $parent;
1944
sub get_highest_auto_digit {
1948
foreach ( keys %{ $self->{_items} } ) {
1950
my $item = $self->{_items}{$_};
1953
if ( exists $self->{_items}{$item}{text}
1954
&& $self->{_items}{$item}{text}->get('visibility') ne 'hidden' ) {
1955
$number = $self->{_items}{$item}{text}{digit} if $self->{_items}{$item}{text}{digit} > $number;
1220
1963
sub get_child_item {
1964
my ($self, $item) = @_;
1224
1966
my $child = undef;
1226
$child = $self->{_items}{$item}{ellipse} if exists $self->{_items}{$item}{ellipse};
1227
$child = $self->{_items}{$item}{text} if exists $self->{_items}{$item}{text};
1228
$child = $self->{_items}{$item}{image} if exists $self->{_items}{$item}{image};
1229
$child = $self->{_items}{$item}{line} if exists $self->{_items}{$item}{line};
1968
#notice (special shapes like numbered ellipse do deliver ellipse here => NOT text!)
1969
#therefore the order matters
1970
if (defined $item && exists $self->{_items}{$item}){
1971
$child = $self->{_items}{$item}{text} if exists $self->{_items}{$item}{text};
1972
$child = $self->{_items}{$item}{ellipse} if exists $self->{_items}{$item}{ellipse};
1973
$child = $self->{_items}{$item}{image} if exists $self->{_items}{$item}{image};
1974
$child = $self->{_items}{$item}{line} if exists $self->{_items}{$item}{line};
1234
1980
sub abort_current_mode {
1237
$self->set_drawing_action(0);
1238
$self->change_drawing_tool_cb(10);
1983
if($self->{_current_item}){
1984
$self->{_canvas}->pointer_ungrab( $self->{_current_item}, time );
1987
#~ print "abort_current_mode\n";
1989
$self->set_drawing_action(1);
1243
1994
sub clear_item_from_canvas {
1995
my ($self, $item) = @_;
1997
#~ print "clear_item_from_canvas\n";
1999
$self->{_last_item} = undef;
2000
$self->{_current_item} = undef;
2001
$self->{_current_new_item} = undef;
1248
my @items_to_delete;
1249
push @items_to_delete, $item;
1251
2005
#maybe there is a parent item to delete?
1252
2006
my $parent = $self->get_parent_item($item);
1255
push @items_to_delete, $parent;
1256
foreach ( keys %{ $self->{_items}{$parent} } ) {
1257
push @items_to_delete, $self->{_items}{$parent}{$_};
1260
foreach ( keys %{ $self->{_items}{$item} } ) {
1261
push @items_to_delete, $self->{_items}{$item}{$_};
1265
foreach (@items_to_delete) {
1267
$self->store_to_xdo_stack($_, 'delete', 'undo');
1268
$_->set('visibility' => 'GOO_CANVAS_ITEM_HIDDEN');
1269
$self->handle_rects('hide', $_);
1270
$self->handle_embedded('hide', $_);
2007
$item = $parent if $parent;
2010
my $child = $self->get_child_item($item);
2012
#only delete if not already deleted (hidden)
2013
return FALSE if($child && $child->get('visibility') eq 'hidden');
2014
#~ print "1st passed\n";
2015
return FALSE if(!$child && $item->get('visibility') eq 'hidden');
2016
#~ print "2nd passed\n";
2018
$self->store_to_xdo_stack($item, 'delete', 'undo');
2019
$item->set('visibility' => 'hidden');
2020
$self->handle_rects('hide', $item);
2021
$self->handle_embedded('hide', $item);
1275
$self->{_last_item} = undef;
1276
$self->{_current_item} = undef;
1277
$self->{_current_new_item} = undef;
1282
2028
sub store_to_xdo_stack {
1283
#~ my $self = shift;
1284
#~ my $item = shift;
1285
#~ my $action = shift;
1288
#~ return FALSE unless $item;
1290
#~ my %do_info = ();
1291
#~ #general properties for ellipse, rectangle, image, text
1292
#~ if($item->isa('Goo::Canvas::Rect')){
1294
#~ my $stroke_pattern = $self->create_color( $self->{_items}{$item}{stroke_color}, $self->{_items}{$item}{stroke_color_alpha} ) if exists $self->{_items}{$item}{stroke_color};
1295
#~ my $fill_pattern = $self->create_color( $self->{_items}{$item}{fill_color}, $self->{_items}{$item}{fill_color_alpha} ) if exists $self->{_items}{$item}{fill_color};
1296
#~ my $line_width = $self->{_items}{$item}->get('line-width');
1300
#~ 'item' => $self->{_items}{$item},
1301
#~ 'action' => $action,
1302
#~ 'x' => $self->{_items}{$item}->get('x'),
1303
#~ 'y' => $self->{_items}{$item}->get('y'),
1304
#~ 'width' => $self->{_items}{$item}->get('width'),
1305
#~ 'height' => $self->{_items}{$item}->get('height'),
1306
#~ 'fill-pattern' => $fill_pattern,
1307
#~ 'stroke-pattern' => $stroke_pattern,
1308
#~ 'line-width' => $line_width,
1311
#~ if ( exists $self->{_items}{$item}{ellipse} ) {
1313
#~ }elsif ( exists $self->{_items}{$item}{text} ) {
1315
#~ }elsif ( exists $self->{_items}{$item}{image} ) {
1317
#~ }elsif ( exists $self->{_items}{$item}{line} ) {
1325
#~ #add polyline specific properties to hash
1326
#~ if($item->isa('Goo::Canvas::Polyline')){
1328
#~ item => $self->{_items}{$item},
1329
#~ action => $action,
1330
#~ points => $self->{_items}{$item}->get('points'),
1334
#~ if($xdo eq 'undo'){
1335
#~ push @{ $self->{_undo} }, \%do_info;
1336
#~ }elsif($xdo eq 'redo'){
1337
#~ push @{ $self->{_redo} }, \%do_info;
1340
#~ #disable undo/redo actions at startup
1341
#~ $self->{_uimanager}->get_widget("/MenuBar/Edit/Undo")->set_sensitive(scalar @{ $self->{_undo} }) if defined $self->{_undo};
1342
#~ $self->{_uimanager}->get_widget("/MenuBar/Edit/Redo")->set_sensitive(scalar @{ $self->{_redo} }) if defined $self->{_redo};
1348
#~ my $self = shift;
1350
#~ my $undo = pop @{ $self->{_undo} };
1352
#~ my $item = $undo->{'item'};
1353
#~ my $action = $undo->{'action'};
1355
#~ #store to redo stack
1356
#~ $self->store_to_xdo_stack($item, $action, 'redo');
1358
#~ $self->deactivate_all;
1360
#~ #finally undo the last event
1361
#~ if($action eq 'modify'){
1362
#~ $self->{_items}{$item}->set(
1363
#~ 'x' => $undo->{'x'},
1364
#~ 'y' => $undo->{'y'},
1365
#~ 'width' => $undo->{'width'},
1366
#~ 'height' => $undo->{'height'},
1367
#~ 'fill-pattern' => $undo->{'fill-pattern'},
1368
#~ 'stroke-pattern' => $undo->{'stroke-pattern'},
1369
#~ 'line-width' => $undo->{'line-width'},
1371
#~ $self->handle_rects( 'update', $self->{_items}{$item} );
1372
#~ $self->handle_embedded( 'update', $self->{_items}{$item} );
1373
#~ $self->{_current_item} = $item;
1374
#~ }elsif($action eq 'delete'){
1375
#~ $self->{_items}{$item}->set('visibility' => 'GOO_CANVAS_ITEM_VISIBLE');
1376
#~ $self->handle_rects( 'update', $self->{_items}{$item} );
1377
#~ $self->handle_embedded( 'update', $self->{_items}{$item} );
1378
#~ $self->{_current_item} = $item;
1379
#~ }elsif($action eq 'create'){
1380
#~ $self->{_items}{$item}->set('visibility' => 'GOO_CANVAS_ITEM_HIDDEN');
1381
#~ $self->handle_rects( 'hide', $self->{_items}{$item} );
1382
#~ $self->handle_embedded( 'hide', $self->{_items}{$item} );
1385
#~ #disable undo/redo actions at startup
1386
#~ $self->{_uimanager}->get_widget("/MenuBar/Edit/Undo")->set_sensitive(scalar @{ $self->{_undo} }) if defined $self->{_undo};
1387
#~ $self->{_uimanager}->get_widget("/MenuBar/Edit/Redo")->set_sensitive(scalar @{ $self->{_redo} }) if defined $self->{_redo};
1393
#~ my $self = shift;
1395
#~ my $redo = pop @{ $self->{_redo} };
1397
#~ my $item = $redo->{'item'};
1398
#~ my $action = $redo->{'action'};
1400
#~ #store to undo stack
1401
#~ $self->store_to_xdo_stack($item, $action, 'undo');
1403
#~ $self->deactivate_all;
1405
#~ #finally undo the last event
1406
#~ if($action eq 'modify'){
1407
#~ $self->{_items}{$item}->set(
1408
#~ 'x' => $redo->{'x'},
1409
#~ 'y' => $redo->{'y'},
1410
#~ 'width' => $redo->{'width'},
1411
#~ 'height' => $redo->{'height'},
1412
#~ 'fill-pattern' => $redo->{'fill-pattern'},
1413
#~ 'stroke-pattern' => $redo->{'stroke-pattern'},
1414
#~ 'line-width' => $redo->{'line-width'},
1416
#~ $self->handle_rects( 'update', $self->{_items}{$item} );
1417
#~ $self->handle_embedded( 'update', $self->{_items}{$item} );
1418
#~ $self->{_current_item} = $item;
1419
#~ }elsif($action eq 'delete'){
1420
#~ $self->{_items}{$item}->set('visibility' => 'GOO_CANVAS_ITEM_HIDDEN');
1421
#~ $self->handle_rects( 'hide', $self->{_items}{$item} );
1422
#~ $self->handle_embedded( 'hide', $self->{_items}{$item} );
1423
#~ $self->{_current_item} = $item;
1424
#~ }elsif($action eq 'create'){
1425
#~ $self->{_items}{$item}->set('visibility' => 'GOO_CANVAS_ITEM_VISIBLE');
1426
#~ $self->handle_rects( 'update', $self->{_items}{$item} );
1427
#~ $self->handle_embedded( 'update', $self->{_items}{$item} );
1430
#~ #disable undo/redo actions at startup
1431
#~ $self->{_uimanager}->get_widget("/MenuBar/Edit/Undo")->set_sensitive(scalar @{ $self->{_undo} }) if defined $self->{_undo};
1432
#~ $self->{_uimanager}->get_widget("/MenuBar/Edit/Redo")->set_sensitive(scalar @{ $self->{_redo} }) if defined $self->{_redo};
2029
#opt1 is currently only used when cropping the image
2030
#it stores the selection
2031
my ($self, $item, $action, $xdo, $opt1) = @_;
2033
return FALSE unless $item;
2035
#~ print "xdo - $item\n";
2038
#general properties for ellipse, rectangle, image, text
2039
if($item->isa('Goo::Canvas::Rect') && $item != $self->{_canvas_bg_rect}){
2041
my $stroke_pattern = $self->create_color( $self->{_items}{$item}{stroke_color}, $self->{_items}{$item}{stroke_color_alpha} ) if exists $self->{_items}{$item}{stroke_color};
2042
my $fill_pattern = $self->create_color( $self->{_items}{$item}{fill_color}, $self->{_items}{$item}{fill_color_alpha} ) if exists $self->{_items}{$item}{fill_color};
2043
my $line_width = $self->{_items}{$item}->get('line-width');
2046
my $mirrored_w = undef;
2047
my $mirrored_h = undef;
2048
my $end_arrow = undef;
2049
my $start_arrow = undef;
2050
my $arrow_width = undef;
2051
my $arrow_length = undef;
2052
my $tip_length = undef;
2060
if ( exists $self->{_items}{$item}{ellipse} ) {
2062
$line_width = $self->{_items}{$item}{ellipse}->get('line-width');
2065
if ( exists $self->{_items}{$item}{text} ) {
2066
$text = $self->{_items}{$item}{text}->get('text');
2067
$digit = $self->{_items}{$item}{text}{digit};
2070
}elsif ( exists $self->{_items}{$item}{text} ) {
2072
$text = $self->{_items}{$item}{text}->get('text');
2074
}elsif ( exists $self->{_items}{$item}{image} ) {
2076
}elsif ( exists $self->{_items}{$item}{line} ) {
2079
$line_width = $self->{_items}{$item}{line}->get('line-width');
2082
$end_arrow = $self->{_items}{$item}{line}->get('end-arrow');
2083
$start_arrow = $self->{_items}{$item}{line}->get('start-arrow');
2084
$arrow_width = $self->{_items}{$item}{line}->get('arrow-width');
2085
$arrow_length = $self->{_items}{$item}{line}->get('arrow-length');
2086
$tip_length = $self->{_items}{$item}{line}->get('arrow-tip-length');
2089
$mirrored_w = $self->{_items}{$item}{mirrored_w};
2090
$mirrored_h = $self->{_items}{$item}{mirrored_h};
2098
'item' => $self->{_items}{$item},
2099
'action' => $action,
2100
'x' => $self->{_items}{$item}->get('x'),
2101
'y' => $self->{_items}{$item}->get('y'),
2102
'width' => $self->{_items}{$item}->get('width'),
2103
'height' => $self->{_items}{$item}->get('height'),
2104
'stroke_color' => $self->{_items}{$item}{stroke_color},
2105
'stroke_color_alpha'=> $self->{_items}{$item}{stroke_color_alpha},
2106
'fill_color' => $self->{_items}{$item}{fill_color},
2107
'fill_color_alpha' => $self->{_items}{$item}{fill_color_alpha},
2108
'fill-pattern' => $fill_pattern,
2109
'stroke-pattern' => $stroke_pattern,
2110
'line-width' => $line_width,
2111
'mirrored_w' => $mirrored_w,
2112
'mirrored_h' => $mirrored_h,
2113
'end-arrow' => $end_arrow,
2114
'start-arrow' => $start_arrow,
2115
'arrow-length' => $arrow_length,
2116
'arrow-width' => $arrow_width,
2117
'arrow-tip-length' => $tip_length,
2123
}elsif($item->isa('Goo::Canvas::Image') && $item == $self->{_canvas_bg}){
2125
#canvas_bg_image and bg_rect properties
2127
'item' => $self->{_canvas_bg},
2128
'action' => $action,
2129
'drawing_pixbuf' => $self->{_drawing_pixbuf},
2130
'x' => $self->{_canvas_bg_rect}->get('x'),
2131
'y' => $self->{_canvas_bg_rect}->get('y'),
2132
'width' => $self->{_canvas_bg_rect}->get('width'),
2133
'height' => $self->{_canvas_bg_rect}->get('height'),
2137
}elsif($item->isa('Goo::Canvas::Rect') && $item == $self->{_canvas_bg_rect}){
2139
#canvas_bg_rect properties
2141
'item' => $self->{_canvas_bg_rect},
2142
'action' => $action,
2143
'x' => $self->{_canvas_bg_rect}->get('x'),
2144
'y' => $self->{_canvas_bg_rect}->get('y'),
2145
'width' => $self->{_canvas_bg_rect}->get('width'),
2146
'height' => $self->{_canvas_bg_rect}->get('height'),
2150
#polyline specific properties to hash
2151
}elsif($item->isa('Goo::Canvas::Polyline')){
2153
my $stroke_pattern = $self->create_color( $self->{_items}{$item}{stroke_color}, $self->{_items}{$item}{stroke_color_alpha} );
2154
my $transform = $self->{_items}{$item}->get('transform');
2155
my $line_width = $self->{_items}{$item}->get('line-width');
2156
my $points = $self->{_items}{$item}->get('points');
2159
'item' => $self->{_items}{$item},
2160
'action' => $action,
2161
'points' => $points,
2162
'stroke-pattern' => $stroke_pattern,
2163
'line-width' => $line_width,
2164
'transform' => $transform,
2170
#reset undo when creating new item after redo
2171
if($action eq 'create'){
2172
while (defined $self->{_redo} && scalar @{ $self->{_redo} } > 0){
2173
shift @{ $self->{_redo} };
2178
push @{ $self->{_undo} }, \%do_info;
2179
}elsif($xdo eq 'redo'){
2180
push @{ $self->{_redo} }, \%do_info;
2183
#disable undo/redo actions
2184
$self->{_uimanager}->get_widget("/MenuBar/Edit/Undo")->set_sensitive(scalar @{ $self->{_undo} }) if defined $self->{_undo};
2185
$self->{_uimanager}->get_widget("/MenuBar/Edit/Redo")->set_sensitive(scalar @{ $self->{_redo} }) if defined $self->{_redo};
2187
$self->{_uimanager}->get_widget("/ToolBar/Undo")->set_sensitive(scalar @{ $self->{_undo} }) if defined $self->{_undo};
2188
$self->{_uimanager}->get_widget("/ToolBar/Redo")->set_sensitive(scalar @{ $self->{_redo} }) if defined $self->{_redo};
2199
$do = pop @{ $self->{_undo} };
2200
}elsif($xdo eq 'redo'){
2201
$do = pop @{ $self->{_redo} };
2204
my $item = $do->{'item'};
2205
my $action = $do->{'action'};
2206
my $opt1 = $do->{'opt1'};
2208
return FALSE unless $item;
2209
return FALSE unless $action;
2211
if($item->isa('Goo::Canvas::Image') && $item == $self->{_canvas_bg}){
2212
$opt1->x($do->{'opt1'}->x*-1) ;
2213
$opt1->y($do->{'opt1'}->y*-1) ;
2216
#create reverse action
2217
my $reverse_action = 'modify';
2218
if ($action eq 'raise'){
2219
$reverse_action = 'lower_xdo';
2220
}elsif ($action eq 'raise_xdo'){
2221
$reverse_action = 'lower_xdo';
2222
}elsif($action eq 'lower'){
2223
$reverse_action = 'raise_xdo';
2224
}elsif($action eq 'lower_xdo'){
2225
$reverse_action = 'raise_xdo';
2226
}elsif($action eq 'create'){
2227
$reverse_action = 'delete_xdo';
2228
}elsif($action eq 'delete'){
2229
$reverse_action = 'create_xdo';
2230
}elsif($action eq 'create_xdo'){
2231
$reverse_action = 'delete_xdo';
2232
}elsif($action eq 'delete_xdo'){
2233
$reverse_action = 'create_xdo';
2238
#store to redo stack
2239
$self->store_to_xdo_stack($item, $reverse_action, 'redo', $opt1);
2240
}elsif($xdo eq 'redo'){
2241
#store to undo stack
2242
$self->store_to_xdo_stack($item, $reverse_action, 'undo', $opt1);
2245
#finally undo the last event
2246
if($action eq 'modify'){
2248
if($item->isa('Goo::Canvas::Rect') && $item != $self->{_canvas_bg_rect}){
2250
$self->{_items}{$item}->set(
2253
'width' => $do->{'width'},
2254
'height' => $do->{'height'},
2257
if ( exists $self->{_items}{$item}{ellipse} ) {
2259
$self->{_items}{$item}{ellipse}->set(
2260
'fill-pattern' => $do->{'fill-pattern'},
2261
'stroke-pattern' => $do->{'stroke-pattern'},
2262
'line-width' => $do->{'line-width'},
2266
if ( exists $self->{_items}{$item}{text} ) {
2267
$self->{_items}{$item}{text}->set(
2268
'text' => $do->{'text'},
2269
'fill-pattern' => $do->{'stroke-pattern'},
2271
$self->{_items}{$item}{text}{digit} = $do->{'digit'};
2274
#restore color and opacity as well
2275
$self->{_items}{$item}{fill_color} = $do->{'fill_color'};
2276
$self->{_items}{$item}{fill_color_alpha} = $do->{'fill_color_alpha'};
2277
$self->{_items}{$item}{stroke_color} = $do->{'stroke_color'};
2278
$self->{_items}{$item}{stroke_color_alpha} = $do->{'stroke_color_alpha'};
2280
}elsif ( exists $self->{_items}{$item}{text} ) {
2282
$self->{_items}{$item}{text}->set(
2283
'text' => $do->{'text'},
2284
'fill-pattern' => $do->{'stroke-pattern'},
2287
#restore color and opacity as well
2288
$self->{_items}{$item}{stroke_color} = $do->{'stroke_color'};
2289
$self->{_items}{$item}{stroke_color_alpha} = $do->{'stroke_color_alpha'};
2291
}elsif ( exists $self->{_items}{$item}{image} ) {
2295
$copy = Gtk2::Gdk::Pixbuf->new_from_file_at_scale($self->{_items}{$item}{orig_pixbuf_filename},$self->{_items}{$item}->get('width'), $self->{_items}{$item}->get('height'), FALSE);
2298
$self->{_items}{$item}{image}->set(
2299
'x' => int $self->{_items}{$item}->get('x'),
2300
'y' => int $self->{_items}{$item}->get('y'),
2301
'width' => $self->{_items}{$item}->get('width'),
2302
'height' => $self->{_items}{$item}->get('height'),
2306
my $response = $self->{_dialogs}->dlg_error_message(
2307
sprintf( $self->{_d}->get("Error while opening image %s."), "'" . $self->{_items}{$item}{orig_pixbuf_filename} . "'"),
2308
$self->{_d}->get( "There was an error opening the image." ),
2309
undef, undef, undef,
2310
undef, undef, undef,
2315
}elsif ( exists $self->{_items}{$item}{line} ) {
2317
#save arrow specific properties
2318
$self->{_items}{$item}{end_arrow} = $do->{'end-arrow'};
2319
$self->{_items}{$item}{start_arrow} = $do->{'start-arrow'};
2320
$self->{_items}{$item}{arrow_width} = $do->{'arrow-width'};
2321
$self->{_items}{$item}{arrow_length} = $do->{'arrow-length'};
2322
$self->{_items}{$item}{arrow_tip_length} = $do->{'arrow-tip-length'};
2324
$self->{_items}{$item}{line}->set(
2325
'fill-pattern' => $do->{'fill-pattern'},
2326
'stroke-pattern' => $do->{'stroke-pattern'},
2327
'line-width' => $do->{'line-width'},
2328
'end-arrow' => $self->{_items}{$item}{end_arrow},
2329
'start-arrow' => $self->{_items}{$item}{start_arrow},
2330
'arrow-length' => $self->{_items}{$item}{arrow_length},
2331
'arrow-width' => $self->{_items}{$item}{arrow_width},
2332
'arrow-tip-length' => $self->{_items}{$item}{arrow_tip_length},
2335
$self->{_items}{$item}{mirrored_w} = $do->{'mirrored_w'} if exists $do->{'mirrored_w'};
2336
$self->{_items}{$item}{mirrored_h} = $do->{'mirrored_h'} if exists $do->{'mirrored_h'};
2338
#restore color and opacity as well
2339
$self->{_items}{$item}{stroke_color} = $do->{'stroke_color'};
2340
$self->{_items}{$item}{stroke_color_alpha} = $do->{'stroke_color_alpha'};
2344
$self->{_items}{$item}->set(
2345
'fill-pattern' => $do->{'fill-pattern'},
2346
'stroke-pattern' => $do->{'stroke-pattern'},
2347
'line-width' => $do->{'line-width'},
2350
#restore color and opacity as well
2351
$self->{_items}{$item}{fill_color} = $do->{'fill_color'};
2352
$self->{_items}{$item}{fill_color_alpha} = $do->{'fill_color_alpha'};
2353
$self->{_items}{$item}{stroke_color} = $do->{'stroke_color'};
2354
$self->{_items}{$item}{stroke_color_alpha} = $do->{'stroke_color_alpha'};
2358
}elsif($item->isa('Goo::Canvas::Image') && $item == $self->{_canvas_bg}){
2360
my $new_w = $do->{'drawing_pixbuf'}->get_width;
2361
my $new_h = $do->{'drawing_pixbuf'}->get_height;
2363
#update bounds and bg_rects
2364
$self->{_canvas_bg_rect}->set(
2369
#we need to move the shapes
2370
$self->move_all($opt1->x, $opt1->y);
2372
#update canvas and show the new pixbuf
2373
$self->{_canvas_bg}->set('pixbuf' => $do->{'drawing_pixbuf'});
2375
#save new pixbuf in var
2376
$self->{_drawing_pixbuf} = $do->{'drawing_pixbuf'}->copy;
2378
#update bounds and bg_rects
2379
$self->{_canvas_bg_rect}->set(
2382
'width' => $do->{'width'},
2383
'height' => $do->{'height'},
2387
$self->{_canvas_bg}->lower;
2388
$self->{_canvas_bg_rect}->lower;
2389
$self->handle_bg_rects( 'raise' );
2391
}elsif($item->isa('Goo::Canvas::Rect') && $item == $self->{_canvas_bg_rect}){
2393
$self->{_canvas_bg_rect}->set(
2396
'width' => $do->{'width'},
2397
'height' => $do->{'height'},
2400
#polyline specific properties
2401
}elsif($item->isa('Goo::Canvas::Polyline')){
2404
#e.g. censor tool does not have a pattern
2405
if($do->{'stroke-pattern'}){
2407
$self->{_items}{$item}->set(
2408
'stroke-pattern' => $do->{'stroke-pattern'},
2409
'line-width' => $do->{'line-width'},
2410
'points' => $do->{'points'},
2411
'transform' => $do->{'transform'},
2414
$self->{_items}{$item}{stroke_color} = $do->{'stroke_color'};
2415
$self->{_items}{$item}{stroke_color_alpha} = $do->{'stroke_color_alpha'};
2419
$self->{_items}{$item}->set(
2420
'line-width' => $do->{'line-width'},
2421
'points' => $do->{'points'},
2422
'transform' => $do->{'transform'},
2428
#handle resize rectangles and embedded objects
2429
if ($item == $self->{_canvas_bg_rect} || $item == $self->{_canvas_bg}){
2431
$self->handle_bg_rects( 'update', $self->{_canvas_bg_rect} );
2435
$self->handle_rects( 'update', $self->{_items}{$item} );
2436
$self->handle_embedded( 'update', $self->{_items}{$item} );
2437
$self->{_current_item} = $item;
2439
#apply item properties to widgets
2440
#line width, fill color, stroke color etc.
2441
$self->set_and_save_drawing_properties($self->{_current_item}, FALSE);
2445
}elsif($action eq 'raise' || $action eq 'raise_xdo'){
2447
my $child = $self->get_child_item($item);
2449
$self->handle_rects( 'lower', $item );
2453
$self->handle_rects( 'lower', $item );
2456
$self->{_canvas_bg}->lower;
2457
$self->{_canvas_bg_rect}->lower;
2459
}elsif($action eq 'lower' || $action eq 'lower_xdo'){
2461
my $child = $self->get_child_item($item);
2465
$self->handle_rects( 'raise', $item );
2468
$self->handle_rects( 'raise', $item );
2471
}elsif($action eq 'delete' || $action eq 'delete_xdo'){
2474
$self->{_last_item} = $self->{_current_item};
2475
$self->{_current_item} = $item;
2476
$self->{_current_new_item} = undef;
2478
$self->{_items}{$item}->set('visibility' => 'visible');
2479
$self->handle_rects( 'update', $self->{_items}{$item} );
2480
$self->handle_embedded( 'update', $self->{_items}{$item} );
2482
}elsif($action eq 'create' || $action eq 'create_xdo'){
2484
$self->{_items}{$item}->set('visibility' => 'hidden');
2485
$self->handle_rects( 'hide', $self->{_items}{$item} );
2486
$self->handle_embedded( 'hide', $self->{_items}{$item} );
2490
#disable undo/redo actions
2491
$self->{_uimanager}->get_widget("/MenuBar/Edit/Undo")->set_sensitive(scalar @{ $self->{_undo} }) if defined $self->{_undo};
2492
$self->{_uimanager}->get_widget("/MenuBar/Edit/Redo")->set_sensitive(scalar @{ $self->{_redo} }) if defined $self->{_redo};
2494
$self->{_uimanager}->get_widget("/ToolBar/Undo")->set_sensitive(scalar @{ $self->{_undo} }) if defined $self->{_undo};
2495
$self->{_uimanager}->get_widget("/ToolBar/Redo")->set_sensitive(scalar @{ $self->{_redo} }) if defined $self->{_redo};
2497
$self->deactivate_all;
2502
sub set_and_save_drawing_properties {
2505
my $save_only = shift;
2507
return FALSE unless $item;
2509
#~ print "set_and_save_drawing_properties\n";
2511
#determine key for item hash
2512
if(my $child = $self->get_child_item($item)){
2515
my $parent = $self->get_parent_item($item);
2516
my $key = $self->get_item_key($item, $parent);
2518
#we do not remember the properties for some tools
2519
#and don't remember them when just selecting items with the cursor
2520
if($self->{_items}{$key}{type} ne "highlighter" &&
2521
$self->{_items}{$key}{type} ne "image" &&
2522
$self->{_current_mode} != 10 )
2525
#remember drawing colors, line width and font settings
2526
#maybe we have to restore them
2527
$self->{_last_fill_color} = $self->{_fill_color_w}->get_color;
2528
$self->{_last_fill_color_alpha} = $self->{_fill_color_w}->get_alpha / 65535;
2529
$self->{_last_stroke_color} = $self->{_stroke_color_w}->get_color;
2530
$self->{_last_stroke_color_alpha} = $self->{_stroke_color_w}->get_alpha / 65535;
2531
$self->{_last_line_width} = $self->{_line_spin_w}->get_value;
2532
$self->{_last_font} = $self->{_font_btn_w}->get_font_name;
2534
#remember the last mode as well
2535
$self->{_last_mode} = $self->{_current_mode};
2536
$self->{_last_mode_descr} = $self->{_current_mode_descr};
2540
return TRUE if $save_only;
2542
#block 'value-change' handlers for widgets
2543
#so we do not apply the changes twice
2544
$self->{_line_spin_w}->signal_handler_block ($self->{_line_spin_wh});
2545
$self->{_stroke_color_w}->signal_handler_block ($self->{_stroke_color_wh});
2546
$self->{_fill_color_w}->signal_handler_block ($self->{_fill_color_wh});
2547
$self->{_font_btn_w}->signal_handler_block ($self->{_font_btn_wh});
2549
if ( $item->isa('Goo::Canvas::Rect')
2550
|| $item->isa('Goo::Canvas::Ellipse')
2551
|| $item->isa('Goo::Canvas::Polyline') )
2555
$self->{_line_spin_w}->set_value( $item->get('line-width') );
2558
#some items, e.g. censor tool, do not have a color - skip them
2559
if($self->{_items}{$key}{stroke_color}){
2560
$self->{_stroke_color_w}->set_color( $self->{_items}{$key}{stroke_color} );
2561
$self->{_stroke_color_w}->set_alpha( int( $self->{_items}{$key}{stroke_color_alpha} * 65535 ) );
2564
if ( $item->isa('Goo::Canvas::Rect') || $item->isa('Goo::Canvas::Ellipse') ) {
2567
$self->{_fill_color_w}->set_color( $self->{_items}{$key}{fill_color} );
2568
$self->{_fill_color_w}->set_alpha( int( $self->{_items}{$key}{fill_color_alpha} * 65535 ) );
2571
if(exists($self->{_items}{$key}{text})){
2572
#determine font description from string
2573
my ( $attr_list, $text_raw, $accel_char ) = Gtk2::Pango->parse_markup( $self->{_items}{$key}{text}->get('text') );
2574
my $font_desc = Gtk2::Pango::FontDescription->from_string( $self->{_font} );
2576
#FIXME, maybe the pango version installed is too old
2581
$font_desc = $attr->copy->desc
2582
if $attr->isa('Gtk2::Pango::AttrFontDesc');
2588
print "\nERROR: Pango Markup could not be parsed:\n$@";
2591
#apply current font settings to button
2592
$self->{_font_btn_w}->set_font_name( $font_desc->to_string );
2597
}elsif ( $item->isa('Goo::Canvas::Text') ) {
2599
#determine font description from string
2600
my ( $attr_list, $text_raw, $accel_char ) = Gtk2::Pango->parse_markup( $item->get('text') );
2601
my $font_desc = Gtk2::Pango::FontDescription->from_string( $self->{_font} );
2603
#FIXME, maybe the pango version installed is too old
2608
$font_desc = $attr->copy->desc
2609
if $attr->isa('Gtk2::Pango::AttrFontDesc');
2615
print "\nERROR: Pango Markup could not be parsed:\n$@";
2619
$self->{_stroke_color_w}->set_color( $self->{_items}{$key}{stroke_color} );
2620
$self->{_stroke_color_w}->set_alpha( int( $self->{_items}{$key}{stroke_color_alpha} * 65535 ) );
2622
#apply current font settings to button
2623
$self->{_font_btn_w}->set_font_name( $font_desc->to_string );
2627
#update global values
2628
$self->{_line_width} = $self->{_line_spin_w}->get_value;
2629
$self->{_stroke_color} = $self->{_stroke_color_w}->get_color;
2630
$self->{_stroke_color_alpha} = $self->{_stroke_color_w}->get_alpha / 65535;
2631
$self->{_fill_color} = $self->{_fill_color_w}->get_color;
2632
$self->{_fill_color_alpha} = $self->{_fill_color_w}->get_alpha / 65636;
2633
my $font_descr = Gtk2::Pango::FontDescription->from_string( $self->{_font_btn_w}->get_font_name );
2634
$self->{_font} = $font_descr->to_string;
2636
#unblock 'value-change' handlers for widgets
2637
$self->{_line_spin_w}->signal_handler_unblock ($self->{_line_spin_wh});
2638
$self->{_stroke_color_w}->signal_handler_unblock ($self->{_stroke_color_wh});
2639
$self->{_fill_color_w}->signal_handler_unblock ($self->{_fill_color_wh});
2640
$self->{_font_btn_w}->signal_handler_unblock ($self->{_font_btn_wh});
2644
sub restore_drawing_properties {
2647
#saved properties available?
2648
return FALSE unless defined $self->{_last_fill_color};
2650
#anything done until now?
2651
return FALSE unless defined $self->{_last_mode};
2653
#~ print "restore_drawing_properties\n";
2655
#block 'value-change' handlers for widgets
2656
#so we do not apply the changes twice
2657
$self->{_line_spin_w}->signal_handler_block ($self->{_line_spin_wh});
2658
$self->{_stroke_color_w}->signal_handler_block ($self->{_stroke_color_wh});
2659
$self->{_fill_color_w}->signal_handler_block ($self->{_fill_color_wh});
2660
$self->{_font_btn_w}->signal_handler_block ($self->{_font_btn_wh});
2663
$self->{_fill_color_w}->set_color($self->{_last_fill_color});
2664
$self->{_fill_color_w}->set_alpha( int($self->{_last_fill_color_alpha} * 65535) );
2665
$self->{_stroke_color_w}->set_color($self->{_last_stroke_color});
2666
$self->{_stroke_color_w}->set_alpha( int($self->{_last_stroke_color_alpha} * 65535) );
2667
$self->{_line_spin_w}->set_value($self->{_last_line_width});
2668
$self->{_font_btn_w}->set_font_name($self->{_last_font});
2670
#update global values
2671
$self->{_line_width} = $self->{_line_spin_w}->get_value;
2672
$self->{_stroke_color} = $self->{_stroke_color_w}->get_color;
2673
$self->{_stroke_color_alpha} = $self->{_stroke_color_w}->get_alpha / 65535;
2674
$self->{_fill_color} = $self->{_fill_color_w}->get_color;
2675
$self->{_fill_color_alpha} = $self->{_fill_color_w}->get_alpha / 65636;
2676
my $font_descr = Gtk2::Pango::FontDescription->from_string( $self->{_font_btn_w}->get_font_name );
2677
$self->{_font} = $font_descr->to_string;
2679
#unblock 'value-change' handlers for widgets
2680
$self->{_line_spin_w}->signal_handler_unblock ($self->{_line_spin_wh});
2681
$self->{_stroke_color_w}->signal_handler_unblock ($self->{_stroke_color_wh});
2682
$self->{_fill_color_w}->signal_handler_unblock ($self->{_fill_color_wh});
2683
$self->{_font_btn_w}->signal_handler_unblock ($self->{_font_btn_wh});
1437
2687
sub event_item_on_button_press {
1438
2688
my ( $self, $item, $target, $ev ) = @_;
1440
my $d = $self->{_shutter_common}->get_gettext;
2690
#~ print "button-press\n";
2692
#canvas is busy now...
2693
$self->{_busy} = TRUE;
1441
2695
my $cursor = Gtk2::Gdk::Cursor->new('left-ptr');
1444
$valid = TRUE if $self->{_canvas}->get_item_at( $ev->x, $ev->y, TRUE );
1447
if ( $valid && $self->{_current_mode_descr} eq "select" ) {
2698
#if it is not activated yet
2701
if ($ev->type eq 'button-press' && $self->{_current_mode_descr} eq "select") {
1449
2703
#embedded item?
1450
2704
my $parent = $self->get_parent_item($item);
1722
2980
my $prop_item = Gtk2::ImageMenuItem->new_from_stock('gtk-properties');
1723
$prop_item->set_sensitive(FALSE) if $item->isa('Goo::Canvas::Image');
2982
#some items do not have properties, e.g. images or censor
2983
$prop_item->set_sensitive(FALSE) if $item->isa('Goo::Canvas::Image') || !exists($self->{_items}{$key}{stroke_color});
1724
2985
$prop_item->signal_connect(
1725
2986
'activate' => sub {
1728
my $prop_dialog = Gtk2::Dialog->new(
1729
$d->get("Preferences"),
1730
$self->{_drawing_window},
1731
[qw/modal destroy-with-parent/],
1732
'gtk-cancel' => 'cancel',
1733
'gtk-apply' => 'apply'
1736
$prop_dialog->set_default_response('apply');
1742
if ( $item->isa('Goo::Canvas::Rect')
1743
|| $item->isa('Goo::Canvas::Ellipse')
1744
|| $item->isa('Goo::Canvas::Polyline') )
1747
my $general_vbox = Gtk2::VBox->new( FALSE, 5 );
1749
my $label_general = Gtk2::Label->new;
1750
$label_general->set_markup( $d->get("<i>Main</i>") );
1751
my $frame_general = Gtk2::Frame->new();
1752
$frame_general->set_label_widget($label_general);
1753
$frame_general->set_border_width(5);
1754
$prop_dialog->vbox->add($frame_general);
1757
my $line_hbox = Gtk2::HBox->new( TRUE, 5 );
1758
$line_hbox->set_border_width(5);
1759
my $linew_label = Gtk2::Label->new( $d->get("Line width") );
1760
$line_spin = Gtk2::SpinButton->new_with_range( 0.5, 10, 0.1 );
1762
$line_spin->set_value( $item->get('line-width') );
1764
$line_hbox->pack_start_defaults($linew_label);
1765
$line_hbox->pack_start_defaults($line_spin);
1766
$general_vbox->pack_start( $line_hbox, FALSE, FALSE, 0 );
1768
if ( $item->isa('Goo::Canvas::Rect') || $item->isa('Goo::Canvas::Ellipse') ) {
1771
my $fill_color_hbox = Gtk2::HBox->new( TRUE, 5 );
1772
$fill_color_hbox->set_border_width(5);
1773
my $fill_color_label = Gtk2::Label->new( $d->get("Fill color") );
1774
$fill_color = Gtk2::ColorButton->new();
1776
$fill_color->set_color( $self->{_items}{$key}{fill_color} );
1777
$fill_color->set_alpha( int( $self->{_items}{$key}{fill_color_alpha} * 65535 ) );
1778
$fill_color->set_use_alpha(TRUE);
1779
$fill_color->set_title( $d->get("Choose fill color") );
1781
$fill_color_hbox->pack_start_defaults($fill_color_label);
1782
$fill_color_hbox->pack_start_defaults($fill_color);
1783
$general_vbox->pack_start( $fill_color_hbox, FALSE, FALSE, 0 );
1787
my $stroke_color_hbox = Gtk2::HBox->new( TRUE, 5 );
1788
$stroke_color_hbox->set_border_width(5);
1789
my $stroke_color_label = Gtk2::Label->new( $d->get("Stroke color") );
1790
$stroke_color = Gtk2::ColorButton->new();
1792
$stroke_color->set_color( $self->{_items}{$key}{stroke_color} );
1793
$stroke_color->set_alpha( int( $self->{_items}{$key}{stroke_color_alpha} * 65535 ) );
1794
$stroke_color->set_use_alpha(TRUE);
1795
$stroke_color->set_title( $d->get("Choose stroke color") );
1797
$stroke_color_hbox->pack_start_defaults($stroke_color_label);
1798
$stroke_color_hbox->pack_start_defaults($stroke_color);
1799
$general_vbox->pack_start( $stroke_color_hbox, FALSE, FALSE, 0 );
1801
$frame_general->add($general_vbox);
1810
if ( $item->isa('Goo::Canvas::Text') ) {
1812
my $text_vbox = Gtk2::VBox->new( FALSE, 5 );
1814
my $label_text = Gtk2::Label->new;
1815
$label_text->set_markup( $d->get("<i>Text</i>") );
1816
my $frame_text = Gtk2::Frame->new();
1817
$frame_text->set_label_widget($label_text);
1818
$frame_text->set_border_width(5);
1819
$prop_dialog->vbox->add($frame_text);
1822
my $font_hbox = Gtk2::HBox->new( TRUE, 5 );
1823
$font_hbox->set_border_width(5);
1824
my $font_label = Gtk2::Label->new( $d->get("Font") );
1825
$font_btn = Gtk2::FontButton->new();
1827
#determine font description from string
1828
my ( $attr_list, $text_raw, $accel_char ) = Gtk2::Pango->parse_markup( $item->get('text') );
1829
my $font_desc = Gtk2::Pango::FontDescription->from_string( $self->{_font} );
1831
#FIXME, maybe the pango version installed is too old
1836
$font_desc = $attr->copy->desc
1837
if $attr->isa('Gtk2::Pango::AttrFontDesc');
1843
print "\nERROR: Pango Markup could not be parsed:\n$@";
1846
$font_hbox->pack_start_defaults($font_label);
1847
$font_hbox->pack_start_defaults($font_btn);
1848
$text_vbox->pack_start( $font_hbox, FALSE, FALSE, 0 );
1851
my $font_color_hbox = Gtk2::HBox->new( TRUE, 5 );
1852
$font_color_hbox->set_border_width(5);
1853
my $font_color_label = Gtk2::Label->new( $d->get("Font color") );
1854
$font_color = Gtk2::ColorButton->new();
1855
$font_color->set_use_alpha(TRUE);
1857
$font_color->set_alpha( int( $self->{_items}{$key}{stroke_color_alpha} * 65535 ) );
1858
$font_color->set_color( $self->{_items}{$key}{stroke_color} );
1859
$font_color->set_title( $d->get("Choose font color") );
1861
$font_color_hbox->pack_start_defaults($font_color_label);
1862
$font_color_hbox->pack_start_defaults($font_color);
1864
$text_vbox->pack_start( $font_color_hbox, FALSE, FALSE, 0 );
1867
my $text = Gtk2::TextBuffer->new;
1868
$text->set_text($text_raw);
1871
my $textview_hbox = Gtk2::HBox->new( FALSE, 5 );
1872
$textview_hbox->set_border_width(5);
1873
$textview = Gtk2::TextView->new_with_buffer($text);
1874
$textview->set_size_request( 150, 200 );
1875
$textview_hbox->pack_start_defaults($textview);
1877
$text_vbox->pack_start_defaults($textview_hbox);
1879
#apply changes directly
1880
$font_btn->signal_connect(
1883
$self->modify_text_in_properties( $font_btn, $textview, $font_color, $item );
1888
$font_color->signal_connect(
1889
'color-set' => sub {
1891
$self->modify_text_in_properties( $font_btn, $textview, $font_color, $item );
1896
#apply current font settings to button
1897
$font_btn->set_font_name( $font_desc->to_string );
1899
#FIXME >> why do we have to invoke this manually??
1900
$font_btn->signal_emit('font-set');
1902
$frame_text->add($text_vbox);
1906
$prop_dialog->show_all;
1907
my $prop_dialog_res = $prop_dialog->run;
1908
if ( $prop_dialog_res eq 'apply' ) {
1911
$self->store_to_xdo_stack($self->{_current_item} , 'modify', 'undo');
1913
#apply rect or ellipse options
1914
if ( $item->isa('Goo::Canvas::Rect') || $item->isa('Goo::Canvas::Ellipse') ) {
1916
my $fill_pattern = $self->create_color( $fill_color->get_color, $fill_color->get_alpha / 65535 );
1917
my $stroke_pattern = $self->create_color( $stroke_color->get_color, $stroke_color->get_alpha / 65535 );
1919
'line-width' => $line_spin->get_value,
1920
'fill-pattern' => $fill_pattern,
1921
'stroke-pattern' => $stroke_pattern
1924
#save color and opacity as well
1925
$self->{_items}{$key}{fill_color} = $fill_color->get_color;
1926
$self->{_items}{$key}{fill_color_alpha} = $fill_color->get_alpha / 65535;
1927
$self->{_items}{$key}{stroke_color} = $stroke_color->get_color;
1928
$self->{_items}{$key}{stroke_color_alpha} = $stroke_color->get_alpha / 65535;
1931
#apply polyline options
1932
if ( $item->isa('Goo::Canvas::Polyline') ) {
1933
my $stroke_pattern = $self->create_color( $stroke_color->get_color, $stroke_color->get_alpha / 65535 );
1935
'line-width' => $line_spin->get_value,
1936
'stroke-pattern' => $stroke_pattern
1939
#save color and opacity as well
1940
$self->{_items}{$key}{stroke_color} = $stroke_color->get_color;
1941
$self->{_items}{$key}{stroke_color_alpha} = $stroke_color->get_alpha / 65535;
1945
if ( $item->isa('Goo::Canvas::Text') ) {
1946
my $font_descr = Gtk2::Pango::FontDescription->from_string( $font_btn->get_font_name );
1949
= $textview->get_buffer->get_text( $textview->get_buffer->get_start_iter, $textview->get_buffer->get_end_iter, FALSE )
1952
my $fill_pattern = $self->create_color( $font_color->get_color, $font_color->get_alpha / 65535 );
1955
'text' => "<span font_desc=' " . $font_descr->to_string . " ' >" . $new_text . "</span>",
1956
'use-markup' => TRUE,
1957
'fill-pattern' => $fill_pattern
1960
#adjust rectangle to display text properly
1961
my $no_lines = $textview->get_buffer->get_line_count;
1962
my $font_size = $font_descr->get_size / 1024;
1964
if ( ( $no_lines * $font_size ) + $parent->get('height') > ( $self->{_drawing_pixbuf}->get_height - 50 ) ) {
1965
$parent->set( 'height' => ( $self->{_drawing_pixbuf}->get_height - $parent->get('height') ) );
1967
$parent->set( 'height' => $no_lines * $font_size + $no_lines * 20 );
1970
$self->handle_rects( 'update', $parent );
1971
$self->handle_embedded( 'update', $parent );
1973
#save color and opacity as well
1974
$self->{_items}{$key}{stroke_color} = $font_color->get_color;
1975
$self->{_items}{$key}{stroke_color_alpha} = $font_color->get_alpha / 65535;
1978
$prop_dialog->destroy;
1982
$prop_dialog->destroy;
2988
$self->show_item_properties($item, $parent, $key);
1993
2997
return $menu_item;
3001
my ($self, $item, $parent) = @_;
3002
if ( exists $self->{_items}{$item} ) {
3009
sub show_item_properties {
3010
my ($self, $item, $parent, $key) = @_;
3012
#~ print "show_item_properties\n";
3015
my $prop_dialog = Gtk2::Dialog->new(
3016
$self->{_d}->get("Preferences"),
3017
$self->{_drawing_window},
3018
[qw/modal destroy-with-parent/],
3019
'gtk-cancel' => 'cancel',
3020
'gtk-apply' => 'apply'
3023
$prop_dialog->set_default_response('apply');
3025
#RECT OR ELLIPSE OR POLYLINE
3026
my $line_spin = undef;
3027
my $fill_color = undef;
3028
my $stroke_color = undef;
3031
my $number_spin = undef;
3034
my $end_arrow = undef;
3035
my $start_arrow = undef;
3036
my $arrow_spin = undef;
3037
my $arrowl_spin = undef;
3038
my $arrowt_spin = undef;
3046
#RECT OR ELLIPSE OR POLYLINE
3048
if ( $item->isa('Goo::Canvas::Rect')
3049
|| $item->isa('Goo::Canvas::Ellipse')
3050
|| $item->isa('Goo::Canvas::Polyline') )
3053
my $general_vbox = Gtk2::VBox->new( FALSE, 5 );
3055
my $label_general = Gtk2::Label->new;
3056
$label_general->set_markup( $self->{_d}->get("<i>Main</i>") );
3057
my $frame_general = Gtk2::Frame->new();
3058
$frame_general->set_label_widget($label_general);
3059
$frame_general->set_border_width(5);
3060
$prop_dialog->vbox->add($frame_general);
3063
my $line_hbox = Gtk2::HBox->new( TRUE, 5 );
3064
$line_hbox->set_border_width(5);
3065
my $linew_label = Gtk2::Label->new( $self->{_d}->get("Line width") );
3066
$line_spin = Gtk2::SpinButton->new_with_range( 0.5, 20, 0.1 );
3068
$line_spin->set_value( $item->get('line-width') );
3070
$line_hbox->pack_start_defaults($linew_label);
3071
$line_hbox->pack_start_defaults($line_spin);
3072
$general_vbox->pack_start( $line_hbox, FALSE, FALSE, 0 );
3074
if ( $item->isa('Goo::Canvas::Rect') || $item->isa('Goo::Canvas::Ellipse') ) {
3077
my $fill_color_hbox = Gtk2::HBox->new( TRUE, 5 );
3078
$fill_color_hbox->set_border_width(5);
3079
my $fill_color_label = Gtk2::Label->new( $self->{_d}->get("Fill color") );
3080
$fill_color = Gtk2::ColorButton->new();
3082
$fill_color->set_color( $self->{_items}{$key}{fill_color} );
3083
$fill_color->set_alpha( int( $self->{_items}{$key}{fill_color_alpha} * 65535 ) );
3084
$fill_color->set_use_alpha(TRUE);
3085
$fill_color->set_title( $self->{_d}->get("Choose fill color") );
3087
$fill_color_hbox->pack_start_defaults($fill_color_label);
3088
$fill_color_hbox->pack_start_defaults($fill_color);
3089
$general_vbox->pack_start( $fill_color_hbox, FALSE, FALSE, 0 );
3093
#some items, e.g. censor tool, do not have a color - skip them
3094
if($self->{_items}{$key}{stroke_color}){
3096
my $stroke_color_hbox = Gtk2::HBox->new( TRUE, 5 );
3097
$stroke_color_hbox->set_border_width(5);
3098
my $stroke_color_label = Gtk2::Label->new( $self->{_d}->get("Stroke color") );
3099
$stroke_color = Gtk2::ColorButton->new();
3101
$stroke_color->set_color( $self->{_items}{$key}{stroke_color} );
3102
$stroke_color->set_alpha( int( $self->{_items}{$key}{stroke_color_alpha} * 65535 ) );
3103
$stroke_color->set_use_alpha(TRUE);
3104
$stroke_color->set_title( $self->{_d}->get("Choose stroke color") );
3106
$stroke_color_hbox->pack_start_defaults($stroke_color_label);
3107
$stroke_color_hbox->pack_start_defaults($stroke_color);
3108
$general_vbox->pack_start( $stroke_color_hbox, FALSE, FALSE, 0 );
3111
$frame_general->add($general_vbox);
3113
#special shapes like numbered ellipse
3114
if(defined $self->{_items}{$key}{text}){
3116
my $numbered_vbox = Gtk2::VBox->new( FALSE, 5 );
3118
my $label_numbered = Gtk2::Label->new;
3119
$label_numbered->set_markup( $self->{_d}->get("<i>Numbering</i>") );
3120
my $frame_numbered = Gtk2::Frame->new();
3121
$frame_numbered->set_label_widget($label_numbered);
3122
$frame_numbered->set_border_width(5);
3123
$prop_dialog->vbox->add($frame_numbered);
3126
my $number_hbox = Gtk2::HBox->new( TRUE, 5 );
3127
$number_hbox->set_border_width(5);
3128
my $numberw_label = Gtk2::Label->new( $self->{_d}->get("Current value") );
3129
$number_spin = Gtk2::SpinButton->new_with_range( 0, 999, 1 );
3131
$number_spin->set_value( $self->{_items}{$key}{text}{digit} );
3133
$number_hbox->pack_start_defaults($numberw_label);
3134
$number_hbox->pack_start_defaults($number_spin);
3135
$numbered_vbox->pack_start( $number_hbox, FALSE, FALSE, 0 );
3138
my $font_hbox = Gtk2::HBox->new( TRUE, 5 );
3139
$font_hbox->set_border_width(5);
3140
my $font_label = Gtk2::Label->new( $self->{_d}->get("Font") );
3141
$font_btn = Gtk2::FontButton->new();
3143
#determine font description from string
3144
my ( $attr_list, $text_raw, $accel_char ) = Gtk2::Pango->parse_markup( $self->{_items}{$key}{text}->get('text') );
3145
my $font_desc = Gtk2::Pango::FontDescription->from_string( $self->{_font} );
3147
#FIXME, maybe the pango version installed is too old
3152
$font_desc = $attr->copy->desc
3153
if $attr->isa('Gtk2::Pango::AttrFontDesc');
3159
print "\nERROR: Pango Markup could not be parsed:\n$@";
3162
#apply current font settings to button
3163
$font_btn->set_font_name( $font_desc->to_string );
3165
$font_hbox->pack_start_defaults($font_label);
3166
$font_hbox->pack_start_defaults($font_btn);
3167
$numbered_vbox->pack_start( $font_hbox, FALSE, FALSE, 0 );
3169
$frame_numbered->add($numbered_vbox);
3176
if ($item->isa('Goo::Canvas::Polyline')
3177
&& defined $self->{_items}{$key}{end_arrow}
3178
&& defined $self->{_items}{$key}{start_arrow})
3180
my $arrow_vbox = Gtk2::VBox->new( FALSE, 5 );
3182
my $label_arrow = Gtk2::Label->new;
3183
$label_arrow->set_markup( $self->{_d}->get("<i>Arrow</i>") );
3184
my $frame_arrow = Gtk2::Frame->new();
3185
$frame_arrow->set_label_widget($label_arrow);
3186
$frame_arrow->set_border_width(5);
3187
$prop_dialog->vbox->add($frame_arrow);
3190
my $arrow_hbox = Gtk2::HBox->new( TRUE, 5 );
3191
$arrow_hbox->set_border_width(5);
3192
my $arroww_label = Gtk2::Label->new( $self->{_d}->get("Width") );
3193
$arrow_spin = Gtk2::SpinButton->new_with_range( 0.5, 10, 0.1 );
3195
$arrow_spin->set_value( $item->get('arrow-width') );
3197
$arrow_hbox->pack_start_defaults($arroww_label);
3198
$arrow_hbox->pack_start_defaults($arrow_spin);
3199
$arrow_vbox->pack_start( $arrow_hbox, FALSE, FALSE, 0 );
3202
my $arrowl_hbox = Gtk2::HBox->new( TRUE, 5 );
3203
$arrowl_hbox->set_border_width(5);
3204
my $arrowl_label = Gtk2::Label->new( $self->{_d}->get("Length") );
3205
$arrowl_spin = Gtk2::SpinButton->new_with_range( 0.5, 10, 0.1 );
3207
$arrowl_spin->set_value( $item->get('arrow-length') );
3209
$arrowl_hbox->pack_start_defaults($arrowl_label);
3210
$arrowl_hbox->pack_start_defaults($arrowl_spin);
3211
$arrow_vbox->pack_start( $arrowl_hbox, FALSE, FALSE, 0 );
3214
my $arrowt_hbox = Gtk2::HBox->new( TRUE, 5 );
3215
$arrowt_hbox->set_border_width(5);
3216
my $arrowt_label = Gtk2::Label->new( $self->{_d}->get("Tip length") );
3217
$arrowt_spin = Gtk2::SpinButton->new_with_range( 0.5, 10, 0.1 );
3219
$arrowt_spin->set_value( $item->get('arrow-tip-length') );
3221
$arrowt_hbox->pack_start_defaults($arrowt_label);
3222
$arrowt_hbox->pack_start_defaults($arrowt_spin);
3223
$arrow_vbox->pack_start( $arrowt_hbox, FALSE, FALSE, 0 );
3225
#checkboxes for start and end arrows
3226
$end_arrow = Gtk2::CheckButton->new ($self->{_d}->get("Display an arrow at the end of the line"));
3227
$end_arrow->set_active($self->{_items}{$key}{end_arrow});
3228
$start_arrow = Gtk2::CheckButton->new ($self->{_d}->get("Display an arrow at the start of the line"));
3229
$start_arrow->set_active($self->{_items}{$key}{start_arrow});
3231
my $end_arrow_hbox = Gtk2::HBox->new( TRUE, 5 );
3232
$end_arrow_hbox->set_border_width(5);
3234
my $start_arrow_hbox = Gtk2::HBox->new( TRUE, 5 );
3235
$start_arrow_hbox->set_border_width(5);
3237
$end_arrow_hbox->pack_start_defaults($end_arrow);
3238
$start_arrow_hbox->pack_start_defaults($start_arrow);
3240
$arrow_vbox->pack_start( $start_arrow_hbox, FALSE, FALSE, 0 );
3241
$arrow_vbox->pack_start( $end_arrow_hbox, FALSE, FALSE, 0 );
3244
$frame_arrow->add($arrow_vbox);
3246
#simple TEXT item (no numbered ellipse)
3247
}elsif ( $item->isa('Goo::Canvas::Text')
3248
&& !defined $self->{_items}{$key}{ellipse} ) {
3250
my $text_vbox = Gtk2::VBox->new( FALSE, 5 );
3252
my $label_text = Gtk2::Label->new;
3253
$label_text->set_markup( $self->{_d}->get("<i>Text</i>") );
3254
my $frame_text = Gtk2::Frame->new();
3255
$frame_text->set_label_widget($label_text);
3256
$frame_text->set_border_width(5);
3257
$prop_dialog->vbox->add($frame_text);
3260
my $font_hbox = Gtk2::HBox->new( TRUE, 5 );
3261
$font_hbox->set_border_width(5);
3262
my $font_label = Gtk2::Label->new( $self->{_d}->get("Font") );
3263
$font_btn = Gtk2::FontButton->new();
3265
#determine font description from string
3266
my ( $attr_list, $text_raw, $accel_char ) = Gtk2::Pango->parse_markup( $item->get('text') );
3267
my $font_desc = Gtk2::Pango::FontDescription->from_string( $self->{_font} );
3269
#FIXME, maybe the pango version installed is too old
3274
$font_desc = $attr->copy->desc
3275
if $attr->isa('Gtk2::Pango::AttrFontDesc');
3281
print "\nERROR: Pango Markup could not be parsed:\n$@";
3284
$font_hbox->pack_start_defaults($font_label);
3285
$font_hbox->pack_start_defaults($font_btn);
3286
$text_vbox->pack_start( $font_hbox, FALSE, FALSE, 0 );
3289
my $font_color_hbox = Gtk2::HBox->new( TRUE, 5 );
3290
$font_color_hbox->set_border_width(5);
3291
my $font_color_label = Gtk2::Label->new( $self->{_d}->get("Font color") );
3292
$font_color = Gtk2::ColorButton->new();
3293
$font_color->set_use_alpha(TRUE);
3295
$font_color->set_alpha( int( $self->{_items}{$key}{stroke_color_alpha} * 65535 ) );
3296
$font_color->set_color( $self->{_items}{$key}{stroke_color} );
3297
$font_color->set_title( $self->{_d}->get("Choose font color") );
3299
$font_color_hbox->pack_start_defaults($font_color_label);
3300
$font_color_hbox->pack_start_defaults($font_color);
3302
$text_vbox->pack_start( $font_color_hbox, FALSE, FALSE, 0 );
3305
my $text = Gtk2::TextBuffer->new;
3306
$text->set_text($text_raw);
3309
my $textview_hbox = Gtk2::HBox->new( FALSE, 5 );
3310
$textview_hbox->set_border_width(5);
3311
$textview = Gtk2::TextView->new_with_buffer($text);
3312
$textview->set_size_request( 150, 200 );
3313
$textview_hbox->pack_start_defaults($textview);
3315
$text_vbox->pack_start_defaults($textview_hbox);
3317
#apply changes directly
3318
$font_btn->signal_connect(
3321
$self->modify_text_in_properties( $font_btn, $textview, $font_color, $item );
3326
$font_color->signal_connect(
3327
'color-set' => sub {
3329
$self->modify_text_in_properties( $font_btn, $textview, $font_color, $item );
3334
#apply current font settings to button
3335
$font_btn->set_font_name( $font_desc->to_string );
3337
#FIXME >> why do we have to invoke this manually??
3338
$font_btn->signal_emit('font-set');
3340
$frame_text->add($text_vbox);
3345
$prop_dialog->show_all;
3346
my $prop_dialog_res = $prop_dialog->run;
3347
if ( $prop_dialog_res eq 'apply' ) {
3349
$self->apply_properties($item, $parent, $key,
3350
$fill_color, $stroke_color, $line_spin,
3351
$font_color, $font_btn, $textview,
3352
$end_arrow , $start_arrow, $arrow_spin, $arrowl_spin, $arrowt_spin,
3355
#apply item properties to widgets
3356
#line width, fill color, stroke color etc.
3357
$self->set_and_save_drawing_properties($self->{_current_item}, FALSE);
3359
#FIXME - we need to save the changed values in this case
3360
$self->set_and_save_drawing_properties($self->{_current_item}, TRUE);
3362
$prop_dialog->destroy;
3366
$prop_dialog->destroy;
3372
sub apply_properties {
3398
#only numbered shapes
3403
#~ print "apply_properties\n";
3405
#remember drawing colors, line width and font settings
3406
#maybe we have to restore them
3407
if($self->{_items}{$key}{type} ne "highlighter" &&
3408
$self->{_items}{$key}{type} ne "censor")
3411
$self->{_last_fill_color} = $self->{_fill_color_w}->get_color;
3412
$self->{_last_fill_color_alpha} = $self->{_fill_color_w}->get_alpha / 65535;
3413
$self->{_last_stroke_color} = $self->{_stroke_color_w}->get_color;
3414
$self->{_last_stroke_color_alpha} = $self->{_stroke_color_w}->get_alpha / 65535;
3415
$self->{_last_line_width} = $self->{_line_spin_w}->get_value;
3416
$self->{_last_font} = $self->{_font_btn_w}->get_font_name;
3418
#remember the last mode as well
3419
$self->{_last_mode} = $self->{_current_mode};
3420
$self->{_last_mode_descr} = $self->{_current_mode_descr};
3425
$self->store_to_xdo_stack($self->{_current_item} , 'modify', 'undo');
3427
#apply rect or ellipse options
3428
if ( $item->isa('Goo::Canvas::Rect') || $item->isa('Goo::Canvas::Ellipse') ) {
3430
my $fill_pattern = $self->create_color( $fill_color->get_color, $fill_color->get_alpha / 65535 );
3431
my $stroke_pattern = $self->create_color( $stroke_color->get_color, $stroke_color->get_alpha / 65535 );
3433
'line-width' => $line_spin->get_value,
3434
'fill-pattern' => $fill_pattern,
3435
'stroke-pattern' => $stroke_pattern
3438
#special shapes like numbered ellipse (digit changed)
3439
if(defined $self->{_items}{$key}{text}){
3441
#determine new or current digit
3443
if(defined $number_spin){
3444
$digit = $number_spin->get_value;
3446
$digit = $self->{_items}{$key}{text}{digit};
3449
my $fill_pattern = undef;
3450
if(defined $font_color){
3451
$fill_pattern = $self->create_color( $font_color->get_color, $font_color->get_alpha / 65535 );
3452
}elsif(defined $stroke_color){
3453
$fill_pattern = $self->create_color( $stroke_color->get_color, $stroke_color->get_alpha / 65535 );
3456
my $font_descr = Gtk2::Pango::FontDescription->from_string( $font_btn->get_font_name );
3457
$self->{_items}{$key}{text}->set(
3458
'text' => "<span font_desc=' " . $font_descr->to_string . " ' >" . $digit . "</span>",
3459
'fill-pattern' => $fill_pattern,
3462
#adjust parent rectangle
3463
my $tb = $self->{_items}{$key}{text}->get_bounds;
3466
my $qs = abs($tb->x1 - $tb->x2);
3467
$qs = abs($tb->y1 - $tb->y2) if abs($tb->y1 - $tb->y2) > abs($tb->x1 - $tb->x2);
3469
#add line width of parent ellipse
3470
$qs += $self->{_items}{$key}{ellipse}->get('line-width')+5;
3477
#save digit in hash as well (only item properties dialog)
3478
if(defined $number_spin){
3479
$self->{_items}{$key}{text}{digit} = $digit;
3482
$self->handle_rects( 'update', $parent );
3483
$self->handle_embedded( 'update', $parent );
3487
#save color and opacity as well
3488
$self->{_items}{$key}{fill_color} = $fill_color->get_color;
3489
$self->{_items}{$key}{fill_color_alpha} = $fill_color->get_alpha / 65535;
3490
$self->{_items}{$key}{stroke_color} = $stroke_color->get_color;
3491
$self->{_items}{$key}{stroke_color_alpha} = $stroke_color->get_alpha / 65535;
3494
#apply polyline options (arrow)
3495
if ($item->isa('Goo::Canvas::Polyline')
3496
&& defined $self->{_items}{$key}{end_arrow}
3497
&& defined $self->{_items}{$key}{start_arrow})
3500
my $stroke_pattern = $self->create_color( $stroke_color->get_color, $stroke_color->get_alpha / 65535 );
3502
#these values are only available in the item menu
3503
if( defined $arrowl_spin
3504
&& defined $arrow_spin
3505
&& defined $arrowt_spin
3506
&& defined $end_arrow
3507
&& defined $start_arrow)
3510
'line-width' => $line_spin->get_value,
3511
'stroke-pattern' => $stroke_pattern,
3512
'end-arrow' => $end_arrow->get_active,
3513
'start-arrow' => $start_arrow->get_active,
3514
'arrow-length' => $arrowl_spin->get_value,
3515
'arrow-width' => $arrow_spin->get_value,
3516
'arrow-tip-length' => $arrowt_spin->get_value,
3521
'line-width' => $line_spin->get_value,
3522
'stroke-pattern' => $stroke_pattern,
3523
'end-arrow' => $self->{_items}{$key}{line}->get('end-arrow'),
3524
'start-arrow' => $self->{_items}{$key}{line}->get('start-arrow'),
3528
#save color and opacity as well
3529
$self->{_items}{$key}{stroke_color} = $stroke_color->get_color;
3530
$self->{_items}{$key}{stroke_color_alpha} = $stroke_color->get_alpha / 65535;
3532
#save arrow specific properties
3533
$self->{_items}{$key}{end_arrow} = $self->{_items}{$key}{line}->get('end-arrow');
3534
$self->{_items}{$key}{start_arrow} = $self->{_items}{$key}{line}->get('start-arrow');
3535
$self->{_items}{$key}{arrow_width} = $self->{_items}{$key}{line}->get('arrow-width');
3536
$self->{_items}{$key}{arrow_length} = $self->{_items}{$key}{line}->get('arrow-length');
3537
$self->{_items}{$key}{arrow_tip_length} = $self->{_items}{$key}{line}->get('arrow-tip-length');
3539
#apply polyline options (freehand, highlighter)
3540
}elsif ( $item->isa('Goo::Canvas::Polyline')
3541
&& defined $self->{_items}{$key}{stroke_color})
3543
my $stroke_pattern = $self->create_color( $stroke_color->get_color, $stroke_color->get_alpha / 65535 );
3545
'line-width' => $line_spin->get_value,
3546
'stroke-pattern' => $stroke_pattern,
3549
#save color and opacity as well
3550
$self->{_items}{$key}{stroke_color} = $stroke_color->get_color;
3551
$self->{_items}{$key}{stroke_color_alpha} = $stroke_color->get_alpha / 65535;
3555
if ( $item->isa('Goo::Canvas::Text') ) {
3556
my $font_descr = Gtk2::Pango::FontDescription->from_string( $font_btn->get_font_name );
3558
my $fill_pattern = $self->create_color( $font_color->get_color, $font_color->get_alpha / 65535 );
3560
my $new_text = undef;
3563
= $textview->get_buffer->get_text( $textview->get_buffer->get_start_iter, $textview->get_buffer->get_end_iter, FALSE )
3566
#determine font description and text from string
3567
my ( $attr_list, $text_raw, $accel_char ) = Gtk2::Pango->parse_markup( $item->get('text') );
3568
$new_text = $text_raw;
3572
'text' => "<span font_desc=' " . $font_descr->to_string . " ' >" . $new_text . "</span>",
3573
'use-markup' => TRUE,
3574
'fill-pattern' => $fill_pattern
3577
#adjust parent rectangle
3578
my $tb = $item->get_bounds;
3580
'width' => abs($tb->x1 - $tb->x2),
3581
'height' => abs($tb->y1 - $tb->y2),
3584
$self->handle_rects( 'update', $parent );
3585
$self->handle_embedded( 'update', $parent );
3587
#save color and opacity as well
3588
$self->{_items}{$key}{stroke_color} = $font_color->get_color;
3589
$self->{_items}{$key}{stroke_color_alpha} = $font_color->get_alpha / 65535;
1996
3595
sub modify_text_in_properties {
1997
3596
my $self = shift;
1998
3597
my $font_btn = shift;
2614
4428
#ui related stuff
2615
4429
sub setup_uimanager {
2616
4430
my $self = shift;
2617
my $d = $self->{_shutter_common}->get_gettext;
2620
my $dicons = $self->{_shutter_common}->get_root . "/share/shutter/resources/icons/drawing_tool";
2622
4432
$self->{_factory} = Gtk2::IconFactory->new();
2623
$self->{_factory}->add( 'shutter-ellipse', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file("$dicons/draw-ellipse.png") ) );
2624
$self->{_factory}->add( 'shutter-eraser', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file("$dicons/draw-eraser.png") ) );
2625
$self->{_factory}->add( 'shutter-freehand', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file("$dicons/draw-freehand.png") ) );
2626
$self->{_factory}->add( 'shutter-pointer', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file("$dicons/draw-pointer.png") ) );
2627
$self->{_factory}->add( 'shutter-rectangle', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file("$dicons/draw-rectangle.png") ) );
2628
$self->{_factory}->add( 'shutter-line', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file("$dicons/draw-line.png") ) );
2629
$self->{_factory}->add( 'shutter-text', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file("$dicons/draw-text.png") ) );
2630
$self->{_factory}->add( 'shutter-censor', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file("$dicons/draw-censor.png") ) );
4433
$self->{_factory}->add( 'shutter-ellipse', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/draw-ellipse.png') ) );
4434
$self->{_factory}->add( 'shutter-eraser', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/draw-eraser.png') ) );
4435
$self->{_factory}->add( 'shutter-freehand', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/draw-freehand.png') ) );
4436
$self->{_factory}->add( 'shutter-highlighter', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/draw-highlighter.png') ) );
4437
$self->{_factory}->add( 'shutter-pointer', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/draw-pointer.png') ) );
4438
$self->{_factory}->add( 'shutter-rectangle', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/draw-rectangle.png') ) );
4439
$self->{_factory}->add( 'shutter-line', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/draw-line.png') ) );
4440
$self->{_factory}->add( 'shutter-arrow', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/draw-arrow.png') ) );
4441
$self->{_factory}->add( 'shutter-text', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/draw-text.png') ) );
4442
$self->{_factory}->add( 'shutter-censor', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/draw-censor.png') ) );
4443
$self->{_factory}->add( 'shutter-number', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/draw-number.png') ) );
4444
$self->{_factory}->add( 'shutter-crop', Gtk2::IconSet->new_from_pixbuf( Gtk2::Gdk::Pixbuf->new_from_file($self->{_dicons}.'/transform-crop.png') ) );
2631
4445
$self->{_factory}->add_default();
2633
my @default_actions = ( [ "File", undef, $d->get("_File") ], [ "Edit", undef, $d->get("_Edit") ], [ "View", undef, $d->get("_View") ] );
2635
my @menu_actions = (
2636
[ "Undo", 'gtk-undo', undef, "<control>Z", undef, sub { $self->undo } ],
2637
[ "Redo", 'gtk-redo', undef, "<control>Y", undef, sub { $self->redo } ],
2638
[ "Copy", 'gtk-copy', undef, "<control>C", undef, sub { $self->{_cut} = FALSE; $self->{_current_copy_item} = $self->{_current_item}; } ],
2639
[ "Cut", 'gtk-cut', undef, "<control>X", undef, sub { $self->{_cut} = TRUE; $self->{_current_copy_item} = $self->{_current_item}; $self->clear_item_from_canvas( $self->{_current_copy_item}); } ],
2640
[ "Paste", 'gtk-paste', undef, "<control>V", undef, sub { $self->paste_item($self->{_current_copy_item}, $self->{_cut} ); $self->{_cut} = FALSE; } ],
2641
[ "Delete", 'gtk-delete', undef, "Delete", undef, sub { $self->clear_item_from_canvas( $self->{_current_item}); } ],
2642
[ "Stop", 'gtk-stop', undef, "Escape", undef, sub { $self->abort_current_mode } ]
2646
my @menu_toggle_actions = (
2647
[ "Autoscroll", undef, $d->get("Automatic scrolling"), undef, undef, sub { my $widget = shift; $self->{_autoscroll} = $widget->get_active; }
2651
my @toolbar_actions = (
2652
[ "Close", 'gtk-close', undef, "<control>Q", undef, sub { $self->quit(TRUE) } ],
2653
[ "Save", 'gtk-save', undef, "<control>S", undef, sub { $self->save(), $self->quit(FALSE) } ],
2654
[ "ZoomIn", 'gtk-zoom-in', undef, "<control>plus", undef, sub { $self->zoom_in_cb($self) } ],
2655
[ "ControlEqual", 'gtk-zoom-in', undef, "<control>equal", undef, sub { $self->zoom_in_cb($self) } ],
2656
[ "ControlKpAdd", 'gtk-zoom-in', undef, "<control>KP_Add", undef, sub { $self->zoom_in_cb($self) } ],
2657
[ "ZoomOut", 'gtk-zoom-out', undef, "<control>minus", undef, sub { $self->zoom_out_cb($self) } ],
2658
[ "ControlKpSub", 'gtk-zoom-out', undef, "<control>KP_Subtract", undef, sub { $self->zoom_out_cb($self) } ],
2659
[ "ZoomNormal", 'gtk-zoom-100', undef, "<control>0", undef, sub { $self->zoom_normal_cb($self) } ]
2662
my @toolbar_drawing_actions = (
2663
[ "Select", 'shutter-pointer', undef, undef, $d->get("Select item to move or resize it"), 10 ],
2664
[ "Freehand", 'shutter-freehand', undef, undef, $d->get("Draw a freehand line"), 20 ],
2665
[ "Line", 'shutter-line', undef, undef, $d->get("Draw a straight line"), 30 ],
2666
[ "Rect", 'shutter-rectangle', undef, undef, $d->get("Draw a rectangle"), 40 ],
2667
[ "Ellipse", 'shutter-ellipse', undef, undef, $d->get("Draw a ellipse"), 50 ],
2668
[ "Text", 'shutter-text', undef, undef, $d->get("Add some text to the screenshot"), 60 ],
2669
[ "Censor", 'shutter-censor', undef, undef, $d->get("Censor portions of your screenshot to hide private data"), 70 ],
2670
[ "Clear", 'shutter-eraser', undef, undef, $d->get("Delete objects"), 80 ],
2671
[ "ClearAll",'gtk-clear', undef, undef, $d->get("Delete all objects"), 90 ]
4447
my @main_actions = (
4448
[ "File", undef, $self->{_d}->get("_File") ],
4449
[ "Edit", undef, $self->{_d}->get("_Edit") ],
4450
[ "View", undef, $self->{_d}->get("_View") ],
4451
[ "Undo", 'gtk-undo', undef, "<control>Z", undef, sub {
4452
$self->abort_current_mode; $self->xdo('undo');
4454
[ "Redo", 'gtk-redo', undef, "<control>Y", undef, sub {
4455
$self->abort_current_mode; $self->xdo('redo');
4457
[ "Copy", 'gtk-copy', undef, "<control>C", undef, sub {
4458
$self->{_cut} = FALSE;
4459
$self->{_current_copy_item} = $self->{_current_item};
4461
[ "Cut", 'gtk-cut', undef, "<control>X", undef, sub {
4462
$self->{_cut} = TRUE;
4463
$self->{_current_copy_item} = $self->{_current_item};
4464
$self->clear_item_from_canvas( $self->{_current_copy_item} );
4466
[ "Paste", 'gtk-paste', undef, "<control>V", undef, sub {
4467
$self->paste_item($self->{_current_copy_item}, $self->{_cut} ); $self->{_cut} = FALSE;
4469
[ "Delete", 'gtk-delete', undef, "Delete", undef, sub {
4470
$self->clear_item_from_canvas( $self->{_current_item} );
4472
[ "Clear", 'gtk-clear', undef, "<control>Delete", undef, sub {
4473
#store items to delete in temporary hash
4476
foreach (keys %{$self->{_items}}){
4477
$time_hash{$self->{_items}{$_}{uid}} = $self->{_items}{$_};
4481
foreach (sort keys %time_hash){
4482
$self->clear_item_from_canvas($time_hash{$_});
4485
[ "Stop", 'gtk-stop', undef, "Escape", undef, sub {
4486
$self->abort_current_mode
4488
[ "Close", 'gtk-close', undef, "<control>Q", undef, sub {
4491
[ "Save", 'gtk-save', undef, "<control>S", undef, sub {
4492
$self->save(), $self->quit(FALSE)
4494
[ "ZoomIn", 'gtk-zoom-in', undef, "<control>plus", undef, sub {
4495
$self->zoom_in_cb($self)
4497
[ "ControlEqual", 'gtk-zoom-in', undef, "<control>equal", undef, sub {
4498
$self->zoom_in_cb($self)
4500
[ "ControlKpAdd", 'gtk-zoom-in', undef, "<control>KP_Add", undef, sub {
4501
$self->zoom_in_cb($self)
4503
[ "ZoomOut", 'gtk-zoom-out', undef, "<control>minus", undef, sub {
4504
$self->zoom_out_cb($self)
4506
[ "ControlKpSub", 'gtk-zoom-out', undef, "<control>KP_Subtract", undef, sub {
4507
$self->zoom_out_cb($self)
4509
[ "ZoomNormal", 'gtk-zoom-100', undef, "<control>0", undef, sub {
4510
$self->zoom_normal_cb($self)
4514
my @toggle_actions = (
4515
[ "Autoscroll", undef, $self->{_d}->get("Automatic scrolling"), undef, undef,
4519
if($widget->get_active){
4520
$self->{_autoscroll} = TRUE;
4522
$self->{_autoscroll} = FALSE;
4525
#'redraw-when-scrolled' to reduce the flicker of static items
4527
#this property is not available in older versions
4528
#it was added to goocanvas on Mon Nov 17 10:28:07 2008 UTC
4529
#http://svn.gnome.org/viewvc/goocanvas?view=revision&revision=28
4530
if($self->{_canvas} && $self->{_canvas}->find_property ('redraw-when-scrolled')){
4531
$self->{_canvas}->set(
4532
'redraw-when-scrolled' => !$self->{_autoscroll}
4537
[ "Fullscreen", 'gtk-fullscreen', undef, "F11", undef,
4541
if($action->get_active){
4542
$self->{_drawing_window}->fullscreen
4544
$self->{_drawing_window}->unfullscreen
4550
my @drawing_actions = (
4551
[ "Select", 'shutter-pointer', undef, undef, $self->{_d}->get("Select item to move or resize it"), 10 ],
4552
[ "Freehand", 'shutter-freehand', undef, undef, $self->{_d}->get("Draw a freehand line"), 20 ],
4553
[ "Highlighter", 'shutter-highlighter', undef, undef, $self->{_d}->get("Highlighter"), 30 ],
4554
[ "Line", 'shutter-line', undef, undef, $self->{_d}->get("Draw a straight line"), 40 ],
4555
[ "Arrow", 'shutter-arrow', undef, undef, $self->{_d}->get("Draw an arrow"), 50 ],
4556
[ "Rect", 'shutter-rectangle', undef, undef, $self->{_d}->get("Draw a rectangle"), 60 ],
4557
[ "Ellipse", 'shutter-ellipse', undef, undef, $self->{_d}->get("Draw a ellipse"), 70 ],
4558
[ "Text", 'shutter-text', undef, undef, $self->{_d}->get("Add some text to the screenshot"), 80 ],
4559
[ "Censor", 'shutter-censor', undef, undef, $self->{_d}->get("Censor portions of your screenshot to hide private data"), 90 ],
4560
[ "Number", 'shutter-number', undef, undef, $self->{_d}->get("Add an auto-increment shape to the screenshot"), 100 ],
4561
[ "Crop", 'shutter-crop', undef, undef, $self->{_d}->get("Crop your screenshot"), 110 ]
2674
4564
my $uimanager = Gtk2::UIManager->new();
2767
4659
return $uimanager;
2770
sub ret_objects_menu {
4662
sub import_from_filesystem {
4666
#used when called recursively
4668
my $directory = shift;
2774
4670
my $menu_objects = Gtk2::Menu->new;
2776
my $d = $self->{_shutter_common}->get_gettext;
2778
my $dobjects = $self->{_shutter_common}->get_root . "/share/shutter/resources/icons/drawing_tool/objects";
4672
my $dobjects = $directory || $self->{_shutter_common}->get_root . "/share/shutter/resources/icons/drawing_tool/objects";
4674
#first directory flag (see description above)
2780
4678
my @objects = glob("$dobjects/*");
2781
foreach my $filename (@objects) {
4679
foreach my $name ( sort { -d $a <=> -d $b } @objects) {
2783
4681
#parse filename
2784
my ( $short, $folder, $type ) = fileparse( $filename, '\..*' );
2789
$orig_pixbuf = Gtk2::Gdk::Pixbuf->new_from_file($filename);
2793
my $small_image = Gtk2::Image->new_from_pixbuf( $orig_pixbuf->scale_down_pixbuf (Gtk2::IconSize->lookup('menu')));
2794
#~ my $small_image_button = Gtk2::Image->new_from_pixbuf( $orig_pixbuf->scale_down_pixbuf (Gtk2::IconSize->lookup('menu')));
2795
my $small_image_button = Gtk2::Image->new_from_pixbuf( $small_image->get_pixbuf );
2798
my $new_item = Gtk2::ImageMenuItem->new_with_label($short);
2799
$new_item->set_image($small_image);
2801
#~ &fct_load_pixbuf_async ($small_image, $filename, $new_item);
2804
unless ( $button->get_icon_widget ) {
2805
$button->set_icon_widget($small_image_button);
2806
$self->{_current_pixbuf} = $orig_pixbuf->copy;
2807
$self->{_current_pixbuf_filename} = $filename;
2810
$new_item->signal_connect(
2812
$self->{_current_pixbuf} = $orig_pixbuf->copy;
2813
$self->{_current_pixbuf_filename} = $filename;
2814
$button->set_icon_widget($small_image_button);
2816
$self->{_canvas}->window->set_cursor( $self->change_cursor_to_current_pixbuf );
2820
$menu_objects->append($new_item);
2823
my $response = $self->{_dialogs}->dlg_error_message(
2824
sprintf( $d->get("Error while opening image %s."), "'" . $filename . "'" ),
2825
$d->get( "There was an error opening the image." ),
2826
undef, undef, undef,
2827
undef, undef, undef,
2834
$menu_objects->append( Gtk2::SeparatorMenuItem->new );
2836
#objects from session
2837
my $session_menu_item = Gtk2::MenuItem->new_with_label( $d->get("Import from session...") );
2838
$session_menu_item->set_submenu( $self->import_from_session($button) );
2840
$menu_objects->append($session_menu_item);
2842
#objects from filesystem
2843
my $filesystem_menu_item = Gtk2::MenuItem->new_with_label( $d->get("Import from filesystem...") );
2844
$filesystem_menu_item->signal_connect(
2847
my $fs = Gtk2::FileChooserDialog->new(
2848
$d->get("Choose file to open"), $self->{_drawing_window}, 'open',
2849
'gtk-cancel' => 'reject',
2850
'gtk-open' => 'accept'
2853
$fs->set_select_multiple(FALSE);
2855
my $filter_all = Gtk2::FileFilter->new;
2856
$filter_all->set_name( $d->get("All compatible image formats") );
2857
$fs->add_filter($filter_all);
2859
foreach ( Gtk2::Gdk::Pixbuf->get_formats ) {
2860
my $filter = Gtk2::FileFilter->new;
2861
$filter->set_name( $_->{name} . " - " . $_->{description} );
2862
foreach ( @{ $_->{extensions} } ) {
2863
$filter->add_pattern( "*." . uc $_ );
2864
$filter_all->add_pattern( "*." . uc $_ );
2865
$filter->add_pattern( "*." . $_ );
2866
$filter_all->add_pattern( "*." . $_ );
2868
$fs->add_filter($filter);
2871
if ( $ENV{'HOME'} ) {
2872
$fs->set_current_folder( $ENV{'HOME'} );
2874
my $fs_resp = $fs->run;
2877
if ( $fs_resp eq "accept" ) {
2878
$new_file = $fs->get_filenames;
2881
my $small_image = Gtk2::Image->new_from_stock( 'gtk-new', 'menu' );
2882
my $small_image_button = Gtk2::Image->new_from_stock( 'gtk-new', 'menu' );
2886
$orig_pixbuf = Gtk2::Gdk::Pixbuf->new_from_file($new_file);
2888
#check if there is any error while loading this file
2890
$self->{_current_pixbuf} = $orig_pixbuf->copy;
2891
$self->{_current_pixbuf_filename} = $new_file;
2892
$button->set_icon_widget($small_image_button);
2894
$self->{_canvas}->window->set_cursor( $self->change_cursor_to_current_pixbuf );
2896
my $response = $self->{_dialogs}->dlg_error_message(
2897
sprintf( $d->get("Error while opening image %s."), "'" . $new_file. "'"),
2898
$d->get( "There was an error opening the image." ),
2899
undef, undef, undef,
2900
undef, undef, undef,
2913
$menu_objects->append($filesystem_menu_item);
4682
my ( $short, $folder, $type ) = fileparse( $name, '\..*' );
4684
#if current object is a directory we call the current sub
4688
#objects from each directory are sorted (files first)
4689
#we display a separator when the first directory is listed
4691
$menu_objects->append( Gtk2::SeparatorMenuItem->new );
4695
#objects from directory $name
4696
my $subdir_item = Gtk2::ImageMenuItem->new_with_label( $short );
4697
$subdir_item->set_image (Gtk2::Image->new_from_stock ('gtk-directory', 'menu'));
4699
#add empty menu first
4700
my $menu_empty = Gtk2::Menu->new;
4701
my $empty_item = Gtk2::MenuItem->new_with_label( $self->{_d}->get("No icon was found") );
4702
$empty_item->set_sensitive(FALSE);
4703
$menu_empty->append($empty_item);
4704
$subdir_item->set_submenu( $menu_empty );
4706
#and populate later (performance)
4707
$subdir_item->{'nid'} = $subdir_item->signal_connect('activate' => sub {
4708
$subdir_item->set_image(Gtk2::Image->new_from_file($self->{_icons}."/throbber_16x16.gif"));
4709
my $submenu = $self->import_from_filesystem($button, $subdir_item, $dobjects . "/$short");
4711
if($submenu->get_children){
4713
$subdir_item->set_submenu( $submenu );
4717
$subdir_item->set_image (Gtk2::Image->new_from_stock ('gtk-directory', 'menu'));
4725
#diconnect handler when this event occurs
4726
$subdir_item->signal_connect('leave-notify-event' => sub {
4727
if($subdir_item->signal_handler_is_connected ($subdir_item->{'nid'})){
4728
$subdir_item->signal_handler_disconnect($subdir_item->{'nid'});
4732
$menu_objects->append($subdir_item);
4736
#there is at least one single file
4740
#init item with filename first
4741
my $new_item = Gtk2::ImageMenuItem->new_with_label($short);
4742
$menu_objects->append($new_item);
4745
$new_item->{'name'} = $name;
4749
#do not do that when called recursively
4753
$menu_objects->append( Gtk2::SeparatorMenuItem->new );
4755
#objects from icontheme
4756
if (Gtk2->CHECK_VERSION( 2, 12, 0 )){
4757
my $icontheme = Gtk2::IconTheme->get_default;
4759
my $utheme_item = Gtk2::ImageMenuItem->new_with_label( $self->{_d}->get("Import from current theme...") );
4760
if($icontheme->has_icon('preferences-desktop-theme')){
4761
$utheme_item->set_image(Gtk2::Image->new_from_icon_name( 'preferences-desktop-theme', 'menu' ));
4764
$utheme_item->set_submenu( $self->import_from_utheme($icontheme, $button) );
4766
$menu_objects->append( $utheme_item );
4768
$menu_objects->append( Gtk2::SeparatorMenuItem->new );
4771
#objects from session
4772
my $session_menu_item = Gtk2::ImageMenuItem->new_with_label( $self->{_d}->get("Import from session...") );
4773
$session_menu_item->set_image (Gtk2::Image->new_from_stock ('gtk-index', 'menu'));
4774
$session_menu_item->set_submenu( $self->import_from_session($button) );
4776
#gen thumbnails in an idle callback
4777
$self->gen_thumbnail_on_idle('gtk-index', $session_menu_item, $button, TRUE, $session_menu_item->get_submenu->get_children);
4779
$menu_objects->append($session_menu_item);
4781
#objects from filesystem
4782
my $filesystem_menu_item = Gtk2::ImageMenuItem->new_with_label( $self->{_d}->get("Import from filesystem...") );
4783
$filesystem_menu_item->set_image (Gtk2::Image->new_from_stock ('gtk-open', 'menu'));
4784
$filesystem_menu_item->signal_connect(
4787
my $fs = Gtk2::FileChooserDialog->new(
4788
$self->{_d}->get("Choose file to open"), $self->{_drawing_window}, 'open',
4789
'gtk-cancel' => 'reject',
4790
'gtk-open' => 'accept'
4793
$fs->set_select_multiple(FALSE);
4795
my $filter_all = Gtk2::FileFilter->new;
4796
$filter_all->set_name( $self->{_d}->get("All compatible image formats") );
4797
$fs->add_filter($filter_all);
4799
foreach ( Gtk2::Gdk::Pixbuf->get_formats ) {
4800
my $filter = Gtk2::FileFilter->new;
4801
$filter->set_name( $_->{name} . " - " . $_->{description} );
4802
foreach ( @{ $_->{extensions} } ) {
4803
$filter->add_pattern( "*." . uc $_ );
4804
$filter_all->add_pattern( "*." . uc $_ );
4805
$filter->add_pattern( "*." . $_ );
4806
$filter_all->add_pattern( "*." . $_ );
4808
$fs->add_filter($filter);
4811
if ( $ENV{'HOME'} ) {
4812
$fs->set_current_folder( $ENV{'HOME'} );
4814
my $fs_resp = $fs->run;
4817
if ( $fs_resp eq "accept" ) {
4818
$new_file = $fs->get_filenames;
4821
$self->{_current_pixbuf} = Gtk2::Gdk::Pixbuf->new_from_file($new_file);
4823
#check if there is any error while loading this file
4825
$self->{_current_pixbuf_filename} = $new_file;
4826
$button->set_icon_widget(Gtk2::Image->new_from_pixbuf(Gtk2::Gdk::Pixbuf->new_from_file_at_size($self->{_dicons}.'/draw-image.svg', Gtk2::IconSize->lookup('menu'))));
4828
$self->{_canvas}->window->set_cursor( $self->change_cursor_to_current_pixbuf );
4830
my $response = $self->{_dialogs}->dlg_error_message(
4831
sprintf( $self->{_d}->get("Error while opening image %s."), "'" . $new_file. "'"),
4832
$self->{_d}->get( "There was an error opening the image." ),
4833
undef, undef, undef,
4834
undef, undef, undef,
4837
$self->abort_current_mode;
4848
$menu_objects->append($filesystem_menu_item);
2915
4852
$button->show_all;
2916
4853
$menu_objects->show_all;
4855
#generate thumbnails in an idle callback
4856
$self->gen_thumbnail_on_idle('gtk-directory', $parent, $button, FALSE, $menu_objects->get_children);
2918
4858
return $menu_objects;
2921
#~ sub fct_load_pixbuf_async {
2926
#~ my $image = shift;
2927
#~ my $filename = shift;
2928
#~ my $menu_item = shift;
2930
#~ my $loader = Gtk2::Gdk::PixbufLoader->new;
2931
#~ my $handle = Gnome2::VFS::Async->open_uri (Gnome2::VFS::URI->new ($filename), 'read', 10, \&fct_open_async, $loader);
2933
#~ $loader->signal_connect('closed' => sub{
2934
#~ print "closed\n";
2935
#~ $image->set_from_pixbuf($loader->get_pixbuf);
2936
#~ $menu_item->set_image($image);
2937
#~ $image->show_all;
2938
#~ $menu_item->show_all;
2941
#~ $loader->signal_connect('area-updated' => sub{
2942
#~ print "updated\n";
2943
#~ $image->set_from_pixbuf($loader->get_pixbuf);
2944
#~ $image->show_all;
2945
#~ $menu_item->set_image($image);
2946
#~ $menu_item->show_all;
2952
#~ sub fct_open_async {
2956
#~ my $handle = shift;
2957
#~ my $result = shift;
2958
#~ my $loader = shift;
2960
#~ if($result eq 'ok'){
2961
#~ $handle->read (10000, \&fct_read_async, $loader);
2963
#~ print "Error!\n";
2964
#~ $handle->close(\&fct_close_async, $loader);
2969
#~ sub fct_read_async {
2973
#~ my $handle = shift;
2974
#~ my $result = shift;
2975
#~ my $buffer = shift;
2976
#~ my $size = shift;
2977
#~ my $size2 = shift;
2978
#~ my $loader = shift;
2980
#~ if($result eq 'ok'){
2981
#~ $loader->write($buffer);
2982
#~ $handle->read(10000, \&fct_read_async, $loader);
2984
#~ $handle->close(\&fct_close_async, $loader);
2988
#~ sub fct_close_async {
2992
#~ my $handle = shift;
2993
#~ my $result = shift;
2994
#~ my $loader = shift;
4861
sub import_from_utheme {
4863
my $icontheme = shift;
4866
my $menu_ctxt = Gtk2::Menu->new;
4868
foreach my $context (sort $icontheme->list_contexts){
4870
#objects from current theme (contexts)
4871
my $utheme_ctxt = Gtk2::ImageMenuItem->new_with_label( $context );
4872
$utheme_ctxt->set_image (Gtk2::Image->new_from_stock ('gtk-directory', 'menu'));
4874
#add empty menu first
4875
my $menu_empty = Gtk2::Menu->new;
4876
my $empty_item = Gtk2::MenuItem->new_with_label( $self->{_d}->get("No icon was found") );
4877
$empty_item->set_sensitive(FALSE);
4878
$menu_empty->append($empty_item);
4879
$utheme_ctxt->set_submenu( $menu_empty );
4881
#and populate later (performance)
4883
$utheme_ctxt->{'nid'} = $utheme_ctxt->signal_connect('activate' => sub {
4885
$utheme_ctxt->set_image(Gtk2::Image->new_from_file($self->{_icons}."/throbber_16x16.gif"));
4886
my $context_submenu = $self->import_from_utheme_ctxt($icontheme, $context, $button);
4888
if($context_submenu->get_children){
4890
$utheme_ctxt->set_submenu( $context_submenu );
4892
#gen thumbnails in an idle callback
4893
$self->gen_thumbnail_on_idle('gtk-directory', $utheme_ctxt, $button, TRUE, $utheme_ctxt->get_submenu->get_children);
4896
$utheme_ctxt->set_image (Gtk2::Image->new_from_stock ('gtk-directory', 'menu'));
4902
#disconnect handler when this event occurs
4903
$utheme_ctxt->signal_connect('leave-notify-event' => sub {
4904
if($utheme_ctxt->signal_handler_is_connected ($utheme_ctxt->{'nid'})){
4905
$utheme_ctxt->signal_handler_disconnect($utheme_ctxt->{'nid'});
4910
$menu_ctxt->append($utheme_ctxt);
4914
$menu_ctxt->show_all;
4919
sub import_from_utheme_ctxt {
4921
my $icontheme = shift;
4922
my $context = shift;
4925
my $menu_ctxt_items = Gtk2::Menu->new;
4927
my $size = Gtk2::IconSize->lookup('dialog');
4929
foreach my $icon (sort $icontheme->list_icons($context)){
4931
#objects from current theme (icons for specific contexts)
4932
my $utheme_ctxt_item = Gtk2::ImageMenuItem->new_with_label( $icon );
4933
my $iconinfo = $icontheme->lookup_icon ($icon, $size, 'generic-fallback');
4935
#save filename and generate thumbnail later
4937
$utheme_ctxt_item->{'name'} = $iconinfo->get_filename;
4939
$menu_ctxt_items->append($utheme_ctxt_item);
4942
$menu_ctxt_items->show_all;
4944
return $menu_ctxt_items;
3000
4947
sub import_from_session {
3003
4951
my $menu_session_objects = Gtk2::Menu->new;
3005
my $d = $self->{_shutter_common}->get_gettext;
3007
4953
my %import_hash = %{ $self->{_import_hash} };
3009
foreach my $key ( sort keys %import_hash ) {
3013
$orig_pixbuf = Gtk2::Gdk::Pixbuf->new_from_file( $import_hash{$key}->{'long'} );
3017
#try to generate a new thumbnail
3018
my $thumb = $self->{_thumbs}->get_thumbnail(
3019
$import_hash{$key}->{'uri'}->to_string,
3020
$import_hash{$key}->{'mime_type'},
3021
$import_hash{$key}->{'mtime'},
3025
my $small_image = Gtk2::Image->new_from_pixbuf( $thumb );
3026
#~ my $small_image_button = Gtk2::Image->new_from_pixbuf( $orig_pixbuf->scale_down_pixbuf (Gtk2::IconSize->lookup('menu')));
3027
my $small_image_button = Gtk2::Image->new_from_pixbuf( $small_image->get_pixbuf );
3029
my $screen_menu_item = Gtk2::ImageMenuItem->new_with_label( $import_hash{$key}->{'short'} );
3030
$screen_menu_item->set_image($small_image);
3032
#set sensitive == FALSE if image eq current file
3033
$screen_menu_item->set_sensitive(FALSE)
3034
if $import_hash{$key}->{'long'} eq $self->{_filename};
3036
$screen_menu_item->signal_connect(
3038
$self->{_current_pixbuf} = $orig_pixbuf->copy;
3039
$self->{_current_pixbuf_filename} = $import_hash{$key}->{'long'};
3040
$button->set_icon_widget($small_image_button);
3042
$self->{_canvas}->window->set_cursor( $self->change_cursor_to_current_pixbuf );
3046
$menu_session_objects->append($screen_menu_item);
3049
my $response = $self->{_dialogs}->dlg_error_message(
3050
sprintf( $d->get("Error while opening image %s."), "'" . $import_hash{$key}->{'long'} . "'" ),
3051
$d->get( "There was an error opening the image." ),
3052
undef, undef, undef,
3053
undef, undef, undef,
4955
foreach my $key ( Sort::Naturally::nsort(keys %import_hash) ) {
4957
#init item with filename
4958
my $screen_menu_item = Gtk2::ImageMenuItem->new_with_label( $import_hash{$key}->{'short'} );
4960
#set sensitive == FALSE if image eq current file
4961
$screen_menu_item->set_sensitive(FALSE)
4962
if $import_hash{$key}->{'long'} eq $self->{_filename};
4964
#save filename and attributes
4965
$screen_menu_item->{'name'} = $import_hash{$key}->{'long'};
4966
$screen_menu_item->{'mime_type'} = $import_hash{$key}->{'mime_type'};
4967
$screen_menu_item->{'mtime'} = $import_hash{$key}->{'mtime'};
4968
$screen_menu_item->{'uri'} = $import_hash{$key}->{'uri'};
4970
$menu_session_objects->append($screen_menu_item);
3060
4973
$menu_session_objects->show_all;