5
// Lluis Sanchez Gual <lluis@novell.com>
7
// Copyright (c) 2010 Novell, Inc (http://www.novell.com)
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:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
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
28
using System.Collections.Generic;
30
using MonoDevelop.Components;
32
namespace MonoDevelop.Components.Docking
34
public class ShadedContainer
45
List<Widget> widgets = new List<Widget> ();
46
Dictionary<Widget, Gdk.Rectangle[]> allocations = new Dictionary<Widget, Gdk.Rectangle[]> ();
48
public ShadedContainer ()
52
public int ShadowSize {
53
get { return this.shadowSize; }
54
set { this.shadowSize = value; RedrawAll (); }
57
public Gdk.Color LightColor {
58
get { return this.lightColor; }
59
set { this.lightColor = value; RedrawAll (); }
62
public Gdk.Color DarkColor {
63
get { return this.darkColor; }
64
set { this.darkColor = value; RedrawAll (); }
67
public void Add (Gtk.Widget 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;
78
sw.AreasChanged += HandleSwAreasChanged;
82
public void Remove (Widget 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;
92
sw.AreasChanged -= HandleSwAreasChanged;
96
bool UpdateAllocation (Widget w)
99
IShadedWidget sw = w as IShadedWidget;
100
Gdk.Rectangle[] newAllocations;
102
List<Gdk.Rectangle> rects = new List<Gdk.Rectangle> ();
103
foreach (Gdk.Rectangle ar in sw.GetShadedAreas ())
105
newAllocations = rects.ToArray ();
107
newAllocations = new Gdk.Rectangle [] { w.Allocation };
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]) {
123
allocations [w] = newAllocations;
127
if (!allocations.ContainsKey (w))
129
allocations.Remove (w);
134
void HandleWRealized (object sender, EventArgs e)
136
if (UpdateAllocation ((Widget) sender))
140
void HandleSwAreasChanged (object sender, EventArgs e)
142
if (UpdateAllocation ((Gtk.Widget)sender))
146
void HandleWSizeAllocated (object o, SizeAllocatedArgs args)
148
if (UpdateAllocation ((Widget) o))
152
void HandleWHidden (object sender, EventArgs e)
157
void HandleWShown (object sender, EventArgs e)
162
void HandleWDestroyed (object sender, EventArgs e)
164
Remove ((Widget)sender);
169
foreach (Widget w in widgets) {
172
IShadedWidget sw = w as IShadedWidget;
174
foreach (Gdk.Rectangle rect in sw.GetShadedAreas ())
175
w.QueueDrawArea (rect.X, rect.Y, rect.Width, rect.Height);
182
public void DrawBackground (Gtk.Widget w)
184
DrawBackground (w, w.Allocation);
187
public void DrawBackground (Gtk.Widget w, Gdk.Rectangle allocation)
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);
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> ();
205
w.GdkWindow.GetOrigin (out x, out y);
206
Gdk.Rectangle allocAbs = allocation;
207
allocAbs.Offset (x, y);
209
Section s = new Section ();
210
s.Size = allocAbs.Width;
213
s.Size = allocAbs.Height;
217
foreach (var rects in allocations) {
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)
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);
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);
242
//HACK: the shadow positions are all worn on recent GTK, disable them for now
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);
252
void DrawShadow (Cairo.Context ctx, Gdk.Rectangle ar, PositionType pos, List<Section> secs)
254
foreach (Section s in secs) {
255
Cairo.Gradient pat = null;
256
Gdk.Rectangle r = ar;
258
case PositionType.Top:
259
r.Height = shadowSize > r.Height ? r.Height / 2 : shadowSize;
262
pat = new Cairo.LinearGradient (r.X, r.Y, r.X, r.Bottom);
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;
269
pat = new Cairo.LinearGradient (r.X, r.Bottom, r.X, r.Y);
271
case PositionType.Left:
272
r.Width = shadowSize > r.Width ? r.Width / 2 : shadowSize;
275
pat = new Cairo.LinearGradient (r.X, r.Y, r.Right, r.Y);
277
case PositionType.Right:
278
r.X = r.Right - shadowSize;
279
r.Width = shadowSize > r.Width ? r.Width / 2 : shadowSize;
282
pat = new Cairo.LinearGradient (r.Right, r.Y, r.X, r.Y);
285
Cairo.Color c = GtkUtil.ToCairoColor (darkColor);
286
pat.AddColorStop (0, c);
288
pat.AddColorStop (1, c);
290
ctx.Rectangle (r.X, r.Y, r.Width, r.Height);
297
void RemoveSection (List<Section> secs, int offset, int size)
303
if (size <= 0 || secs.Count == 0)
305
Section last = secs [secs.Count - 1];
306
int rem = (last.Offset + last.Size) - (offset + size);
312
for (int n=0; n<secs.Count; n++) {
313
Section s = secs [n];
314
if (s.Offset >= offset + size)
316
if (offset >= s.Offset + s.Size)
318
if (offset <= s.Offset && offset + size >= s.Offset + s.Size) {
319
// Remove the whole section
324
if (offset <= s.Offset) {
325
int newOfs = offset + size;
326
s.Size = s.Size - (newOfs - s.Offset);
329
// Nothing else to remove
332
if (offset + size >= s.Offset + s.Size) {
333
s.Size = offset - s.Offset;
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;
348
public interface IShadedWidget
350
IEnumerable<Gdk.Rectangle> GetShadedAreas ();
351
event EventHandler AreasChanged;