~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/ShadedContainer.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// 
2
 
// ShadedContainer.cs
3
 
//  
4
 
// Author:
5
 
//       Lluis Sanchez Gual <lluis@novell.com>
6
 
// 
7
 
// Copyright (c) 2010 Novell, Inc (http://www.novell.com)
8
 
// 
9
 
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
 
// of this software and associated documentation files (the "Software"), to deal
11
 
// in the Software without restriction, including without limitation the rights
12
 
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 
// copies of the Software, and to permit persons to whom the Software is
14
 
// furnished to do so, subject to the following conditions:
15
 
// 
16
 
// The above copyright notice and this permission notice shall be included in
17
 
// all copies or substantial portions of the Software.
18
 
// 
19
 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
 
// THE SOFTWARE.
26
 
 
27
 
using System;
28
 
using System.Collections.Generic;
29
 
using Gtk;
30
 
using MonoDevelop.Components;
31
 
 
32
 
namespace MonoDevelop.Components.Docking
33
 
{
34
 
        public class ShadedContainer
35
 
        {
36
 
                struct Section {
37
 
                        public int Offset;
38
 
                        public int Size;
39
 
                }
40
 
                
41
 
                Gdk.Color lightColor;
42
 
                Gdk.Color darkColor;
43
 
                int shadowSize = 2;
44
 
                
45
 
                List<Widget> widgets = new List<Widget> ();
46
 
                Dictionary<Widget, Gdk.Rectangle[]> allocations = new Dictionary<Widget, Gdk.Rectangle[]> ();
47
 
                        
48
 
                public ShadedContainer ()
49
 
                {
50
 
                }
51
 
                
52
 
                public int ShadowSize {
53
 
                        get { return this.shadowSize; }
54
 
                        set { this.shadowSize = value; RedrawAll (); }
55
 
                }
56
 
                
57
 
                public Gdk.Color LightColor {
58
 
                        get { return this.lightColor; }
59
 
                        set { this.lightColor = value; RedrawAll (); }
60
 
                }
61
 
 
62
 
                public Gdk.Color DarkColor {
63
 
                        get { return this.darkColor; }
64
 
                        set { this.darkColor = value; RedrawAll (); }
65
 
                }
66
 
                
67
 
                public void Add (Gtk.Widget w)
68
 
                {
69
 
                        widgets.Add (w);
70
 
                        UpdateAllocation (w);
71
 
                        w.Destroyed += HandleWDestroyed;
72
 
                        w.Shown += HandleWShown;
73
 
                        w.Hidden += HandleWHidden;
74
 
                        w.SizeAllocated += HandleWSizeAllocated;
75
 
                        w.Realized += HandleWRealized;
76
 
                        IShadedWidget sw = w as IShadedWidget;
77
 
                        if (sw != null)
78
 
                                sw.AreasChanged += HandleSwAreasChanged;
79
 
                        RedrawAll ();
80
 
                }
81
 
 
82
 
                public void Remove (Widget w)
83
 
                {
84
 
                        widgets.Remove (w);
85
 
                        allocations.Remove (w);
86
 
                        w.Destroyed -= HandleWDestroyed;
87
 
                        w.Shown -= HandleWShown;
88
 
                        w.Hidden -= HandleWHidden;
89
 
                        w.Realized -= HandleWRealized;
90
 
                        IShadedWidget sw = w as IShadedWidget;
91
 
                        if (sw != null)
92
 
                                sw.AreasChanged -= HandleSwAreasChanged;
93
 
                        RedrawAll ();
94
 
                }
95
 
                
96
 
                bool UpdateAllocation (Widget w)
97
 
                {
98
 
                        if (w.IsRealized) {
99
 
                                IShadedWidget sw = w as IShadedWidget;
100
 
                                Gdk.Rectangle[] newAllocations;
101
 
                                if (sw != null) {
102
 
                                        List<Gdk.Rectangle> rects = new List<Gdk.Rectangle> ();
103
 
                                        foreach (Gdk.Rectangle ar in sw.GetShadedAreas ())
104
 
                                                rects.Add (ar);
105
 
                                        newAllocations = rects.ToArray ();
106
 
                                } else {
107
 
                                        newAllocations = new Gdk.Rectangle [] { w.Allocation };
108
 
                                }
109
 
                                Gdk.Rectangle[] oldAllocations;
110
 
                                if (allocations.TryGetValue (w, out oldAllocations)) {
111
 
                                        if (oldAllocations.Length == newAllocations.Length) {
112
 
                                                bool changed = false;
113
 
                                                for (int n=0; n<oldAllocations.Length; n++) {
114
 
                                                        if (newAllocations[n] != oldAllocations[n]) {
115
 
                                                                changed = true;
116
 
                                                                break;
117
 
                                                        }
118
 
                                                }
119
 
                                                if (!changed)
120
 
                                                        return false;
121
 
                                        }
122
 
                                }
123
 
                                allocations [w] = newAllocations;
124
 
                                return true;
125
 
                        }
126
 
                        else {
127
 
                                if (!allocations.ContainsKey (w))
128
 
                                        return false;
129
 
                                allocations.Remove (w);
130
 
                                return true;
131
 
                        }
132
 
                }
133
 
 
134
 
                void HandleWRealized (object sender, EventArgs e)
135
 
                {
136
 
                        if (UpdateAllocation ((Widget) sender))
137
 
                                RedrawAll ();
138
 
                }
139
 
 
140
 
                void HandleSwAreasChanged (object sender, EventArgs e)
141
 
                {
142
 
                        if (UpdateAllocation ((Gtk.Widget)sender))
143
 
                                RedrawAll ();
144
 
                }
145
 
                
146
 
                void HandleWSizeAllocated (object o, SizeAllocatedArgs args)
147
 
                {
148
 
                        if (UpdateAllocation ((Widget) o))
149
 
                                RedrawAll ();
150
 
                }
151
 
 
152
 
                void HandleWHidden (object sender, EventArgs e)
153
 
                {
154
 
                        RedrawAll ();
155
 
                }
156
 
 
157
 
                void HandleWShown (object sender, EventArgs e)
158
 
                {
159
 
                        RedrawAll ();
160
 
                }
161
 
 
162
 
                void HandleWDestroyed (object sender, EventArgs e)
163
 
                {
164
 
                        Remove ((Widget)sender);
165
 
                }
166
 
                
167
 
                void RedrawAll ()
168
 
                {
169
 
                        foreach (Widget w in widgets) {
170
 
                                if (!w.Visible)
171
 
                                        continue;
172
 
                                IShadedWidget sw = w as IShadedWidget;
173
 
                                if (sw != null) {
174
 
                                        foreach (Gdk.Rectangle rect in sw.GetShadedAreas ())
175
 
                                                w.QueueDrawArea (rect.X, rect.Y, rect.Width, rect.Height);
176
 
                                }
177
 
                                else
178
 
                                        w.QueueDraw ();
179
 
                        }
180
 
                }
181
 
                
182
 
                public void DrawBackground (Gtk.Widget w)
183
 
                {
184
 
                        DrawBackground (w, w.Allocation);
185
 
                }
186
 
                
187
 
                public void DrawBackground (Gtk.Widget w, Gdk.Rectangle allocation)
188
 
                {
189
 
                        if (shadowSize == 0) {
190
 
                                Gdk.Rectangle wr = new Gdk.Rectangle (allocation.X, allocation.Y, allocation.Width, allocation.Height);
191
 
                                using (Cairo.Context ctx = Gdk.CairoHelper.Create (w.GdkWindow)) {
192
 
                                        ctx.Rectangle (wr.X, wr.Y, wr.Width, wr.Height);
193
 
                                        ctx.Color = GtkUtil.ToCairoColor (lightColor);
194
 
                                        ctx.Fill ();
195
 
                                }
196
 
                                return;
197
 
                        }
198
 
                        
199
 
                        List<Section> secsT = new List<Section> ();
200
 
                        List<Section> secsB = new List<Section> ();
201
 
                        List<Section> secsR = new List<Section> ();
202
 
                        List<Section> secsL = new List<Section> ();
203
 
                        
204
 
                        int x, y;
205
 
                        w.GdkWindow.GetOrigin (out x, out y);
206
 
                        Gdk.Rectangle allocAbs = allocation;
207
 
                        allocAbs.Offset (x, y);
208
 
                        
209
 
                        Section s = new Section ();
210
 
                        s.Size = allocAbs.Width;
211
 
                        secsT.Add (s);
212
 
                        secsB.Add (s);
213
 
                        s.Size = allocAbs.Height;
214
 
                        secsL.Add (s);
215
 
                        secsR.Add (s);
216
 
                                                
217
 
                        foreach (var rects in allocations) {
218
 
                                int sx, sy;
219
 
                                rects.Key.GdkWindow.GetOrigin (out sx, out sy);
220
 
                                foreach (Gdk.Rectangle srt in rects.Value) {
221
 
                                        Gdk.Rectangle srtAbs = srt;
222
 
                                        srtAbs.Offset (sx, sy);
223
 
                                        if (srtAbs == allocAbs)
224
 
                                                continue;
225
 
                                        if (srtAbs.Right == allocAbs.X)
226
 
                                                RemoveSection (secsL, srtAbs.Y - allocAbs.Y, srtAbs.Height);
227
 
                                        if (srtAbs.Bottom == allocAbs.Y)
228
 
                                                RemoveSection (secsT, srtAbs.X - allocAbs.X, srtAbs.Width);
229
 
                                        if (srtAbs.X == allocAbs.Right)
230
 
                                                RemoveSection (secsR, srtAbs.Y - allocAbs.Y, srtAbs.Height);
231
 
                                        if (srtAbs.Y == allocAbs.Bottom)
232
 
                                                RemoveSection (secsB, srtAbs.X - allocAbs.X, srtAbs.Width);
233
 
                                }
234
 
                        }                       
235
 
                        
236
 
                        Gdk.Rectangle r = allocation;
237
 
                        using (Cairo.Context ctx = Gdk.CairoHelper.Create (w.GdkWindow)) {
238
 
                                ctx.Rectangle (r.X, r.Y, r.Width, r.Height);
239
 
                                ctx.Color = GtkUtil.ToCairoColor (lightColor);
240
 
                                ctx.Fill ();
241
 
                                
242
 
                                //HACK: the shadow positions are all worn on recent GTK, disable them for now
243
 
                                /*
244
 
                                DrawShadow (ctx, r, PositionType.Left, secsL);
245
 
                                DrawShadow (ctx, r, PositionType.Top, secsT);
246
 
                                DrawShadow (ctx, r, PositionType.Right, secsR);
247
 
                                DrawShadow (ctx, r, PositionType.Bottom, secsB);
248
 
                                */
249
 
                        }
250
 
                }
251
 
                
252
 
                void DrawShadow (Cairo.Context ctx, Gdk.Rectangle ar, PositionType pos, List<Section> secs)
253
 
                {
254
 
                        foreach (Section s in secs) {
255
 
                                Cairo.Gradient pat = null;
256
 
                                Gdk.Rectangle r = ar;
257
 
                                switch (pos) {
258
 
                                        case PositionType.Top: 
259
 
                                                r.Height = shadowSize > r.Height ? r.Height / 2 : shadowSize;
260
 
                                                r.X += s.Offset;
261
 
                                                r.Width = s.Size;
262
 
                                                pat = new Cairo.LinearGradient (r.X, r.Y, r.X, r.Bottom);
263
 
                                                break;
264
 
                                        case PositionType.Bottom: 
265
 
                                                r.Y = r.Bottom - shadowSize;
266
 
                                                r.Height = shadowSize > r.Height ? r.Height / 2 : shadowSize;
267
 
                                                r.X = r.X + s.Offset;
268
 
                                                r.Width = s.Size;
269
 
                                                pat = new Cairo.LinearGradient (r.X, r.Bottom, r.X, r.Y);
270
 
                                                break;
271
 
                                        case PositionType.Left: 
272
 
                                                r.Width = shadowSize > r.Width ? r.Width / 2 : shadowSize; 
273
 
                                                r.Y += s.Offset;
274
 
                                                r.Height = s.Size;
275
 
                                                pat = new Cairo.LinearGradient (r.X, r.Y, r.Right, r.Y);
276
 
                                                break;
277
 
                                        case PositionType.Right: 
278
 
                                                r.X = r.Right - shadowSize;
279
 
                                                r.Width = shadowSize > r.Width ? r.Width / 2 : shadowSize; 
280
 
                                                r.Y += s.Offset;
281
 
                                                r.Height = s.Size;
282
 
                                                pat = new Cairo.LinearGradient (r.Right, r.Y, r.X, r.Y);
283
 
                                                break;
284
 
                                }
285
 
                                Cairo.Color c = GtkUtil.ToCairoColor (darkColor);
286
 
                                pat.AddColorStop (0, c);
287
 
                                c.A = 0;
288
 
                                pat.AddColorStop (1, c);
289
 
                                ctx.NewPath ();
290
 
                                ctx.Rectangle (r.X, r.Y, r.Width, r.Height);
291
 
                                ctx.Pattern = pat;
292
 
                                ctx.Fill ();
293
 
                                pat.Destroy ();
294
 
                        }
295
 
                }
296
 
                
297
 
                void RemoveSection (List<Section> secs, int offset, int size)
298
 
                {
299
 
                        if (offset < 0) {
300
 
                                size += offset;
301
 
                                offset = 0;
302
 
                        }
303
 
                        if (size <= 0 || secs.Count == 0)
304
 
                                return;
305
 
                        Section last = secs [secs.Count - 1];
306
 
                        int rem = (last.Offset + last.Size) - (offset + size);
307
 
                        if (rem < 0) {
308
 
                                size += rem;
309
 
                                if (size <= 0)
310
 
                                        return;
311
 
                        }
312
 
                        for (int n=0; n<secs.Count; n++) {
313
 
                                Section s = secs [n];
314
 
                                if (s.Offset >= offset + size)
315
 
                                        continue;
316
 
                                if (offset >= s.Offset + s.Size)
317
 
                                        continue;
318
 
                                if (offset <= s.Offset && offset + size >= s.Offset + s.Size) {
319
 
                                        // Remove the whole section
320
 
                                        secs.RemoveAt (n);
321
 
                                        n--;
322
 
                                        continue;
323
 
                                }
324
 
                                if (offset <= s.Offset) {
325
 
                                        int newOfs = offset + size;
326
 
                                        s.Size = s.Size - (newOfs - s.Offset);
327
 
                                        s.Offset = newOfs;
328
 
                                        secs [n] = s;
329
 
                                        // Nothing else to remove
330
 
                                        return;
331
 
                                }
332
 
                                if (offset + size >= s.Offset + s.Size) {
333
 
                                        s.Size = offset - s.Offset;
334
 
                                        secs [n] = s;
335
 
                                        continue;
336
 
                                }
337
 
                                // Split section
338
 
                                Section s2 = new Section ();
339
 
                                s2.Offset = offset + size;
340
 
                                s2.Size = (s.Offset + s.Size) - (offset + size);
341
 
                                secs.Insert (n + 1, s2);
342
 
                                s.Size = offset - s.Offset;
343
 
                                secs [n] = s;
344
 
                        }
345
 
                }
346
 
        }
347
 
        
348
 
        public interface IShadedWidget
349
 
        {
350
 
                IEnumerable<Gdk.Rectangle> GetShadedAreas ();
351
 
                event EventHandler AreasChanged;
352
 
        }
353
 
}
354