More actions to make valaunch gtk+3.0 ready
[valaunch:valaunch.git] / src / valaunch-frame.vala
1 /*
2  * Copyright (C) 2005 Imendio AB
3  * Copyright (C) 2010 Jörn Magens
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This library 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 GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author:
21  *    Christian Kellner <gicmo@gnome.org>
22  */
23
24 [CCode (cname = "gtk_widget_is_drawable")]
25 public extern bool gtk_widget_is_drawable(Gtk.Widget widget);
26
27 [CCode (cname = "gtk_widget_get_realized")]
28 public extern bool gtk_widget_get_realized(Gtk.Widget widget);
29
30 private class Valaunch.Frame : Gtk.Bin { 
31         private bool _frame;
32         private bool _fill;
33         private bool draw_frame;
34         private uint16 _frame_alpha;
35         private Gtk.Allocation child_alloc;
36         private Gdk.Color? _frame_color = Gdk.Color();
37         
38         public double radius { get; set; }
39         
40         public bool frame { 
41                 get {
42                         return _frame;
43                 }
44                 set {
45                         if(this.draw_frame == value) {
46                                 return;
47                         }
48                         this._frame = value;
49                         this.draw_frame = value;
50                         if(gtk_widget_is_drawable(this))//this.is_drawable()) 
51                                 this.queue_draw();
52                 }
53         }
54         
55         public Gdk.Color? frame_color { 
56                 get {
57                         return _frame_color;
58                 }
59                 set {
60                         if(this._frame_color.red == value.red &&
61                                 this._frame_color.green == value.green &&
62                                 this._frame_color.blue == value.blue) {
63                                 return;
64                         }
65                         this._frame_color.red = value.red;
66                         this._frame_color.green = value.green;
67                         this._frame_color.blue = value.blue;
68                         _frame_color = value;
69                         
70                         if(gtk_widget_is_drawable(this))//this.is_drawable()) 
71                                 this.queue_draw();
72                 }
73         }
74         
75         public uint16 frame_alpha { 
76                 get {
77                         return _frame_alpha;
78                 }
79                 set {
80                         if(this._frame_alpha == value) {
81                                 return;
82                         }
83                         
84                         this._frame_alpha = value;
85                         
86                         if(gtk_widget_is_drawable(this))//this.is_drawable()) 
87                                 this.queue_draw();
88                 } 
89         }
90         
91         public bool fill {
92                 get {
93                         return _fill;
94                 }
95                 set {
96                         if(this.fill == value) {
97                                 return;
98                         }
99                         this._fill = value;
100                         
101                         if(gtk_widget_is_drawable(this))//this.is_drawable()) 
102                                 this.queue_draw();
103                 }
104         }
105         
106         private Gdk.Color _fill_color;
107         public Gdk.Color fill_color { 
108                 get {
109                         return _fill_color;
110                 }
111                 set {
112                         if(this._fill_color.red == value.red &&
113                                 this._fill_color.green == value.green &&
114                                 this._fill_color.blue == value.blue) {
115                                 return;
116                         }
117                         this._fill_color.red   = value.red;
118                         this._fill_color.green = value.green;
119                         this._fill_color.blue  = value.blue;
120                         
121                         if(gtk_widget_is_drawable(this))//this.is_drawable())
122                                 this.queue_draw();
123                 }
124         }
125         
126         private uint16 _fill_alpha;
127         public uint16 fill_alpha { 
128                 get {
129                         return _fill_alpha;
130                 }
131                 set {
132                         if(this._fill_alpha == value) {
133                                 return;
134                         }
135                         this._fill_alpha = value;
136                         
137                         if(gtk_widget_is_drawable(this))//()) 
138                                 this.queue_draw();
139                 } 
140         }
141         
142         public Frame() {
143                 this.fill        = false;
144                 this.fill_alpha  = uint16.MAX;
145                 
146                 this.draw_frame  = false;
147                 this.frame_alpha = uint16.MAX;
148                 
149                 this.radius      = -1.0;
150         }
151
152         void cc_rectangle_re(Cairo.Context cr, double x, double y,
153                              double width, double height, double radius) {
154                 
155                 double cx, cy;
156         
157                 width  -= 2 * radius;
158                 height -= 2 * radius;
159                 
160                 cr.move_to(x + radius, y);
161                 
162                 cr.rel_line_to(width, 0.0);
163                 
164                 cr.get_current_point(out cx, out cy);
165                 cr.arc(cx, cy + radius, radius, 3.0 * GLib.Math.PI_2, 0);
166                 
167                 cr.rel_line_to(0.0, height);
168                 
169                 cr.get_current_point(out cx, out cy);
170                 cr.arc(cx - radius, cy, radius, 0, GLib.Math.PI_2);
171                 
172                 cr.rel_line_to(- width, 0.0);
173                 
174                 cr.get_current_point(out cx, out cy);
175                 cr.arc(cx, cy - radius, radius, GLib.Math.PI_2, GLib.Math.PI);
176                 
177                 cr.rel_line_to(0.0, -height);
178                 
179                 cr.get_current_point(out cx, out cy);
180                 cr.arc(cx + radius, cy, radius, GLib.Math.PI, 3.0 * GLib.Math.PI_2);
181                 
182                 cr.close_path();
183
184         }
185
186         private void paint(ref Gdk.Rectangle area) {
187                 Cairo.Context cr;
188                 int x, y, width, height;
189                 double radius;
190                 
191                 if(!gtk_widget_is_drawable(this)) {//this.is_drawable()) {
192                         return;
193                 }
194                 
195                 if(!this.draw_frame && !this.fill) {
196                         /* Nothing to draw. */
197                         return;
198                 }
199                 
200                 x = this.child_alloc.x - this.style.xthickness;
201                 y = this.child_alloc.y - this.style.ythickness;
202                 
203                 width  = this.child_alloc.width + 2 * this.style.xthickness;
204                 height = this.child_alloc.height + 2 * this.style.ythickness;
205                 
206                 if(this.radius < 0.0) {
207                         radius = double.min((double)width, (double)height);
208                         radius = (radius / 100) * 10;
209                         this.radius = radius;
210                 } 
211                 else {
212                         radius = this.radius;
213                 }
214                 
215                 cr = Gdk.cairo_create(this.get_window());
216                 cr.rectangle(x, y, width, height);
217                 cr.clip();
218                 
219                 cc_rectangle_re(cr, x, y, width, height, radius);
220                 
221                 cr.set_operator(Cairo.Operator.OVER);
222                 
223                 if(this.fill) {
224                         double r, g, b, a;
225                         r = (double) this._fill_color.red / uint16.MAX;
226                         g = (double) this._fill_color.green / uint16.MAX;
227                         b = (double) this._fill_color.blue / uint16.MAX;
228                         a = (double) this._fill_alpha / uint16.MAX;
229                         cr.set_source_rgba(r, g, b, a);
230                         cr.fill_preserve();
231                 }
232
233                 if(this.draw_frame) {
234                         double r, g, b, a;
235                         r = (double) this._frame_color.red / uint16.MAX;
236                         g = (double) this._frame_color.green / uint16.MAX;
237                         b = (double) this._frame_color.blue / uint16.MAX;
238                         a = (double) this._frame_alpha / uint16.MAX;
239                         cr.set_source_rgba(r, g, b, a);
240                         cr.stroke();
241                 }
242         }
243
244         public override bool expose_event(Gdk.EventExpose event) {
245                 if(gtk_widget_is_drawable(this)) { //this.is_drawable()) {
246                         paint(ref event.area);
247                         base.expose_event(event);
248                 }
249                 return false;
250         }
251
252
253         public override void size_request(out Gtk.Requisition requisition) {
254                 Gtk.Requisition cr;
255                 requisition.width = 0;
256                 requisition.height = 0;
257                 
258                 if(this.get_child() != null && this.get_child().visible) {
259                         this.get_child().size_request(out cr);
260                         
261                         requisition.width = int.max(requisition.width, cr.width);
262                         requisition.height += cr.height;
263                 }
264                 requisition.width  += (int)((this.border_width + this.style.xthickness) * 2);
265                 requisition.height += (int)((this.border_width + this.style.ythickness) * 2);
266         }
267
268         public override void size_allocate(Gdk.Rectangle allocation) {
269                 Gtk.Allocation new_alloc = {};
270                 this.set_allocation((Gtk.Allocation)allocation);
271                 new_alloc.x = (int)(this.border_width + this.style.xthickness);
272                 new_alloc.width = int.max(1, ((int) allocation.width - new_alloc.x * 2));
273                 new_alloc.y = (int)(this.border_width + this.style.ythickness);
274                 new_alloc.height = int.max(1, ((int) allocation.height - new_alloc.y - (int) this.border_width - (int) this.style.ythickness));
275                 new_alloc.x += allocation.x;
276                 new_alloc.y += allocation.y;
277                 if((new_alloc.x != this.child_alloc.x || new_alloc.y != this.child_alloc.y ||
278                       new_alloc.width != this.child_alloc.width || new_alloc.height != this.child_alloc.height)) {
279                         this.get_window().invalidate_rect(allocation, false);
280                 }
281                 
282                 if(this.get_child() != null && this.get_child().visible) 
283                         ((Gtk.Bin)this).get_child().size_allocate ((Gdk.Rectangle)new_alloc);
284                 
285                 this.child_alloc = new_alloc;
286         }
287 }
288