Motion events in a DrawingArea

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Motion events in a DrawingArea

Daniel Kasak-4
Hi all.

I'm trying to capture mouse events in a DrawingArea ( in Gtk3 ). I'm
adapting code at http://www.perlmonks.org/?node_id=583578 ... but when
I go:

$self->{drawing_area}->set_events(
    [ qw/   exposure-mask
            leave-notify-mask
            button-press-mask
            pointer-motion-mask
            pointer-motion-hint-mask
        /
    ]
);

 ... I get a warning:

Gtk-CRITICAL **: gtk_widget_set_events: assertion
'!_gtk_widget_get_realized (widget)' failed

I've tried putting this later on in the code when I guess the widget
*should* be realized, eg at the end of the render_graph() method which
I hook up thus:

$self->{drawing_area}->signal_connect( draw => sub {
$self->render_graph( @_ ) } );

 ... but it still gives the same error.

Next I try to connect to a signal handler anyway:

$self->{drawing_area}->signal_connect(
    'motion_notify_event'
  , sub { $self->handle_graph_mouse_move( @_ ) }
);

 ... but this handler never gets called.

I guess things have changed in Gtk3? I haven't been able to find an
updated demo, even in C. Any hints as to what I'm missing?

Dan
_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Motion events in a DrawingArea

oldtechaa
You can just set up an anonymous signal handler like below:

