1 /***************************************************************************
2  *   Copyright (C) 2015 by Pere Ràfols Soler                               *
3  *   sapista2@gmail.com                                                    *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 
21 #include "button.h"
22 #include "colors.h"
23 
24 #define OUTER_BORDER 2
25 
Button(const Glib::ustring & label)26 Button::Button ( const Glib::ustring& label ):
27 m_label(label), m_bFocus(false), m_bPress(false)
28 {
29   set_size_request( 12 + 10*m_label.length(), 20);
30 
31   //Connect mouse signals
32   add_events(Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::POINTER_MOTION_MASK | Gdk::LEAVE_NOTIFY_MASK);
33   signal_button_press_event().connect(sigc::mem_fun(*this, &Button::on_button_press_event),true);
34   signal_button_release_event().connect(sigc::mem_fun(*this, &Button::on_button_release_event),true);
35   signal_motion_notify_event().connect(sigc::mem_fun(*this, &Button::on_mouse_motion_event),true);
36   signal_leave_notify_event().connect(sigc::mem_fun(*this, &Button::on_mouse_leave_widget),true);
37 }
38 
~Button()39 Button::~Button()
40 {
41 
42 }
43 
on_button_press_event(GdkEventButton * event)44 bool Button::on_button_press_event ( GdkEventButton* event )
45 {
46   //Check click type
47   if( event->button == 1 && event->type == GDK_BUTTON_PRESS)
48   {
49     m_bPress = event->x > OUTER_BORDER &&
50                event->x < (width - OUTER_BORDER) &&
51                event->y > OUTER_BORDER &&
52                event->y < (height - OUTER_BORDER);
53     m_sigPress.emit();
54     redraw();
55   }
56   return true;
57 }
58 
on_button_release_event(GdkEventButton * event)59 bool Button::on_button_release_event ( GdkEventButton* event )
60 {
61   if( event->x > OUTER_BORDER &&
62     event->x < (width - OUTER_BORDER) &&
63     event->y > OUTER_BORDER &&
64     event->y < (height - OUTER_BORDER))
65   {
66     m_sigClick.emit();
67   }
68   m_sigRelease.emit();
69   m_bPress = false;
70   m_bFocus = false;
71   redraw();
72   return true;
73 }
74 
on_mouse_motion_event(GdkEventMotion * event)75 bool Button::on_mouse_motion_event ( GdkEventMotion* event )
76 {
77    m_bFocus = event->x > OUTER_BORDER &&
78               event->x < (width - OUTER_BORDER) &&
79               event->y > OUTER_BORDER &&
80               event->y < (height - OUTER_BORDER);
81   redraw();
82   return true;
83 }
84 
on_mouse_leave_widget(GdkEventCrossing * event)85 bool Button::on_mouse_leave_widget ( GdkEventCrossing* event )
86 {
87   m_bFocus = false;
88   redraw();
89   m_sigRelease.emit();
90   return true;
91 }
92 
93 
set_label(const Glib::ustring & label)94 void Button::set_label ( const Glib::ustring& label )
95 {
96   m_label = label;
97   redraw();
98 }
99 
signal_clicked()100 Button::signal_Click Button::signal_clicked()
101 {
102   return m_sigClick;
103 }
104 
signal_press()105 Button::signal_Click Button::signal_press()
106 {
107   return m_sigPress;
108 }
109 
signal_release()110 Button::signal_Click Button::signal_release()
111 {
112   return m_sigRelease;
113 }
114 
115 
redraw()116 void Button::redraw()
117 {
118   Glib::RefPtr<Gdk::Window> win = get_window();
119   if(win)
120   {
121     Gdk::Rectangle r(0, 0, get_allocation().get_width(), get_allocation().get_height());
122     win->invalidate_rect(r, false);
123   }
124 }
125 
on_expose_event(GdkEventExpose * event)126 bool Button::on_expose_event ( GdkEventExpose* event )
127 {
128   Glib::RefPtr<Gdk::Window> window = get_window();
129   if(window)
130   {
131     Gtk::Allocation allocation = get_allocation();
132     width = allocation.get_width();
133     height = allocation.get_height();
134 
135     Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
136 
137     //Paint backgroud
138     cr->save();
139     cr->set_source_rgb(BACKGROUND_R, BACKGROUND_G, BACKGROUND_B);
140     cr->paint(); //Fill all with background color
141     cr->restore();
142 
143     //Draw button rectangle
144     cr->save();
145     double radius = height / 5.0;
146     double degrees = M_PI / 180.0;
147     cr->begin_new_sub_path();
148     cr->arc (width - OUTER_BORDER - radius, OUTER_BORDER + radius, radius, -90 * degrees, 0 * degrees);
149     cr->arc (width - OUTER_BORDER - radius, height - OUTER_BORDER - radius, radius, 0 * degrees, 90 * degrees);
150     cr->arc (OUTER_BORDER + radius, height- OUTER_BORDER - radius, radius, 90 * degrees, 180 * degrees);
151     cr->arc ( OUTER_BORDER + radius, OUTER_BORDER + radius, radius, 180 * degrees, 270 * degrees);
152     cr->close_path();
153 
154     if(m_bFocus)
155     {
156       cr->set_source_rgb(0.2, 0.6, 0.5);
157     }
158     else if(m_bPress)
159     {
160       cr->set_source_rgb(0.5, 0.7, 0.8);
161     }
162     else
163     {
164       cr->set_source_rgb(0.5, 0.5, 0.5);
165     }
166 
167     cr->set_line_width(1);
168     cr->stroke_preserve();
169 
170     Cairo::RefPtr<Cairo::LinearGradient> bkg_gradient_ptr = Cairo::LinearGradient::create(width/2, OUTER_BORDER, width/2, height - OUTER_BORDER);
171     bkg_gradient_ptr->add_color_stop_rgba (0.0, 0.1, 0.2, 0.2, 0.3 );
172 
173     if(m_bPress)
174     {
175       bkg_gradient_ptr->add_color_stop_rgba (0.7, 0.1, 0.2, 0.3, 0.8 );
176     }
177     else
178     {
179       bkg_gradient_ptr->add_color_stop_rgba (0.7, 0.4, 0.4, 0.4, 0.8 );
180     }
181 
182     cr->set_source(bkg_gradient_ptr);
183     cr->fill();
184     cr->restore();
185 
186     //Label
187     cr->save();
188     if(m_bFocus)
189     {
190       cr->set_source_rgb(0.2, 0.6, 0.5);
191     }
192     else if(m_bPress)
193     {
194       cr->set_source_rgb(0.7, 0.7, 0.9);
195     }
196     else
197     {
198      cr->set_source_rgb(TEXT_R, TEXT_G, TEXT_B);
199     }
200 
201 
202     Glib::RefPtr<Pango::Layout> pangoLayout = Pango::Layout::create(cr);
203     Pango::FontDescription font_desc("sans 11px");
204     pangoLayout->set_font_description(font_desc);
205     pangoLayout->set_width(Pango::SCALE * (width - OUTER_BORDER));
206     pangoLayout->set_height(Pango::SCALE * (height - OUTER_BORDER));
207     pangoLayout->set_alignment(Pango::ALIGN_CENTER);
208     cr->move_to(OUTER_BORDER, OUTER_BORDER + 2);
209     pangoLayout->set_text(m_label.c_str());
210     pangoLayout->show_in_cairo_context(cr);
211     cr->stroke();
212     cr->restore();
213 
214   }
215 
216   return true;
217 }
218