├── .gitignore
├── 10a-Cell-renderer-text.pl
├── 3a-A-basic-window.pl
├── 3b-A-better-window.pl
├── 4a-Adding-buttons.pl
├── 4b-Adding-button-functions.pl
├── 5a-Fun-with-labels.pl
├── 6a-Checkbox-Basics.pl
├── 6b-Radiobox.pl
├── 6c-Spinbox.pl
├── 6d-Toggle-Button.pl
├── 7b-Layout-Grid.pl
├── 8a-Display-Progress-bar.pl
├── 8b-Spinner.pl
├── 8c-Switch.pl
├── 8d-Separators.pl
├── 9a-cairo-drawing.pl
├── 9b-cairo-animation.pl
├── Perl Gtk3 Tutorial.odt
├── Perl Gtk3 Tutorial.pdf
├── README.md
├── mandelbrot-fractal.pl
└── pong.pl
/.gitignore:
--------------------------------------------------------------------------------
1 | blib/
2 | .build/
3 | _build/
4 | cover_db/
5 | inc/
6 | Build
7 | Build.bat
8 | .last_cover_stats
9 | Makefile
10 | Makefile.old
11 | MANIFEST.bak
12 | META.yml
13 | MYMETA.yml
14 | nytprof.out
15 | pm_to_blib
16 |
--------------------------------------------------------------------------------
/10a-Cell-renderer-text.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use feature ':5.10';
6 | use Gtk3 '-init';
7 | use Glib qw/TRUE FALSE/;
8 |
9 | my $window = Gtk3::Window->new('toplevel');
10 | $window->set_title("Cell Renderer Example");
11 | $window->set_position("mouse");
12 | $window->set_default_size(250, 100);
13 | $window->set_border_width(5);
14 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
15 |
16 | my $data = Gtk3::ListStore->new( 'Glib::Int', 'Glib::String', 'Glib::String' );
17 | $data->set( $data->append, 0, 1, 1, 'First bit');
18 | $data->set( $data->append, 0, 2, 1, 'second' );
19 | $data->set( $data->append, 0, 3, 2, 'third' );
20 | my $tree = Gtk3::TreeView->new($data);
21 |
22 | my $spinner = Gtk3::CellRendererSpin->new;
23 | $spinner->set_property( editable => TRUE );
24 | my $adj = Gtk3::Adjustment->new( 0, 0, 100, 1, 10, 0 );
25 | $spinner->set_property( adjustment => $adj );
26 | $spinner->signal_connect( edited => \&on_amount_edited, $data );
27 | my $col0 = Gtk3::TreeViewColumn->new_with_attributes( 'Number', $spinner, text => 0 );
28 | $tree->append_column($col0);
29 |
30 | my $col1 = Gtk3::TreeViewColumn->new_with_attributes( 'Text', Gtk3::CellRendererText->new, text => 1 );
31 | $tree->append_column($col1);
32 |
33 | my $ren_text = Gtk3::CellRendererText->new();
34 | $ren_text->set_property('editable', TRUE);
35 | $ren_text->signal_connect (edited => \&cell_edited, $data);
36 | my $col2 = Gtk3::TreeViewColumn->new_with_attributes( 'Ed Text', $ren_text, text => 2 );
37 | $tree->append_column($col2);
38 |
39 | $window->add($tree);
40 | $window->show_all;
41 | Gtk3->main;
42 |
43 | sub on_amount_edited {
44 | my ( $widget, $path, $value, $model ) = @_;
45 | my $path_str = Gtk3::TreePath->new($path);
46 | my $iter = $model->get_iter($path_str);
47 | $model->set( $iter, 0, int($value) );
48 | }
49 |
50 | sub cell_edited {
51 | my ($cell, $path, $value, $model) = @_;
52 | my $path_str = Gtk3::TreePath->new($path);
53 | my $iter = $model->get_iter($path_str);
54 | $model->set($iter, 2, $value);
55 | }
56 |
57 |
58 |
--------------------------------------------------------------------------------
/3a-A-basic-window.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 |
9 | my $window = Gtk3::Window->new('toplevel');
10 | $window->show_all;
11 | Gtk3->main;
12 |
13 |
--------------------------------------------------------------------------------
/3b-A-better-window.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 |
9 | my $window = Gtk3::Window->new('toplevel');
10 | $window->set_title("My Title");
11 | $window->set_position("mouse");
12 | $window->set_default_size(400, 50);
13 | $window->set_border_width(20);
14 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
15 |
16 | $window->show_all;
17 | Gtk3->main;
18 |
--------------------------------------------------------------------------------
/4a-Adding-buttons.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 |
9 | use Glib qw/TRUE FALSE/;
10 |
11 | sub quit_function {
12 | say "Exiting Gtk3";
13 | Gtk3->main_quit;
14 | return FALSE;
15 | }
16 |
17 | my $window = Gtk3::Window->new('toplevel');
18 | $window->set_title("My Title");
19 | $window->set_position("mouse");
20 | $window->set_default_size(400, 50);
21 | $window->set_border_width(20);
22 | $window->signal_connect (delete_event => \&quit_function);
23 |
24 | my $button1 = Gtk3::Button->new("Quit");
25 | $button1->signal_connect (clicked => \&quit_function);
26 |
27 | my $button2 = Gtk3::Button->new("Another Quit");
28 | $button2->signal_connect (clicked => \&quit_function);
29 |
30 | my $hbox = Gtk3::Box->new("horizontal", 5);
31 |
32 | $hbox->pack_start($button1, TRUE, TRUE, 0);
33 | $hbox->pack_start($button2, TRUE, TRUE, 0);
34 |
35 | $hbox->set_homogeneous (TRUE);
36 |
37 | $window->add($hbox);
38 |
39 | $window->show_all;
40 | Gtk3->main;
41 |
--------------------------------------------------------------------------------
/4b-Adding-button-functions.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 |
9 | use Glib qw/TRUE FALSE/;
10 |
11 | #### DECLARATIONS
12 |
13 | my $window = Gtk3::Window->new('toplevel');
14 | $window->set_title("My Title");
15 | $window->set_position("mouse");
16 | $window->set_default_size(400, 50);
17 | $window->set_border_width(20);
18 | $window->signal_connect (delete_event => \&quit_function);
19 |
20 | my $button1 = Gtk3::Button->new("Quit");
21 | $button1->signal_connect (clicked => \&quit_function);
22 |
23 | my $button2 = Gtk3::Button->new("Say Hello");
24 | $button2->signal_connect (clicked => \&say_something, "Hello");
25 |
26 | my $button3 = Gtk3::Button->new("Say Goodbye");
27 | $button3->signal_connect (clicked => \&say_something, "Goodbye");
28 |
29 | my $hbox = Gtk3::Box->new("horizontal", 5);
30 | $hbox->set_homogeneous (TRUE);
31 | $hbox->pack_start($button1, TRUE, TRUE, 0);
32 | $hbox->pack_start($button2, TRUE, TRUE, 0);
33 | $hbox->pack_start($button3, TRUE, TRUE, 0);
34 |
35 | my $vbox = Gtk3::Box->new("vertical", 5);
36 | $vbox->add($hbox);
37 |
38 | my $label = Gtk3::Label->new("Am I connected?");
39 | $vbox->add($label);
40 |
41 | $window->add($vbox);
42 | $window->show_all;
43 |
44 | #### FUNCTIONS
45 |
46 | sub quit_function {
47 | say "Exiting Gtk3";
48 | Gtk3->main_quit;
49 | return FALSE;
50 | }
51 |
52 | sub say_something {
53 | my ($button, $userdata) = @_;
54 | $label->set_label( $userdata );
55 | return FALSE;
56 | }
57 |
58 | Gtk3->main;
59 |
--------------------------------------------------------------------------------
/5a-Fun-with-labels.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 |
9 | use Glib qw/TRUE FALSE/;
10 |
11 | #### DECLARATIONS
12 |
13 | my $window = Gtk3::Window->new('toplevel');
14 | $window->set_title("My Title");
15 | $window->set_position("mouse");
16 | $window->set_default_size(400, 50);
17 | $window->set_border_width(20);
18 | $window->signal_connect (delete_event => \&quit_function);
19 |
20 | my $button1 = Gtk3::Button->new("Twist");
21 | $button1->signal_connect (clicked => \&say_something, "twist");
22 |
23 | my $button2 = Gtk3::Button->new("red");
24 | $button2->signal_connect (clicked => \&say_something, "red");
25 |
26 | my $button3 = Gtk3::Button->new("weird");
27 | $button3->signal_connect (clicked => \&say_something, "weird");
28 |
29 | my $hbox = Gtk3::Box->new("horizontal", 5);
30 | $hbox->set_homogeneous (TRUE);
31 | $hbox->pack_start($button1, TRUE, TRUE, 0);
32 | $hbox->pack_start($button2, TRUE, TRUE, 0);
33 | $hbox->pack_start($button3, TRUE, TRUE, 0);
34 |
35 | my $vbox = Gtk3::Box->new("vertical", 5);
36 | $vbox->add($hbox);
37 |
38 | my $label = Gtk3::Label->new("Am I connected?");
39 | $vbox->add($label);
40 |
41 | $window->add($vbox);
42 | $window->show_all;
43 |
44 | #### FUNCTIONS
45 |
46 | sub quit_function {
47 | say "Exiting Gtk3";
48 | Gtk3->main_quit;
49 | return FALSE;
50 | }
51 |
52 | sub say_something {
53 | my ($button, $userdata) = @_;
54 | if ($userdata eq "twist") {
55 | my $angle = $label->get_angle;
56 | $label->set_angle( $angle - 30 );
57 | } elsif ($userdata eq "red") {
58 | $label->set_markup('Red and connected');
59 | } elsif ($userdata eq "weird") {
60 | $label->set_markup('Weird');
61 | }
62 | return FALSE;
63 | }
64 |
65 | Gtk3->main;
66 |
--------------------------------------------------------------------------------
/6a-Checkbox-Basics.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | #
4 | # This example borrows very heavily from the
5 | # The Python GTK+ 3 Tutorial
6 | # http://python-gtk-3-tutorial.readthedocs.org/en/latest/index.html
7 | #
8 |
9 | use strict;
10 | use warnings;
11 | use diagnostics;
12 | use feature ':5.14';
13 | use Gtk3 '-init';
14 | use Glib qw/TRUE FALSE/;
15 |
16 | my $window = Gtk3::Window->new('toplevel');
17 | $window->set_title("Basic Check Boxes");
18 | $window->set_position("mouse");
19 | $window->set_default_size(200, 100);
20 | $window->set_border_width(5);
21 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
22 |
23 | my $vbox = Gtk3::Box->new("vertical", 5);
24 | $window->add($vbox);
25 |
26 | my $entry = Gtk3::Entry->new;
27 | $entry->set_text("Hello World");
28 | $vbox->pack_start($entry, TRUE, TRUE, 0);
29 |
30 | my $hbox = Gtk3::Box->new("horizontal", 6);
31 | $vbox->pack_start($hbox, TRUE, TRUE, 0);
32 |
33 | my $check_button1 = Gtk3::CheckButton->new_with_label('Editable');
34 | $check_button1->signal_connect (toggled => \&cb_toggled, "editable");
35 | $check_button1->set_active(TRUE);
36 | $hbox->pack_start($check_button1, TRUE, TRUE, 0);
37 |
38 | my $check_button2 = Gtk3::CheckButton->new_with_label("Visible");
39 | $check_button2->signal_connect (toggled => \&cb_toggled, "visible");
40 | $check_button2->set_active(TRUE);
41 | $hbox->pack_start($check_button2, TRUE, TRUE, 0);
42 |
43 | my $check_button3 = Gtk3::CheckButton->new_with_label("Icon");
44 | $check_button3->signal_connect (toggled => \&cb_toggled, "icon");
45 | $check_button3->set_active(FALSE);
46 | $hbox->pack_start($check_button3, TRUE, TRUE, 0);
47 |
48 | $window->show_all;
49 | Gtk3->main;
50 |
51 | sub cb_toggled {
52 | my ($widget, $data) = @_;
53 | my $value = $widget->get_active;
54 |
55 | if ($data eq 'visible') {
56 | $entry->set_visibility($value);
57 | } elsif ($data eq 'editable') {
58 | $entry->set_editable($value);
59 | } elsif ($data eq 'icon') {
60 | my $stock_id = undef;
61 | if ($value == TRUE) {
62 | $stock_id = Gtk3::STOCK_FIND;
63 | }
64 | $entry->set_icon_from_stock('secondary', $stock_id);
65 | }
66 | return FALSE;
67 | }
68 |
--------------------------------------------------------------------------------
/6b-Radiobox.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 | use Glib qw/TRUE FALSE/;
9 |
10 | my $window = Gtk3::Window->new('toplevel');
11 | $window->set_title("Basic Radio Boxes");
12 | $window->set_position("mouse");
13 | $window->set_default_size(200, 100);
14 | $window->set_border_width(5);
15 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
16 |
17 | my $hbox = Gtk3::Box->new("horizontal", 5);
18 | $window->add($hbox);
19 |
20 | my $rbutton1 = Gtk3::RadioButton->new_with_label_from_widget(undef, "Button 1");
21 | $hbox->pack_start($rbutton1, TRUE, TRUE, 0);
22 | $rbutton1->signal_connect (toggled => \&rb_toggled, "rb1");
23 |
24 | my $rbutton2 = Gtk3::RadioButton->new_with_label_from_widget($rbutton1, "Button 2");
25 | $hbox->pack_start($rbutton2, TRUE, TRUE, 0);
26 | $rbutton2->signal_connect (toggled => \&rb_toggled, "rb2");
27 |
28 | my $rbutton3 = Gtk3::RadioButton->new_with_label_from_widget($rbutton1, "Button 3");
29 | $hbox->pack_start($rbutton3, TRUE, TRUE, 0);
30 | $rbutton3->signal_connect (toggled => \&rb_toggled, "rb3");
31 |
32 | $window->show_all;
33 | Gtk3->main;
34 |
35 | sub rb_toggled {
36 | my ($widget, $data) = @_;
37 | print "Radio button $data is now ";
38 | if ($widget->get_active == TRUE) {
39 | say " set ON";
40 | } else {
41 | say " set OFF";
42 | }
43 | return FALSE;
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/6c-Spinbox.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 | use Glib qw/TRUE FALSE/;
9 |
10 | my $window = Gtk3::Window->new('toplevel');
11 | $window->set_title("Spinbox Example");
12 | $window->set_position("mouse");
13 | $window->set_default_size(250, 100);
14 | $window->set_border_width(5);
15 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
16 |
17 | my $vbox = Gtk3::Box->new("vertical", 5);
18 | $window->add($vbox);
19 |
20 | my $adjust = Gtk3::Adjustment->new(5, 0, 10, 1, 10, 0);
21 | my $spin = Gtk3::SpinButton->new($adjust, 1, 1);
22 | $vbox->pack_start($spin, FALSE, FALSE, 0);
23 |
24 | my $hbox = Gtk3::Box->new("horizontal", 5);
25 | $vbox->pack_start($hbox, FALSE, FALSE, 0);
26 |
27 | my $zero_button = Gtk3::Button->new('Zero');
28 | $hbox->pack_start($zero_button, FALSE, FALSE, 0);
29 | $zero_button->signal_connect ( clicked => \&zero );
30 |
31 | my $check_accuracy = Gtk3::CheckButton->new_with_label('High accuracy');
32 | $hbox->pack_start($check_accuracy, FALSE, FALSE, 0);
33 | $check_accuracy->signal_connect ( toggled => \&toggle_accuracy );
34 |
35 | my $hbox2 = Gtk3::Box->new("horizontal", 5);
36 | $vbox->pack_start($hbox2, FALSE, FALSE, 0);
37 |
38 | my $update_button = Gtk3::Button->new('Update');
39 | $hbox2->pack_start($update_button, FALSE, FALSE, 0);
40 | $update_button->signal_connect ( clicked => \&update );
41 |
42 | my $label = Gtk3::Label->new("No Value");
43 | $hbox2->pack_start($label, FALSE, FALSE, 0);
44 |
45 |
46 | $window->show_all;
47 | Gtk3->main;
48 |
49 | sub zero {
50 | my ($widget, $data) = @_;
51 | $spin->set_value(0);
52 | return FALSE;
53 | }
54 |
55 | sub toggle_accuracy{
56 | my ($widget, $data) = @_;
57 | my $value = $widget->get_active;
58 | if ( $value == TRUE ) {
59 | $spin->set_digits(2);
60 | } else {
61 | $spin->set_digits(1);
62 | }
63 | return FALSE;
64 | }
65 |
66 | sub update {
67 | $label->set_label( $spin->get_value );
68 | return FALSE;
69 | }
70 |
--------------------------------------------------------------------------------
/6d-Toggle-Button.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 | use Glib qw/TRUE FALSE/;
9 |
10 | my $window = Gtk3::Window->new('toplevel');
11 | $window->set_title("Spin and toggle Example");
12 | $window->set_position("mouse");
13 | $window->set_default_size(250, 100);
14 | $window->set_border_width(5);
15 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
16 |
17 | my $vbox = Gtk3::Box->new("vertical", 5);
18 | $window->add($vbox);
19 |
20 | my $adjust = Gtk3::Adjustment->new(5, 0, 10, 1, 10, 0);
21 | my $spin = Gtk3::SpinButton->new($adjust, 1, 1);
22 | $vbox->pack_start($spin, FALSE, FALSE, 0);
23 |
24 | my $hbox = Gtk3::Box->new("horizontal", 5);
25 | $vbox->pack_start($hbox, FALSE, FALSE, 0);
26 |
27 | my $zero_button = Gtk3::Button->new('Zero');
28 | $hbox->pack_start($zero_button, FALSE, FALSE, 0);
29 | $zero_button->signal_connect ( clicked => \&zero );
30 |
31 | my $toggle_accuracy = Gtk3::ToggleButton->new_with_label('High accuracy');
32 | $hbox->pack_start($toggle_accuracy, FALSE, FALSE, 0);
33 | $toggle_accuracy->signal_connect ( toggled => \&toggle_accuracy );
34 |
35 | my $hbox2 = Gtk3::Box->new("horizontal", 5);
36 | $vbox->pack_start($hbox2, FALSE, FALSE, 0);
37 |
38 | my $update_button = Gtk3::Button->new('Update');
39 | $hbox->pack_start($update_button, FALSE, FALSE, 0);
40 | $update_button->signal_connect ( clicked => \&update );
41 |
42 | my $label = Gtk3::Label->new("No Value");
43 | $hbox->pack_start($label, FALSE, FALSE, 0);
44 |
45 | $window->show_all;
46 | Gtk3->main;
47 |
48 | sub zero {
49 | my ($widget, $data) = @_;
50 | $spin->set_value(0);
51 | return FALSE;
52 | }
53 |
54 | sub toggle_accuracy{
55 | my ($widget, $data) = @_;
56 | my $value = $widget->get_active;
57 | if ( $value == TRUE ) {
58 | $spin->set_digits(2);
59 | } else {
60 | $spin->set_digits(1);
61 | }
62 | return FALSE;
63 | }
64 |
65 | sub update {
66 | $label->set_label( $spin->get_value );
67 | return FALSE;
68 | }
69 |
--------------------------------------------------------------------------------
/7b-Layout-Grid.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 | use Glib qw/TRUE FALSE/;
9 |
10 | my $window = Gtk3::Window->new('toplevel');
11 | $window->set_title("Grid Example");
12 | $window->set_position("mouse");
13 | $window->set_default_size(250, 100);
14 | $window->set_border_width(5);
15 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
16 |
17 | my $grid = Gtk3::Grid->new;
18 | $window->add($grid);
19 |
20 | my $toggle1 = Gtk3::ToggleButton->new_with_label('One');
21 | my $toggle2 = Gtk3::ToggleButton->new_with_label('Two');
22 | my $toggle3 = Gtk3::ToggleButton->new_with_label('Three');
23 | my $toggle4 = Gtk3::ToggleButton->new_with_label('Four');
24 | my $toggle5 = Gtk3::ToggleButton->new_with_label('Five');
25 | my $toggle6 = Gtk3::ToggleButton->new_with_label('Six');
26 |
27 | $grid->add($toggle1);
28 | $grid->attach($toggle2, 1, 0, 2, 1);
29 | $grid->attach_next_to($toggle3, $toggle1, 'bottom', 1, 2);
30 | $grid->attach_next_to($toggle4, $toggle3, 'right', 2, 1);
31 | $grid->attach($toggle5, 1, 2, 1, 1);
32 | $grid->attach_next_to($toggle6, $toggle5, 'GTK_POS_RIGHT', 1, 1);
33 |
34 | $window->show_all;
35 | Gtk3->main;
36 |
--------------------------------------------------------------------------------
/8a-Display-Progress-bar.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 | use Glib qw/TRUE FALSE/;
9 |
10 | my $window = Gtk3::Window->new('toplevel');
11 | $window->set_title("Progress Bar");
12 | $window->set_position("mouse");
13 | $window->set_default_size(250, 100);
14 | $window->set_border_width(5);
15 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
16 |
17 | my $vbox = Gtk3::Box->new("vertical", 5);
18 | $window->add($vbox);
19 |
20 | my $progress = Gtk3::ProgressBar->new;
21 | $progress->set_orientation("horizontal");
22 | $progress->set_inverted(FALSE);
23 | $progress->set_text(undef);
24 | $progress->set_show_text(FALSE);
25 | $vbox->add($progress);
26 |
27 | my $hbox = Gtk3::Box->new("horizontal", 2);
28 | $vbox->add($hbox);
29 |
30 | my $toggle1 = Gtk3::ToggleButton->new_with_label('Text');
31 | my $toggle2 = Gtk3::ToggleButton->new_with_label('Percent');
32 | my $toggle3 = Gtk3::ToggleButton->new_with_label('Invert');
33 | $hbox->pack_start($toggle1, TRUE, TRUE, 0);
34 | $hbox->pack_start($toggle2, TRUE, TRUE, 0);
35 | $hbox->pack_start($toggle3, TRUE, TRUE, 0);
36 |
37 | $toggle1->signal_connect ( toggled => \&showtext );
38 | $toggle2->signal_connect ( toggled => \&showpercent );
39 | $toggle3->signal_connect ( toggled => \&invert );
40 |
41 | my $increment = 0.01;
42 | my $timer = Glib::Timeout->add (50, \&update);
43 |
44 | $window->show_all;
45 | Gtk3->main;
46 |
47 | sub showtext {
48 | my ($widget, $data) = @_;
49 | my $text = undef;
50 | if ( $widget->get_active ) {
51 | $text = "some text";
52 | }
53 | $progress->set_text( $text );
54 | $progress->set_show_text( $widget->get_active );
55 | return FALSE;
56 | }
57 |
58 | sub showpercent {
59 | my ($widget, $data) = @_;
60 | my $show = $widget->get_active;
61 | $progress->set_text( undef );
62 | $progress->set_show_text( $show );
63 | return FALSE;
64 | }
65 |
66 | sub invert {
67 | my ($widget, $data) = @_;
68 | $progress->set_inverted( $widget->get_active );
69 | return FALSE;
70 | }
71 |
72 | sub update {
73 | if ( $progress->get_fraction >= 1 ) {
74 | $increment = -0.01;
75 | }
76 | if ( $progress->get_fraction <= 0 ) {
77 | $increment = 0.01;
78 | }
79 | $progress->set_fraction( $progress->get_fraction + $increment );
80 | return TRUE;
81 | }
82 |
--------------------------------------------------------------------------------
/8b-Spinner.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 | use Glib qw/TRUE FALSE/;
9 |
10 | my $window = Gtk3::Window->new('toplevel');
11 | $window->set_title("Spinner Example");
12 | $window->set_position("mouse");
13 | $window->set_default_size(250, 100);
14 | $window->set_border_width(5);
15 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
16 |
17 | my $vbox = Gtk3::Box->new("vertical", 5);
18 | $window->add($vbox);
19 |
20 | my $spinner = Gtk3::Spinner->new;
21 | my $toggle1 = Gtk3::ToggleButton->new_with_label('Spin');
22 | $toggle1->set_active( FALSE );
23 |
24 | $vbox->pack_start($spinner, TRUE, TRUE, 5 );
25 | $vbox->pack_start($toggle1, TRUE, TRUE, 5 );
26 |
27 | $toggle1->signal_connect ( toggled => \&toggle );
28 |
29 | $window->show_all;
30 | Gtk3->main;
31 |
32 | sub toggle {
33 | my ($widget, $data) = @_;
34 | if ( $widget->get_active == TRUE ) {
35 | $spinner->start;
36 | $toggle1->set_label("Stop");
37 | } else {
38 | $spinner->stop;
39 | $toggle1->set_label("Spin");
40 | }
41 | return FALSE;
42 | }
43 |
--------------------------------------------------------------------------------
/8c-Switch.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 | use Glib qw/TRUE FALSE/;
9 | use Data::Dumper;
10 |
11 | my $window = Gtk3::Window->new('toplevel');
12 | $window->set_title("Switch Example");
13 | $window->set_position("mouse");
14 | $window->set_default_size(250, 100);
15 | $window->set_border_width(5);
16 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
17 |
18 | my $vbox = Gtk3::Box->new("vertical", 5);
19 | $window->add($vbox);
20 |
21 | my $spinner = Gtk3::Spinner->new;
22 | my $switch = Gtk3::Switch->new;
23 | $switch->set_active( FALSE );
24 |
25 | $vbox->pack_start($spinner, TRUE, TRUE, 5 );
26 | $vbox->pack_start($switch, TRUE, TRUE, 5 );
27 |
28 | $switch->signal_connect( 'notify::active' => \&toggle );
29 |
30 | $window->show_all;
31 | Gtk3->main;
32 |
33 | sub toggle {
34 | my ($widget, $data) = @_;
35 | say Dumper($data);
36 | if ( $widget->get_active == TRUE ) {
37 | $spinner->start;
38 | } else {
39 | $spinner->stop;
40 | }
41 | return FALSE;
42 | }
43 |
--------------------------------------------------------------------------------
/8d-Separators.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use diagnostics;
6 | use feature ':5.14';
7 | use Gtk3 '-init';
8 | use Glib qw/TRUE FALSE/;
9 | use Data::Dumper;
10 |
11 | my $window = Gtk3::Window->new('toplevel');
12 | $window->set_title("Switch Example");
13 | $window->set_position("mouse");
14 | $window->set_default_size(250, 100);
15 | $window->set_border_width(5);
16 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
17 |
18 | my $vbox = Gtk3::Box->new("vertical", 5);
19 | $window->add($vbox);
20 |
21 | my $spinner = Gtk3::Spinner->new;
22 | my $switch = Gtk3::Switch->new;
23 | $switch->set_active( FALSE );
24 |
25 | my $sep = Gtk3::Separator->new("horizontal");
26 |
27 | $vbox->pack_start($spinner, TRUE, TRUE, 5 );
28 | $vbox->pack_start($sep, FALSE, FALSE, 2 );
29 | $vbox->pack_start($switch, TRUE, TRUE, 5 );
30 |
31 | $switch->signal_connect( 'notify::active' => \&toggle );
32 |
33 | $window->show_all;
34 | Gtk3->main;
35 |
36 | sub toggle {
37 | my ($widget, $data) = @_;
38 | say Dumper($data);
39 | if ( $widget->get_active == TRUE ) {
40 | $spinner->start;
41 | } else {
42 | $spinner->stop;
43 | }
44 | return FALSE;
45 | }
46 |
--------------------------------------------------------------------------------
/9a-cairo-drawing.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use feature ':5.14';
6 | use Gtk3 '-init';
7 | use Glib qw/TRUE FALSE/;
8 | use Cairo::GObject;
9 |
10 | use constant PI => 3.1415927;
11 |
12 | my $window = Gtk3::Window->new('toplevel');
13 | $window->set_title("Cairo Basics");
14 | $window->set_position("mouse");
15 | $window->set_default_size(600, 400);
16 | $window->set_border_width(5);
17 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
18 |
19 | my $frame = Gtk3::Frame->new("Cairo Drawings");
20 | $window->add($frame);
21 |
22 | my $drawable = Gtk3::DrawingArea->new;
23 | $drawable->signal_connect( draw => \&cairo_draw );
24 | $frame->add($drawable);
25 |
26 | $window->show_all;
27 |
28 | Gtk3->main;
29 |
30 | sub cairo_draw {
31 | my ( $widget, $context, $ref_status ) = @_;
32 |
33 | # Background
34 | $context->set_source_rgb(0.9, 0.9, 0.7);
35 | $context->paint;
36 |
37 | # Solid box
38 | $context->set_source_rgb(0.6, 0.0, 0.0);
39 | $context->set_line_width(10);
40 | $context->rectangle( 5, 5, 160, 130);
41 | $context->stroke;
42 |
43 | # Transparent Rectangle
44 | $context->set_source_rgba(0.0, 0.7, 0.0, 0.5);
45 | $context->set_line_width(10);
46 | $context->rectangle( 85, 85, 160, 230);
47 | $context->fill;
48 |
49 | # Circle with border - transparent
50 | $context->set_source_rgba(0.0, 0.0, 0.9, 0.5);
51 | $context->arc( 220, 150, 100, 0, PI * 2 );
52 | $context->set_line_width(10);
53 | $context->stroke_preserve;
54 | $context->set_source_rgba(0.9, 0.2, 0.2, 0.2);
55 | $context->fill;
56 |
57 | # Segment
58 | $context->set_source_rgba(0.9, 0.2, 0.2, 0.4);
59 | $context->set_line_width(2);
60 | $context->arc( 400, 200, 100, 0, 5);
61 | $context->stroke_preserve;
62 | $context->line_to(400, 200);
63 | $context->stroke_preserve;
64 | $context->close_path;
65 | $context->stroke_preserve;
66 | $context->set_source_rgba(0.1, 0.4, 0.4, 0.4);
67 | $context->fill;
68 |
69 | # Arc
70 | $context->set_source_rgba(0.1, 0.1, 0.1, 0.8);
71 | $context->set_line_width(2);
72 | $context->arc( 450, 220, 100, 0, 5);
73 | $context->stroke;
74 |
75 | # Line
76 | $context->set_source_rgba(0, 0, 0, 0.5);
77 | $context->set_line_width(30);
78 | $context->move_to(50, 50);
79 | $context->line_to(550, 350);
80 | $context->stroke;
81 |
82 | # Curve
83 | $context->set_line_width(10);
84 | $context->set_source_rgba(0.9, 0.9, 0, 0.9);
85 | $context->move_to(50, 50);
86 | $context->curve_to( 100, 250, 250, 150, 550, 350);
87 | $context->stroke;
88 |
89 | # Text
90 | $context->set_source_rgba(0.0, 0.9, 0.9, 0.7);
91 | $context->select_font_face( "Sans", "normal", "bold" );
92 | $context->set_font_size( 50 );
93 | $context->move_to(220, 50);
94 | $context->show_text( "Ooooooh");
95 | $context->stroke;
96 |
97 | $context->move_to(370, 170);
98 | $context->text_path( "pretty" );
99 | $context->set_source_rgba(0.9, 0, 0.9, 0.7);
100 | $context->fill_preserve;
101 | $context->set_source_rgba(0.2, 0.1, 0.1, 0.7);
102 | $context->set_line_width( 2 );
103 | $context->stroke;
104 |
105 | # Linear Gradients
106 | my $pattern2 = Cairo::LinearGradient->create(520, 20, 570, 320);
107 | $pattern2->add_color_stop_rgba(0, 0, 0.7, 1, 0.5);
108 | $pattern2->add_color_stop_rgba(1, 0, 0, 0.5, 0.95);
109 | $context->set_source( $pattern2 );
110 | $context->rectangle( 520, 20, 570, 320);
111 | $context->fill;
112 |
113 | # Radial Gradients
114 | my $pattern = Cairo::RadialGradient->create(40, 220, 25, 60, 240, 150);
115 | $pattern->add_color_stop_rgba(0, 1, 0.7, 1, 0.95);
116 | $pattern->add_color_stop_rgba(1, 0, 0, 0.5, 0.95);
117 | $context->set_source( $pattern );
118 | $context->arc( 80, 250, 80, 0, PI * 2 );
119 | $context->fill;
120 |
121 | return FALSE;
122 | }
123 |
--------------------------------------------------------------------------------
/9b-cairo-animation.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use feature ':5.14';
6 | use Gtk3 '-init';
7 | use Glib qw/TRUE FALSE/;
8 | use Cairo::GObject;
9 | use Data::Dumper;
10 |
11 | use constant PI => 3.1415927;
12 | use constant WIDTH => 600;
13 | use constant HEIGHT => 400;
14 | use constant RADIUS => 20;
15 |
16 | my %status = (
17 | vector => { 'x' => 2, 'y' => 3 },
18 | position => { 'x' => 20, 'y' => 30 },
19 | );
20 |
21 | my $window = Gtk3::Window->new('toplevel');
22 | $window->set_title("Cairo animation");
23 | $window->set_position("mouse");
24 | $window->set_default_size(WIDTH+10, HEIGHT+30);
25 | $window->set_border_width(5);
26 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
27 |
28 | my $frame = Gtk3::Frame->new("Bouncing ball");
29 | $window->add($frame);
30 |
31 | my $drawable = Gtk3::DrawingArea->new;
32 | $drawable->signal_connect( draw => \&cairo_draw, \%status );
33 | $frame->add($drawable);
34 |
35 | $window->show_all;
36 |
37 | my $timer = Glib::Timeout->add( 20, \&update );
38 |
39 | Gtk3->main;
40 |
41 | sub update {
42 | $status{'position'}{'x'} += $status{'vector'}{'x'};
43 | $status{'position'}{'y'} += $status{'vector'}{'y'};
44 | if ( $status{'position'}{'y'} >= HEIGHT - RADIUS ) {
45 | $status{'vector'}{'y'} = -$status{'vector'}{'y'};
46 | }
47 | if ( $status{'position'}{'y'} <= RADIUS ) {
48 | $status{'vector'}{'y'} = -$status{'vector'}{'y'};
49 | }
50 | if ( $status{'position'}{'x'} >= WIDTH - RADIUS ) {
51 | $status{'vector'}{'x'} = -$status{'vector'}{'x'};
52 | }
53 | if ( $status{'position'}{'x'} <= RADIUS ) {
54 | $status{'vector'}{'x'} = -$status{'vector'}{'x'};
55 | }
56 | $drawable->queue_draw;
57 | return TRUE;
58 | }
59 |
60 | sub cairo_draw {
61 | my ( $widget, $context, $ref_status ) = @_;
62 |
63 | # Background
64 | my $pattern2 = Cairo::LinearGradient->create( 0, 0, WIDTH , HEIGHT);
65 | $pattern2->add_color_stop_rgba(0, 0.2, 0.7, 0.9, 0.7);
66 | $pattern2->add_color_stop_rgba(1, 0.2, 0.7, 0.5, 0.7);
67 | $context->set_source( $pattern2 );
68 | $context->rectangle( 0, 0, WIDTH , HEIGHT);
69 | $context->fill;
70 |
71 | # Ball
72 | my $pattern = Cairo::RadialGradient->create(
73 | $ref_status->{'position'}{'x'},
74 | $ref_status->{'position'}{'y'},
75 | RADIUS,
76 | $ref_status->{'position'}{'x'}-2,
77 | $ref_status->{'position'}{'y'}-2,
78 | RADIUS / 2
79 | );
80 | $pattern->add_color_stop_rgb(0, 0.8, 0.6, 0.8);
81 | $pattern->add_color_stop_rgb(1, 1, 0.7, 1);
82 | $context->set_source( $pattern );
83 | $context->arc(
84 | $ref_status->{'position'}{'x'},
85 | $ref_status->{'position'}{'y'},
86 | RADIUS,
87 | 0,
88 | PI * 2,
89 | );
90 | $context->fill;
91 |
92 | return FALSE;
93 | }
94 |
--------------------------------------------------------------------------------
/Perl Gtk3 Tutorial.odt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kevinphilp/Perl-gtk3-Tutorial/71955c37e9b30fcecf89b8d3ea4210c2693e1cd7/Perl Gtk3 Tutorial.odt
--------------------------------------------------------------------------------
/Perl Gtk3 Tutorial.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kevinphilp/Perl-gtk3-Tutorial/71955c37e9b30fcecf89b8d3ea4210c2693e1cd7/Perl Gtk3 Tutorial.pdf
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Perl-gtk3-Tutorial
2 | ==================
3 |
4 | A basic introduction to using the Gtk3 toolkit with the Perl bindings. This tutorial was written to help my son and I learn Gtk3/Perl. The tutorial takes a series of standard widgets and presents them with a full, working example and an explanation of how it works.
5 |
6 | We are posting this on the internet in case other people find it useful.
7 |
--------------------------------------------------------------------------------
/mandelbrot-fractal.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | # Based on http://warp.povusers.org/Mandelbrot/
4 |
5 | use strict;
6 | use warnings;
7 | use feature ':5.14';
8 | use Gtk3 '-init';
9 | use Glib qw/TRUE FALSE/;
10 | use Cairo::GObject;
11 | use Data::Dumper;
12 |
13 | use constant LOOPS => 100;
14 |
15 | use constant MAX_X => 800; # REAL
16 | use constant MAX_Y => 800; # IMAG
17 |
18 | use constant MIN_REAL => -2.0; # -2.0
19 | use constant MIN_IMAG => -1.2; # -1.2
20 | use constant MAX_REAL => 1.0; # 1.0
21 | my $MAX_IMAG = MIN_IMAG + (MAX_REAL - MIN_REAL) * (MAX_X / MAX_Y);
22 | my $re_factor = (MAX_REAL - MIN_REAL) / (MAX_X - 1);
23 | my $im_factor = ($MAX_IMAG - MIN_IMAG) / (MAX_Y - 1);
24 |
25 | my @farray = ();
26 |
27 | my $window = Gtk3::Window->new('toplevel');
28 | $window->set_title("Mandelbrot Set");
29 | $window->set_position("mouse");
30 | $window->set_default_size(MAX_X + 50, MAX_Y + 100);
31 | $window->set_border_width(5);
32 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
33 |
34 | my $vbox = Gtk3::Box->new("vertical", 1);
35 | $window->add($vbox);
36 |
37 | my $frame = Gtk3::Frame->new("Cairo Drawings");
38 | $vbox->pack_start($frame, TRUE, TRUE, 0);
39 |
40 | my $drawable = Gtk3::DrawingArea->new;
41 | $drawable->signal_connect( draw => \&cairo_draw );
42 | $frame->add($drawable);
43 |
44 | my $surface = Cairo::ImageSurface->create ('argb32', MAX_X, MAX_Y);
45 | my $cr = Cairo::Context->create ($surface);
46 |
47 | fractal();
48 | drawbuf();
49 |
50 | $window->show_all;
51 |
52 | Gtk3->main;
53 |
54 | sub fractal {
55 | for (my $y = 0; $y <= MAX_Y; $y++ ) {
56 | my $c_im = $MAX_IMAG - $y * $im_factor;
57 | for (my $x = 0; $x <= MAX_X; $x++ ) {
58 | $farray[$x][$y]{'real'} = MIN_REAL + $x * $re_factor;
59 | $farray[$x][$y]{'imag'} = $c_im;
60 | my $z = calcz( $farray[$x][$y]{'real'}, $farray[$x][$y]{'imag'} );
61 | $farray[$x][$y]{'z'} = $z;
62 | }
63 | }
64 | }
65 |
66 | sub calcz {
67 | my ($c_re, $c_im) = @_;
68 | my $z_re = $c_re;
69 | my $z_im = $c_im;
70 | my $inside = TRUE;
71 | for (my $n=0; $n <= LOOPS; $n++) {
72 | my $z_re2 = ($z_re * $z_re);
73 | my $z_im2 = ($z_im * $z_im);
74 | if ( ($z_re2 + $z_im2) > 4 ) {
75 | return $n;
76 | }
77 | $z_im = 2 * $z_re * $z_im + $c_im;
78 | $z_re = $z_re2 - $z_im2 + $c_re;
79 | }
80 | return 0;
81 | }
82 |
83 | sub drawbuf {
84 | $cr->set_line_width(1);
85 | for (my $y = 0; $y <= MAX_Y; $y++ ) {
86 | for (my $x = 0; $x <= MAX_X; $x++ ) {
87 | $cr->set_source_rgb( $farray[$x][$y]{'z'} / LOOPS, 0, 0 );
88 | $cr->rectangle( $x, $y, 1, 1);
89 | $cr->stroke;
90 | }
91 | }
92 | }
93 |
94 | sub cairo_draw {
95 | my ( $widget, $context, $ref_status ) = @_;
96 | $context->set_source_surface($surface, 0, 0);
97 | $context->paint;
98 | return FALSE;
99 | }
100 |
--------------------------------------------------------------------------------
/pong.pl:
--------------------------------------------------------------------------------
1 | #! /usr/bin/perl
2 |
3 | use strict;
4 | use warnings;
5 | use feature ':5.14';
6 | use Gtk3 '-init';
7 | use Glib qw/TRUE FALSE/;
8 | use Cairo::GObject;
9 | use Data::Dumper;
10 |
11 | use constant PI => 3.1415927;
12 | use constant WIDTH => 600;
13 | use constant HEIGHT => 400;
14 | use constant RADIUS => 12;
15 |
16 | my %status = (
17 | vector => { 'x' => 2, 'y' => 3 },
18 | position => { 'x' => 20, 'y' => 30 },
19 | playerA => { 'y' => 50 },
20 | playerB => { 'y' => 50 }
21 | );
22 |
23 | my $window = Gtk3::Window->new('toplevel');
24 | $window->set_title("Grid Example");
25 | $window->set_position("mouse");
26 | $window->set_default_size(WIDTH +50, HEIGHT +100);
27 | $window->set_border_width(5);
28 | $window->signal_connect (delete_event => sub { Gtk3->main_quit });
29 | $window->signal_connect( key_press_event => \&keypress );
30 |
31 | my $vbox = Gtk3::Box->new("vertical", 5);
32 | $window->add($vbox);
33 |
34 | my $hbox = Gtk3::Box->new("horizontal", 5);
35 | $vbox->add($hbox);
36 |
37 | my $toggle1 = Gtk3::ToggleButton->new_with_label('Text');
38 | my $toggle2 = Gtk3::ToggleButton->new_with_label('Percent');
39 | my $toggle3 = Gtk3::ToggleButton->new_with_label('Invert');
40 | $hbox->pack_start($toggle1, TRUE, TRUE, 0);
41 | $hbox->pack_start($toggle2, TRUE, TRUE, 0);
42 | $hbox->pack_start($toggle3, TRUE, TRUE, 0);
43 |
44 | my $frame = Gtk3::Frame->new("Pong");
45 | $vbox->pack_start($frame, TRUE, TRUE, 5);
46 |
47 | my $drawable = Gtk3::DrawingArea->new;
48 | $drawable->signal_connect( draw => \&cairo_draw, \%status );
49 | $frame->add($drawable);
50 |
51 | $window->show_all;
52 |
53 | my $timer = Glib::Timeout->add( 20, \&update );
54 |
55 | Gtk3->main;
56 |
57 | sub keypress {
58 | my ( $widget, $event ) = @_;
59 |
60 | given($event->key->{'string'}) {
61 | when ('q') { $status{'playerA'}{'y'} -= 3; }
62 | when ('a') { $status{'playerA'}{'y'} += 3; }
63 | when ('p') { $status{'playerB'}{'y'} -= 3; }
64 | when ('l') { $status{'playerB'}{'y'} += 3; }
65 | }
66 | return FALSE;
67 | }
68 |
69 | sub update {
70 | $status{'position'}{'x'} += $status{'vector'}{'x'};
71 | $status{'position'}{'y'} += $status{'vector'}{'y'};
72 | if ( $status{'position'}{'y'} >= HEIGHT - RADIUS ) {
73 | $status{'vector'}{'y'} = -$status{'vector'}{'y'};
74 | }
75 | if ( $status{'position'}{'y'} <= RADIUS ) {
76 | $status{'vector'}{'y'} = -$status{'vector'}{'y'};
77 | }
78 | if ( $status{'position'}{'x'} >= WIDTH - RADIUS ) {
79 | $status{'vector'}{'x'} = -$status{'vector'}{'x'};
80 | }
81 | if ( $status{'position'}{'x'} <= RADIUS ) {
82 | $status{'vector'}{'x'} = -$status{'vector'}{'x'};
83 | }
84 | $drawable->queue_draw;
85 | return TRUE;
86 | }
87 |
88 | sub cairo_draw {
89 | my ( $widget, $context, $ref_status ) = @_;
90 |
91 | # Background
92 | $context->set_source_rgb(0.19, 0.69, 0);
93 | $context->rectangle(0, 0, WIDTH, HEIGHT);
94 | $context->fill;
95 |
96 | # Ball
97 | $context->set_source_rgb(0.69, 0.19, 0);
98 | $context->arc(
99 | $ref_status->{'position'}{'x'},
100 | $ref_status->{'position'}{'y'},
101 | RADIUS,
102 | 0,
103 | PI * 2
104 | );
105 | $context->stroke_preserve;
106 | $context->set_source_rgb(0.6, 0.4, 0.2);
107 | $context->fill;
108 |
109 | # Paddle A
110 | $context->set_source_rgb(0.0, 0.0, 0.7);
111 | $context->rectangle( 15, $ref_status->{'playerA'}{'y'}, 10, 30);
112 | $context->fill;
113 |
114 | # Paddle B
115 | $context->set_source_rgb(0.0, 0.0, 0.7);
116 | $context->rectangle( WIDTH - 15, $ref_status->{'playerB'}{'y'}, 10, 30);
117 | $context->fill;
118 |
119 | return FALSE;
120 | }
121 |
--------------------------------------------------------------------------------