Re: Editor application with grid



On Sun, 17 Sep 2006 03:09:16 +0200
Dieter Schicker <dieter schicker uni-graz at> wrote:

I'm planning to implement an editor application where I want to give
users the ability to drag together different types of widgets on a grid.
I wanted to do it in Java, but now after some weeks of experience with
gtk perl I would really like to implement it with Gtk. 

Has anybody done something similar already? Any hints?

Anytime I hear the word "drag", I think to use the Canvas.
It's pretty easy to drag items on a canvas, then detect what
occupies a certain rectangular region. But you said 
"drag together different types of widgets", which is a harder
problem. 
Here is a simple example which I ripped from the canvas demo.
I use ellipses, but you could use text items instead.
You could also add "data-riders" to each item (similar to tags),
to move groups of items together, that would be a bit more complex.

Otherwise, there is the "testdnd" script in the examples subdir
of the Gtk2 module.

#!/usr/bin/perl
use warnings;
use strict;
use Gnome2::Canvas;
use Gtk2::Gdk::Keysyms;
use Glib qw(TRUE FALSE);
use constant M_PI => 3.141529;

# control anti-aliasing by setting a 0 or 1
my $aa = 1;  # 0 for no anti-alias

sub zoom_changed {
        my ($adj, $canvas) = @_;
        $canvas->set_pixels_per_unit ($adj->value);
}

my $dragging = FALSE;
my ($x, $y);

sub item_event {
        my ($item, $event) = @_;

        # set item_[xy] to the event x,y position in the parent's
        # item-relative coordinates
        my ($item_x, $item_y) = $item->parent->w2i ($event->coords);

        if ($event->type eq 'button-press') {
                if ($event->button == 1) {
                        if ($event->state >= 'shift-mask') {
                                $item->destroy;
                        } else {
                                $x = $item_x;
                                $y = $item_y;

                                $item->grab ([qw/pointer-motion-mask
                                                 button-release-mask/],
                                             Gtk2::Gdk::Cursor->new ('fleur'),
                                            $event->time);

                                $dragging = TRUE;
                        }
                } elsif ($event->button == 2) {
                        if ($event->state >= 'shift-mask') {
                                $item->lower_to_bottom;
                        } else {
                                $item->lower (1);
                        }
                } elsif ($event->button == 3) {
                        if ($event->state >= 'shift-mask') {
                                $item->raise_to_top;
                        } else {
                                $item->raise (1);
                        }
                }

        } elsif ($event->type eq 'motion-notify') {
                if ($dragging && $event->state >= 'button1-mask') {
                        my $new_x = $item_x;
                        my $new_y = $item_y;

                        $item->move ($new_x - $x, $new_y - $y);
                        $x = $new_x;
                        $y = $new_y;
                }

        } elsif ($event->type eq 'button-release') {
                $item->ungrab ($event->time);
                $dragging = FALSE;
        }

        return FALSE;
}


sub setup_item {
        my $item = shift;
        $item->signal_connect (event => \&item_event);
}


my $gray50_width = 2;
my $gray50_height = 2;
my $gray50_bits = pack "CC", 0x02, 0x01;


