Merge remote-tracking branch 'remotes/origin/exportvis' into windows+cc
[ardour.git] / libs / gtkmm2ext / cairo_widget.cc
1 /*
2     Copyright (C) 2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include "gtkmm2ext/cairo_widget.h"
21 #include "gtkmm2ext/gui_thread.h"
22
23 static const char* has_cairo_widget_background_info = "has_cairo_widget_background_info";
24
25 CairoWidget::CairoWidget ()
26         : _active_state (Gtkmm2ext::Off)
27         , _visual_state (Gtkmm2ext::NoVisualState)
28         , _need_bg (true)
29 {
30
31 }
32
33 CairoWidget::~CairoWidget ()
34 {
35 }
36
37 bool
38 CairoWidget::on_expose_event (GdkEventExpose *ev)
39 {
40         cairo_t* cr = gdk_cairo_create (get_window ()->gobj());
41         cairo_rectangle (cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
42         cairo_clip (cr);
43
44         /* paint expose area the color of the parent window bg 
45         */
46         
47         Gdk::Color bg (get_parent_bg());
48         
49         cairo_rectangle (cr, ev->area.x, ev->area.y, ev->area.width, ev->area.height);
50         cairo_set_source_rgb (cr, bg.get_red_p(), bg.get_green_p(), bg.get_blue_p());
51         cairo_fill (cr);
52
53         render (cr);
54
55         cairo_destroy (cr);
56
57         return true;
58 }
59
60 /** Marks the widget as dirty, so that render () will be called on
61  *  the next GTK expose event.
62  */
63
64 void
65 CairoWidget::set_dirty ()
66 {
67         ENSURE_GUI_THREAD (*this, &CairoWidget::set_dirty);
68         queue_draw ();
69 }
70
71 /** Handle a size allocation.
72  *  @param alloc GTK allocation.
73  */
74 void
75 CairoWidget::on_size_allocate (Gtk::Allocation& alloc)
76 {
77         Gtk::EventBox::on_size_allocate (alloc);
78
79         set_dirty ();
80 }
81
82 Gdk::Color
83 CairoWidget::get_parent_bg ()
84 {
85         Widget* parent;
86
87         parent = get_parent ();
88
89         while (parent) {
90                 void* p = g_object_get_data (G_OBJECT(parent->gobj()), has_cairo_widget_background_info);
91
92                 if (p) {
93                         Glib::RefPtr<Gtk::Style> style = parent->get_style();
94                         return style->get_bg (get_state());
95                 }
96                 
97                 if (!parent->get_has_window()) {
98                         parent = parent->get_parent();
99                 } else {
100                         break;
101                 }
102         }
103
104         if (parent && parent->get_has_window()) {
105                 return parent->get_style ()->get_bg (parent->get_state());
106         } 
107
108         return get_style ()->get_bg (get_state());
109 }
110
111 void
112 CairoWidget::set_active_state (Gtkmm2ext::ActiveState s)
113 {
114         if (_active_state != s) {
115                 _active_state = s;
116                 StateChanged ();
117         }
118 }
119
120 void
121 CairoWidget::set_visual_state (Gtkmm2ext::VisualState s)
122 {
123         if (_visual_state != s) {
124                 _visual_state = s;
125                 StateChanged ();
126         }
127 }
128
129 void
130 CairoWidget::set_active (bool yn)
131 {
132         /* this is an API simplification for buttons
133            that only use the Active and Normal states.
134         */
135
136         if (yn) {
137                 set_active_state (Gtkmm2ext::ExplicitActive);
138         } else {
139                 unset_active_state ();
140         }
141 }
142
143 void
144 CairoWidget::on_state_changed (Gtk::StateType)
145 {
146         /* this will catch GTK-level state changes from calls like
147            ::set_sensitive() 
148         */
149
150         if (get_state() == Gtk::STATE_INSENSITIVE) {
151                 set_visual_state (Gtkmm2ext::VisualState (visual_state() | Gtkmm2ext::Insensitive));
152         } else {
153                 set_visual_state (Gtkmm2ext::VisualState (visual_state() & ~Gtkmm2ext::Insensitive));
154         }
155
156         queue_draw ();
157 }
158
159 void
160 CairoWidget::set_draw_background (bool yn)
161 {
162         _need_bg = yn;
163 }
164
165 void
166 CairoWidget::provide_background_for_cairo_widget (Gtk::Widget& w, const Gdk::Color& bg)
167 {
168         /* set up @w to be able to provide bg information to 
169            any CairoWidgets that are packed inside it.
170         */
171
172         w.modify_bg (Gtk::STATE_NORMAL, bg);
173         w.modify_bg (Gtk::STATE_INSENSITIVE, bg);
174         w.modify_bg (Gtk::STATE_ACTIVE, bg);
175         w.modify_bg (Gtk::STATE_SELECTED, bg);
176
177         g_object_set_data (G_OBJECT(w.gobj()), has_cairo_widget_background_info, (void*) 0xfeedface);
178 }