1/* 2 * Notes - panel plugin for Xfce Desktop Environment 3 * Copyright (c) 2010 Mike Massonnet <mmassonnet@xfce.org> 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 Library 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 Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20const double M_PI = 3.14159265358979323846; 21 22namespace Xnp { 23 24 public abstract class IconButton : Gtk.EventBox { 25 26 protected bool active = false; 27 28 public signal void clicked (); 29 30 construct { 31 ((Gtk.Widget)this).name = "notes-icon-button"; 32 set_visible_window (false); 33 set_above_child (true); 34 set_size_request (22, 22); 35 36 enter_notify_event.connect (on_enter_notify_event); 37 leave_notify_event.connect (on_leave_notify_event); 38 button_release_event.connect (on_button_release_event); 39 } 40 41 protected abstract void draw_icon (Cairo.Context cr, int width, int height); 42 43 protected void set_widget_source_color (Cairo.Context cr) { 44 var style_context = get_style_context (); 45 46 if (sensitive && active) { 47 Gdk.cairo_set_source_rgba (cr, style_context.get_color (Gtk.StateFlags.PRELIGHT)); 48 } 49 else if (sensitive && !active) 50 Gdk.cairo_set_source_rgba (cr, style_context.get_color (Gtk.StateFlags.NORMAL)); 51 else if (!sensitive) 52 Gdk.cairo_set_source_rgba (cr, style_context.get_color (Gtk.StateFlags.INSENSITIVE)); 53 } 54 55 public override void add (Gtk.Widget widget) { 56 warning ("This object doesn't allow packing child widgets."); 57 } 58 59 public override bool draw (Cairo.Context cr) { 60 int width = get_allocated_width (); 61 int height = get_allocated_height (); 62 var style_context = get_style_context (); 63 64 style_context.save (); 65 style_context.add_class (Gtk.STYLE_CLASS_BUTTON); 66 style_context.render_frame (cr, 0, 0, width, height); 67 style_context.render_background (cr, 0, 0, width, height); 68 style_context.restore (); 69 70 cr.save (); 71 cr.translate (2, 2); 72 draw_icon (cr, width - 4, height - 4); 73 cr.restore (); 74 75 return false; 76 } 77 78 private bool on_enter_notify_event (Gdk.EventCrossing event) { 79 active = true; 80 get_window ().invalidate_rect (null, false); 81 return false; 82 } 83 84 private bool on_leave_notify_event (Gdk.EventCrossing event) { 85 active = false; 86 get_window ().invalidate_rect (null, false); 87 return false; 88 } 89 90 private bool on_button_release_event (Gdk.EventButton event) { 91 if (event.button != 1) 92 return false; 93 94 int cur_x = (int)event.x; 95 int cur_y = (int)event.y; 96 int width, height; 97 get_size_request (out width, out height); 98 99 if (cur_x >= 0 && cur_x < width && cur_y >= 0 && cur_y < height) 100 clicked (); 101 102 return false; 103 } 104 105 } 106 107 public enum TitleBarButtonType { 108 EMPTY, 109 CLOSE, 110 LEFT_ARROW, 111 RIGHT_ARROW, 112 REFRESH, 113 } 114 115 public class TitleBarButton : IconButton { 116 117 public TitleBarButtonType icon_type { default = TitleBarButtonType.EMPTY; get; construct set; } 118 119 public TitleBarButton (TitleBarButtonType icon_type) { 120 Object (icon_type: icon_type); 121 } 122 123 protected override void draw_icon (Cairo.Context cr, int width, int height) { 124 switch (icon_type) { 125 case TitleBarButtonType.CLOSE: 126 draw_close_button (cr, width, height); 127 break; 128 case TitleBarButtonType.LEFT_ARROW: 129 draw_left_arrow_button (cr, width, height); 130 break; 131 case TitleBarButtonType.RIGHT_ARROW: 132 draw_right_arrow_button (cr, width, height); 133 break; 134 case TitleBarButtonType.REFRESH: 135 draw_refresh_button (cr, width, height); 136 break; 137 default: 138 break; 139 } 140 } 141 142 private void draw_left_arrow_button (Cairo.Context cr, int width, int height) { 143 int border = 4; 144 int x1 = border; 145 int x2 = width - border; 146 int y1 = border; 147 int y2 = height - border; 148 if (x2 <= x1 || y2 <= y1) { 149 return; 150 } 151 152 cr.set_line_cap (Cairo.LineCap.ROUND); 153 154 for (int i = 0; i < 2; i++) { 155 if (i == 0) { 156 cr.set_source_rgba (1, 1, 1, active ? 0.4 : 0.2); 157 cr.set_line_width (4); 158 } 159 else { 160 set_widget_source_color (cr); 161 cr.set_line_width (2.66); 162 } 163 cr.move_to (x1, height / 2); 164 cr.line_to (x2, height / 2); 165 cr.move_to (width / 2, y1); 166 cr.line_to (x1, height / 2); 167 cr.line_to (width / 2, y2); 168 cr.stroke (); 169 } 170 } 171 172 private void draw_right_arrow_button (Cairo.Context cr, int width, int height) { 173 int border = 4; 174 int x1 = border; 175 int x2 = width - border; 176 int y1 = border; 177 int y2 = height - border; 178 if (x2 <= x1 || y2 <= y1) { 179 return; 180 } 181 182 cr.set_line_cap (Cairo.LineCap.ROUND); 183 184 for (int i = 0; i < 2; i++) { 185 if (i == 0) { 186 cr.set_source_rgba (1, 1, 1, active ? 0.4 : 0.2); 187 cr.set_line_width (4); 188 } 189 else { 190 set_widget_source_color (cr); 191 cr.set_line_width (2.66); 192 } 193 cr.move_to (x1, height / 2); 194 cr.line_to (x2, height / 2); 195 cr.move_to (width / 2, y1); 196 cr.line_to (x2, height / 2); 197 cr.line_to (width / 2, y2); 198 cr.stroke (); 199 } 200 } 201 202 private void draw_close_button (Cairo.Context cr, int width, int height) { 203 int border = 4; 204 int x1 = border; 205 int x2 = width - border; 206 int y1 = border; 207 int y2 = height - border; 208 if (x2 <= x1 || y2 <= y1) { 209 return; 210 } 211 212 cr.set_line_cap (Cairo.LineCap.ROUND); 213 214 for (int i = 0; i < 2; i++) { 215 if (i == 0) { 216 cr.set_source_rgba (1, 1, 1, active ? 0.4 : 0.2); 217 cr.set_line_width (4); 218 } 219 else { 220 set_widget_source_color (cr); 221 cr.set_line_width (2.66); 222 } 223 cr.move_to (x1, y1); 224 cr.line_to (x2, y2); 225 cr.move_to (x2, y1); 226 cr.line_to (x1, y2); 227 cr.stroke (); 228 } 229 } 230 231 private void draw_refresh_button (Cairo.Context cr, int width, int height) { 232 int border = 6; 233 int x1 = border; 234 int x2 = width - border; 235 int y1 = border; 236 int y2 = height - border; 237 if (x2 <= x1 || y2 <= y1) { 238 return; 239 } 240 241 cr.set_line_cap (Cairo.LineCap.ROUND); 242 243 for (int j = 0; j < 2; j++) { 244 for (int i = 0; i < 2; i++) { 245 if (i == 0) { 246 cr.set_source_rgba (1, 1, 1, active ? 0.4 : 0.2); 247 cr.set_line_width (4); 248 } 249 else { 250 set_widget_source_color (cr); 251 cr.set_line_width (2.44); 252 } 253 cr.save (); 254 cr.translate (x1 + (x2 - x1) / 2, y1 + (y2 - y1) / 2); 255 if (j == 0) { 256 cr.rotate (-M_PI / 16.0); 257 } 258 else { 259 cr.rotate ((15.0 * M_PI) / 16.0); 260 } 261 cr.arc (0, 0, x2 - x1, (5.0 * M_PI) / 16.0, M_PI); 262 var r = (x2 - x1) / 2.0; 263 cr.line_to (-r * 2.0, (3.0 * r) / 2.0); 264 cr.move_to (-r * 2.0, 0.0); 265 cr.line_to (-r, r / 2.0); 266 cr.stroke (); 267 cr.restore (); 268 } 269 } 270 } 271 } 272 273} 274