$window->signal_connect(
        'realize' => sub {
            $window->set_events(
                [
                    'button-press-mask', 'button-motion-mask',
                    'button-release-mask'
                ]
         );
}

This will request the events only when you can be sure the window is realized.

oldtechaa


On Aug 16, 2017 8:12 AM, "Daniel Kasak" <[hidden email]> wrote:
Hi all.

I'm trying to capture mouse events in a DrawingArea ( in Gtk3 ). I'm
adapting code at http://www.perlmonks.org/?node_id=583578 ... but when
I go:

$self->{drawing_area}->set_events(
    [ qw/   exposure-mask
            leave-notify-mask
            button-press-mask
            pointer-motion-mask
            pointer-motion-hint-mask
        /
    ]
);

 ... I get a warning:

Gtk-CRITICAL **: gtk_widget_set_events: assertion
'!_gtk_widget_get_realized (widget)' failed

I've tried putting this later on in the code when I guess the widget
*should* be realized, eg at the end of the render_graph() method which
I hook up thus:

$self->{drawing_area}->signal_connect( draw => sub {
$self->render_graph( @_ ) } );

 ... but it still gives the same error.

Next I try to connect to a signal handler anyway:

$self->{drawing_area}->signal_connect(
    'motion_notify_event'
  , sub { $self->handle_graph_mouse_move( @_ ) }
);

 ... but this handler never gets called.

I guess things have changed in Gtk3? I haven't been able to find an
updated demo, even in C. Any hints as to what I'm missing?

Dan
_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list


_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Motion events in a DrawingArea

Gtk+ - Perl mailing list
Daniel Kasak <[hidden email]> writes:
>
> $self->{drawing_area}->set_events(

Gtk 2 is ->add_events() usually from INIT_INSTANCE to have extra events
selected when realized, if that's still so.
_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Motion events in a DrawingArea

Daniel Kasak-4
In reply to this post by Daniel Kasak-4
Thanks Torsten.

I've gotten closer, and also reduced my app down to a minimal example
- see below.

So what's happening now is that my callback is being called, but
*only* when I click+drag inside the drawing area. Is there a different
signal that will fire for *just* mouse movements?

In the example, you can ignore the render_graph() and
draw_graph_text() methods - I left them there just so there was
*something* being rendered.

Dan

---

#!/usr/bin/perl

use strict;
use warnings FATAL => 'all';

use Gtk3 -init;
use Pango;

my $window = Gtk3::Window->new;
$window->set_title('drawing area');
$window->signal_connect( destroy => sub { Gtk3->main_quit } );

my $drawing_area = Gtk3::DrawingArea->new;
$drawing_area->set_size_request( 600, 300 );
$drawing_area->signal_connect( draw => sub { render_graph( @_ ) } );

$drawing_area->set_events(
    [ qw/   exposure-mask
            leave-notify-mask
            button-press-mask
            motion_notify_event
            pointer-motion-mask
            pointer-motion-hint-mask
        /
    ]
);

$drawing_area->signal_connect(
    'motion_notify_event'
  , sub { handle_graph_mouse_move( @_ ) }
);

$window->add( $drawing_area );

$window->show_all;

Gtk3->main();

sub render_graph {

    my ( $widget, $cairo_context ) = @_;

    use constant  NO_OF_GRAPHS  => 1;
    use constant  GRAPH_NO      => 1;

    my $surface = $cairo_context->get_target;

    # Create a white backing for the graphs
    $cairo_context->set_source_rgb( 0, 0, 0 );

    my $total_width  = $widget->get_allocated_width;
    my $total_height = $widget->get_allocated_height;
    my $graph_area_height = $total_height;

    my $ac_power_y_scale       = $graph_area_height / ( 3000 ) / NO_OF_GRAPHS;
    my $y_segment = 1;

    print "==================================\n";
    print "total height: $total_height\n";
    print "==================================\n";

    my $earliest_sec = 0 * 3600;
    my $latest_sec   = 24 * 3600;
    my $sec_scale    = $total_width / ( $latest_sec - $earliest_sec );

    $cairo_context->rectangle( 0, 0, $total_width, $total_height );
    $cairo_context->fill;

    $cairo_context->set_source_rgb( 255, 255, 255 );

    # Now render the X & Y axis labels and partitioning lines
    my $line_context = Cairo::Context->create( $surface );
    $line_context->set_source_rgba( 1, 1, 1, 0.2 );
    $line_context->set_line_width( 3 );

    for ( my $hour = 0; $hour <= 24; $hour++ ) {

        my $secs_past_earliest = ( $hour * 3600 ) - $earliest_sec;
        my $this_x = $secs_past_earliest * $sec_scale;

        # For the text label, the X value we pass into
$self->draw_graph_text is where it starts rendering text.
        # We want the text centered around $this_x ... which is
different for 1 & 2 digit numbers ...
        my $label_x_offset = $hour < 10 ? -3 : -8;

        draw_graph_text( $cairo_context, $hour, 0, $this_x +
$label_x_offset, $total_height - 20 );

        # white line
        #        $cairo_context->set_source_rgb( 255, 255, 255 );
        #        $cairo_context->rectangle( $this_x, $total_height, 5, 0 );
        #        $cairo_context->fill;

        $line_context->move_to( $this_x, $total_height - 23 );
        $line_context->line_to( $this_x, 0 );
        $line_context->line_to( $this_x + 1, 0);
        $line_context->line_to( $this_x + 1, $total_height - 23 );
        $line_context->line_to( $this_x, $total_height - 23 );
        $line_context->fill;

    }

    $cairo_context->set_source_rgb( 255, 255, 255 );

    # kw scale
    print "Rendering POWER axis ticks ...\n";

    my $tick_increment = 3000 / 4;
    foreach my $tick_no ( 1, 2, 3, 4 ) {

        my $this_tick_value = $tick_no * $tick_increment;
        my $y = ( $y_segment * GRAPH_NO ) - ( $tick_no *
$tick_increment * $ac_power_y_scale );

        # For the text, the $y that we pass into $self->draw_graph_text
        # is the TOP ( lower value ) that the text can occupy
        my $label_y_offset = -8;

        draw_graph_text(
            $cairo_context
            , $tick_no * $tick_increment
            , 0
            , 0
            , $y + $label_y_offset
        );

        $line_context->move_to( 30, $y );
        $line_context->line_to( $total_width, $y );
        $line_context->line_to( $total_width, $y - 1 );
        $line_context->line_to( 30, $y - 1 );
        $line_context->line_to( 30, $y );
        $line_context->fill;

    }

}

sub draw_graph_text {

    my ( $cr, $text, $angle, $x, $y ) = @_;

    print "Writing [$text] at x [$x] y [$y]\n";

    my $layout = Pango::Cairo::create_layout( $cr );
    $layout->set_text( $text );

    my $desc = Pango::FontDescription->from_string( "Sans Bold 10" );
    $layout->set_font_description( $desc );

    $cr->save;

    $cr->rotate( $angle );

    # Inform Pango to re-layout the text with the new transformation
    Pango::Cairo::update_layout( $cr, $layout );

    my ( $width, $height ) = $layout->get_size;
    $cr->move_to( $x, $y );
    Pango::Cairo::show_layout( $cr, $layout );

    $cr->restore;

}

sub handle_graph_mouse_move {

    my ( $widget, $event ) = @_;

    use Data::Dumper;

    print "event:\n" . Dumper( $event ) . "\n";

}

On Thu, Aug 17, 2017 at 3:35 AM, Torsten Schoenfeld <[hidden email]> wrote:

> On 16.08.2017 14:12, Daniel Kasak wrote:
>> I'm trying to capture mouse events in a DrawingArea ( in Gtk3 ). I'm
>> adapting code at http://www.perlmonks.org/?node_id=583578 ... but when
>> I go:
>>
>> $self->{drawing_area}->set_events(
>>     [ qw/   exposure-mask
>>             leave-notify-mask
>>             button-press-mask
>>             pointer-motion-mask
>>             pointer-motion-hint-mask
>>         /
>>     ]
>> );
>>
>>  ... I get a warning:
>>
>> Gtk-CRITICAL **: gtk_widget_set_events: assertion
>> '!_gtk_widget_get_realized (widget)' failed
>
> We would need to see more code to give specific advice, but the error
> message suggests that you need to call set_events() earlier, because the
> widget has already been realized.  (Note the "!" in the assertion.)
_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Motion events in a DrawingArea

Jeremy Volkening-2
In reply to this post by Gtk+ - Perl mailing list
On Thu, Aug 17, 2017 at 06:01:38PM +1000, Kevin Ryde via gtk-perl-list wrote:
>Daniel Kasak <[hidden email]> writes:
>>
>> $self->{drawing_area}->set_events(
>
>Gtk 2 is ->add_events() usually from INIT_INSTANCE to have extra events
>selected when realized, if that's still so.

I also use add_events() rather than set_events() with Gtk3. A MWE
showing a responsive DrawingArea is below.

Jeremy

--
All generalizations are false, including this one.
                -- Mark Twain

#!/usr/bin/perl

use strict;
use warnings;
use 5.012;

use Glib qw/TRUE FALSE/;
use Gtk3 qw/-init/;

my $da = Gtk3::DrawingArea->new();
#$da->signal_connect( 'draw'          => \&draw_canvas );
#$da->signal_connect( 'size-allocate' => \&resize      );

$da->add_events(0x004|0x100|0x200);
$da->signal_connect( 'motion-notify-event'  => \&_on_motion );
$da->signal_connect( 'button-release-event' => \&_on_click  );

my $mw = Gtk3::Window->new('toplevel');
$mw->set_size_request(100, 100);
$mw->signal_connect( destroy => sub { Gtk3->main_quit } );

$mw->add($da);
$mw->show_all;

Gtk3->main;


sub _on_motion {
    my ($da, $ev) = @_;
    say join ' ', 'MOTION at', $ev->x, $ev->y;
}

sub _on_click {
    my ($da, $ev) = @_;
    say join ' ', 'CLICK at', $ev->x, $ev->y;
}
_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list
Reply | Threaded
Open this post in threaded view
|

Re: Motion events in a DrawingArea

Jeremy Volkening-2
In reply to this post by Daniel Kasak-4
On Wed, Aug 16, 2017 at 10:12:04PM +1000, Daniel Kasak wrote:
>Hi all.
>
>I'm trying to capture mouse events in a DrawingArea ( in Gtk3 ). I'm
>adapting code at http://www.perlmonks.org/?node_id=583578 ... but when

Also, when I have used complex DrawingAreas in past projects, it was
convenient to create a separate subclass. Here is the preamble from a
Gtk2 DrawingArea-based widget I wrote:

# --begin code--

package Gtk2::MassCanvas;

use warnings;
use strict;
use 5.012;

use Glib qw/TRUE FALSE/;
use Gtk2;
use Cairo;
use Gtk2::Pango;

use Glib::Object::Subclass
    Gtk2::DrawingArea::,
        signals => {
                expose_event         => \&expose,
                configure_event      => \&resize,
                motion_notify_event  => \&on_motion,
                button_press_event   => \&on_click,
                button_release_event => \&on_release,
                key_press_event      => \&_on_key_press,
                scroll_event         => \&on_scroll,
        };

# --end code--


This makes setting up signal handling a piece of cake. I don't know this
still works in Gtk3, however,

Jeremy



--
Truth is the most valuable thing we have -- so let us economize it.
                -- Mark Twain

_______________________________________________
gtk-perl-list mailing list
[hidden email]
https://mail.gnome.org/mailman/listinfo/gtk-perl-list