sub setup_ellipses {
        my $root = shift;

        if ($root->canvas->aa) {
                setup_item (Gnome2::Canvas::Item->new ($root,
                                                   'Gnome2::Canvas::Ellipse',
                                                   "x1", 210.0,
                                                   "y1", 80.0,
                                                   "x2", 280.0,
                                                   "y2", 140.0,
                                                    "fill_color_rgba", 0x3cb37180,
                                                   "outline_color", "black",
                                                   "width_pixels", 0));
        } else {
                my $stipple = Gtk2::Gdk::Bitmap->create_from_data
                        (undef, $gray50_bits, $gray50_width, $gray50_height);
                setup_item (Gnome2::Canvas::Item->new ($root,
                                                   'Gnome2::Canvas::Ellipse',
                                                   "x1", 210.0,
                                                   "y1", 80.0,
                                                   "x2", 280.0,
                                                   "y2", 140.0,
                                                   "fill_color", "cadetblue",
                                                   "fill_stipple", $stipple,
                                                   "outline_color", "black",
                                                   "width_pixels", 0));
        }


if ($root->canvas->aa) {
                setup_item (Gnome2::Canvas::Item->new ($root,
                                                   'Gnome2::Canvas::Ellipse',
                                                   "x1", 310.0,
                                                   "y1", 80.0,
                                                   "x2", 380.0,
                                                   "y2", 140.0,
                                                   "fill_color_rgba", 0xb3713c80,
                                                   "outline_color", "black",
                                                   "width_pixels", 0));
        } else {
                my $stipple = Gtk2::Gdk::Bitmap->create_from_data
                        (undef, $gray50_bits, $gray50_width, $gray50_height);
                setup_item (Gnome2::Canvas::Item->new ($root,
                                                   'Gnome2::Canvas::Ellipse',
                                                   "x1", 310.0,
                                                   "y1", 80.0,
                                                   "x2", 380.0,
                                                   "y2", 140.0,
                                                   "fill_color", "brown",
                                                   "fill_stipple", $stipple,
                                                   "outline_color", "black",
                                                   "width_pixels", 0));
        }


        if ($root->canvas->aa) {
                setup_item (Gnome2::Canvas::Item->new ($root,
                                                   'Gnome2::Canvas::Ellipse',
                                                   "x1", 210.0,
                                                   "y1", 180.0,
                                                   "x2", 280.0,
                                                   "y2", 240.0,
                                                   "fill_color_rgba", 0x5f9ea080,
                                                   "outline_color", "black",
                                                   "width_pixels", 0));
        } else {
                my $stipple = Gtk2::Gdk::Bitmap->create_from_data
                        (undef, $gray50_bits, $gray50_width, $gray50_height);
                setup_item (Gnome2::Canvas::Item->new ($root,
                                                   'Gnome2::Canvas::Ellipse',
                                                   "x1", 210.0,
                                                   "y1", 180.0,
                                                   "x2", 280.0,
                                                   "y2", 240.0,
                                                   "fill_color", "green",
                                                   "fill_stipple", $stipple,
                                                   "outline_color", "black",
                                                   "width_pixels", 0));
        }


if ($root->canvas->aa) {
                setup_item (Gnome2::Canvas::Item->new ($root,
                                                   'Gnome2::Canvas::Ellipse',
                                                   "x1", 310.0,
                                                   "y1", 180.0,
                                                   "x2", 380.0,
                                                   "y2", 240.0,
                                                   "fill_color_rgba", 0xff9ea080,
                                                   "outline_color", "black",
                                                   "width_pixels", 0));
        } else {
                my $stipple = Gtk2::Gdk::Bitmap->create_from_data
                        (undef, $gray50_bits, $gray50_width, $gray50_height);
                setup_item (Gnome2::Canvas::Item->new ($root,
                                                   'Gnome2::Canvas::Ellipse',
                                                   "x1", 310.0,
                                                   "y1", 180.0,
                                                   "x2", 380.0,
                                                   "y2", 240.0,
                                                   "fill_color", "pink",
                                                   "fill_stipple", $stipple,
                                                   "outline_color", "black",
                                                   "width_pixels", 0));
        }

}



use constant VERTICES => 10;
use constant RADIUS   => 60.0;


use constant SCALE => 7.0;


sub key_press {
        my ($canvas, $event) = @_;

        my ($x, $y) = $canvas->get_scroll_offsets;

        if ($event->keyval == $Gtk2::Gdk::Keysyms{Up}) {
                $canvas->scroll_to ($x, $y - 20);
        } elsif ($event->keyval == $Gtk2::Gdk::Keysyms{Down}) {
                $canvas->scroll_to ($x, $y + 20);
        } elsif ($event->keyval == $Gtk2::Gdk::Keysyms{Left}) {
                $canvas->scroll_to ($x - 10, $y);
        } elsif ($event->keyval == $Gtk2::Gdk::Keysyms{Right}) {
                $canvas->scroll_to ($x + 10, $y);
        } else {
                return FALSE;
        }

        return TRUE;
}

