381. How to create a round button - Part 3?

Problem

This is in response to the comments of Laurent from France with regards to creating round buttons with rollover effect.

We have created a round button with rollover effect in How to create a round button - Part 2?.

Laurent commented that the rollover effect can be achieved more easily with the use of GtkWidget::set_state().

This article shows you what the code will look like using GtkWidget::set_state() as suggested by Laurent as shown below. Do take a look at the code. You will find the code is indeed cleaner and more elegant. Also, you'll find this method GtkWidget::set_state() very useful in some of your applications.

How to create a round button - Part 3?


Solution

  • When setting the pixmap of the button with GtkStyle::bg_pixmap, we can define different pixmap for the different states: NORMAL, PRELIGHT and ACTIVE.
    • NORMAL: when the button is in the normal, unclicked state
    • PRELIGHT: when you move your mouse over the button
    • ACTIVE: when you have clicked the button
  • Once you have defined the pixmap for the different states, when you set the state of the button with GtkWidget::set_state(), the corresponding pixmap will be displayed automatically!

Sample Code

Note: The following image files are required by the sample code below. Please save a copy of the image files and put them in the same directory where you store the sample code.

 button_rew1.png
 button_rew2.png
 button_play1.png
 button_play2.png
 button_ff1.png
 button_ff2.png

1   
2   
3   
5   
6   
7   
8   
9   
11   
13   
18   
19   
20   
21   
26   
27   
28   
29   
30   
31   
32   
33   
34   
35   
36   
37   
38   
39   
40   
41   
42   
43   
44   
45   
46   
47   
48   
49   
50   
51   
52   
53   
54   
55   
56   
57   
58   
59   
60   
61   
62   
63   
64   
65   
66   
67   
68   
69   
70   
74   
75   
76   
77   
78   
79   
80   
81   
82   
83   
84   
85   
86   
87   
93   
94   
95   
96   
97   
98   
100   
101   
102   
108   
109   
110   
111   
118   
119   
120   
121   
<?php
$window = new GtkWindow();
$window->set_size_request(400, 200);
$window->connect_simple('destroy', array('Gtk','main_quit'));
$vbox = new GtkVBox();
$window->add($vbox);

// create a hbox to hold the buttons
$vbox->pack_start($hbox = new GtkHBox());

$buttons2 = new RoundButtons($hbox, array(
    array('button_rew1.png', 'button_rew2.png'),
    array('button_play1.png', 'button_play2.png'),
    array('button_ff1.png', 'button_ff2.png')));

class RoundButtons {

    function RoundButtons($container, $buttons) {
        $button_id = 0;
        $this->button_count = count($buttons);
        foreach($buttons as $button_img) {
            $this->create_round_button($container,
                $button_id, $button_img[0], $button_img[1]);
            $this->button_state[$button_id] = 0;
            ++$button_id;
        }
    }

    function create_round_button($container, $button_id, $image0, $image1) {
        $pixbuf[0]=GdkPixbuf::new_from_file($image0);
        list($this->pixmap[$button_id][0],
            $this->mask[$button_id][0]) =
                $pixbuf[0]-> render_pixmap_and_mask(255);

        $pixbuf[1]=GdkPixbuf::new_from_file($image1);
        list($this->pixmap[$button_id][1],
            $this->mask[$button_id][1]) =
                $pixbuf[1]-> render_pixmap_and_mask(255);

        $eventbox = new GtkEventBox();
        $this->eventbox[$button_id] = $eventbox;
        $eventbox->set_size_request(100, -1);
        $container->pack_start($eventbox, 0, 0);

        $style = $eventbox->get_style();
        $style=$style->copy();

        $style->bg_pixmap[Gtk::STATE_NORMAL] = 
            $this->pixmap[$button_id][0]; // note 1

        $style->bg_pixmap[Gtk::STATE_PRELIGHT] =  
            $this->pixmap[$button_id][1]; // note 2

        $style->bg_pixmap[Gtk::STATE_ACTIVE] = 
            $this->pixmap[$button_id][1]; // note 3
        $eventbox->set_style($style);

        $eventbox->shape_combine_mask($this->mask[$button_id][0], 0, 0);


        $eventbox->connect('button-press-event',
            array(&$this, 'on_button_press'), $button_id);
        $eventbox->connect('enter-notify-event',
            array(&$this, 'on_enter_leave'), $button_id, 1);
        $eventbox->connect('leave-notify-event',
            array(&$this, 'on_enter_leave'), $button_id, 0);
    }

    function on_button_press($widget, $event, $button_id) {
        echo "button_pressed: button $button_id!\n";
        for ($i=0; $i<$this->button_count; ++$i) {
            $state = ($i==$button_id) ? Gtk::STATE_ACTIVE : Gtk::STATE_NORMAL;
            $this->eventbox[$i]->set_state($state); // note 4
            $this->button_state[$i] = $state;
        }
        return true;
    }

    function on_enter_leave($widget, $event, $button_id, $enter_leave) {
        if ($enter_leave==0 && $this->button_state[$button_id]) return;
        $state = ($enter_leave) ? Gtk::STATE_PRELIGHT : Gtk::STATE_NORMAL;
        $widget->set_state($state); // note 5
        return true;
    }
}

$window->show_all();
Gtk::main();

?>

Output

As shown above.
 

Explanation

  1. Define the pixmap of the button for the NORMAL state.
  2. Define the pixmap of the button for the PRELIGHT state.
  3. Define the pixmap of the button for the ACTIVE state.
  4. When the user clicks a button, we set the state of the clicked button to ACTIVE and the unclicked buttons to NORMAL. Note that the corresponding pixmap will be updated automatically.
  5. When the mouse is over a button, we set the state of the corresponding button to PRELIGHT and the others to NORMAL. When the mouse leaves a button, we set all buttons to state NORMAL. Note that the corresponding pixmap will be updated automatically.

Related Links

Add comment


Security code
Refresh