sub create {
        my $aa = shift;

        my $vbox = Gtk2::VBox->new (FALSE, 4);
        $vbox->set_border_width (4);
        $vbox->show;

        my $w = Gtk2::Label->new ("Drag an item with button 1.  Click button 2 on an item to lower it,\n"
                        . "or button 3 to raise it.  Shift+click with buttons 2 or 3 to send\n"
                        . "an item to the bottom or top, respectively.");
        $vbox->pack_start ($w, FALSE, FALSE, 0);
        $w->show;

        my $hbox = Gtk2::HBox->new (FALSE, 4);
        $vbox->pack_start ($hbox, FALSE, FALSE, 0);
        $hbox->show;

        # Create the canvas

        #gtk_widget_push_colormap (gdk_rgb_get_cmap ());
#### FIXME
###     Gtk2::Widget->push_colormap (Gtk2::Gdk::Rgb->get_cmap);
        my $canvas = $aa ? Gnome2::Canvas->new_aa : Gnome2::Canvas->new;

        my $white = Gtk2::Gdk::Color->new (0xFFFF,0xFFFF,0xFFFF);
        $canvas->modify_bg('normal',$white);

        $canvas->set_center_scroll_region (FALSE);

        # Setup canvas items

        my $root = $canvas->root;

        setup_ellipses ($root);

        # Zoom

        $w = Gtk2::Label->new ("Zoom:");
        $hbox->pack_start ($w, FALSE, FALSE, 0);
        $w->show;

        my $adj = Gtk2::Adjustment->new (1.00, 0.05, 5.00, 0.05, 0.50, 0.50);
        $adj->signal_connect (value_changed => \&zoom_changed, $canvas);
        $w = Gtk2::SpinButton->new ($adj, 0.0, 2);
        $w->set_size_request (50, -1);
        $hbox->pack_start ($w, FALSE, FALSE, 0);
        $w->show;

        # Layout the stuff

        my $table = Gtk2::Table->new (2, 2, FALSE);
        $table->set_row_spacings (4);
        $table->set_col_spacings (4);
        $vbox->pack_start ($table, TRUE, TRUE, 0);
        $table->show;

        my $frame = Gtk2::Frame->new;
        $frame->set_shadow_type ('in');
        $table->attach ($frame,
                        0, 1, 0, 1,
                        [qw/expand fill shrink/],
                        [qw/expand fill shrink/],
                        0, 0);
        $frame->show;

        $canvas->set_size_request (600, 450);
        $canvas->set_scroll_region (0, 0, 600, 450);
        $frame->add ($canvas);
        $canvas->show;

        $canvas->signal_connect_after (key_press_event => \&key_press);

        $w = Gtk2::HScrollBar->new ($canvas->get_hadjustment);
        $table->attach ($w,
                        0, 1, 1, 2,
                        [qw/expand fill shrink/],
                        [qw/fill/],
                        0, 0);
        $w->show;;

        $w = Gtk2::VScrollBar->new ($canvas->get_vadjustment);
        $table->attach ($w,
                        1, 2, 0, 1,
                        ['fill'],
                        [qw/expand fill shrink/],
                        0, 0);
        $w->show;

        $canvas->set_flags ('can-focus');
        $canvas->grab_focus;

        return $vbox;
}


Gtk2->init;

my $mw = Gtk2::Window->new;

$mw->signal_connect (delete_event => sub { Gtk2->main_quit; 1 });

$mw->add( create($aa) );  # 0 no anti-alias , 1 yes

$mw->show;

Gtk2->main;
__END__


 

-- 
I'm not really a human, but I play one on earth.
http://zentara.net/japh.html



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]