Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLluis Sanchez <lluis@novell.com>2010-03-17 15:35:28 +0300
committerLluis Sanchez <lluis@novell.com>2010-03-17 15:35:28 +0300
commit8fa37870e9cc22ffccdd494fa951b2c3807d7978 (patch)
treebda14806802947c51676c183b08f166878964c40 /main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking
parentf1a8582658af8aeb0f6fa459965a2e4d0684c347 (diff)
parent585086f0ea0a49166046bb8f48d2def87907d0e0 (diff)
Merged MD.Projects into MD.Core, and MD.Projects.Gui, MD.Core.Gui and MD.Components into MD.Ide.
svn path=/trunk/monodevelop/; revision=153730
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking')
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/AutoHideBox.cs403
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBar.cs176
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBarItem.cs373
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs450
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockFrame.cs668
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockFrameTopLevel.cs61
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroup.cs1134
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroupItem.cs385
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroupType.cs41
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItem.cs513
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemBehavior.cs48
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemContainer.cs425
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemStatus.cs42
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemToolbar.cs181
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockLayout.cs107
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockObject.cs284
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockPosition.cs45
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/PlaceholderWindow.cs143
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/ShadedContainer.cs314
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/TabStrip.cs407
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-auto-hide.pngbin0 -> 211 bytes
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-close-12.pngbin0 -> 239 bytes
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-dock.pngbin0 -> 237 bytes
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-menu-left-12.pngbin0 -> 195 bytes
-rw-r--r--main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-menu-right-12.pngbin0 -> 191 bytes
25 files changed, 6200 insertions, 0 deletions
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/AutoHideBox.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/AutoHideBox.cs
new file mode 100644
index 0000000000..2b181c0c96
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/AutoHideBox.cs
@@ -0,0 +1,403 @@
+//
+// AutoHideBox.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using Gtk;
+using Gdk;
+
+namespace MonoDevelop.Components.Docking
+{
+ class AutoHideBox: DockFrameTopLevel
+ {
+ static Gdk.Cursor resizeCursorW = new Gdk.Cursor (Gdk.CursorType.SbHDoubleArrow);
+ static Gdk.Cursor resizeCursorH = new Gdk.Cursor (Gdk.CursorType.SbVDoubleArrow);
+
+ bool resizing;
+ int resizePos;
+ int origSize;
+ int origPos;
+ bool horiz;
+ bool startPos;
+ DockFrame frame;
+ bool animating;
+ int targetSize;
+ int targetPos;
+ ScrollableContainer scrollable;
+ Gtk.PositionType position;
+ bool disposed;
+ bool insideGrip;
+
+ const int gripSize = 8;
+
+ public AutoHideBox (DockFrame frame, DockItem item, Gtk.PositionType pos, int size)
+ {
+ this.position = pos;
+ this.frame = frame;
+ this.targetSize = size;
+ horiz = pos == PositionType.Left || pos == PositionType.Right;
+ startPos = pos == PositionType.Top || pos == PositionType.Left;
+ Events = Events | Gdk.EventMask.EnterNotifyMask | Gdk.EventMask.LeaveNotifyMask;
+
+ Box fr;
+ CustomFrame cframe = new CustomFrame ();
+ switch (pos) {
+ case PositionType.Left: cframe.SetMargins (1, 1, 0, 1); break;
+ case PositionType.Right: cframe.SetMargins (1, 1, 1, 0); break;
+ case PositionType.Top: cframe.SetMargins (0, 1, 1, 1); break;
+ case PositionType.Bottom: cframe.SetMargins (1, 0, 1, 1); break;
+ }
+ EventBox sepBox = new EventBox ();
+ cframe.Add (sepBox);
+
+ if (horiz) {
+ fr = new HBox ();
+ sepBox.Realized += delegate { sepBox.GdkWindow.Cursor = resizeCursorW; };
+ sepBox.WidthRequest = gripSize;
+ } else {
+ fr = new VBox ();
+ sepBox.Realized += delegate { sepBox.GdkWindow.Cursor = resizeCursorH; };
+ sepBox.HeightRequest = gripSize;
+ }
+
+ sepBox.Events = EventMask.AllEventsMask;
+
+ if (pos == PositionType.Left || pos == PositionType.Top)
+ fr.PackEnd (cframe, false, false, 0);
+ else
+ fr.PackStart (cframe, false, false, 0);
+
+ Add (fr);
+ ShowAll ();
+ Hide ();
+
+ scrollable = new ScrollableContainer ();
+ scrollable.ScrollMode = false;
+ scrollable.Show ();
+
+ item.Widget.Show ();
+ scrollable.Add (item.Widget);
+ fr.PackStart (scrollable, true, true, 0);
+
+ sepBox.ButtonPressEvent += OnSizeButtonPress;
+ sepBox.ButtonReleaseEvent += OnSizeButtonRelease;
+ sepBox.MotionNotifyEvent += OnSizeMotion;
+ sepBox.ExposeEvent += OnGripExpose;
+ sepBox.EnterNotifyEvent += delegate { insideGrip = true; sepBox.QueueDraw (); };
+ sepBox.LeaveNotifyEvent += delegate { insideGrip = false; sepBox.QueueDraw (); };
+ }
+
+ public bool Disposed {
+ get { return disposed; }
+ set { disposed = value; }
+ }
+
+ public void AnimateShow ()
+ {
+ animating = true;
+ scrollable.ScrollMode = true;
+ scrollable.SetSize (position, targetSize);
+
+ switch (position) {
+ case PositionType.Left:
+ WidthRequest = 0;
+ break;
+ case PositionType.Right:
+ targetPos = X = X + WidthRequest;
+ WidthRequest = 0;
+ break;
+ case PositionType.Top:
+ HeightRequest = 0;
+ break;
+ case PositionType.Bottom:
+ targetPos = Y = Y + HeightRequest;
+ HeightRequest = 0;
+ break;
+ }
+ Show ();
+ GLib.Timeout.Add (10, RunAnimateShow);
+ }
+
+ protected override void OnShown ()
+ {
+ base.OnShown ();
+ }
+
+
+ public void AnimateHide ()
+ {
+ animating = true;
+ scrollable.ScrollMode = true;
+ scrollable.SetSize (position, targetSize);
+ GLib.Timeout.Add (10, RunAnimateHide);
+ }
+
+ bool RunAnimateShow ()
+ {
+ if (!animating)
+ return false;
+
+ switch (position) {
+ case PositionType.Left:
+ WidthRequest += 1 + (targetSize - WidthRequest) / 3;
+ if (WidthRequest < targetSize)
+ return true;
+ break;
+ case PositionType.Right:
+ WidthRequest += 1 + (targetSize - WidthRequest) / 3;
+ X = targetPos - WidthRequest;
+ if (WidthRequest < targetSize)
+ return true;
+ break;
+ case PositionType.Top:
+ HeightRequest += 1 + (targetSize - HeightRequest) / 3;
+ if (HeightRequest < targetSize)
+ return true;
+ break;
+ case PositionType.Bottom:
+ HeightRequest += 1 + (targetSize - HeightRequest) / 3;
+ Y = targetPos - HeightRequest;
+ if (HeightRequest < targetSize)
+ return true;
+ break;
+ }
+
+ scrollable.ScrollMode = false;
+ if (horiz)
+ WidthRequest = targetSize;
+ else
+ HeightRequest = targetSize;
+ animating = false;
+ return false;
+ }
+
+ bool RunAnimateHide ()
+ {
+ if (!animating)
+ return false;
+
+ switch (position) {
+ case PositionType.Left: {
+ int ns = WidthRequest - 1 - WidthRequest / 3;
+ if (ns > 0) {
+ WidthRequest = ns;
+ return true;
+ }
+ break;
+ }
+ case PositionType.Right: {
+ int ns = WidthRequest - 1 - WidthRequest / 3;
+ if (ns > 0) {
+ WidthRequest = ns;
+ X = targetPos - ns;
+ return true;
+ }
+ break;
+ }
+ case PositionType.Top: {
+ int ns = HeightRequest - 1 - HeightRequest / 3;
+ if (ns > 0) {
+ HeightRequest = ns;
+ return true;
+ }
+ break;
+ }
+ case PositionType.Bottom: {
+ int ns = HeightRequest - 1 - HeightRequest / 3;
+ if (ns > 0) {
+ HeightRequest = ns;
+ Y = targetPos - ns;
+ return true;
+ }
+ break;
+ }
+ }
+
+ Hide ();
+ animating = false;
+ return false;
+ }
+
+ protected override void OnHidden ()
+ {
+ base.OnHidden ();
+ animating = false;
+ }
+
+
+ public int Size {
+ get {
+ return horiz ? WidthRequest : HeightRequest;
+ }
+ }
+
+ void OnSizeButtonPress (object ob, Gtk.ButtonPressEventArgs args)
+ {
+ if (args.Event.Button == 1 && !animating) {
+ int n;
+ if (horiz) {
+ Toplevel.GetPointer (out resizePos, out n);
+ origSize = WidthRequest;
+ if (!startPos) {
+ origPos = X + origSize;
+ }
+ } else {
+ Toplevel.GetPointer (out n, out resizePos);
+ origSize = HeightRequest;
+ if (!startPos) {
+ origPos = Y + origSize;
+ }
+ }
+ resizing = true;
+ }
+ }
+
+ void OnSizeButtonRelease (object ob, Gtk.ButtonReleaseEventArgs args)
+ {
+ resizing = false;
+ }
+
+ void OnSizeMotion (object ob, Gtk.MotionNotifyEventArgs args)
+ {
+ if (resizing) {
+ int newPos, n;
+ if (horiz) {
+ Toplevel.GetPointer (out newPos, out n);
+ int diff = startPos ? (newPos - resizePos) : (resizePos - newPos);
+ int newSize = origSize + diff;
+ if (newSize < Child.SizeRequest ().Width)
+ newSize = Child.SizeRequest ().Width;
+ if (!startPos) {
+ X = origPos - newSize;
+ }
+ WidthRequest = newSize;
+ } else {
+ Toplevel.GetPointer (out n, out newPos);
+ int diff = startPos ? (newPos - resizePos) : (resizePos - newPos);
+ int newSize = origSize + diff;
+ if (newSize < Child.SizeRequest ().Height)
+ newSize = Child.SizeRequest ().Height;
+ if (!startPos) {
+ Y = origPos - newSize;
+ }
+ HeightRequest = newSize;
+ }
+ frame.QueueResize ();
+ }
+ }
+
+ void OnGripExpose (object ob, Gtk.ExposeEventArgs args)
+ {
+ EventBox w = (EventBox) ob;
+ Gdk.Rectangle handleRect = w.Allocation;
+// w.GdkWindow.DrawRectangle (w.Style.DarkGC (StateType.Normal), true, handleRect);
+ handleRect.X = handleRect.Y = 0;
+
+/* switch (position) {
+ case PositionType.Top:
+ handleRect.Height -= 4; handleRect.Y += 1;
+ Gtk.Style.PaintHline (w.Style, w.GdkWindow, StateType.Normal, args.Event.Area, w, "", 0, w.Allocation.Width, gripSize - 2);
+ break;
+ case PositionType.Bottom:
+ handleRect.Height -= 4; handleRect.Y += 3;
+ Gtk.Style.PaintHline (w.Style, w.GdkWindow, StateType.Normal, args.Event.Area, w, "", 0, w.Allocation.Width, 0);
+ break;
+ case PositionType.Left:
+ handleRect.Width -= 4; handleRect.X += 1;
+ Gtk.Style.PaintVline (w.Style, w.GdkWindow, StateType.Normal, args.Event.Area, w, "", 0, w.Allocation.Height, gripSize - 2);
+ break;
+ case PositionType.Right:
+ handleRect.Width -= 4; handleRect.X += 3;
+ Gtk.Style.PaintVline (w.Style, w.GdkWindow, StateType.Normal, args.Event.Area, w, "", 0, w.Allocation.Height, 0);
+ break;
+ }*/
+
+ Orientation or = horiz ? Orientation.Vertical : Orientation.Horizontal;
+ StateType s = insideGrip ? StateType.Prelight : StateType.Normal;
+ Gtk.Style.PaintHandle (w.Style, w.GdkWindow, s, ShadowType.None, args.Event.Area, w, "paned", handleRect.Left, handleRect.Top, handleRect.Width, handleRect.Height, or);
+ }
+ }
+
+ class ScrollableContainer: EventBox
+ {
+ PositionType expandPos;
+ bool scrollMode;
+ int targetSize;
+
+ public bool ScrollMode {
+ get {
+ return scrollMode;
+ }
+ set {
+ scrollMode = value;
+ QueueResize ();
+ }
+ }
+
+ public void SetSize (PositionType expandPosition, int targetSize)
+ {
+ this.expandPos = expandPosition;
+ this.targetSize = targetSize;
+ QueueResize ();
+ }
+
+ protected override void OnSizeRequested (ref Requisition req)
+ {
+ base.OnSizeRequested (ref req);
+ if (scrollMode || Child == null) {
+ req.Width = 0;
+ req.Height = 0;
+ }
+ else
+ req = Child.SizeRequest ();
+ }
+
+ protected override void OnSizeAllocated (Rectangle alloc)
+ {
+ if (scrollMode && Child != null) {
+ switch (expandPos) {
+ case PositionType.Bottom:
+ alloc = new Rectangle (alloc.X, alloc.Y, alloc.Width, targetSize);
+ break;
+ case PositionType.Top:
+ alloc = new Rectangle (alloc.X, alloc.Y - targetSize + alloc.Height, alloc.Width, targetSize);
+ break;
+ case PositionType.Right:
+ alloc = new Rectangle (alloc.X, alloc.Y, targetSize, alloc.Height);
+ break;
+ case PositionType.Left:
+ alloc = new Rectangle (alloc.X - targetSize + alloc.Width, alloc.Y, targetSize, alloc.Height);
+ break;
+ }
+ }
+ base.OnSizeAllocated (alloc);
+ }
+ }
+
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBar.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBar.cs
new file mode 100644
index 0000000000..d62ab5dd1c
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBar.cs
@@ -0,0 +1,176 @@
+//
+// DockBar.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System;
+using Gtk;
+using System.Collections.Generic;
+
+namespace MonoDevelop.Components.Docking
+{
+ public class DockBar: Gtk.EventBox
+ {
+ Gtk.PositionType position;
+ Box box;
+ DockFrame frame;
+ Label filler;
+ bool alwaysVisible;
+
+ internal DockBar (DockFrame frame, Gtk.PositionType position)
+ {
+ frame.ShadedContainer.Add (this);
+ VisibleWindow = false;
+ this.frame = frame;
+ this.position = position;
+ Gtk.Alignment al = new Alignment (0,0,0,0);
+ if (Orientation == Gtk.Orientation.Horizontal)
+ box = new HBox ();
+ else
+ box = new VBox ();
+
+ uint sizePadding = 1;
+ uint startPadding = 6;
+ switch (Frame.CompactGuiLevel) {
+ case 1: sizePadding = 2; break;
+ case 4: startPadding = 3; break;
+ case 5: startPadding = 0; sizePadding = 0; break;
+ }
+
+ switch (position) {
+ case PositionType.Top: al.BottomPadding = sizePadding; al.LeftPadding = al.RightPadding = startPadding; break;
+ case PositionType.Bottom: al.TopPadding = sizePadding; al.LeftPadding = al.RightPadding = startPadding; break;
+ case PositionType.Left: al.RightPadding = sizePadding; al.TopPadding = al.BottomPadding = startPadding; break;
+ case PositionType.Right: al.LeftPadding = sizePadding; al.TopPadding = al.BottomPadding = startPadding; break;
+ }
+
+ box.Spacing = 3;
+ al.Add (box);
+ Add (al);
+
+ filler = new Label ();
+ filler.WidthRequest = 4;
+ filler.HeightRequest = 4;
+ box.PackEnd (filler);
+
+ ShowAll ();
+ UpdateVisibility ();
+ }
+
+ public bool IsExtracted {
+ get { return OriginalBar != null; }
+ }
+
+ internal DockBar OriginalBar { get; set; }
+
+ public bool AlwaysVisible {
+ get { return this.alwaysVisible; }
+ set { this.alwaysVisible = value; UpdateVisibility (); }
+ }
+
+
+ internal Gtk.Orientation Orientation {
+ get {
+ return (position == PositionType.Left || position == PositionType.Right) ? Gtk.Orientation.Vertical : Gtk.Orientation.Horizontal;
+ }
+ }
+
+ internal Gtk.PositionType Position {
+ get {
+ return position;
+ }
+ }
+
+ internal DockFrame Frame {
+ get {
+ return frame;
+ }
+ }
+
+ internal DockBarItem AddItem (DockItem item, int size)
+ {
+ DockBarItem it = new DockBarItem (this, item, size);
+ box.PackStart (it, false, false, 0);
+ it.ShowAll ();
+ UpdateVisibility ();
+ it.Shown += OnItemVisibilityChanged;
+ it.Hidden += OnItemVisibilityChanged;
+ return it;
+ }
+
+ void OnItemVisibilityChanged (object o, EventArgs args)
+ {
+ UpdateVisibility ();
+ }
+
+ internal void OnCompactLevelChanged ()
+ {
+ UpdateVisibility ();
+ if (OriginalBar != null)
+ OriginalBar.UpdateVisibility ();
+ }
+
+ internal void UpdateVisibility ()
+ {
+ filler.Visible = (Frame.CompactGuiLevel < 3);
+ int visibleCount = 0;
+ foreach (Gtk.Widget w in box.Children) {
+ if (w.Visible)
+ visibleCount++;
+ }
+ Visible = alwaysVisible || filler.Visible || visibleCount > 0;
+ }
+
+ internal void RemoveItem (DockBarItem it)
+ {
+ box.Remove (it);
+ it.Shown -= OnItemVisibilityChanged;
+ it.Hidden -= OnItemVisibilityChanged;
+ UpdateVisibility ();
+ }
+
+ internal void UpdateTitle (DockItem item)
+ {
+ foreach (Widget w in box.Children) {
+ DockBarItem it = w as DockBarItem;
+ if (it != null && it.DockItem == item) {
+ it.UpdateTab ();
+ break;
+ }
+ }
+ }
+
+ protected override bool OnExposeEvent (Gdk.EventExpose evnt)
+ {
+ frame.ShadedContainer.DrawBackground (this);
+ return base.OnExposeEvent (evnt);
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBarItem.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBarItem.cs
new file mode 100644
index 0000000000..b7354ad4b5
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockBarItem.cs
@@ -0,0 +1,373 @@
+//
+// DockBarItem.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System;
+using Gtk;
+
+namespace MonoDevelop.Components.Docking
+{
+ class DockBarItem: EventBox
+ {
+ DockBar bar;
+ DockItem it;
+ Box box;
+ Label label;
+ Alignment mainBox;
+ AutoHideBox autoShowFrame;
+ AutoHideBox hiddenFrame;
+ uint autoShowTimeout = uint.MaxValue;
+ uint autoHideTimeout = uint.MaxValue;
+ int size;
+
+ public DockBarItem (DockBar bar, DockItem it, int size)
+ {
+ Events = Events | Gdk.EventMask.EnterNotifyMask | Gdk.EventMask.LeaveNotifyMask;
+ this.size = size;
+ this.bar = bar;
+ this.it = it;
+ VisibleWindow = false;
+ UpdateTab ();
+ }
+
+ public void Close ()
+ {
+ UnscheduleAutoShow ();
+ UnscheduleAutoHide ();
+ AutoHide (false);
+ bar.RemoveItem (this);
+ Destroy ();
+ }
+
+ public int Size {
+ get { return size; }
+ set { size = value; }
+ }
+
+ public void UpdateTab ()
+ {
+ if (Child != null) {
+ Widget w = Child;
+ Remove (w);
+ w.Destroy ();
+ }
+
+ mainBox = new Alignment (0,0,1,1);
+ if (bar.Orientation == Gtk.Orientation.Horizontal) {
+ box = new HBox ();
+ mainBox.LeftPadding = mainBox.RightPadding = 2;
+ }
+ else {
+ box = new VBox ();
+ mainBox.TopPadding = mainBox.BottomPadding = 2;
+ }
+
+ Gtk.Widget customLabel = null;
+ if (it.DockLabelProvider != null)
+ customLabel = it.DockLabelProvider.CreateLabel (bar.Orientation);
+
+ if (customLabel != null) {
+ customLabel.ShowAll ();
+ box.PackStart (customLabel, true, true, 0);
+ }
+ else {
+ if (it.Icon != null)
+ box.PackStart (new Gtk.Image (it.Icon), false, false, 0);
+
+ if (!string.IsNullOrEmpty (it.Label)) {
+ label = new Gtk.Label (it.Label);
+ label.UseMarkup = true;
+ if (bar.Orientation == Gtk.Orientation.Vertical)
+ label.Angle = 270;
+ box.PackStart (label, true, true, 0);
+ } else
+ label = null;
+ }
+
+ box.BorderWidth = 2;
+ box.Spacing = 2;
+ mainBox.Add (box);
+ mainBox.ShowAll ();
+ Add (mainBox);
+ SetNormalColor ();
+ }
+
+ public MonoDevelop.Components.Docking.DockItem DockItem {
+ get {
+ return it;
+ }
+ }
+
+ protected override void OnHidden ()
+ {
+ base.OnHidden ();
+ UnscheduleAutoShow ();
+ UnscheduleAutoHide ();
+ AutoHide (false);
+ }
+
+ protected override bool OnExposeEvent (Gdk.EventExpose evnt)
+ {
+ if (State == StateType.Prelight) {
+ int w = Allocation.Width, h = Allocation.Height;
+ double x=Allocation.Left, y=Allocation.Top, r=3;
+ x += 0.5; y += 0.5; h -=1; w -= 1;
+
+ using (Cairo.Context ctx = Gdk.CairoHelper.Create (GdkWindow)) {
+ HslColor c = new HslColor (Style.Background (Gtk.StateType.Normal));
+ HslColor c1 = c;
+ HslColor c2 = c;
+ if (State != StateType.Prelight) {
+ c1.L *= 0.8;
+ c2.L *= 0.95;
+ } else {
+ c1.L *= 1.1;
+ c2.L *= 1;
+ }
+ Cairo.Gradient pat;
+ switch (bar.Position) {
+ case PositionType.Top: pat = new Cairo.LinearGradient (x, y, x, y+h); break;
+ case PositionType.Bottom: pat = new Cairo.LinearGradient (x, y, x, y+h); break;
+ case PositionType.Left: pat = new Cairo.LinearGradient (x+w, y, x, y); break;
+ default: pat = new Cairo.LinearGradient (x, y, x+w, y); break;
+ }
+ pat.AddColorStop (0, c1);
+ pat.AddColorStop (1, c2);
+ ctx.NewPath ();
+ ctx.Arc (x+r, y+r, r, 180 * (Math.PI / 180), 270 * (Math.PI / 180));
+ ctx.LineTo (x+w-r, y);
+ ctx.Arc (x+w-r, y+r, r, 270 * (Math.PI / 180), 360 * (Math.PI / 180));
+ ctx.LineTo (x+w, y+h);
+ ctx.LineTo (x, y+h);
+ ctx.ClosePath ();
+ ctx.Pattern = pat;
+ ctx.FillPreserve ();
+ c1 = c;
+ c1.L *= 0.7;
+ ctx.LineWidth = 1;
+ ctx.Color = c1;
+ ctx.Stroke ();
+
+ // Inner line
+ ctx.NewPath ();
+ ctx.Arc (x+r+1, y+r+1, r, 180 * (Math.PI / 180), 270 * (Math.PI / 180));
+ ctx.LineTo (x+w-r-1, y+1);
+ ctx.Arc (x+w-r-1, y+r+1, r, 270 * (Math.PI / 180), 360 * (Math.PI / 180));
+ ctx.LineTo (x+w-1, y+h-1);
+ ctx.LineTo (x+1, y+h-1);
+ ctx.ClosePath ();
+ c1 = c;
+ //c1.L *= 0.9;
+ ctx.LineWidth = 1;
+ ctx.Color = c1;
+ ctx.Stroke ();
+ }
+ }
+
+ bool res = base.OnExposeEvent (evnt);
+ return res;
+ }
+
+ public void Present (bool giveFocus)
+ {
+ AutoShow ();
+ if (giveFocus) {
+ GLib.Timeout.Add (200, delegate {
+ // Using a small delay because AutoShow uses an animation and setting focus may
+ // not work until the item is visible
+ it.SetFocus ();
+ ScheduleAutoHide (false);
+ return false;
+ });
+ }
+ }
+
+ void AutoShow ()
+ {
+ UnscheduleAutoHide ();
+ if (autoShowFrame == null) {
+ if (hiddenFrame != null)
+ bar.Frame.AutoHide (it, hiddenFrame, false);
+ autoShowFrame = bar.Frame.AutoShow (it, bar, size);
+ autoShowFrame.EnterNotifyEvent += OnFrameEnter;
+ autoShowFrame.LeaveNotifyEvent += OnFrameLeave;
+ autoShowFrame.KeyPressEvent += OnFrameKeyPress;
+ SetPrelight ();
+ }
+ }
+
+ void AutoHide (bool animate)
+ {
+ UnscheduleAutoShow ();
+ if (autoShowFrame != null) {
+ size = autoShowFrame.Size;
+ hiddenFrame = autoShowFrame;
+ autoShowFrame.Hidden += delegate {
+ hiddenFrame = null;
+ };
+ bar.Frame.AutoHide (it, autoShowFrame, animate);
+ autoShowFrame.EnterNotifyEvent -= OnFrameEnter;
+ autoShowFrame.LeaveNotifyEvent -= OnFrameLeave;
+ autoShowFrame.KeyPressEvent -= OnFrameKeyPress;
+ autoShowFrame = null;
+ UnsetPrelight ();
+ }
+ }
+
+ void ScheduleAutoShow ()
+ {
+ UnscheduleAutoHide ();
+ if (autoShowTimeout == uint.MaxValue) {
+ autoShowTimeout = GLib.Timeout.Add (bar.Frame.AutoShowDelay, delegate {
+ autoShowTimeout = uint.MaxValue;
+ AutoShow ();
+ return false;
+ });
+ }
+ }
+
+ void ScheduleAutoHide (bool cancelAutoShow)
+ {
+ ScheduleAutoHide (cancelAutoShow, false);
+ }
+
+ void ScheduleAutoHide (bool cancelAutoShow, bool force)
+ {
+ if (cancelAutoShow)
+ UnscheduleAutoShow ();
+ if (force)
+ it.Widget.FocusChild = null;
+ if (autoHideTimeout == uint.MaxValue) {
+ autoHideTimeout = GLib.Timeout.Add (force ? 0 : bar.Frame.AutoHideDelay, delegate {
+ // Don't hide the item if it has the focus. Try again later.
+ if (it.Widget.FocusChild != null)
+ return true;
+ autoHideTimeout = uint.MaxValue;
+ AutoHide (true);
+ return false;
+ });
+ }
+ }
+
+ void UnscheduleAutoShow ()
+ {
+ if (autoShowTimeout != uint.MaxValue) {
+ GLib.Source.Remove (autoShowTimeout);
+ autoShowTimeout = uint.MaxValue;
+ }
+ }
+
+ void UnscheduleAutoHide ()
+ {
+ if (autoHideTimeout != uint.MaxValue) {
+ GLib.Source.Remove (autoHideTimeout);
+ autoHideTimeout = uint.MaxValue;
+ }
+ }
+
+ protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt)
+ {
+ ScheduleAutoShow ();
+ SetPrelight ();
+ return base.OnEnterNotifyEvent (evnt);
+ }
+
+ protected override bool OnLeaveNotifyEvent (Gdk.EventCrossing evnt)
+ {
+ ScheduleAutoHide (true);
+ if (autoShowFrame == null)
+ UnsetPrelight ();
+ return base.OnLeaveNotifyEvent (evnt);
+ }
+
+ void SetPrelight ()
+ {
+ if (State != StateType.Prelight) {
+ State = StateType.Prelight;
+ if (label != null)
+ label.ModifyFg (StateType.Normal, Style.Foreground (Gtk.StateType.Normal));
+ }
+ }
+
+ void UnsetPrelight ()
+ {
+ if (State == StateType.Prelight) {
+ State = StateType.Normal;
+ SetNormalColor ();
+ }
+ }
+
+ protected override void OnRealized ()
+ {
+ base.OnRealized();
+ SetNormalColor ();
+ }
+
+
+ void SetNormalColor ()
+ {
+ if (label != null) {
+ HslColor c = Style.Background (Gtk.StateType.Normal);
+ c.L *= 0.4;
+ label.ModifyFg (StateType.Normal, c);
+ }
+ }
+
+ void OnFrameEnter (object s, Gtk.EnterNotifyEventArgs args)
+ {
+ AutoShow ();
+ }
+
+ void OnFrameKeyPress (object s, Gtk.KeyPressEventArgs args)
+ {
+ if (args.Event.Key == Gdk.Key.Escape)
+ ScheduleAutoHide (true, true);
+ }
+
+ void OnFrameLeave (object s, Gtk.LeaveNotifyEventArgs args)
+ {
+ if (args.Event.Detail != Gdk.NotifyType.Inferior)
+ ScheduleAutoHide (true);
+ }
+
+ protected override bool OnButtonPressEvent (Gdk.EventButton evnt)
+ {
+ if (evnt.Button == 1) {
+ if (evnt.Type == Gdk.EventType.TwoButtonPress)
+ it.Status = DockItemStatus.Dockable;
+ else
+ AutoShow ();
+ }
+ else if (evnt.Button == 3)
+ it.ShowDockPopupMenu (evnt.Time);
+ return base.OnButtonPressEvent (evnt);
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs
new file mode 100644
index 0000000000..cba733da8e
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockContainer.cs
@@ -0,0 +1,450 @@
+//
+// DockContainer.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+
+using System;
+using System.Collections.Generic;
+using Gtk;
+using Gdk;
+
+namespace MonoDevelop.Components.Docking
+{
+ class DockContainer: Container, IShadedWidget
+ {
+ DockLayout layout;
+ DockFrame frame;
+
+ List<TabStrip> notebooks = new List<TabStrip> ();
+ List<DockItem> items = new List<DockItem> ();
+
+ bool needsRelayout = true;
+
+ DockGroup currentHandleGrp;
+ int currentHandleIndex;
+ bool dragging;
+ int dragPos;
+ int dragSize;
+
+ PlaceholderWindow placeholderWindow;
+
+ static Gdk.Cursor hresizeCursor = new Gdk.Cursor (CursorType.SbHDoubleArrow);
+ static Gdk.Cursor vresizeCursor = new Gdk.Cursor (CursorType.SbVDoubleArrow);
+
+ public DockContainer (DockFrame frame)
+ {
+ this.Events = EventMask.ButtonPressMask | EventMask.ButtonReleaseMask | EventMask.PointerMotionMask | EventMask.LeaveNotifyMask;
+ this.frame = frame;
+ frame.ShadedContainer.Add (this);
+ }
+
+ internal DockGroupItem FindDockGroupItem (string id)
+ {
+ if (layout == null)
+ return null;
+ else
+ return layout.FindDockGroupItem (id);
+ }
+
+ public List<DockItem> Items {
+ get { return items; }
+ }
+
+ public DockLayout Layout {
+ get { return layout; }
+ set { layout = value; }
+ }
+
+ public void Clear ()
+ {
+ layout = null;
+ }
+
+ public void LoadLayout (DockLayout dl)
+ {
+ // Sticky items currently selected in notebooks will remain
+ // selected after switching the layout
+ List<DockItem> sickyOnTop = new List<DockItem> ();
+ foreach (DockItem it in items) {
+ if ((it.Behavior & DockItemBehavior.Sticky) != 0) {
+ DockGroupItem gitem = FindDockGroupItem (it.Id);
+ if (gitem != null && gitem.ParentGroup.IsSelectedPage (it))
+ sickyOnTop.Add (it);
+ }
+ }
+
+ if (layout != null)
+ layout.StoreAllocation ();
+ layout = dl;
+ layout.RestoreAllocation ();
+
+ // Make sure items not present in this layout are hidden
+ foreach (DockItem it in items) {
+ if ((it.Behavior & DockItemBehavior.Sticky) != 0)
+ it.Visible = it.StickyVisible;
+ if (layout.FindDockGroupItem (it.Id) == null)
+ it.HideWidget ();
+ }
+
+ RelayoutWidgets ();
+
+ foreach (DockItem it in sickyOnTop)
+ it.Present (false);
+ }
+
+ public void StoreAllocation ()
+ {
+ if (layout != null)
+ layout.StoreAllocation ();
+ }
+
+ protected override void OnSizeRequested (ref Requisition req)
+ {
+ if (layout != null) {
+ LayoutWidgets ();
+ req = layout.SizeRequest ();
+ }
+ }
+
+ protected override void OnSizeAllocated (Gdk.Rectangle rect)
+ {
+ base.OnSizeAllocated (rect);
+ if (layout == null)
+ return;
+
+ // This container has its own window, so allocation of children
+ // is relative to 0,0
+ rect.X = rect.Y = 0;
+ LayoutWidgets ();
+ layout.Size = -1;
+ layout.SizeAllocate (rect);
+ }
+
+ protected override void ForAll (bool include_internals, Gtk.Callback callback)
+ {
+ List<Widget> widgets = new List<Widget> ();
+ foreach (Widget w in notebooks)
+ widgets.Add (w);
+ foreach (DockItem it in items) {
+ if (it.HasWidget && it.Widget.Parent == this)
+ widgets.Add (it.Widget);
+ }
+ foreach (Widget w in widgets)
+ callback (w);
+ }
+
+ protected override bool OnExposeEvent (Gdk.EventExpose evnt)
+ {
+ bool res = base.OnExposeEvent (evnt);
+
+ if (layout != null) {
+ layout.Draw (evnt.Area, currentHandleGrp, currentHandleIndex);
+ }
+ return res;
+ }
+
+
+ public void RelayoutWidgets ()
+ {
+ needsRelayout = true;
+ QueueResize ();
+ }
+
+ void LayoutWidgets ()
+ {
+ if (!needsRelayout)
+ return;
+ needsRelayout = false;
+
+ // Create the needed notebooks and place the widgets in there
+
+ List<DockGroup> tabbedGroups = new List<DockGroup> ();
+ GetTabbedGroups (layout, tabbedGroups);
+
+ for (int n=0; n<tabbedGroups.Count; n++) {
+ DockGroup grp = tabbedGroups [n];
+ TabStrip ts;
+ if (n < notebooks.Count) {
+ ts = notebooks [n];
+ }
+ else {
+ ts = new TabStrip (frame);
+ ts.Show ();
+ notebooks.Add (ts);
+ ts.Parent = this;
+ }
+ grp.UpdateNotebook (ts);
+ }
+
+ // Remove spare tab strips
+ for (int n = notebooks.Count - 1; n >= tabbedGroups.Count; n--) {
+ TabStrip ts = notebooks [n];
+ notebooks.RemoveAt (n);
+ ts.Clear ();
+ ts.Unparent ();
+ ts.Destroy ();
+ }
+
+ // Add widgets to the container
+
+ layout.LayoutWidgets ();
+ NotifySeparatorsChanged ();
+ }
+
+ void GetTabbedGroups (DockGroup grp, List<DockGroup> tabbedGroups)
+ {
+ if (grp.Type == DockGroupType.Tabbed) {
+ if (grp.VisibleObjects.Count > 1)
+ tabbedGroups.Add (grp);
+ else
+ grp.ResetNotebook ();
+ }
+ else {
+ // Make sure it doesn't have a notebook bound to it
+ grp.ResetNotebook ();
+ foreach (DockObject ob in grp.Objects) {
+ if (ob is DockGroup)
+ GetTabbedGroups ((DockGroup) ob, tabbedGroups);
+ }
+ }
+ }
+
+ protected override bool OnButtonPressEvent (Gdk.EventButton ev)
+ {
+ if (currentHandleGrp != null) {
+ dragging = true;
+ dragPos = (currentHandleGrp.Type == DockGroupType.Horizontal) ? (int)ev.X : (int)ev.Y;
+ DockObject obj = currentHandleGrp.VisibleObjects [currentHandleIndex];
+ dragSize = (currentHandleGrp.Type == DockGroupType.Horizontal) ? obj.Allocation.Width : obj.Allocation.Height;
+ }
+ return base.OnButtonPressEvent (ev);
+ }
+
+ protected override bool OnButtonReleaseEvent (Gdk.EventButton e)
+ {
+ dragging = false;
+ return base.OnButtonReleaseEvent (e);
+ }
+
+ protected override bool OnMotionNotifyEvent (Gdk.EventMotion e)
+ {
+ if (dragging) {
+ NotifySeparatorsChanged ();
+ int newpos = (currentHandleGrp.Type == DockGroupType.Horizontal) ? (int)e.X : (int)e.Y;
+ if (newpos != dragPos) {
+ int nsize = dragSize + (newpos - dragPos);
+ currentHandleGrp.ResizeItem (currentHandleIndex, nsize);
+ layout.DrawSeparators (Allocation, currentHandleGrp, currentHandleIndex, true, null);
+ }
+ }
+ else if (layout != null && placeholderWindow == null) {
+ int index;
+ DockGroup grp;
+ if (FindHandle (layout, (int)e.X, (int)e.Y, out grp, out index)) {
+ if (currentHandleGrp != grp || currentHandleIndex != index) {
+ if (grp.Type == DockGroupType.Horizontal)
+ this.GdkWindow.Cursor = hresizeCursor;
+ else
+ this.GdkWindow.Cursor = vresizeCursor;
+ currentHandleGrp = grp;
+ currentHandleIndex = index;
+ layout.DrawSeparators (Allocation, currentHandleGrp, currentHandleIndex, true, null);
+ }
+ }
+ else if (currentHandleGrp != null) {
+ ResetHandleHighlight ();
+ }
+ }
+ return base.OnMotionNotifyEvent (e);
+ }
+
+ void ResetHandleHighlight ()
+ {
+ this.GdkWindow.Cursor = null;
+ currentHandleGrp = null;
+ currentHandleIndex = -1;
+ if (layout != null)
+ layout.DrawSeparators (Allocation, null, -1, true, null);
+ }
+
+ protected override bool OnLeaveNotifyEvent (EventCrossing evnt)
+ {
+ if (!dragging && evnt.Mode != CrossingMode.Grab)
+ ResetHandleHighlight ();
+ return base.OnLeaveNotifyEvent (evnt);
+ }
+
+
+ bool FindHandle (DockGroup grp, int x, int y, out DockGroup foundGrp, out int objectIndex)
+ {
+ if (grp.Type != DockGroupType.Tabbed && grp.Allocation.Contains (x, y)) {
+ for (int n=0; n<grp.VisibleObjects.Count; n++) {
+ DockObject obj = grp.VisibleObjects [n];
+ if (n < grp.Objects.Count - 1) {
+ if ((grp.Type == DockGroupType.Horizontal && x > obj.Allocation.Right && x < obj.Allocation.Right + frame.TotalHandleSize) ||
+ (grp.Type == DockGroupType.Vertical && y > obj.Allocation.Bottom && y < obj.Allocation.Bottom + frame.TotalHandleSize))
+ {
+ foundGrp = grp;
+ objectIndex = n;
+ return true;
+ }
+ }
+ if (obj is DockGroup) {
+ if (FindHandle ((DockGroup) obj, x, y, out foundGrp, out objectIndex))
+ return true;
+ }
+ }
+ }
+
+ foundGrp = null;
+ objectIndex = 0;
+ return false;
+ }
+
+ protected override void OnRealized ()
+ {
+ WidgetFlags |= WidgetFlags.Realized;
+
+ Gdk.WindowAttr attributes = new Gdk.WindowAttr ();
+ attributes.X = Allocation.X;
+ attributes.Y = Allocation.Y;
+ attributes.Height = Allocation.Height;
+ attributes.Width = Allocation.Width;
+ attributes.WindowType = Gdk.WindowType.Child;
+ attributes.Wclass = Gdk.WindowClass.InputOutput;
+ attributes.Visual = Visual;
+ attributes.Colormap = Colormap;
+ attributes.EventMask = (int)(Events |
+ Gdk.EventMask.ExposureMask |
+ Gdk.EventMask.Button1MotionMask |
+ Gdk.EventMask.ButtonPressMask |
+ Gdk.EventMask.ButtonReleaseMask);
+
+ Gdk.WindowAttributesType attributes_mask =
+ Gdk.WindowAttributesType.X |
+ Gdk.WindowAttributesType.Y |
+ Gdk.WindowAttributesType.Colormap |
+ Gdk.WindowAttributesType.Visual;
+ GdkWindow = new Gdk.Window (ParentWindow, attributes, (int)attributes_mask);
+ GdkWindow.UserData = Handle;
+
+ Style = Style.Attach (GdkWindow);
+ Style.SetBackground (GdkWindow, State);
+
+ //GdkWindow.SetBackPixmap (null, true);
+ }
+
+ internal void ShowPlaceholder ()
+ {
+ placeholderWindow = new PlaceholderWindow (frame);
+ }
+
+ internal bool UpdatePlaceholder (DockItem item, Gdk.Size size, bool allowDocking)
+ {
+ if (placeholderWindow == null)
+ return false;
+
+ int px, py;
+ GetPointer (out px, out py);
+
+ placeholderWindow.AllowDocking = allowDocking;
+
+ DockDelegate dockDelegate;
+ Gdk.Rectangle rect;
+ if (allowDocking && layout.GetDockTarget (item, px, py, out dockDelegate, out rect)) {
+ int ox, oy;
+ GdkWindow.GetOrigin (out ox, out oy);
+
+ placeholderWindow.Relocate (ox + rect.X, oy + rect.Y, rect.Width, rect.Height, true);
+ placeholderWindow.Show ();
+ return true;
+ } else {
+ int ox, oy;
+ GdkWindow.GetOrigin (out ox, out oy);
+ placeholderWindow.Relocate (ox + px - size.Width / 2, oy + py - 18, size.Width, size.Height, false);
+ placeholderWindow.Show ();
+ }
+ return false;
+ }
+
+ internal void DockInPlaceholder (DockItem item)
+ {
+ if (placeholderWindow == null || !placeholderWindow.Visible)
+ return;
+
+ item.Status = DockItemStatus.Dockable;
+
+ int px, py;
+ GetPointer (out px, out py);
+
+ DockDelegate dockDelegate;
+ Gdk.Rectangle rect;
+ if (placeholderWindow.AllowDocking && layout.GetDockTarget (item, px, py, out dockDelegate, out rect)) {
+ DockGroupItem dummyItem = new DockGroupItem (frame, new DockItem (frame, "__dummy"));
+ DockGroupItem gitem = layout.FindDockGroupItem (item.Id);
+ gitem.ParentGroup.ReplaceItem (gitem, dummyItem);
+ dockDelegate (item);
+ dummyItem.ParentGroup.Remove (dummyItem);
+ RelayoutWidgets ();
+ } else {
+ DockGroupItem gi = FindDockGroupItem (item.Id);
+ int pw, ph;
+ placeholderWindow.GetPosition (out px, out py);
+ placeholderWindow.GetSize (out pw, out ph);
+ gi.FloatRect = new Rectangle (px, py, pw, ph);
+ item.Status = DockItemStatus.Floating;
+ }
+ }
+
+ internal void HidePlaceholder ()
+ {
+ if (placeholderWindow != null) {
+ placeholderWindow.Destroy ();
+ placeholderWindow = null;
+ }
+ }
+
+ public IEnumerable<Rectangle> GetShadedAreas ()
+ {
+ List<Gdk.Rectangle> rects = new List<Gdk.Rectangle> ();
+ layout.DrawSeparators (Allocation, currentHandleGrp, currentHandleIndex, true, rects);
+ return rects;
+ }
+
+ internal void NotifySeparatorsChanged ()
+ {
+ if (AreasChanged != null)
+ AreasChanged (this, EventArgs.Empty);
+ }
+
+ public event EventHandler AreasChanged;
+
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockFrame.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockFrame.cs
new file mode 100644
index 0000000000..f372dd4245
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockFrame.cs
@@ -0,0 +1,668 @@
+//
+// MonoDevelop.Components.Docking.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Xml;
+using System.Collections;
+using System.Collections.Generic;
+using Gtk;
+using Gdk;
+
+namespace MonoDevelop.Components.Docking
+{
+ public class DockFrame: HBox
+ {
+ internal const double ItemDockCenterArea = 0.4;
+ internal const int GroupDockSeparatorSize = 40;
+
+ internal bool ShadedSeparators = true;
+
+ DockContainer container;
+
+ int handleSize = IsWindows ? 4 : 6;
+ int handlePadding = 0;
+ int defaultItemWidth = 130;
+ int defaultItemHeight = 130;
+ uint autoShowDelay = 400;
+ uint autoHideDelay = 500;
+
+ SortedDictionary<string,DockLayout> layouts = new SortedDictionary<string,DockLayout> ();
+ List<DockFrameTopLevel> topLevels = new List<DockFrameTopLevel> ();
+ string currentLayout;
+ int compactGuiLevel = 3;
+
+ DockBar dockBarTop, dockBarBottom, dockBarLeft, dockBarRight;
+ VBox mainBox;
+ ShadedContainer shadedContainer;
+
+ public DockFrame ()
+ {
+ shadedContainer = new ShadedContainer ();
+
+ dockBarTop = new DockBar (this, Gtk.PositionType.Top);
+ dockBarBottom = new DockBar (this, Gtk.PositionType.Bottom);
+ dockBarLeft = new DockBar (this, Gtk.PositionType.Left);
+ dockBarRight = new DockBar (this, Gtk.PositionType.Right);
+
+ container = new DockContainer (this);
+ HBox hbox = new HBox ();
+ hbox.PackStart (dockBarLeft, false, false, 0);
+ hbox.PackStart (container, true, true, 0);
+ hbox.PackStart (dockBarRight, false, false, 0);
+ mainBox = new VBox ();
+ mainBox.PackStart (dockBarTop, false, false, 0);
+ mainBox.PackStart (hbox, true, true, 0);
+ mainBox.PackStart (dockBarBottom, false, false, 0);
+ Add (mainBox);
+ mainBox.ShowAll ();
+ mainBox.NoShowAll = true;
+ CompactGuiLevel = 2;
+ dockBarTop.UpdateVisibility ();
+ dockBarBottom.UpdateVisibility ();
+ dockBarLeft.UpdateVisibility ();
+ dockBarRight.UpdateVisibility ();
+ }
+
+ /// <summary>
+ /// Compactness level of the gui, from 1 (not compact) to 5 (very compact).
+ /// </summary>
+ public int CompactGuiLevel {
+ get { return compactGuiLevel; }
+ set {
+ compactGuiLevel = value;
+ switch (compactGuiLevel) {
+ case 1: handleSize = 6; break;
+ case 2:
+ case 3: handleSize = IsWindows ? 4 : 6; break;
+ case 4:
+ case 5: handleSize = 3; break;
+ }
+ handlePadding = 0;
+ dockBarTop.OnCompactLevelChanged ();
+ dockBarBottom.OnCompactLevelChanged ();
+ dockBarLeft.OnCompactLevelChanged ();
+ dockBarRight.OnCompactLevelChanged ();
+ container.RelayoutWidgets ();
+ }
+ }
+
+ public DockBar ExtractDockBar (PositionType pos)
+ {
+ DockBar db = new DockBar (this, pos);
+ switch (pos) {
+ case PositionType.Left: db.OriginalBar = dockBarLeft; dockBarLeft = db; break;
+ case PositionType.Top: db.OriginalBar = dockBarTop; dockBarTop = db; break;
+ case PositionType.Right: db.OriginalBar = dockBarRight; dockBarRight = db; break;
+ case PositionType.Bottom: db.OriginalBar = dockBarBottom; dockBarBottom = db; break;
+ }
+ return db;
+ }
+
+ internal DockBar GetDockBar (PositionType pos)
+ {
+ switch (pos) {
+ case Gtk.PositionType.Top: return dockBarTop;
+ case Gtk.PositionType.Bottom: return dockBarBottom;
+ case Gtk.PositionType.Left: return dockBarLeft;
+ case Gtk.PositionType.Right: return dockBarRight;
+ }
+ return null;
+ }
+
+ internal DockContainer Container {
+ get { return container; }
+ }
+
+ public ShadedContainer ShadedContainer {
+ get { return this.shadedContainer; }
+ }
+
+ public int HandleSize {
+ get {
+ return handleSize;
+ }
+ set {
+ handleSize = value;
+ }
+ }
+
+ public int HandlePadding {
+ get {
+ return handlePadding;
+ }
+ set {
+ handlePadding = value;
+ }
+ }
+
+ public int DefaultItemWidth {
+ get {
+ return defaultItemWidth;
+ }
+ set {
+ defaultItemWidth = value;
+ }
+ }
+
+ public int DefaultItemHeight {
+ get {
+ return defaultItemHeight;
+ }
+ set {
+ defaultItemHeight = value;
+ }
+ }
+
+ internal int TotalHandleSize {
+ get { return handleSize + handlePadding*2; }
+ }
+
+ public DockItem AddItem (string id)
+ {
+ foreach (DockItem dit in container.Items) {
+ if (dit.Id == id) {
+ if (dit.IsPositionMarker) {
+ dit.IsPositionMarker = false;
+ return dit;
+ }
+ throw new InvalidOperationException ("An item with id '" + id + "' already exists.");
+ }
+ }
+
+ DockItem it = new DockItem (this, id);
+ container.Items.Add (it);
+ return it;
+ }
+
+ public void RemoveItem (DockItem it)
+ {
+ if (container.Layout != null)
+ container.Layout.RemoveItemRec (it);
+ foreach (DockGroup grp in layouts.Values)
+ grp.RemoveItemRec (it);
+ container.Items.Remove (it);
+ }
+
+ public DockItem GetItem (string id)
+ {
+ foreach (DockItem it in container.Items) {
+ if (it.Id == id) {
+ if (!it.IsPositionMarker)
+ return it;
+ else
+ return null;
+ }
+ }
+ return null;
+ }
+
+ public IEnumerable<DockItem> GetItems ()
+ {
+ return container.Items;
+ }
+
+ bool LoadLayout (string layoutName)
+ {
+ DockLayout dl;
+ if (!layouts.TryGetValue (layoutName, out dl))
+ return false;
+
+ container.LoadLayout (dl);
+ return true;
+ }
+
+ public void CreateLayout (string name)
+ {
+ CreateLayout (name, false);
+ }
+
+ public void DeleteLayout (string name)
+ {
+ layouts.Remove (name);
+ }
+
+ public void CreateLayout (string name, bool copyCurrent)
+ {
+ DockLayout dl;
+ if (container.Layout == null || !copyCurrent) {
+ dl = GetDefaultLayout ();
+ } else {
+ container.StoreAllocation ();
+ dl = (DockLayout) container.Layout.Clone ();
+ }
+ dl.Name = name;
+ layouts [name] = dl;
+ }
+
+ public string CurrentLayout {
+ get {
+ return currentLayout;
+ }
+ set {
+ if (currentLayout == value)
+ return;
+ if (LoadLayout (value)) {
+ currentLayout = value;
+ }
+ }
+ }
+
+ public bool HasLayout (string id)
+ {
+ return layouts.ContainsKey (id);
+ }
+
+ public string[] Layouts {
+ get {
+ if (layouts.Count == 0)
+ return new string [0];
+ string[] arr = new string [layouts.Count];
+ layouts.Keys.CopyTo (arr, 0);
+ return arr;
+ }
+ }
+
+ public uint AutoShowDelay {
+ get {
+ return autoShowDelay;
+ }
+ set {
+ autoShowDelay = value;
+ }
+ }
+
+ public uint AutoHideDelay {
+ get {
+ return autoHideDelay;
+ }
+ set {
+ autoHideDelay = value;
+ }
+ }
+
+ public void SaveLayouts (string file)
+ {
+ using (XmlTextWriter w = new XmlTextWriter (file, System.Text.Encoding.UTF8)) {
+ w.Formatting = Formatting.Indented;
+ SaveLayouts (w);
+ }
+ }
+
+ public void SaveLayouts (XmlWriter writer)
+ {
+ if (container.Layout != null)
+ container.Layout.StoreAllocation ();
+ writer.WriteStartElement ("layouts");
+ foreach (DockLayout la in layouts.Values)
+ la.Write (writer);
+ writer.WriteEndElement ();
+ }
+
+ public void LoadLayouts (string file)
+ {
+ using (XmlReader r = new XmlTextReader (new System.IO.StreamReader (file))) {
+ LoadLayouts (r);
+ }
+ }
+
+ public void LoadLayouts (XmlReader reader)
+ {
+ layouts.Clear ();
+ container.Clear ();
+ currentLayout = null;
+
+ reader.MoveToContent ();
+ if (reader.IsEmptyElement) {
+ reader.Skip ();
+ return;
+ }
+ reader.ReadStartElement ("layouts");
+ reader.MoveToContent ();
+ while (reader.NodeType != XmlNodeType.EndElement) {
+ if (reader.NodeType == XmlNodeType.Element) {
+ DockLayout layout = DockLayout.Read (this, reader);
+ layouts.Add (layout.Name, layout);
+ }
+ else
+ reader.Skip ();
+ reader.MoveToContent ();
+ }
+ reader.ReadEndElement ();
+ container.RelayoutWidgets ();
+ }
+
+ internal void UpdateTitle (DockItem item)
+ {
+ DockGroupItem gitem = container.FindDockGroupItem (item.Id);
+ if (gitem == null)
+ return;
+
+ gitem.ParentGroup.UpdateTitle (item);
+ dockBarTop.UpdateTitle (item);
+ dockBarBottom.UpdateTitle (item);
+ dockBarLeft.UpdateTitle (item);
+ dockBarRight.UpdateTitle (item);
+ }
+
+ internal void Present (DockItem item, bool giveFocus)
+ {
+ DockGroupItem gitem = container.FindDockGroupItem (item.Id);
+ if (gitem == null)
+ return;
+
+ gitem.ParentGroup.Present (item, giveFocus);
+ }
+
+ internal bool GetVisible (DockItem item)
+ {
+ DockGroupItem gitem = container.FindDockGroupItem (item.Id);
+ if (gitem == null)
+ return false;
+ return gitem.VisibleFlag;
+ }
+
+ internal bool GetVisible (DockItem item, string layoutName)
+ {
+ DockLayout dl;
+ if (!layouts.TryGetValue (layoutName, out dl))
+ return false;
+
+ DockGroupItem gitem = dl.FindDockGroupItem (item.Id);
+ if (gitem == null)
+ return false;
+ return gitem.VisibleFlag;
+ }
+
+ internal void SetVisible (DockItem item, bool visible)
+ {
+ if (container.Layout == null)
+ return;
+ DockGroupItem gitem = container.FindDockGroupItem (item.Id);
+
+ if (gitem == null) {
+ if (visible) {
+ // The item is not present in the layout. Add it now.
+ if (!string.IsNullOrEmpty (item.DefaultLocation))
+ gitem = AddDefaultItem (container.Layout, item);
+
+ if (gitem == null) {
+ // No default position
+ gitem = new DockGroupItem (this, item);
+ container.Layout.AddObject (gitem);
+ }
+ } else
+ return; // Already invisible
+ }
+ gitem.SetVisible (visible);
+ container.RelayoutWidgets ();
+ }
+
+ internal DockItemStatus GetStatus (DockItem item)
+ {
+ DockGroupItem gitem = container.FindDockGroupItem (item.Id);
+ if (gitem == null)
+ return DockItemStatus.Dockable;
+ return gitem.Status;
+ }
+
+ internal void SetStatus (DockItem item, DockItemStatus status)
+ {
+ DockGroupItem gitem = container.FindDockGroupItem (item.Id);
+ if (gitem == null) {
+ item.DefaultStatus = status;
+ return;
+ }
+ gitem.StoreAllocation ();
+ gitem.Status = status;
+ container.RelayoutWidgets ();
+ }
+
+ DockLayout GetDefaultLayout ()
+ {
+ DockLayout group = new DockLayout (this);
+
+ // Add items which don't have relative defaut positions
+
+ List<DockItem> todock = new List<DockItem> ();
+ foreach (DockItem item in container.Items) {
+ if (string.IsNullOrEmpty (item.DefaultLocation)) {
+ DockGroupItem dgt = new DockGroupItem (this, item);
+ dgt.SetVisible (item.DefaultVisible);
+ group.AddObject (dgt);
+ }
+ else
+ todock.Add (item);
+ }
+
+ // Add items with relative positions.
+ int lastCount = 0;
+ while (lastCount != todock.Count) {
+ lastCount = todock.Count;
+ for (int n=0; n<todock.Count; n++) {
+ DockItem it = todock [n];
+ if (AddDefaultItem (group, it) != null) {
+ todock.RemoveAt (n);
+ n--;
+ }
+ }
+ }
+
+ // Items which could not be docked because of an invalid default location
+ foreach (DockItem item in todock) {
+ DockGroupItem dgt = new DockGroupItem (this, item);
+ dgt.SetVisible (false);
+ group.AddObject (dgt);
+ }
+// group.Dump ();
+ return group;
+ }
+
+ DockGroupItem AddDefaultItem (DockGroup grp, DockItem it)
+ {
+ string[] positions = it.DefaultLocation.Split (';');
+ foreach (string pos in positions) {
+ int i = pos.IndexOf ('/');
+ if (i == -1) continue;
+ string id = pos.Substring (0,i).Trim ();
+ DockGroup g = grp.FindGroupContaining (id);
+ if (g != null) {
+ DockPosition dpos;
+ try {
+ dpos = (DockPosition) Enum.Parse (typeof(DockPosition), pos.Substring(i+1).Trim(), true);
+ }
+ catch {
+ continue;
+ }
+ DockGroupItem dgt = g.AddObject (it, dpos, id);
+ dgt.SetVisible (it.DefaultVisible);
+ dgt.Status = it.DefaultStatus;
+ return dgt;
+ }
+ }
+ return null;
+ }
+
+ internal void AddTopLevel (DockFrameTopLevel w, int x, int y)
+ {
+ w.Parent = this;
+ w.X = x;
+ w.Y = y;
+ Requisition r = w.SizeRequest ();
+ w.Allocation = new Gdk.Rectangle (Allocation.X + x, Allocation.Y + y, r.Width, r.Height);
+ topLevels.Add (w);
+ }
+
+ internal void RemoveTopLevel (DockFrameTopLevel w)
+ {
+ w.Unparent ();
+ topLevels.Remove (w);
+ QueueResize ();
+ }
+
+ public Gdk.Rectangle GetCoordinates (Gtk.Widget w)
+ {
+ int px, py;
+ if (!w.TranslateCoordinates (this, 0, 0, out px, out py))
+ return new Gdk.Rectangle (0,0,0,0);
+
+ Gdk.Rectangle rect = w.Allocation;
+ rect.X = px - Allocation.X;
+ rect.Y = py - Allocation.Y;
+ return rect;
+ }
+
+ internal void ShowPlaceholder ()
+ {
+ container.ShowPlaceholder ();
+ }
+
+ internal void DockInPlaceholder (DockItem item)
+ {
+ container.DockInPlaceholder (item);
+ }
+
+ internal void HidePlaceholder ()
+ {
+ container.HidePlaceholder ();
+ }
+
+ internal void UpdatePlaceholder (DockItem item, Gdk.Size size, bool allowDocking)
+ {
+ container.UpdatePlaceholder (item, size, allowDocking);
+ }
+
+ internal DockBarItem BarDock (Gtk.PositionType pos, DockItem item, int size)
+ {
+ return GetDockBar (pos).AddItem (item, size);
+ }
+
+ internal AutoHideBox AutoShow (DockItem item, DockBar bar, int size)
+ {
+ AutoHideBox aframe = new AutoHideBox (this, item, bar.Position, size);
+ Gdk.Size sTop = GetBarFrameSize (dockBarTop);
+ Gdk.Size sBot = GetBarFrameSize (dockBarBottom);
+ Gdk.Size sLeft = GetBarFrameSize (dockBarLeft);
+ Gdk.Size sRgt = GetBarFrameSize (dockBarRight);
+
+ int x,y;
+ if (bar == dockBarLeft || bar == dockBarRight) {
+ aframe.HeightRequest = Allocation.Height - sTop.Height - sBot.Height;
+ aframe.WidthRequest = size;
+ y = sTop.Height;
+ if (bar == dockBarLeft)
+ x = sLeft.Width;
+ else
+ x = Allocation.Width - size - sRgt.Width;
+ } else {
+ aframe.WidthRequest = Allocation.Width - sLeft.Width - sRgt.Width;
+ aframe.HeightRequest = size;
+ x = sLeft.Width;
+ if (bar == dockBarTop)
+ y = sTop.Height;
+ else
+ y = Allocation.Height - size - sBot.Height;
+ }
+ AddTopLevel (aframe, x, y);
+ aframe.AnimateShow ();
+ return aframe;
+ }
+
+ Gdk.Size GetBarFrameSize (DockBar bar)
+ {
+ if (bar.OriginalBar != null)
+ bar = bar.OriginalBar;
+ if (!bar.Visible)
+ return new Gdk.Size (0,0);
+ Gtk.Requisition req = bar.SizeRequest ();
+ return new Gdk.Size (req.Width, req.Height);
+ }
+
+ internal void AutoHide (DockItem item, AutoHideBox widget, bool animate)
+ {
+ if (animate) {
+ widget.Hidden += delegate {
+ if (!widget.Disposed)
+ AutoHide (item, widget, false);
+ };
+ widget.AnimateHide ();
+ }
+ else {
+ Gtk.Container parent = (Gtk.Container) item.Widget.Parent;
+ parent.Remove (item.Widget);
+ RemoveTopLevel (widget);
+ widget.Disposed = true;
+ widget.Destroy ();
+ }
+ }
+
+ protected override void OnSizeAllocated (Rectangle allocation)
+ {
+ base.OnSizeAllocated (allocation);
+
+ foreach (DockFrameTopLevel tl in topLevels) {
+ Requisition r = tl.SizeRequest ();
+ tl.SizeAllocate (new Gdk.Rectangle (allocation.X + tl.X, allocation.Y + tl.Y, r.Width, r.Height));
+ }
+ }
+
+ protected override void ForAll (bool include_internals, Callback callback)
+ {
+ base.ForAll (include_internals, callback);
+ List<DockFrameTopLevel> clone = new List<DockFrameTopLevel> (topLevels);
+ foreach (DockFrameTopLevel child in clone)
+ callback (child);
+ }
+
+ protected override void OnRealized ()
+ {
+ base.OnRealized ();
+ HslColor cLight = new HslColor (Style.Background (Gtk.StateType.Normal));
+ HslColor cDark = cLight;
+ cLight.L *= 0.9;
+ cDark.L *= 0.8;
+ shadedContainer.LightColor = cLight;
+ shadedContainer.DarkColor = cDark;
+ }
+
+
+ static internal bool IsWindows {
+ get { return System.IO.Path.DirectorySeparatorChar == '\\'; }
+ }
+
+ internal static Cairo.Color ToCairoColor (Gdk.Color color)
+ {
+ return new Cairo.Color (color.Red / (double) ushort.MaxValue, color.Green / (double) ushort.MaxValue, color.Blue / (double) ushort.MaxValue);
+ }
+ }
+
+
+ internal delegate void DockDelegate (DockItem item);
+
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockFrameTopLevel.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockFrameTopLevel.cs
new file mode 100644
index 0000000000..7cb00af05b
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockFrameTopLevel.cs
@@ -0,0 +1,61 @@
+//
+// DockFrameTopLevel.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+
+using System;
+using Gtk;
+
+namespace MonoDevelop.Components.Docking
+{
+ class DockFrameTopLevel: EventBox
+ {
+ int x, y;
+
+ public int X {
+ get { return x; }
+ set {
+ x = value;
+ if (Parent != null)
+ Parent.QueueResize ();
+ }
+ }
+
+ public int Y {
+ get { return y; }
+ set {
+ y = value;
+ if (Parent != null)
+ Parent.QueueResize ();
+ }
+ }
+ }
+
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroup.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroup.cs
new file mode 100644
index 0000000000..6fc5396660
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroup.cs
@@ -0,0 +1,1134 @@
+//
+// MonoDevelop.Components.Docking.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Xml;
+using System.Collections.Generic;
+using Gtk;
+
+namespace MonoDevelop.Components.Docking
+{
+ class DockGroup: DockObject
+ {
+ DockGroupType type;
+ List<DockObject> dockObjects = new List<DockObject> ();
+ List<DockObject> visibleObjects;
+ AllocStatus allocStatus = AllocStatus.NotSet;
+ TabStrip boundTabStrip;
+ DockGroupItem tabFocus;
+ int currentTabPage;
+
+ enum AllocStatus { NotSet, Invalid, RestorePending, NewSizeRequest, Valid };
+
+ public DockGroup (DockFrame frame, DockGroupType type): base (frame)
+ {
+ this.type = type;
+ }
+
+ internal DockGroup (DockFrame frame): base (frame)
+ {
+ }
+
+ public DockGroupType Type {
+ get {
+ return type;
+ }
+ set {
+ type = value;
+ }
+ }
+
+ public List<DockObject> Objects {
+ get { return dockObjects; }
+ }
+
+ void MarkForRelayout ()
+ {
+ if (allocStatus == AllocStatus.Valid)
+ allocStatus = AllocStatus.Invalid;
+ }
+
+ public void AddObject (DockObject obj)
+ {
+ obj.ParentGroup = this;
+ dockObjects.Add (obj);
+ ResetVisibleGroups ();
+ }
+
+ public DockGroupItem AddObject (DockItem obj, DockPosition pos, string relItemId)
+ {
+ int npos = -1;
+ if (relItemId != null) {
+ for (int n=0; n<dockObjects.Count; n++) {
+ DockGroupItem it = dockObjects [n] as DockGroupItem;
+ if (it != null && it.Id == relItemId)
+ npos = n;
+ }
+ }
+
+ if (npos == -1) {
+ if (pos == DockPosition.Left || pos == DockPosition.Top)
+ npos = 0;
+ else
+ npos = dockObjects.Count - 1;
+ }
+
+ DockGroupItem gitem = null;
+
+ if (pos == DockPosition.Left || pos == DockPosition.Right) {
+ if (type != DockGroupType.Horizontal)
+ gitem = Split (DockGroupType.Horizontal, pos == DockPosition.Left, obj, npos);
+ else
+ gitem = InsertObject (obj, npos, pos);
+ }
+ else if (pos == DockPosition.Top || pos == DockPosition.Bottom) {
+ if (type != DockGroupType.Vertical)
+ gitem = Split (DockGroupType.Vertical, pos == DockPosition.Top, obj, npos);
+ else
+ gitem = InsertObject (obj, npos, pos);
+ }
+ else if (pos == DockPosition.CenterBefore || pos == DockPosition.Center) {
+ if (type != DockGroupType.Tabbed)
+ gitem = Split (DockGroupType.Tabbed, pos == DockPosition.CenterBefore, obj, npos);
+ else {
+ if (pos == DockPosition.Center)
+ npos++;
+ gitem = new DockGroupItem (Frame, obj);
+ dockObjects.Insert (npos, gitem);
+ gitem.ParentGroup = this;
+ }
+ }
+ ResetVisibleGroups ();
+ return gitem;
+ }
+
+ DockGroupItem InsertObject (DockItem obj, int npos, DockPosition pos)
+ {
+ if (pos == DockPosition.Bottom || pos == DockPosition.Right)
+ npos++;
+
+ DockGroupItem gitem = new DockGroupItem (Frame, obj);
+ dockObjects.Insert (npos, gitem);
+ gitem.ParentGroup = this;
+ return gitem;
+ }
+
+ DockGroupItem Split (DockGroupType newType, bool addFirst, DockItem obj, int npos)
+ {
+ DockGroupItem item = new DockGroupItem (Frame, obj);
+
+ if (npos == -1 || type == DockGroupType.Tabbed) {
+ if (ParentGroup != null && ParentGroup.Type == newType) {
+ // No need to split. Just add the new item as a sibling of this one.
+ int i = ParentGroup.Objects.IndexOf (this);
+ if (addFirst)
+ ParentGroup.Objects.Insert (i, item);
+ else
+ ParentGroup.Objects.Insert (i+1, item);
+ item.ParentGroup = ParentGroup;
+ item.ResetDefaultSize ();
+ }
+ else {
+ DockGroup grp = Copy ();
+ dockObjects.Clear ();
+ if (addFirst) {
+ dockObjects.Add (item);
+ dockObjects.Add (grp);
+ } else {
+ dockObjects.Add (grp);
+ dockObjects.Add (item);
+ }
+ item.ParentGroup = this;
+ item.ResetDefaultSize ();
+ grp.ParentGroup = this;
+ grp.ResetDefaultSize ();
+ Type = newType;
+ }
+ }
+ else {
+ DockGroup grp = new DockGroup (Frame, newType);
+ DockObject replaced = dockObjects[npos];
+ if (addFirst) {
+ grp.AddObject (item);
+ grp.AddObject (replaced);
+ } else {
+ grp.AddObject (replaced);
+ grp.AddObject (item);
+ }
+ grp.CopySizeFrom (replaced);
+ dockObjects [npos] = grp;
+ grp.ParentGroup = this;
+ }
+ return item;
+ }
+
+ internal DockGroup FindGroupContaining (string id)
+ {
+ DockGroupItem it = FindDockGroupItem (id);
+ if (it != null)
+ return it.ParentGroup;
+ else
+ return null;
+ }
+
+ internal DockGroupItem FindDockGroupItem (string id)
+ {
+ foreach (DockObject ob in dockObjects) {
+ DockGroupItem it = ob as DockGroupItem;
+ if (it != null && it.Id == id)
+ return it;
+ DockGroup g = ob as DockGroup;
+ if (g != null) {
+ it = g.FindDockGroupItem (id);
+ if (it != null)
+ return it;
+ }
+ }
+ return null;
+ }
+
+ DockGroup Copy ()
+ {
+ DockGroup grp = new DockGroup (Frame, type);
+ grp.dockObjects = new List<MonoDevelop.Components.Docking.DockObject> (dockObjects);
+ foreach (DockObject obj in grp.dockObjects)
+ obj.ParentGroup = grp;
+
+ grp.CopySizeFrom (this);
+ return grp;
+ }
+
+ public int GetObjectIndex (DockObject obj)
+ {
+ for (int n=0; n<dockObjects.Count; n++) {
+ if (dockObjects [n] == obj)
+ return n;
+ }
+ return -1;
+ }
+
+ public bool RemoveItemRec (DockItem item)
+ {
+ foreach (DockObject ob in dockObjects) {
+ if (ob is DockGroup) {
+ if (((DockGroup)ob).RemoveItemRec (item))
+ return true;
+ } else {
+ DockGroupItem dit = ob as DockGroupItem;
+ if (dit != null && dit.Item == item) {
+ Remove (ob);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void Remove (DockObject obj)
+ {
+ dockObjects.Remove (obj);
+ Reduce ();
+ obj.ParentGroup = null;
+ visibleObjects = null;
+
+ if (VisibleObjects.Count > 0) {
+ CalcNewSizes ();
+ MarkForRelayout ();
+ } else
+ ParentGroup.UpdateVisible (this);
+ }
+
+ public void Reduce ()
+ {
+ if (ParentGroup != null && dockObjects.Count == 1) {
+ DockObject obj = dockObjects [0];
+ int n = ParentGroup.GetObjectIndex (this);
+ ParentGroup.dockObjects [n] = obj;
+ obj.ParentGroup = ParentGroup;
+ obj.CopySizeFrom (this);
+ dockObjects.Clear ();
+ ResetVisibleGroups ();
+ ParentGroup.ResetVisibleGroups ();
+ }
+ }
+
+ internal List<DockObject> VisibleObjects {
+ get {
+ if (visibleObjects == null) {
+ visibleObjects = new List<DockObject> ();
+ foreach (DockObject obj in dockObjects)
+ if (obj.Visible)
+ visibleObjects.Add (obj);
+ }
+ return visibleObjects;
+ }
+ }
+
+ void ResetVisibleGroups ()
+ {
+ visibleObjects = null;
+ MarkForRelayout ();
+ }
+
+ internal void UpdateVisible (DockObject child)
+ {
+ visibleObjects = null;
+ bool visChanged;
+ CalcNewSizes ();
+ MarkForRelayout ();
+
+ visChanged = child.Visible ? VisibleObjects.Count == 1 : VisibleObjects.Count == 0;
+
+ if (visChanged && ParentGroup != null)
+ ParentGroup.UpdateVisible (this);
+ }
+
+ internal override void RestoreAllocation ()
+ {
+ base.RestoreAllocation ();
+ allocStatus = Size >= 0 ? AllocStatus.RestorePending : AllocStatus.NotSet;
+ foreach (DockObject ob in dockObjects)
+ ob.RestoreAllocation ();
+ }
+
+ internal override void StoreAllocation ()
+ {
+ base.StoreAllocation ();
+ foreach (DockObject ob in dockObjects)
+ ob.StoreAllocation ();
+ if (Type == DockGroupType.Tabbed && boundTabStrip != null)
+ currentTabPage = boundTabStrip.CurrentTab;
+ }
+
+ public override bool Expand {
+ get {
+ foreach (DockObject ob in dockObjects)
+ if (ob.Expand)
+ return true;
+ return false;
+ }
+ }
+
+ public override void SizeAllocate (Gdk.Rectangle newAlloc)
+ {
+ Gdk.Rectangle oldAlloc = Allocation;
+ base.SizeAllocate (newAlloc);
+
+ if (type == DockGroupType.Tabbed) {
+ if (boundTabStrip != null) {
+ int tabsHeight = boundTabStrip.SizeRequest ().Height;
+ boundTabStrip.SizeAllocate (new Gdk.Rectangle (newAlloc.X, newAlloc.Bottom - tabsHeight, newAlloc.Width, tabsHeight));
+ }
+ if (allocStatus == AllocStatus.Valid && newAlloc == oldAlloc) {
+ // Even if allocation has not changed, SizeAllocation has to be called on all items to avoid redrawing issues.
+ foreach (DockObject ob in VisibleObjects)
+ ob.SizeAllocate (ob.Allocation);
+ return;
+ }
+ if (VisibleObjects.Count > 1 && boundTabStrip != null) {
+ int tabsHeight = boundTabStrip.SizeRequest ().Height;
+ newAlloc.Height -= tabsHeight;
+ boundTabStrip.QueueDraw ();
+ } else if (VisibleObjects.Count != 0) {
+ ((DockGroupItem)VisibleObjects [0]).Item.Widget.Show ();
+ }
+ allocStatus = AllocStatus.Valid;
+ foreach (DockObject ob in VisibleObjects) {
+ ob.Size = ob.PrefSize = -1;
+ ob.SizeAllocate (newAlloc);
+ }
+ return;
+ }
+
+ bool horiz = type == DockGroupType.Horizontal;
+ int pos = horiz ? Allocation.Left : Allocation.Top;
+
+ if (allocStatus == AllocStatus.Valid && newAlloc == oldAlloc) {
+ // The layout of this group (as a whole) has not changed, but the layout
+ // of child items may have changed. Assign the new sizes.
+
+ if (CheckMinSizes ())
+ allocStatus = AllocStatus.NewSizeRequest;
+ else {
+ foreach (DockObject ob in VisibleObjects) {
+ Gdk.Rectangle rect;
+ int ins = ob.AllocSize;
+ if (horiz)
+ rect = new Gdk.Rectangle (pos, Allocation.Y, ins, Allocation.Height);
+ else
+ rect = new Gdk.Rectangle (Allocation.X, pos, Allocation.Width, ins);
+ ob.SizeAllocate (rect);
+ pos += ins + Frame.TotalHandleSize;
+ }
+ return;
+ }
+ }
+
+ // This is the space available for the child items (excluding size
+ // required for the resize handles)
+ int realSize = GetRealSize (VisibleObjects);
+
+ if (allocStatus == AllocStatus.NotSet/* || allocStatus == AllocStatus.RestorePending*/) {
+ // It is the first size allocation. Calculate all sizes.
+ CalcNewSizes ();
+ }
+ else if (allocStatus != AllocStatus.NewSizeRequest) {
+ // Available space has changed, so the size of the items must be changed.
+ // First of all, get the change fraction
+ double change;
+ if (horiz)
+ change = (double) newAlloc.Width / (double) oldAlloc.Width;
+ else
+ change = (double) newAlloc.Height / (double) oldAlloc.Height;
+
+ // Get the old total size of the visible objects. Used to calculate the
+ // proportion of size of each item.
+ double tsize = 0;
+ double rsize = 0;
+ foreach (DockObject ob in VisibleObjects) {
+ tsize += ob.PrefSize;
+ rsize += ob.Size;
+ }
+
+ foreach (DockObject ob in dockObjects) {
+ if (ob.Visible) {
+ // Proportionally spread the new available space among all visible objects
+ ob.Size = ob.PrefSize = (ob.PrefSize / tsize) * (double) realSize;
+ } else {
+ // For non-visible objects, change the size by the same grow fraction. In this
+ // way, when the item is shown again, it size will have the correct proportions.
+ ob.Size = ob.Size * change;
+ ob.PrefSize = ob.PrefSize * change;
+ }
+ ob.DefaultSize = ob.DefaultSize * change;
+ }
+ CheckMinSizes ();
+ }
+
+ allocStatus = AllocStatus.Valid;
+
+ // Sizes for all items have been set.
+ // Sizes are real numbers to ensure that the values are not degradated when resizing
+ // pixel by pixel. Now those have to be converted to integers, that is, actual allocated sizes.
+
+ int ts = 0;
+ for (int n=0; n<VisibleObjects.Count; n++) {
+ DockObject ob = VisibleObjects [n];
+
+ int ins = (int) Math.Truncate (ob.Size);
+
+ if (n == VisibleObjects.Count - 1)
+ ins = realSize - ts;
+
+ ts += ins;
+
+ if (ins < 0)
+ ins = 0;
+
+ ob.AllocSize = ins;
+
+ if (horiz)
+ ob.SizeAllocate (new Gdk.Rectangle (pos, Allocation.Y, ins, Allocation.Height));
+ else
+ ob.SizeAllocate (new Gdk.Rectangle (Allocation.X, pos, Allocation.Width, ins));
+
+ pos += ins + Frame.TotalHandleSize;
+ }
+ }
+
+ int GetRealSize (List<DockObject> objects)
+ {
+ // Returns the space available for the child items (excluding size
+ // required for the resize handles)
+
+ int realSize;
+ if (type == DockGroupType.Horizontal)
+ realSize = Allocation.Width;
+ else
+ realSize = Allocation.Height;
+
+ // Ignore space required for the handles
+ if (objects.Count > 1)
+ realSize -= (Frame.TotalHandleSize * (objects.Count - 1));
+
+ return realSize;
+ }
+
+ internal void CalcNewSizes ()
+ {
+ // Calculates the size assigned by default to each child item.
+ // Size is proportionally assigned to each item, taking into account
+ // the available space, and the default size of each item.
+
+ // If there are items with the Expand flag set, those will proportionally
+ // take the space left after allocating the other (not exandable) items.
+
+ // This is the space available for the child items (excluding size
+ // required for the resize handles)
+ double realSize = (double) GetRealSize (VisibleObjects);
+
+ bool hasExpandItems = false;
+ double noexpandSize = 0;
+ double minExpandSize = 0;
+ double defaultExpandSize = 0;
+
+ for (int n=0; n<VisibleObjects.Count; n++) {
+ DockObject ob = VisibleObjects [n];
+ if (ob.Expand) {
+ minExpandSize += ob.MinSize;
+ defaultExpandSize += ob.DefaultSize;
+ hasExpandItems = true;
+ }
+ else {
+ ob.Size = ob.DefaultSize;
+ noexpandSize += ob.DefaultSize;
+ }
+ }
+
+ double expandSize = realSize - noexpandSize;
+ foreach (DockObject ob in VisibleObjects) {
+ if (!hasExpandItems)
+ ob.Size = (ob.DefaultSize / noexpandSize) * realSize;
+ else if (ob.Expand)
+ ob.Size = (ob.DefaultSize / defaultExpandSize) * expandSize;
+ ob.PrefSize = ob.Size;
+ }
+
+ CheckMinSizes ();
+ }
+
+ bool CheckMinSizes ()
+ {
+ // Checks if any of the items has a size smaller than permitted.
+ // In this case it tries to regain size by reducing other items.
+
+ // First of all calculate the size to be regained, and the size available
+ // from other items
+
+ bool sizesChanged = false;
+
+ double avSize = 0;
+ double regSize = 0;
+ foreach (DockObject ob in VisibleObjects) {
+ if (ob.Size < ob.MinSize) {
+ regSize += ob.MinSize - ob.Size;
+ ob.Size = ob.MinSize;
+ sizesChanged = true;
+ } else {
+ avSize += ob.Size - ob.MinSize;
+ }
+ }
+
+ if (!sizesChanged)
+ return false;
+
+ // Now spread the required size among the resizable items
+
+ if (regSize > avSize)
+ regSize = avSize;
+
+ double ratio = (avSize - regSize) / avSize;
+ foreach (DockObject ob in VisibleObjects) {
+ if (ob.Size <= ob.MinSize)
+ continue;
+ double avs = ob.Size - ob.MinSize;
+ ob.Size = ob.MinSize + avs * ratio;
+ }
+ return sizesChanged;
+ }
+
+ internal override Gtk.Requisition SizeRequest ()
+ {
+ bool getMaxW = true, getMaxH = true;
+ if (type == DockGroupType.Horizontal)
+ getMaxW = false;
+ else if (type == DockGroupType.Vertical)
+ getMaxH = false;
+
+ Requisition ret = new Requisition ();
+ ret.Height = VisibleObjects.Count * Frame.TotalHandleSize;
+ foreach (DockObject ob in VisibleObjects) {
+ Requisition req = ob.SizeRequest ();
+ if (getMaxH) {
+ if (req.Height > ret.Height)
+ ret.Height = req.Height;
+ } else
+ ret.Height += req.Height;
+
+ if (getMaxW) {
+ if (req.Width > ret.Width)
+ ret.Width = req.Width;
+ } else
+ ret.Width += req.Width;
+ }
+ if (type == DockGroupType.Tabbed && VisibleObjects.Count > 1 && boundTabStrip != null) {
+ Gtk.Requisition tabs = boundTabStrip.SizeRequest ();
+ ret.Height += tabs.Height;
+ if (ret.Width < tabs.Width)
+ ret.Width = tabs.Width;
+ }
+ return ret;
+ }
+
+ internal void UpdateNotebook (TabStrip ts)
+ {
+ Gtk.Widget oldpage = null;
+ int oldtab = -1;
+
+ if (tabFocus != null) {
+ oldpage = tabFocus.Item.Widget;
+ tabFocus = null;
+ } else if (boundTabStrip != null) {
+ oldpage = boundTabStrip.CurrentPage;
+ oldtab = boundTabStrip.CurrentTab;
+ }
+
+ ts.Clear ();
+
+ // Add missing pages
+ foreach (DockObject ob in VisibleObjects) {
+ DockGroupItem it = ob as DockGroupItem;
+ ts.AddTab (it.Item.Widget, it.Item.Icon, it.Item.Label);
+ }
+
+ boundTabStrip = ts;
+
+ if (currentTabPage != -1 && currentTabPage < boundTabStrip.TabCount) {
+ boundTabStrip.CurrentTab = currentTabPage;
+ // Discard the currentTabPage value. Current page is now tracked by the tab strip
+ currentTabPage = -1;
+ }
+ else if (oldpage != null)
+ boundTabStrip.CurrentPage = oldpage;
+
+ if (boundTabStrip.CurrentTab == -1) {
+ if (oldtab != -1) {
+ if (oldtab < boundTabStrip.TabCount)
+ boundTabStrip.CurrentTab = oldtab;
+ else
+ boundTabStrip.CurrentTab = boundTabStrip.TabCount - 1;
+ } else
+ boundTabStrip.CurrentTab = 0;
+ }
+ if (Frame.CompactGuiLevel == 3 && IsNextToMargin (PositionType.Bottom))
+ boundTabStrip.BottomPadding = 3;
+ else
+ boundTabStrip.BottomPadding = 0;
+ }
+
+ internal void Present (DockItem it, bool giveFocus)
+ {
+ if (type == DockGroupType.Tabbed) {
+ for (int n=0; n<VisibleObjects.Count; n++) {
+ DockGroupItem dit = VisibleObjects[n] as DockGroupItem;
+ if (dit.Item == it) {
+ currentTabPage = n;
+ if (boundTabStrip != null)
+ boundTabStrip.CurrentPage = it.Widget;
+ break;
+ }
+ }
+ }
+ if (giveFocus && it.Visible)
+ it.SetFocus ();
+ }
+
+ internal bool IsSelectedPage (DockItem it)
+ {
+ if (type != DockGroupType.Tabbed || boundTabStrip == null || boundTabStrip.CurrentTab == -1 || VisibleObjects == null || boundTabStrip.CurrentTab >= VisibleObjects.Count)
+ return false;
+ DockGroupItem dit = VisibleObjects[boundTabStrip.CurrentTab] as DockGroupItem;
+ return dit.Item == it;
+ }
+
+ internal void UpdateTitle (DockItem it)
+ {
+ if (it.Visible && type == DockGroupType.Tabbed && boundTabStrip != null)
+ boundTabStrip.SetTabLabel (it.Widget, it.Icon, it.Label);
+ }
+
+ internal void FocusItem (DockGroupItem it)
+ {
+ tabFocus = it;
+ }
+
+ internal void ResetNotebook ()
+ {
+ boundTabStrip = null;
+ }
+
+ public void LayoutWidgets ()
+ {
+ foreach (DockObject ob in VisibleObjects) {
+ DockGroupItem it = ob as DockGroupItem;
+ if (it != null) {
+ if (it.Item.Widget.Parent == null)
+ it.Item.Widget.Parent = Frame.Container;
+ if (!it.Item.Widget.Visible && type != DockGroupType.Tabbed)
+ it.Item.Widget.Show ();
+ }
+ else
+ ((DockGroup)ob).LayoutWidgets ();
+ }
+ }
+
+ internal override void GetDefaultSize (out int width, out int height)
+ {
+ if (type == DockGroupType.Tabbed) {
+ width = -1;
+ height = -1;
+ foreach (DockObject ob in VisibleObjects) {
+ int dh, dw;
+ ob.GetDefaultSize (out dw, out dh);
+ if (dw > width)
+ width = dw;
+ if (dh > height)
+ height = dh;
+ }
+ }
+ else if (type == DockGroupType.Vertical) {
+ height = VisibleObjects.Count > 0 ? (VisibleObjects.Count - 1) * Frame.TotalHandleSize : 0;
+ width = -1;
+ foreach (DockObject ob in VisibleObjects) {
+ int dh, dw;
+ ob.GetDefaultSize (out dw, out dh);
+ if (dw > width)
+ width = dw;
+ height += dh;
+ }
+ }
+ else {
+ width = VisibleObjects.Count > 0 ? (VisibleObjects.Count - 1) * Frame.TotalHandleSize : 0;
+ height = -1;
+ foreach (DockObject ob in VisibleObjects) {
+ int dh, dw;
+ ob.GetDefaultSize (out dw, out dh);
+ if (dh > height)
+ height = dh;
+ width += dw;
+ }
+ }
+ }
+
+ internal override void GetMinSize (out int width, out int height)
+ {
+ if (type == DockGroupType.Tabbed) {
+ width = -1;
+ height = -1;
+ foreach (DockObject ob in VisibleObjects) {
+ int dh, dw;
+ ob.GetMinSize (out dw, out dh);
+ if (dw > width)
+ width = dw;
+ if (dh > height)
+ height = dh;
+ }
+ }
+ else if (type == DockGroupType.Vertical) {
+ height = VisibleObjects.Count > 1 ? (VisibleObjects.Count - 1) * Frame.TotalHandleSize : 0;
+ width = -1;
+ foreach (DockObject ob in VisibleObjects) {
+ int dh, dw;
+ ob.GetMinSize (out dw, out dh);
+ if (dw > width)
+ width = dw;
+ height += dh;
+ }
+ }
+ else {
+ width = VisibleObjects.Count > 0 ? (VisibleObjects.Count - 1) * Frame.TotalHandleSize : 0;
+ height = -1;
+ foreach (DockObject ob in VisibleObjects) {
+ int dh, dw;
+ ob.GetMinSize (out dw, out dh);
+ if (dh > height)
+ height = dh;
+ width += dw;
+ }
+ }
+ }
+
+ public void Draw (Gdk.Rectangle exposedArea, DockGroup currentHandleGrp, int currentHandleIndex)
+ {
+ if (type != DockGroupType.Tabbed) {
+ DrawSeparators (exposedArea, currentHandleGrp, currentHandleIndex, false, false, null);
+ foreach (DockObject it in VisibleObjects) {
+ DockGroup grp = it as DockGroup;
+ if (grp != null)
+ grp.Draw (exposedArea, currentHandleGrp, currentHandleIndex);
+ }
+ }
+ }
+
+ public void DrawSeparators (Gdk.Rectangle exposedArea, DockGroup currentHandleGrp, int currentHandleIndex, bool invalidateOnly, List<Gdk.Rectangle> areasList)
+ {
+ DrawSeparators (exposedArea, currentHandleGrp, currentHandleIndex, invalidateOnly, true, areasList);
+ }
+
+ void DrawSeparators (Gdk.Rectangle exposedArea, DockGroup currentHandleGrp, int currentHandleIndex, bool invalidateOnly, bool drawChildrenSep, List<Gdk.Rectangle> areasList)
+ {
+ if (type == DockGroupType.Tabbed || VisibleObjects.Count == 0)
+ return;
+
+ DockObject last = VisibleObjects [VisibleObjects.Count - 1];
+
+ bool horiz = type == DockGroupType.Horizontal;
+ int x = Allocation.X;
+ int y = Allocation.Y;
+ int hw = horiz ? Frame.HandleSize : Allocation.Width;
+ int hh = horiz ? Allocation.Height : Frame.HandleSize;
+ Gtk.Orientation or = horiz ? Gtk.Orientation.Vertical : Gtk.Orientation.Horizontal;
+
+ for (int n=0; n<VisibleObjects.Count; n++) {
+ DockObject ob = VisibleObjects [n];
+ DockGroup grp = ob as DockGroup;
+ if (grp != null && drawChildrenSep)
+ grp.DrawSeparators (exposedArea, currentHandleGrp, currentHandleIndex, invalidateOnly, areasList);
+ if (ob != last) {
+ if (horiz)
+ x += ob.Allocation.Width + Frame.HandlePadding;
+ else
+ y += ob.Allocation.Height + Frame.HandlePadding;
+
+ if (areasList != null) {
+ if (Frame.ShadedSeparators)
+ areasList.Add (new Gdk.Rectangle (x, y, hw, hh));
+ } else if (invalidateOnly) {
+ Frame.Container.QueueDrawArea (x, y, hw, hh);
+ }
+ else {
+ if (Frame.ShadedSeparators) {
+ Frame.ShadedContainer.DrawBackground (Frame.Container, new Gdk.Rectangle (x, y, hw, hh));
+ } else {
+ StateType state = (currentHandleGrp == this && currentHandleIndex == n) ? StateType.Prelight : StateType.Normal;
+ if (!DockFrame.IsWindows)
+ Gtk.Style.PaintHandle (Frame.Style, Frame.Container.GdkWindow, state, ShadowType.None, exposedArea, Frame, "paned", x, y, hw, hh, or);
+ }
+ }
+
+ if (horiz)
+ x += Frame.HandleSize + Frame.HandlePadding;
+ else
+ y += Frame.HandleSize + Frame.HandlePadding;
+ }
+ }
+ }
+
+ public void ResizeItem (int index, int newSize)
+ {
+ DockObject o1 = VisibleObjects [index];
+ DockObject o2 = VisibleObjects [index+1];
+
+ int dsize;
+
+ dsize = newSize - o1.AllocSize;
+ if (dsize < 0 && o1.AllocSize + dsize < o1.MinSize)
+ dsize = o1.MinSize - o1.AllocSize;
+ else if (dsize > 0 && o2.AllocSize - dsize < o2.MinSize)
+ dsize = o2.AllocSize - o2.MinSize;
+
+ // Assign the new sizes, applying the current ratio
+ double sizeDif = (double)dsize;
+
+ o1.AllocSize += dsize;
+ o2.AllocSize -= dsize;
+
+ o1.DefaultSize += (o1.DefaultSize * sizeDif) / o1.Size;
+ o1.Size = o1.AllocSize;
+ o1.PrefSize = o1.Size;
+
+ o2.DefaultSize -= (o2.DefaultSize * sizeDif) / o2.Size;
+ o2.Size = o2.AllocSize;
+ o2.PrefSize = o2.Size;
+
+ o1.QueueResize ();
+ o2.QueueResize ();
+ }
+
+ internal override void QueueResize ()
+ {
+ foreach (DockObject obj in VisibleObjects)
+ obj.QueueResize ();
+ }
+
+ internal double GetObjectsSize ()
+ {
+ double total = 0;
+ foreach (DockObject obj in VisibleObjects)
+ total += obj.Size;
+ return total;
+ }
+
+ void DockTarget (DockItem item, int n)
+ {
+ DockGroupItem gitem = new DockGroupItem (Frame, item);
+ dockObjects.Insert (n, gitem);
+ gitem.ParentGroup = this;
+ gitem.SetVisible (true);
+ ResetVisibleGroups ();
+ CalcNewSizes ();
+ }
+
+ internal override bool GetDockTarget (DockItem item, int px, int py, out DockDelegate dockDelegate, out Gdk.Rectangle rect)
+ {
+ if (!Allocation.Contains (px, py) || VisibleObjects.Count == 0) {
+ dockDelegate = null;
+ rect = Gdk.Rectangle.Zero;
+ return false;
+ }
+
+ if (type == DockGroupType.Tabbed) {
+ // Tabs can only contain DockGroupItems
+ return ((DockGroupItem)VisibleObjects[0]).GetDockTarget (item, px, py, Allocation, out dockDelegate, out rect);
+ }
+ else if (type == DockGroupType.Horizontal) {
+ if (px >= Allocation.Right - DockFrame.GroupDockSeparatorSize) {
+ // Dock to the right of the group
+ dockDelegate = delegate (DockItem it) {
+ DockTarget (it, dockObjects.Count);
+ };
+ rect = new Gdk.Rectangle (Allocation.Right - DockFrame.GroupDockSeparatorSize, Allocation.Y, DockFrame.GroupDockSeparatorSize, Allocation.Height);
+ return true;
+ }
+ else if (px <= Allocation.Left + DockFrame.GroupDockSeparatorSize) {
+ // Dock to the left of the group
+ dockDelegate = delegate (DockItem it) {
+ DockTarget (it, 0);
+ };
+ rect = new Gdk.Rectangle (Allocation.Left, Allocation.Y, DockFrame.GroupDockSeparatorSize, Allocation.Height);
+ return true;
+ }
+ // Dock in a separator
+ for (int n=0; n<VisibleObjects.Count; n++) {
+ DockObject ob = VisibleObjects [n];
+ if (n < VisibleObjects.Count - 1 &&
+ px >= ob.Allocation.Right - DockFrame.GroupDockSeparatorSize/2 &&
+ px <= ob.Allocation.Right + DockFrame.GroupDockSeparatorSize/2)
+ {
+ int dn = dockObjects.IndexOf (ob);
+ dockDelegate = delegate (DockItem it) {
+ DockTarget (it, dn+1);
+ };
+ rect = new Gdk.Rectangle (ob.Allocation.Right - DockFrame.GroupDockSeparatorSize/2, Allocation.Y, DockFrame.GroupDockSeparatorSize, Allocation.Height);
+ return true;
+ }
+ else if (ob.GetDockTarget (item, px, py, out dockDelegate, out rect))
+ return true;
+ }
+ }
+ else if (type == DockGroupType.Vertical) {
+ if (py >= Allocation.Bottom - DockFrame.GroupDockSeparatorSize) {
+ // Dock to the bottom of the group
+ dockDelegate = delegate (DockItem it) {
+ DockTarget (it, dockObjects.Count);
+ };
+ rect = new Gdk.Rectangle (Allocation.X, Allocation.Bottom - DockFrame.GroupDockSeparatorSize, Allocation.Width, DockFrame.GroupDockSeparatorSize);
+ return true;
+ }
+ else if (py <= Allocation.Top + DockFrame.GroupDockSeparatorSize) {
+ // Dock to the top of the group
+ dockDelegate = delegate (DockItem it) {
+ DockTarget (it, 0);
+ };
+ rect = new Gdk.Rectangle (Allocation.X, Allocation.Top, Allocation.Width, DockFrame.GroupDockSeparatorSize);
+ return true;
+ }
+ // Dock in a separator
+ for (int n=0; n<VisibleObjects.Count; n++) {
+ DockObject ob = VisibleObjects [n];
+ if (n < VisibleObjects.Count - 1 &&
+ py >= ob.Allocation.Bottom - DockFrame.GroupDockSeparatorSize/2 &&
+ py <= ob.Allocation.Bottom + DockFrame.GroupDockSeparatorSize/2)
+ {
+ int dn = dockObjects.IndexOf (ob);
+ dockDelegate = delegate (DockItem it) {
+ DockTarget (it, dn+1);
+ };
+ rect = new Gdk.Rectangle (Allocation.X, ob.Allocation.Bottom - DockFrame.GroupDockSeparatorSize/2, Allocation.Width, DockFrame.GroupDockSeparatorSize);
+ return true;
+ }
+ else if (ob.GetDockTarget (item, px, py, out dockDelegate, out rect))
+ return true;
+ }
+ }
+ dockDelegate = null;
+ rect = Gdk.Rectangle.Zero;
+ return false;
+ }
+
+ public void ReplaceItem (DockObject ob1, DockObject ob2)
+ {
+ int i = dockObjects.IndexOf (ob1);
+ dockObjects [i] = ob2;
+ ob2.ParentGroup = this;
+ ob2.ResetDefaultSize ();
+ ob2.Size = ob1.Size;
+ ob2.DefaultSize = ob1.DefaultSize;
+ ob2.AllocSize = ob1.AllocSize;
+ ResetVisibleGroups ();
+ }
+
+ public override void CopyFrom (DockObject other)
+ {
+ base.CopyFrom (other);
+ DockGroup grp = (DockGroup) other;
+ dockObjects = new List<DockObject> ();
+ foreach (DockObject ob in grp.dockObjects) {
+ DockObject cob = ob.Clone ();
+ cob.ParentGroup = this;
+ dockObjects.Add (cob);
+ }
+ type = grp.type;
+ ResetVisibleGroups ();
+ boundTabStrip = null;
+ tabFocus = null;
+ }
+
+ internal override bool Visible {
+ get {
+ foreach (DockObject ob in dockObjects)
+ if (ob.Visible)
+ return true;
+ return false;
+ }
+ }
+
+ internal void Dump ()
+ {
+ Dump (0);
+ }
+
+ internal override void Dump (int ind)
+ {
+ Console.WriteLine (new string (' ', ind) + "Group (" + type + ") size:" + Size + " DefaultSize:" + DefaultSize + " alloc:" + Allocation);
+ foreach (DockObject ob in dockObjects) {
+ ob.Dump (ind + 2);
+ }
+ }
+
+ internal override void Write (XmlWriter writer)
+ {
+ base.Write (writer);
+ writer.WriteAttributeString ("type", type.ToString ());
+ if (type == DockGroupType.Tabbed && currentTabPage != -1)
+ writer.WriteAttributeString ("currentTabPage", currentTabPage.ToString ());
+
+ foreach (DockObject ob in dockObjects) {
+ if (ob is DockGroupItem)
+ writer.WriteStartElement ("item");
+ else
+ writer.WriteStartElement ("group");
+ ob.Write (writer);
+ writer.WriteEndElement ();
+ }
+ }
+
+ internal override void Read (XmlReader reader)
+ {
+ base.Read (reader);
+ type = (DockGroupType) Enum.Parse (typeof(DockGroupType), reader.GetAttribute ("type"));
+ if (type == DockGroupType.Tabbed) {
+ string s = reader.GetAttribute ("currentTabPage");
+ if (s != null)
+ currentTabPage = int.Parse (s);
+ }
+
+ reader.MoveToElement ();
+ if (reader.IsEmptyElement) {
+ reader.Skip ();
+ return;
+ }
+
+ reader.ReadStartElement ();
+ reader.MoveToContent ();
+ while (reader.NodeType != XmlNodeType.EndElement) {
+ if (reader.NodeType == XmlNodeType.Element) {
+ if (reader.LocalName == "item") {
+ string id = reader.GetAttribute ("id");
+ DockItem it = Frame.GetItem (id);
+ if (it == null) {
+ it = Frame.AddItem (id);
+ it.IsPositionMarker = true;
+ }
+ DockGroupItem gitem = new DockGroupItem (Frame, it);
+ gitem.Read (reader);
+ AddObject (gitem);
+
+ reader.MoveToElement ();
+ reader.Skip ();
+ }
+ else if (reader.LocalName == "group") {
+ DockGroup grp = new DockGroup (Frame);
+ grp.Read (reader);
+ AddObject (grp);
+ }
+ }
+ else
+ reader.Skip ();
+ reader.MoveToContent ();
+ }
+ reader.ReadEndElement ();
+ }
+
+ public bool IsChildNextToMargin (Gtk.PositionType margin, DockObject obj)
+ {
+ if (type == DockGroupType.Tabbed)
+ return true;
+ else if (type == DockGroupType.Horizontal) {
+ if (margin == PositionType.Top || margin == PositionType.Bottom)
+ return true;
+ int i = VisibleObjects.IndexOf (obj);
+ if (margin == PositionType.Left && i == 0)
+ return true;
+ if (margin == PositionType.Right && i == VisibleObjects.Count - 1)
+ return true;
+ }
+ else if (type == DockGroupType.Vertical) {
+ if (margin == PositionType.Left || margin == PositionType.Right)
+ return true;
+ int i = VisibleObjects.IndexOf (obj);
+ if (margin == PositionType.Top && i == 0)
+ return true;
+ if (margin == PositionType.Bottom && i == VisibleObjects.Count - 1)
+ return true;
+ }
+ return false;
+ }
+
+ internal TabStrip TabStrip {
+ get { return boundTabStrip; }
+ }
+
+ public override string ToString ()
+ {
+ return "[DockGroup " + type + "]";
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroupItem.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroupItem.cs
new file mode 100644
index 0000000000..89e01c2b90
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroupItem.cs
@@ -0,0 +1,385 @@
+//
+// DockGroupItem.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Xml;
+using Gtk;
+
+namespace MonoDevelop.Components.Docking
+{
+ internal class DockGroupItem: DockObject
+ {
+ DockItem item;
+ bool visibleFlag;
+ DockItemStatus status;
+ Gdk.Rectangle floatRect;
+ Gtk.PositionType barDocPosition;
+ int autoHideSize = -1;
+
+ public DockItem Item {
+ get {
+ return item;
+ }
+ set {
+ item = value;
+ }
+ }
+
+ public string Id {
+ get { return item.Id; }
+ }
+
+ public DockGroupItem (DockFrame frame, DockItem item): base (frame)
+ {
+ this.item = item;
+ visibleFlag = item.Visible;
+ }
+
+ internal override void GetDefaultSize (out int width, out int height)
+ {
+ width = item.DefaultWidth;
+ height = item.DefaultHeight;
+ }
+
+ internal override void GetMinSize (out int width, out int height)
+ {
+ Requisition req = SizeRequest ();
+ width = req.Width;
+ height = req.Height;
+ }
+
+ internal override Requisition SizeRequest ()
+ {
+ return item.Widget.SizeRequest ();
+ }
+
+ public override void SizeAllocate (Gdk.Rectangle newAlloc)
+ {
+ item.Widget.SizeAllocate (newAlloc);
+ base.SizeAllocate (newAlloc);
+ }
+
+ public override bool Expand {
+ get { return item.Expand; }
+ }
+
+ internal override void QueueResize ()
+ {
+ item.Widget.QueueResize ();
+ }
+
+ internal override bool GetDockTarget (DockItem item, int px, int py, out DockDelegate dockDelegate, out Gdk.Rectangle rect)
+ {
+ return GetDockTarget (item, px, py, Allocation, out dockDelegate, out rect);
+ }
+
+ public bool GetDockTarget (DockItem item, int px, int py, Gdk.Rectangle rect, out DockDelegate dockDelegate, out Gdk.Rectangle outrect)
+ {
+ dockDelegate = null;
+
+ if (item != this.item && this.item.Visible && rect.Contains (px, py)) {
+ int xdockMargin = (int) ((double)rect.Width * (1.0 - DockFrame.ItemDockCenterArea)) / 2;
+ int ydockMargin = (int) ((double)rect.Height * (1.0 - DockFrame.ItemDockCenterArea)) / 2;
+ DockPosition pos;
+
+/* if (ParentGroup.Type == DockGroupType.Tabbed) {
+ rect = new Gdk.Rectangle (rect.X + xdockMargin, rect.Y + ydockMargin, rect.Width - xdockMargin*2, rect.Height - ydockMargin*2);
+ pos = DockPosition.CenterAfter;
+ }
+*/ if (px <= rect.X + xdockMargin && ParentGroup.Type != DockGroupType.Horizontal) {
+ outrect = new Gdk.Rectangle (rect.X, rect.Y, xdockMargin, rect.Height);
+ pos = DockPosition.Left;
+ }
+ else if (px >= rect.Right - xdockMargin && ParentGroup.Type != DockGroupType.Horizontal) {
+ outrect = new Gdk.Rectangle (rect.Right - xdockMargin, rect.Y, xdockMargin, rect.Height);
+ pos = DockPosition.Right;
+ }
+ else if (py <= rect.Y + ydockMargin && ParentGroup.Type != DockGroupType.Vertical) {
+ outrect = new Gdk.Rectangle (rect.X, rect.Y, rect.Width, ydockMargin);
+ pos = DockPosition.Top;
+ }
+ else if (py >= rect.Bottom - ydockMargin && ParentGroup.Type != DockGroupType.Vertical) {
+ outrect = new Gdk.Rectangle (rect.X, rect.Bottom - ydockMargin, rect.Width, ydockMargin);
+ pos = DockPosition.Bottom;
+ }
+ else {
+ outrect = new Gdk.Rectangle (rect.X + xdockMargin, rect.Y + ydockMargin, rect.Width - xdockMargin*2, rect.Height - ydockMargin*2);
+ pos = DockPosition.Center;
+ }
+
+ dockDelegate = delegate (DockItem dit) {
+ DockGroupItem it = ParentGroup.AddObject (dit, pos, Id);
+ it.SetVisible (true);
+ ParentGroup.FocusItem (it);
+ };
+ return true;
+ }
+ outrect = Gdk.Rectangle.Zero;
+ return false;
+ }
+
+ internal override void Dump (int ind)
+ {
+ Console.WriteLine (new string (' ', ind) + item.Id + " size:" + Size + " alloc:" + Allocation);
+ }
+
+ internal override void Write (XmlWriter writer)
+ {
+ base.Write (writer);
+ writer.WriteAttributeString ("id", item.Id);
+ writer.WriteAttributeString ("visible", visibleFlag.ToString ());
+ writer.WriteAttributeString ("status", status.ToString ());
+
+ if (status == DockItemStatus.AutoHide)
+ writer.WriteAttributeString ("autoHidePosition", barDocPosition.ToString ());
+
+ if (autoHideSize != -1)
+ writer.WriteAttributeString ("autoHideSize", autoHideSize.ToString ());
+
+ if (!floatRect.Equals (Gdk.Rectangle.Zero)) {
+ writer.WriteAttributeString ("floatX", floatRect.X.ToString ());
+ writer.WriteAttributeString ("floatY", floatRect.Y.ToString ());
+ writer.WriteAttributeString ("floatWidth", floatRect.Width.ToString ());
+ writer.WriteAttributeString ("floatHeight", floatRect.Height.ToString ());
+ }
+ }
+
+ internal override void Read (XmlReader reader)
+ {
+ base.Read (reader);
+ visibleFlag = bool.Parse (reader.GetAttribute ("visible")) && !item.IsPositionMarker;
+ status = (DockItemStatus) Enum.Parse (typeof (DockItemStatus), reader.GetAttribute ("status"));
+ int fx=0, fy=0, fw=0, fh=0;
+ string s = reader.GetAttribute ("floatX");
+ if (s != null)
+ fx = int.Parse (s);
+ s = reader.GetAttribute ("floatY");
+ if (s != null)
+ fy = int.Parse (s);
+ s = reader.GetAttribute ("floatWidth");
+ if (s != null)
+ fw = int.Parse (s);
+ s = reader.GetAttribute ("floatHeight");
+ if (s != null)
+ fh = int.Parse (s);
+ s = reader.GetAttribute ("autoHidePosition");
+ if (s != null)
+ barDocPosition = (PositionType) Enum.Parse (typeof (PositionType), s);
+ s = reader.GetAttribute ("autoHideSize");
+ if (s != null)
+ autoHideSize = int.Parse (s);
+ floatRect = new Gdk.Rectangle (fx, fy, fw, fh);
+ }
+
+ public override void CopyFrom (DockObject ob)
+ {
+ base.CopyFrom (ob);
+ DockGroupItem it = (DockGroupItem)ob;
+ item = it.item;
+ visibleFlag = it.visibleFlag;
+ floatRect = it.floatRect;
+ }
+
+ internal override bool Visible {
+ get { return visibleFlag && status == DockItemStatus.Dockable; }
+ }
+
+ internal bool VisibleFlag {
+ get { return visibleFlag; }
+ }
+
+ public DockItemStatus Status {
+ get {
+ return status;
+ }
+ set {
+ if (status == value)
+ return;
+
+ DockItemStatus oldValue = status;
+ status = value;
+
+ if (status == DockItemStatus.Floating) {
+ if (floatRect.Equals (Gdk.Rectangle.Zero)) {
+ int x, y;
+ item.Widget.TranslateCoordinates (item.Widget.Toplevel, 0, 0, out x, out y);
+ Gtk.Window win = Frame.Toplevel as Window;
+ if (win != null) {
+ int wx, wy;
+ win.GetPosition (out wx, out wy);
+ floatRect = new Gdk.Rectangle (wx + x, wy + y, Allocation.Width, Allocation.Height);
+ }
+ }
+ item.SetFloatMode (floatRect);
+ }
+ else if (status == DockItemStatus.AutoHide) {
+ SetBarDocPosition ();
+ item.SetAutoHideMode (barDocPosition, GetAutoHideSize (barDocPosition));
+ }
+ else
+ item.ResetMode ();
+
+ if (oldValue == DockItemStatus.Dockable || status == DockItemStatus.Dockable) {
+ // Update visibility if changing from/to dockable mode
+ if (ParentGroup != null)
+ ParentGroup.UpdateVisible (this);
+ }
+ }
+ }
+
+ void SetBarDocPosition ()
+ {
+ // Determine the best position for docking the item
+
+ if (Allocation.IsEmpty) {
+ // If the item is in a group, use the dock location of other items
+ DockObject current = this;
+ do {
+ if (EstimateBarDocPosition (current.ParentGroup, current, out barDocPosition, out autoHideSize))
+ return;
+ current = current.ParentGroup;
+ } while (current.ParentGroup != null);
+
+ // Can't find a good location. Just guess.
+ barDocPosition = PositionType.Bottom;
+ autoHideSize = 200;
+ return;
+ }
+ barDocPosition = CalcBarDocPosition ();
+ }
+
+ bool EstimateBarDocPosition (DockGroup grp, DockObject ignoreChild, out PositionType pos, out int size)
+ {
+ foreach (DockObject ob in grp.Objects) {
+ if (ob == ignoreChild)
+ continue;
+ if (ob is DockGroup) {
+ if (EstimateBarDocPosition ((DockGroup)ob, null, out pos, out size))
+ return true;
+ } else if (ob is DockGroupItem) {
+ DockGroupItem it = (DockGroupItem) ob;
+ if (it.status == DockItemStatus.AutoHide) {
+ pos = it.barDocPosition;
+ size = it.autoHideSize;
+ return true;
+ }
+ if (!it.Allocation.IsEmpty) {
+ pos = it.CalcBarDocPosition ();
+ size = it.GetAutoHideSize (pos);
+ return true;
+ }
+ }
+ }
+ pos = PositionType.Bottom;
+ size = 0;
+ return false;
+ }
+
+ PositionType CalcBarDocPosition ()
+ {
+ if (Allocation.Width < Allocation.Height) {
+ int mid = Allocation.Left + Allocation.Width / 2;
+ if (mid > Frame.Allocation.Left + Frame.Allocation.Width / 2)
+ return PositionType.Right;
+ else
+ return PositionType.Left;
+ } else {
+ int mid = Allocation.Top + Allocation.Height / 2;
+ if (mid > Frame.Allocation.Top + Frame.Allocation.Height / 2)
+ return PositionType.Bottom;
+ else
+ return PositionType.Top;
+ }
+ }
+
+ internal void SetVisible (bool value)
+ {
+ if (visibleFlag != value) {
+ visibleFlag = value;
+ if (visibleFlag)
+ item.ShowWidget ();
+ else
+ item.HideWidget ();
+ if (ParentGroup != null)
+ ParentGroup.UpdateVisible (this);
+ }
+ }
+
+ internal override void StoreAllocation ()
+ {
+ base.StoreAllocation ();
+ if (Status == DockItemStatus.Floating)
+ floatRect = item.FloatingPosition;
+ else if (Status == DockItemStatus.AutoHide)
+ autoHideSize = item.AutoHideSize;
+ }
+
+ internal override void RestoreAllocation ()
+ {
+ base.RestoreAllocation ();
+ item.UpdateVisibleStatus ();
+
+ if (Status == DockItemStatus.Floating)
+ item.SetFloatMode (floatRect);
+ else if (Status == DockItemStatus.AutoHide)
+ item.SetAutoHideMode (barDocPosition, GetAutoHideSize (barDocPosition));
+ else
+ item.ResetMode ();
+
+ if (!visibleFlag)
+ item.HideWidget ();
+ }
+
+ int GetAutoHideSize (Gtk.PositionType pos)
+ {
+ if (autoHideSize != -1)
+ return autoHideSize;
+
+ if (pos == PositionType.Left || pos == PositionType.Right)
+ return Allocation.Width;
+ else
+ return Allocation.Height;
+ }
+
+ public Gdk.Rectangle FloatRect {
+ get {
+ return floatRect;
+ }
+ set {
+ floatRect = value;
+ }
+ }
+
+ public override string ToString ()
+ {
+ return "[DockItem " + Item.Id + "]";
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroupType.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroupType.cs
new file mode 100644
index 0000000000..f77a3e9a60
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockGroupType.cs
@@ -0,0 +1,41 @@
+//
+// DockGroupType.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+namespace MonoDevelop.Components.Docking
+{
+ enum DockGroupType
+ {
+ Horizontal,
+ Vertical,
+ Tabbed
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItem.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItem.cs
new file mode 100644
index 0000000000..dd47a99572
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItem.cs
@@ -0,0 +1,513 @@
+//
+// DockItem.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Xml;
+using Gtk;
+using Mono.Unix;
+
+namespace MonoDevelop.Components.Docking
+{
+ public class DockItem
+ {
+ Widget content;
+ DockItemContainer widget;
+ string defaultLocation;
+ bool defaultVisible = true;
+ DockItemStatus defaultStatus = DockItemStatus.Dockable;
+ string id;
+ DockFrame frame;
+ int defaultWidth = -1;
+ int defaultHeight = -1;
+ string label;
+ Gdk.Pixbuf icon;
+ bool expand;
+ bool drawFrame = true;
+ DockItemBehavior behavior;
+ Gtk.Window floatingWindow;
+ DockBarItem dockBarItem;
+ bool lastVisibleStatus;
+ bool lastContentVisibleStatus;
+ bool gettingContent;
+ bool isPositionMarker;
+ bool stickyVisible;
+ IDockItemLabelProvider dockLabelProvider;
+ DockItemToolbar toolbarTop;
+ DockItemToolbar toolbarBottom;
+ DockItemToolbar toolbarLeft;
+ DockItemToolbar toolbarRight;
+
+ public event EventHandler VisibleChanged;
+ public event EventHandler ContentVisibleChanged;
+ public event EventHandler ContentRequired;
+
+ internal DockItem (DockFrame frame, string id)
+ {
+ this.frame = frame;
+ this.id = id;
+ }
+
+ internal DockItem (DockFrame frame, Widget w, string id)
+ {
+ this.frame = frame;
+ this.id = id;
+ content = w;
+ }
+
+ public string Id {
+ get { return id; }
+ }
+
+ internal bool StickyVisible {
+ get { return stickyVisible; }
+ set { stickyVisible = value; }
+ }
+
+ public string Label {
+ get { return label ?? string.Empty; }
+ set {
+ label = value;
+ if (widget != null)
+ widget.Label = label;
+ frame.UpdateTitle (this);
+ if (floatingWindow != null)
+ floatingWindow.Title = GetWindowTitle ();
+ }
+ }
+
+ public bool Visible {
+ get {
+ return frame.GetVisible (this);
+ }
+ set {
+ stickyVisible = value;
+ frame.SetVisible (this, value);
+ UpdateVisibleStatus ();
+ }
+ }
+
+ public bool VisibleInLayout (string layout)
+ {
+ return frame.GetVisible (this, layout);
+ }
+
+ public DockItemStatus Status {
+ get {
+ return frame.GetStatus (this);
+ }
+ set {
+ frame.SetStatus (this, value);
+ }
+ }
+
+ public IDockItemLabelProvider DockLabelProvider {
+ get { return this.dockLabelProvider; }
+ set { this.dockLabelProvider = value; }
+ }
+
+ internal DockItemContainer Widget {
+ get {
+ if (widget == null) {
+ widget = new DockItemContainer (frame, this);
+ widget.Visible = false; // Required to ensure that the Shown event is fired
+ widget.Label = label;
+ widget.Shown += SetupContent;
+ }
+ return widget;
+ }
+ }
+
+ void SetupContent (object ob, EventArgs args)
+ {
+ widget.Shown -= SetupContent;
+
+ if (ContentRequired != null) {
+ gettingContent = true;
+ try {
+ ContentRequired (this, EventArgs.Empty);
+ } finally {
+ gettingContent = false;
+ }
+ }
+
+ widget.UpdateContent ();
+ widget.Shown += delegate {
+ UpdateContentVisibleStatus ();
+ };
+ widget.Hidden += delegate {
+ UpdateContentVisibleStatus ();
+ };
+ widget.ParentSet += delegate {
+ UpdateContentVisibleStatus ();
+ };
+ UpdateContentVisibleStatus ();
+ }
+
+ public Widget Content {
+ get {
+ return content;
+ }
+ set {
+ content = value;
+ if (!gettingContent && widget != null)
+ widget.UpdateContent ();
+ }
+ }
+
+ public DockItemToolbar GetToolbar (PositionType position)
+ {
+ switch (position) {
+ case PositionType.Top:
+ if (toolbarTop == null)
+ toolbarTop = new DockItemToolbar (this, PositionType.Top);
+ return toolbarTop;
+ case PositionType.Bottom:
+ if (toolbarBottom == null)
+ toolbarBottom = new DockItemToolbar (this, PositionType.Bottom);
+ return toolbarBottom;
+ case PositionType.Left:
+ if (toolbarLeft == null)
+ toolbarLeft = new DockItemToolbar (this, PositionType.Left);
+ return toolbarLeft;
+ case PositionType.Right:
+ if (toolbarRight == null)
+ toolbarRight = new DockItemToolbar (this, PositionType.Right);
+ return toolbarRight;
+ default: throw new ArgumentException ();
+ }
+ }
+
+ internal bool HasWidget {
+ get { return widget != null; }
+ }
+
+ public string DefaultLocation {
+ get { return defaultLocation; }
+ set { defaultLocation = value; }
+ }
+
+ public bool DefaultVisible {
+ get { return defaultVisible; }
+ set { defaultVisible = value; }
+ }
+
+ public DockItemStatus DefaultStatus {
+ get { return defaultStatus; }
+ set { defaultStatus = value; }
+ }
+
+ public int DefaultWidth {
+ get {
+ return defaultWidth;
+ }
+ set {
+ defaultWidth = value;
+ }
+ }
+
+ public int DefaultHeight {
+ get {
+ return defaultHeight;
+ }
+ set {
+ defaultHeight = value;
+ }
+ }
+
+ public Gdk.Pixbuf Icon {
+ get {
+ return icon;
+ }
+ set {
+ icon = value;
+ }
+ }
+
+ public DockItemBehavior Behavior {
+ get {
+ return behavior;
+ }
+ set {
+ behavior = value;
+ if (widget != null)
+ widget.UpdateBehavior ();
+ }
+ }
+
+ public bool Expand {
+ get {
+ return expand;
+ }
+ set {
+ expand = value;
+ }
+ }
+
+ public bool DrawFrame {
+ get {
+ return drawFrame;
+ }
+ set {
+ drawFrame = value;
+ }
+ }
+
+ public void Present (bool giveFocus)
+ {
+ if (dockBarItem != null)
+ dockBarItem.Present (Status == DockItemStatus.AutoHide || giveFocus);
+ else
+ frame.Present (this, Status == DockItemStatus.AutoHide || giveFocus);
+ }
+
+ public bool ContentVisible {
+ get {
+ if (widget == null)
+ return false;
+ return widget.Parent != null && widget.Visible;
+ }
+ }
+
+ internal void SetFocus ()
+ {
+ SetFocus (Widget);
+ }
+
+ internal static void SetFocus (Widget w)
+ {
+ w.ChildFocus (DirectionType.TabForward);
+
+ Window win = w.Toplevel as Gtk.Window;
+ if (win == null)
+ return;
+
+ // Make sure focus is not given to internal children
+ if (win.Focus != null) {
+ Container c = win.Focus.Parent as Container;
+ if (c.Children.Length == 0)
+ win.Focus = c;
+ }
+ }
+
+ internal void UpdateVisibleStatus ()
+ {
+ bool vis = frame.GetVisible (this);
+ if (vis != lastVisibleStatus) {
+ lastVisibleStatus = vis;
+ if (VisibleChanged != null)
+ VisibleChanged (this, EventArgs.Empty);
+ }
+ UpdateContentVisibleStatus ();
+ }
+
+ internal void UpdateContentVisibleStatus ()
+ {
+ bool vis = ContentVisible;
+ if (vis != lastContentVisibleStatus) {
+ lastContentVisibleStatus = vis;
+ if (ContentVisibleChanged != null)
+ ContentVisibleChanged (this, EventArgs.Empty);
+ }
+ }
+
+ internal void ShowWidget ()
+ {
+ if (floatingWindow != null)
+ floatingWindow.Show ();
+ if (dockBarItem != null)
+ dockBarItem.Show ();
+ Widget.Show ();
+ }
+
+ internal void HideWidget ()
+ {
+ if (floatingWindow != null)
+ floatingWindow.Hide ();
+ else if (dockBarItem != null)
+ dockBarItem.Hide ();
+ else if (widget != null)
+ widget.Hide ();
+ }
+
+ internal void SetFloatMode (Gdk.Rectangle rect)
+ {
+ ResetBarUndockMode ();
+ if (floatingWindow == null) {
+ if (Widget.Parent != null)
+ Widget.Unparent ();
+ floatingWindow = new Window (GetWindowTitle ());
+ floatingWindow.TransientFor = frame.Toplevel as Gtk.Window;
+ floatingWindow.TypeHint = Gdk.WindowTypeHint.Utility;
+ floatingWindow.Add (Widget);
+ floatingWindow.DeleteEvent += delegate (object o, DeleteEventArgs a) {
+ if (behavior == DockItemBehavior.CantClose)
+ Status = DockItemStatus.Dockable;
+ else
+ Visible = false;
+ a.RetVal = true;
+ };
+ }
+ floatingWindow.Move (rect.X, rect.Y);
+ floatingWindow.Resize (rect.Width, rect.Height);
+ floatingWindow.Show ();
+ Widget.UpdateBehavior ();
+ Widget.Show ();
+ }
+
+ internal void ResetFloatMode ()
+ {
+ if (floatingWindow != null) {
+ floatingWindow.Remove (Widget);
+ floatingWindow.Destroy ();
+ floatingWindow = null;
+ widget.UpdateBehavior ();
+ }
+ }
+
+ internal Gdk.Rectangle FloatingPosition {
+ get {
+ if (floatingWindow != null) {
+ int x,y,w,h;
+ floatingWindow.GetPosition (out x, out y);
+ floatingWindow.GetSize (out w, out h);
+ return new Gdk.Rectangle (x,y,w,h);
+ }
+ else
+ return Gdk.Rectangle.Zero;
+ }
+ }
+
+ internal void ResetMode ()
+ {
+ ResetFloatMode ();
+ ResetBarUndockMode ();
+ }
+
+ internal void SetAutoHideMode (Gtk.PositionType pos, int size)
+ {
+ ResetMode ();
+ if (widget != null) {
+ widget.Hide (); // Avoids size allocation warning
+ widget.Unparent ();
+ }
+ dockBarItem = frame.BarDock (pos, this, size);
+ if (widget != null)
+ widget.UpdateBehavior ();
+ }
+
+ void ResetBarUndockMode ()
+ {
+ if (dockBarItem != null) {
+ dockBarItem.Close ();
+ dockBarItem = null;
+ if (widget != null)
+ widget.UpdateBehavior ();
+ }
+ }
+
+ internal int AutoHideSize {
+ get {
+ if (dockBarItem != null)
+ return dockBarItem.Size;
+ else
+ return -1;
+ }
+ }
+
+ internal bool IsPositionMarker {
+ get {
+ return isPositionMarker;
+ }
+ set {
+ isPositionMarker = value;
+ }
+ }
+
+ string GetWindowTitle ()
+ {
+ if (Label.IndexOf ('<') == -1)
+ return Label;
+ try {
+ XmlDocument doc = new XmlDocument ();
+ doc.LoadXml ("<a>" + Label + "</a>");
+ return doc.InnerText;
+ } catch {
+ return label;
+ }
+ }
+
+ internal void ShowDockPopupMenu (uint time)
+ {
+ Menu menu = new Menu ();
+
+ // Hide menuitem
+ if ((Behavior & DockItemBehavior.CantClose) == 0) {
+ MenuItem mitem = new MenuItem (Catalog.GetString("Hide"));
+ mitem.Activated += delegate { Visible = false; };
+ menu.Append (mitem);
+ }
+
+ CheckMenuItem citem;
+
+ // Dockable menuitem
+ citem = new CheckMenuItem (Catalog.GetString("Dockable"));
+ citem.Active = Status == DockItemStatus.Dockable;
+ citem.DrawAsRadio = true;
+ citem.Toggled += delegate { Status = DockItemStatus.Dockable; };
+ menu.Append (citem);
+
+ // Floating menuitem
+ if ((Behavior & DockItemBehavior.NeverFloating) == 0) {
+ citem = new CheckMenuItem (Catalog.GetString("Floating"));
+ citem.Active = Status == DockItemStatus.Floating;
+ citem.DrawAsRadio = true;
+ citem.Toggled += delegate { Status = DockItemStatus.Floating; };
+ menu.Append (citem);
+ }
+
+ // Auto Hide menuitem
+ if ((Behavior & DockItemBehavior.CantAutoHide) == 0) {
+ citem = new CheckMenuItem (Catalog.GetString("Auto Hide"));
+ citem.Active = Status == DockItemStatus.AutoHide;
+ citem.DrawAsRadio = true;
+ citem.Toggled += delegate { Status = DockItemStatus.AutoHide; };
+ menu.Append (citem);
+ }
+
+ menu.ShowAll ();
+ menu.Popup (null, null, null, 3, time);
+ }
+ }
+
+ public interface IDockItemLabelProvider
+ {
+ Gtk.Widget CreateLabel (Orientation orientation);
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemBehavior.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemBehavior.cs
new file mode 100644
index 0000000000..1c62d92188
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemBehavior.cs
@@ -0,0 +1,48 @@
+//
+// DockItemBehavior.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+namespace MonoDevelop.Components.Docking
+{
+ [Flags]
+ public enum DockItemBehavior
+ {
+ Normal,
+ NeverFloating = 1 << 0,
+ NeverVertical = 1 << 1,
+ NeverHorizontal = 1 << 2,
+ CantClose = 1 << 3,
+ CantAutoHide = 1 << 4,
+ NoGrip = 1 << 5,
+ Sticky = 1 << 6, // Visibility is the same for al layouts
+ Locked = NoGrip,
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemContainer.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemContainer.cs
new file mode 100644
index 0000000000..43af768044
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemContainer.cs
@@ -0,0 +1,425 @@
+//
+// DockItemContainer.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using Gtk;
+using Mono.Unix;
+
+namespace MonoDevelop.Components.Docking
+{
+ class DockItemContainer: VBox
+ {
+ static Gdk.Pixbuf pixClose;
+ static Gdk.Pixbuf pixAutoHide;
+ static Gdk.Pixbuf pixDock;
+
+ Gtk.Label title;
+ Gtk.Button btnClose;
+ Gtk.Button btnDock;
+ string txt;
+ Gtk.EventBox header;
+ Gtk.Alignment headerAlign;
+ DockFrame frame;
+ DockItem item;
+ Widget widget;
+ Container borderFrame;
+ bool allowPlaceholderDocking;
+ bool pointerHover;
+ Box contentBox;
+
+ static Gdk.Cursor fleurCursor = new Gdk.Cursor (Gdk.CursorType.Fleur);
+ static Gdk.Cursor handCursor = new Gdk.Cursor (Gdk.CursorType.Hand2);
+
+ static DockItemContainer ()
+ {
+ try {
+ pixClose = Gdk.Pixbuf.LoadFromResource ("stock-close-12.png");
+ pixAutoHide = Gdk.Pixbuf.LoadFromResource ("stock-auto-hide.png");
+ pixDock = Gdk.Pixbuf.LoadFromResource ("stock-dock.png");
+ } catch (Exception) {
+ }
+ }
+
+ public DockItemContainer (DockFrame frame, DockItem item)
+ {
+ this.frame = frame;
+ this.item = item;
+
+ ResizeMode = Gtk.ResizeMode.Queue;
+ Spacing = 0;
+
+ title = new Gtk.Label ();
+ title.Xalign = 0;
+ title.Xpad = 3;
+ title.UseMarkup = true;
+
+ btnDock = new Button (new Gtk.Image (pixAutoHide));
+ btnDock.Relief = ReliefStyle.None;
+ btnDock.CanFocus = false;
+ btnDock.WidthRequest = btnDock.HeightRequest = 17;
+ btnDock.Clicked += OnClickDock;
+
+ btnClose = new Button (new Gtk.Image (pixClose));
+ btnClose.TooltipText = Catalog.GetString ("Hide");
+ btnClose.Relief = ReliefStyle.None;
+ btnClose.CanFocus = false;
+ btnClose.WidthRequest = btnClose.HeightRequest = 17;
+ btnClose.Clicked += delegate {
+ item.Visible = false;
+ };
+
+ HBox box = new HBox (false, 0);
+ box.PackStart (title, true, true, 0);
+ box.PackEnd (btnClose, false, false, 0);
+ box.PackEnd (btnDock, false, false, 0);
+
+ headerAlign = new Alignment (0.0f, 0.0f, 1.0f, 1.0f);
+ headerAlign.TopPadding = headerAlign.BottomPadding = headerAlign.RightPadding = headerAlign.LeftPadding = 1;
+ headerAlign.Add (box);
+
+ header = new EventBox ();
+ header.Events |= Gdk.EventMask.KeyPressMask | Gdk.EventMask.KeyReleaseMask;
+ header.ButtonPressEvent += HeaderButtonPress;
+ header.ButtonReleaseEvent += HeaderButtonRelease;
+ header.MotionNotifyEvent += HeaderMotion;
+ header.KeyPressEvent += HeaderKeyPress;
+ header.KeyReleaseEvent += HeaderKeyRelease;
+ header.Add (headerAlign);
+ header.ExposeEvent += HeaderExpose;
+ header.Realized += delegate {
+ header.GdkWindow.Cursor = handCursor;
+ };
+
+ foreach (Widget w in new Widget [] { header, btnDock, btnClose }) {
+ w.EnterNotifyEvent += HeaderEnterNotify;
+ w.LeaveNotifyEvent += HeaderLeaveNotify;
+ }
+
+ PackStart (header, false, false, 0);
+ ShowAll ();
+
+ PackStart (item.GetToolbar (PositionType.Top).Container, false, false, 0);
+
+ HBox hbox = new HBox ();
+ hbox.Show ();
+ hbox.PackStart (item.GetToolbar (PositionType.Left).Container, false, false, 0);
+
+ contentBox = new HBox ();
+ contentBox.Show ();
+ hbox.PackStart (contentBox, true, true, 0);
+
+ hbox.PackStart (item.GetToolbar (PositionType.Right).Container, false, false, 0);
+
+ PackStart (hbox, true, true, 0);
+
+ PackStart (item.GetToolbar (PositionType.Bottom).Container, false, false, 0);
+
+ UpdateBehavior ();
+ }
+
+ void OnClickDock (object s, EventArgs a)
+ {
+ if (item.Status == DockItemStatus.AutoHide || item.Status == DockItemStatus.Floating)
+ item.Status = DockItemStatus.Dockable;
+ else
+ item.Status = DockItemStatus.AutoHide;
+ }
+
+ public void UpdateContent ()
+ {
+ if (widget != null)
+ ((Gtk.Container)widget.Parent).Remove (widget);
+ widget = item.Content;
+
+ if (item.DrawFrame) {
+ if (borderFrame == null) {
+ borderFrame = new CustomFrame (1, 1, 1, 1);
+ borderFrame.Show ();
+ contentBox.Add (borderFrame);
+ }
+ if (widget != null) {
+ borderFrame.Add (widget);
+ widget.Show ();
+ }
+ }
+ else if (widget != null) {
+ if (borderFrame != null) {
+ contentBox.Remove (borderFrame);
+ borderFrame = null;
+ }
+ contentBox.Add (widget);
+ widget.Show ();
+ }
+ }
+
+ public void UpdateBehavior ()
+ {
+ btnClose.Visible = (item.Behavior & DockItemBehavior.CantClose) == 0;
+ header.Visible = (item.Behavior & DockItemBehavior.Locked) == 0;
+ btnDock.Visible = (item.Behavior & DockItemBehavior.CantAutoHide) == 0;
+
+ if (item.Status == DockItemStatus.AutoHide || item.Status == DockItemStatus.Floating) {
+ btnDock.Image = new Gtk.Image (pixDock);
+ btnDock.TooltipText = Catalog.GetString ("Dock");
+ }
+ else {
+ btnDock.Image = new Gtk.Image (pixAutoHide);
+ btnDock.TooltipText = Catalog.GetString ("Auto Hide");
+ }
+ }
+
+ void HeaderButtonPress (object ob, Gtk.ButtonPressEventArgs args)
+ {
+ if (args.Event.Button == 1) {
+ frame.ShowPlaceholder ();
+ header.GdkWindow.Cursor = fleurCursor;
+ frame.Toplevel.KeyPressEvent += HeaderKeyPress;
+ frame.Toplevel.KeyReleaseEvent += HeaderKeyRelease;
+ allowPlaceholderDocking = true;
+ }
+ else if (args.Event.Button == 3) {
+ item.ShowDockPopupMenu (args.Event.Time);
+ }
+ }
+
+ void HeaderButtonRelease (object ob, Gtk.ButtonReleaseEventArgs args)
+ {
+ if (args.Event.Button == 1) {
+ frame.DockInPlaceholder (item);
+ frame.HidePlaceholder ();
+ if (header.GdkWindow != null)
+ header.GdkWindow.Cursor = handCursor;
+ frame.Toplevel.KeyPressEvent -= HeaderKeyPress;
+ frame.Toplevel.KeyReleaseEvent -= HeaderKeyRelease;
+ }
+ }
+
+ void HeaderMotion (object ob, Gtk.MotionNotifyEventArgs args)
+ {
+ frame.UpdatePlaceholder (item, Allocation.Size, allowPlaceholderDocking);
+ }
+
+ [GLib.ConnectBeforeAttribute]
+ void HeaderKeyPress (object ob, Gtk.KeyPressEventArgs a)
+ {
+ if (a.Event.Key == Gdk.Key.Control_L || a.Event.Key == Gdk.Key.Control_R) {
+ allowPlaceholderDocking = false;
+ frame.UpdatePlaceholder (item, Allocation.Size, false);
+ }
+ if (a.Event.Key == Gdk.Key.Escape) {
+ frame.HidePlaceholder ();
+ frame.Toplevel.KeyPressEvent -= HeaderKeyPress;
+ frame.Toplevel.KeyReleaseEvent -= HeaderKeyRelease;
+ Gdk.Pointer.Ungrab (0);
+ }
+ }
+
+ [GLib.ConnectBeforeAttribute]
+ void HeaderKeyRelease (object ob, Gtk.KeyReleaseEventArgs a)
+ {
+ if (a.Event.Key == Gdk.Key.Control_L || a.Event.Key == Gdk.Key.Control_R) {
+ allowPlaceholderDocking = true;
+ frame.UpdatePlaceholder (item, Allocation.Size, true);
+ }
+ }
+
+ private void HeaderExpose (object ob, Gtk.ExposeEventArgs a)
+ {
+ Gdk.Rectangle rect = new Gdk.Rectangle (0, 0, header.Allocation.Width - 1, header.Allocation.Height);
+ HslColor gcol = frame.Style.Background (Gtk.StateType.Normal);
+
+ if (pointerHover)
+ gcol.L *= 1.1;
+ else
+ gcol.L *= 1;
+
+ if (gcol.L > 1)
+ gcol.L = 1;
+
+ using (Cairo.Context cr = Gdk.CairoHelper.Create (a.Event.Window)) {
+ cr.NewPath ();
+ cr.MoveTo (0, 0);
+ cr.RelLineTo (rect.Width, 0);
+ cr.RelLineTo (0, rect.Height);
+ cr.RelLineTo (-rect.Width, 0);
+ cr.RelLineTo (0, -rect.Height);
+ cr.ClosePath ();
+ Cairo.Gradient pat = new Cairo.LinearGradient (0, 0, rect.Width, rect.Height);
+ Cairo.Color color1 = gcol;
+ pat.AddColorStop (0, color1);
+ color1.A = 0.3;
+ pat.AddColorStop (1, color1);
+ cr.Pattern = pat;
+ cr.FillPreserve ();
+ }
+
+// header.GdkWindow.DrawRectangle (gc, true, rect);
+ header.GdkWindow.DrawRectangle (frame.Style.DarkGC (Gtk.StateType.Normal), false, rect);
+
+ foreach (Widget child in header.Children)
+ header.PropagateExpose (child, a.Event);
+ }
+
+ private void HeaderLeaveNotify (object ob, EventArgs a)
+ {
+ pointerHover = false;
+ header.QueueDraw ();
+ }
+
+ private void HeaderEnterNotify (object ob, EventArgs a)
+ {
+ pointerHover = true;
+ header.QueueDraw ();
+ }
+
+ public string Label {
+ get { return txt; }
+ set {
+ title.Markup = "<small>" + value + "</small>";
+ txt = value;
+ }
+ }
+ }
+
+ class CustomFrame: Bin
+ {
+ Gtk.Widget child;
+ int topMargin;
+ int bottomMargin;
+ int leftMargin;
+ int rightMargin;
+
+ int topPadding;
+ int bottomPadding;
+ int leftPadding;
+ int rightPadding;
+
+ public CustomFrame ()
+ {
+ }
+
+ public CustomFrame (int topMargin, int bottomMargin, int leftMargin, int rightMargin)
+ {
+ SetMargins (topMargin, bottomMargin, leftMargin, rightMargin);
+ }
+
+ public void SetMargins (int topMargin, int bottomMargin, int leftMargin, int rightMargin)
+ {
+ this.topMargin = topMargin;
+ this.bottomMargin = bottomMargin;
+ this.leftMargin = leftMargin;
+ this.rightMargin = rightMargin;
+ }
+
+ public void SetPadding (int topPadding, int bottomPadding, int leftPadding, int rightPadding)
+ {
+ this.topPadding = topPadding;
+ this.bottomPadding = bottomPadding;
+ this.leftPadding = leftPadding;
+ this.rightPadding = rightPadding;
+ }
+
+ public bool GradientBackround { get; set; }
+
+ protected override void OnAdded (Widget widget)
+ {
+ base.OnAdded (widget);
+ child = widget;
+ }
+
+ protected override void OnSizeRequested (ref Requisition requisition)
+ {
+ requisition = child.SizeRequest ();
+ requisition.Width += leftMargin + rightMargin + leftPadding + rightPadding;
+ requisition.Height += topMargin + bottomMargin + topPadding + bottomPadding;
+ }
+
+ protected override void OnSizeAllocated (Gdk.Rectangle allocation)
+ {
+ base.OnSizeAllocated (allocation);
+ if (allocation.Width > leftMargin + rightMargin + leftPadding + rightPadding) {
+ allocation.X += leftMargin + leftPadding;
+ allocation.Width -= leftMargin + rightMargin + leftPadding + rightPadding;
+ }
+ if (allocation.Height > topMargin + bottomMargin + topPadding + bottomPadding) {
+ allocation.Y += topMargin + topPadding;
+ allocation.Height -= topMargin + bottomMargin + topPadding + bottomPadding;
+ }
+ child.SizeAllocate (allocation);
+ }
+
+ protected override bool OnExposeEvent (Gdk.EventExpose evnt)
+ {
+ Gdk.Rectangle rect;
+
+ if (GradientBackround) {
+ rect = new Gdk.Rectangle (Allocation.X, Allocation.Y, Allocation.Width, Allocation.Height);
+ HslColor gcol = Style.Background (Gtk.StateType.Normal);
+
+ using (Cairo.Context cr = Gdk.CairoHelper.Create (GdkWindow)) {
+ cr.NewPath ();
+ cr.MoveTo (rect.X, rect.Y);
+ cr.RelLineTo (rect.Width, 0);
+ cr.RelLineTo (0, rect.Height);
+ cr.RelLineTo (-rect.Width, 0);
+ cr.RelLineTo (0, -rect.Height);
+ cr.ClosePath ();
+ Cairo.Gradient pat = new Cairo.LinearGradient (rect.X, rect.Y, rect.X, rect.Bottom);
+ Cairo.Color color1 = gcol;
+ pat.AddColorStop (0, color1);
+ gcol.L -= 0.1;
+ if (gcol.L < 0) gcol.L = 0;
+ pat.AddColorStop (1, gcol);
+ cr.Pattern = pat;
+ cr.FillPreserve ();
+ }
+ }
+
+ bool res = base.OnExposeEvent (evnt);
+
+ Gdk.GC borderColor = Style.DarkGC (Gtk.StateType.Normal);
+
+ rect = Allocation;
+ for (int n=0; n<topMargin; n++)
+ GdkWindow.DrawLine (borderColor, rect.X, rect.Y + n, rect.Right - 1, rect.Y + n);
+
+ for (int n=0; n<bottomMargin; n++)
+ GdkWindow.DrawLine (borderColor, rect.X, rect.Bottom - n - 1, rect.Right - 1, rect.Bottom - n - 1);
+
+ for (int n=0; n<leftMargin; n++)
+ GdkWindow.DrawLine (borderColor, rect.X + n, rect.Y, rect.X + n, rect.Bottom - 1);
+
+ for (int n=0; n<rightMargin; n++)
+ GdkWindow.DrawLine (borderColor, rect.Right - n - 1, rect.Y, rect.Right - n - 1, rect.Bottom - 1);
+
+ return res;
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemStatus.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemStatus.cs
new file mode 100644
index 0000000000..e6e56d2fa4
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemStatus.cs
@@ -0,0 +1,42 @@
+//
+// DockItemStatus.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System;
+
+namespace MonoDevelop.Components.Docking
+{
+ public enum DockItemStatus
+ {
+ Dockable,
+ Floating,
+ AutoHide
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemToolbar.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemToolbar.cs
new file mode 100644
index 0000000000..d85c8c8f89
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockItemToolbar.cs
@@ -0,0 +1,181 @@
+//
+// DockItemToolbar.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@novell.com>
+//
+// Copyright (c) 2010 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using Gtk;
+
+namespace MonoDevelop.Components.Docking
+{
+ public class DockItemToolbar
+ {
+ DockItem parentItem;
+ CustomFrame frame;
+ Box box;
+ PositionType position;
+ bool empty = true;
+
+ internal DockItemToolbar (DockItem parentItem, PositionType position)
+ {
+ this.parentItem = parentItem;
+ frame = new CustomFrame ();
+ switch (position) {
+ case PositionType.Top:
+ frame.SetMargins (0, 0, 1, 1);
+ frame.SetPadding (0, 2, 2, 0);
+ break;
+ case PositionType.Bottom:
+ frame.SetMargins (0, 1, 1, 1);
+ frame.SetPadding (2, 2, 2, 0);
+ break;
+ case PositionType.Left:
+ frame.SetMargins (0, 1, 1, 0);
+ frame.SetPadding (0, 0, 2, 2);
+ break;
+ case PositionType.Right:
+ frame.SetMargins (0, 1, 0, 1);
+ frame.SetPadding (0, 0, 2, 2);
+ break;
+ }
+ this.position = position;
+ if (position == PositionType.Top || position == PositionType.Bottom)
+ box = new HBox (false, 3);
+ else
+ box = new VBox (false, 3);
+ box.Show ();
+ frame.Add (box);
+ frame.GradientBackround = true;
+ }
+
+ public DockItem DockItem {
+ get { return parentItem; }
+ }
+
+ internal Widget Container {
+ get { return frame; }
+ }
+
+ public PositionType Position {
+ get { return this.position; }
+ }
+
+ public void Add (Widget widget)
+ {
+ Add (widget, false);
+ }
+
+ public void Add (Widget widget, bool fill)
+ {
+ Add (widget, fill, -1);
+ }
+
+ public void Add (Widget widget, bool fill, int padding)
+ {
+ Add (widget, fill, padding, -1);
+ }
+
+ void Add (Widget widget, bool fill, int padding, int index)
+ {
+ int defaultPadding = 3;
+
+ if (widget is Button) {
+ ((Button)widget).Relief = ReliefStyle.None;
+ ((Button)widget).FocusOnClick = false;
+ defaultPadding = 0;
+ }
+ else if (widget is Entry) {
+ ((Entry)widget).HasFrame = false;
+ }
+ else if (widget is ComboBox) {
+ ((ComboBox)widget).HasFrame = false;
+ }
+ else if (widget is VSeparator)
+ ((VSeparator)widget).HeightRequest = 10;
+
+ if (padding == -1)
+ padding = defaultPadding;
+
+ box.PackStart (widget, fill, fill, (uint)padding);
+ if (empty) {
+ empty = false;
+ frame.Show ();
+ }
+ if (index != -1) {
+ Box.BoxChild bc = (Box.BoxChild) box [widget];
+ bc.Position = index;
+ }
+ }
+
+ public void Insert (Widget w, int index)
+ {
+ Add (w, false, 0, index);
+ }
+
+ public void Remove (Widget widget)
+ {
+ box.Remove (widget);
+ }
+
+ public bool Visible {
+ get {
+ return empty || frame.Visible;
+ }
+ set {
+ frame.Visible = value;
+ }
+ }
+
+ public bool Sensitive {
+ get { return frame.Sensitive; }
+ set { frame.Sensitive = value; }
+ }
+
+ public void ShowAll ()
+ {
+ frame.ShowAll ();
+ }
+
+ public Widget[] Children {
+ get { return box.Children; }
+ }
+ }
+
+ public class DockToolButton: Gtk.Button
+ {
+ public DockToolButton (string stockId)
+ {
+ Image = new Gtk.Image (stockId, IconSize.Menu);
+ Image.Show ();
+ }
+
+ public DockToolButton (string stockId, string label)
+ {
+ Label = label;
+ Image = new Gtk.Image (stockId, IconSize.Menu);
+ Image.Show ();
+ }
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockLayout.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockLayout.cs
new file mode 100644
index 0000000000..e215378f3f
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockLayout.cs
@@ -0,0 +1,107 @@
+//
+// MonoDevelop.Components.Docking.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+
+using System;
+using System.Xml;
+using System.Collections.Generic;
+
+namespace MonoDevelop.Components.Docking
+{
+ class DockLayout: DockGroup
+ {
+ string name;
+ int layoutWidth = 1024;
+ int layoutHeight = 768;
+
+ public DockLayout (DockFrame frame): base (frame, DockGroupType.Horizontal)
+ {
+ }
+
+ public string Name {
+ get {
+ return name;
+ }
+ set {
+ name = value;
+ }
+ }
+
+ internal override void Write (XmlWriter writer)
+ {
+ writer.WriteStartElement ("layout");
+ writer.WriteAttributeString ("name", name);
+ writer.WriteAttributeString ("width", layoutWidth.ToString ());
+ writer.WriteAttributeString ("height", layoutHeight.ToString ());
+ base.Write (writer);
+ writer.WriteEndElement ();
+ }
+
+ internal override void Read (XmlReader reader)
+ {
+ name = reader.GetAttribute ("name");
+ string s = reader.GetAttribute ("width");
+ if (s != null)
+ layoutWidth = int.Parse (s);
+ s = reader.GetAttribute ("height");
+ if (s != null)
+ layoutHeight = int.Parse (s);
+ base.Read (reader);
+ }
+
+ public static DockLayout Read (DockFrame frame, XmlReader reader)
+ {
+ DockLayout layout = new DockLayout (frame);
+ layout.Read (reader);
+ return layout;
+ }
+
+ public override void SizeAllocate (Gdk.Rectangle rect)
+ {
+ Size = rect.Width;
+ base.SizeAllocate (rect);
+ }
+
+ internal override void StoreAllocation ()
+ {
+ base.StoreAllocation ();
+ layoutWidth = Allocation.Width;
+ layoutHeight = Allocation.Height;
+ }
+
+ internal override void RestoreAllocation ()
+ {
+ Allocation = new Gdk.Rectangle (0, 0, layoutWidth, layoutHeight);
+ base.RestoreAllocation ();
+ }
+
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockObject.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockObject.cs
new file mode 100644
index 0000000000..f909bf3542
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockObject.cs
@@ -0,0 +1,284 @@
+//
+// DockObject.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System;
+using System.Xml;
+using Gtk;
+using System.Globalization;
+
+namespace MonoDevelop.Components.Docking
+{
+ internal abstract class DockObject
+ {
+ DockGroup parentGroup;
+ DockFrame frame;
+ Gdk.Rectangle rect;
+
+ // The current size in pixels of this item
+ double size = -1;
+
+ // The current size in pixels of this item, but as an integer.
+ // In general it is the same value as size, but it may change a bit due to rounding.
+ int allocSize = -1;
+
+ double defaultHorSize = -1;
+ double defaultVerSize = -1;
+ double prefSize = 0;
+
+ // Those are the last known coordinates of the item. They are stored in StoreAllocation
+ // and restored to rect in RestoreAllocation. This is needed for example when a layout
+ // is cloned. It is convenient to have allocation information in the cloned layout, even
+ // if the layout has never been displayed (e.g., to decide the autohide dock location)
+ int ax=-1, ay=-1;
+
+ public DockObject (DockFrame frame)
+ {
+ this.frame = frame;
+ }
+
+ internal DockGroup ParentGroup {
+ get {
+ return parentGroup;
+ }
+ set {
+ parentGroup = value;
+ if (size < 0)
+ size = prefSize = DefaultSize;
+ }
+ }
+
+ public double Size {
+ get {
+ return size;
+ }
+ set {
+ size = value;
+ }
+ }
+
+ public bool HasAllocatedSize {
+ get { return allocSize != -1; }
+ }
+
+ public double DefaultSize {
+ get {
+ if (defaultHorSize < 0)
+ InitDefaultSizes ();
+ if (parentGroup != null) {
+ if (parentGroup.Type == DockGroupType.Horizontal)
+ return defaultHorSize;
+ else if (parentGroup.Type == DockGroupType.Vertical)
+ return defaultVerSize;
+ }
+ return 0;
+ }
+ set {
+ if (parentGroup != null) {
+ if (parentGroup.Type == DockGroupType.Horizontal)
+ defaultHorSize = value;
+ else if (parentGroup.Type == DockGroupType.Vertical)
+ defaultVerSize = value;
+ }
+ }
+ }
+
+ internal void ResetDefaultSize ()
+ {
+ defaultHorSize = -1;
+ defaultVerSize = -1;
+ }
+
+ public int MinSize {
+ get {
+ int w,h;
+ GetMinSize (out w, out h);
+ if (parentGroup != null) {
+ if (parentGroup.Type == DockGroupType.Horizontal)
+ return w;
+ else if (parentGroup.Type == DockGroupType.Vertical)
+ return h;
+ }
+ return w;
+ }
+ }
+
+ public abstract bool Expand { get; }
+
+ public virtual void SizeAllocate (Gdk.Rectangle rect)
+ {
+ this.rect = rect;
+ }
+
+ internal Gdk.Rectangle Allocation {
+ get {
+ return rect;
+ }
+ set {
+ rect = value;
+ }
+ }
+
+ public int AllocSize {
+ get {
+ return allocSize;
+ }
+ set {
+ allocSize = value;
+ }
+ }
+
+ public MonoDevelop.Components.Docking.DockFrame Frame {
+ get {
+ return frame;
+ }
+ }
+
+ public double PrefSize {
+ get {
+ return prefSize;
+ }
+ set {
+ prefSize = value;
+ }
+ }
+
+ void InitDefaultSizes ()
+ {
+ int width, height;
+ GetDefaultSize (out width, out height);
+ if (width == -1)
+ width = frame.DefaultItemWidth;
+ if (height == -1)
+ height = frame.DefaultItemHeight;
+ defaultHorSize = (double) width;
+ defaultVerSize = (double) height;
+ }
+
+ internal virtual void GetDefaultSize (out int width, out int height)
+ {
+ width = -1;
+ height = -1;
+ }
+
+ internal virtual void GetMinSize (out int width, out int height)
+ {
+ width = 0;
+ height = 0;
+ }
+
+ internal abstract void QueueResize ();
+
+ internal abstract bool GetDockTarget (DockItem item, int px, int py, out DockDelegate dockDelegate, out Gdk.Rectangle rect);
+
+ internal abstract Gtk.Requisition SizeRequest ();
+
+ internal abstract bool Visible { get; }
+
+ internal abstract void Dump (int ind);
+
+ internal virtual void RestoreAllocation ()
+ {
+ if (parentGroup != null) {
+ int x = ax != -1 ? ax : 0;
+ int y = ay != -1 ? ay : 0;
+ if (parentGroup.Type == DockGroupType.Horizontal)
+ rect = new Gdk.Rectangle (x, y, (int)size, parentGroup.Allocation.Height);
+ else if (parentGroup.Type == DockGroupType.Vertical)
+ rect = new Gdk.Rectangle (x, y, parentGroup.Allocation.Width, (int)size);
+ }
+ }
+
+ internal virtual void StoreAllocation ()
+ {
+ if (Visible) {
+ if (parentGroup == null || parentGroup.Type == DockGroupType.Horizontal)
+ size = prefSize = (int) rect.Width;
+ else if (parentGroup.Type == DockGroupType.Vertical)
+ size = prefSize = (int) rect.Height;
+ ax = Allocation.X;
+ ay = Allocation.Y;
+ }
+ }
+
+ internal virtual void Write (XmlWriter writer)
+ {
+ writer.WriteAttributeString ("size", size.ToString (CultureInfo.InvariantCulture));
+ writer.WriteAttributeString ("prefSize", prefSize.ToString (CultureInfo.InvariantCulture));
+ writer.WriteAttributeString ("defaultHorSize", defaultHorSize.ToString (CultureInfo.InvariantCulture));
+ writer.WriteAttributeString ("defaultVerSize", defaultVerSize.ToString (CultureInfo.InvariantCulture));
+ }
+
+ internal virtual void Read (XmlReader reader)
+ {
+ size = double.Parse (reader.GetAttribute ("size"), CultureInfo.InvariantCulture);
+ prefSize = double.Parse (reader.GetAttribute ("prefSize"), CultureInfo.InvariantCulture);
+ defaultHorSize = double.Parse (reader.GetAttribute ("defaultHorSize"), CultureInfo.InvariantCulture);
+ defaultVerSize = double.Parse (reader.GetAttribute ("defaultVerSize"), CultureInfo.InvariantCulture);
+ }
+
+ public virtual void CopyFrom (DockObject ob)
+ {
+ parentGroup = null;
+ frame = ob.frame;
+ rect = ob.rect;
+ size = ob.size;
+ allocSize = ob.allocSize;
+ defaultHorSize = ob.defaultHorSize;
+ defaultVerSize = ob.defaultVerSize;
+ prefSize = ob.prefSize;
+ }
+
+ public DockObject Clone ()
+ {
+ DockObject ob = (DockObject) this.MemberwiseClone ();
+ ob.CopyFrom (this);
+ return ob;
+ }
+
+ public virtual void CopySizeFrom (DockObject obj)
+ {
+ size = obj.size;
+ allocSize = obj.allocSize;
+ defaultHorSize = obj.defaultHorSize;
+ defaultVerSize = obj.defaultVerSize;
+ prefSize = obj.prefSize;
+ }
+
+ public virtual bool IsNextToMargin (Gtk.PositionType margin)
+ {
+ if (ParentGroup == null)
+ return true;
+ if (!ParentGroup.IsNextToMargin (margin))
+ return false;
+ return ParentGroup.IsChildNextToMargin (margin, this);
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockPosition.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockPosition.cs
new file mode 100644
index 0000000000..39404ad97e
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/DockPosition.cs
@@ -0,0 +1,45 @@
+//
+// DockPosition.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+
+using System;
+
+namespace MonoDevelop.Components.Docking
+{
+ enum DockPosition
+ {
+ Left,
+ Right,
+ Top,
+ Bottom,
+ Center,
+ CenterBefore
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/PlaceholderWindow.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/PlaceholderWindow.cs
new file mode 100644
index 0000000000..a2f1f4977a
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/PlaceholderWindow.cs
@@ -0,0 +1,143 @@
+//
+// PlaceholderWindow.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using Gdk;
+using Gtk;
+
+namespace MonoDevelop.Components.Docking
+{
+ internal class PlaceholderWindow: Gtk.Window
+ {
+ Gdk.GC redgc;
+ uint anim;
+ int rx, ry, rw, rh;
+ bool allowDocking;
+
+ public bool AllowDocking {
+ get {
+ return allowDocking;
+ }
+ set {
+ allowDocking = value;
+ }
+ }
+
+ public PlaceholderWindow (DockFrame frame): base (Gtk.WindowType.Popup)
+ {
+ SkipTaskbarHint = true;
+ Decorated = false;
+ TransientFor = (Gtk.Window) frame.Toplevel;
+ TypeHint = WindowTypeHint.Utility;
+
+ // Create the mask for the arrow
+
+ Realize ();
+ redgc = new Gdk.GC (GdkWindow);
+ redgc.RgbFgColor = frame.Style.Background (StateType.Selected);
+ }
+
+ void CreateShape (int width, int height)
+ {
+ Gdk.Color black, white;
+ black = new Gdk.Color (0, 0, 0);
+ black.Pixel = 1;
+ white = new Gdk.Color (255, 255, 255);
+ white.Pixel = 0;
+
+ Gdk.Pixmap pm = new Pixmap (this.GdkWindow, width, height, 1);
+ Gdk.GC gc = new Gdk.GC (pm);
+ gc.Background = white;
+ gc.Foreground = white;
+ pm.DrawRectangle (gc, true, 0, 0, width, height);
+
+ gc.Foreground = black;
+ pm.DrawRectangle (gc, false, 0, 0, width - 1, height - 1);
+ pm.DrawRectangle (gc, false, 1, 1, width - 3, height - 3);
+
+ this.ShapeCombineMask (pm, 0, 0);
+ }
+
+ protected override void OnSizeAllocated (Rectangle allocation)
+ {
+ base.OnSizeAllocated (allocation);
+ CreateShape (allocation.Width, allocation.Height);
+ }
+
+
+ protected override bool OnExposeEvent (Gdk.EventExpose args)
+ {
+ //base.OnExposeEvent (args);
+ int w, h;
+ this.GetSize (out w, out h);
+ this.GdkWindow.DrawRectangle (redgc, false, 0, 0, w-1, h-1);
+ this.GdkWindow.DrawRectangle (redgc, false, 1, 1, w-3, h-3);
+ return true;
+ }
+
+ public void Relocate (int x, int y, int w, int h, bool animate)
+ {
+ if (x != rx || y != ry || w != rw || h != rh) {
+ Move (x, y);
+ Resize (w, h);
+
+ rx = x; ry = y; rw = w; rh = h;
+
+ if (anim != 0) {
+ GLib.Source.Remove (anim);
+ anim = 0;
+ }
+ if (animate && w < 150 && h < 150) {
+ int sa = 7;
+ Move (rx-sa, ry-sa);
+ Resize (rw+sa*2, rh+sa*2);
+ anim = GLib.Timeout.Add (10, RunAnimation);
+ }
+ }
+ }
+
+ bool RunAnimation ()
+ {
+ int cx, cy, ch, cw;
+ GetSize (out cw, out ch);
+ GetPosition (out cx, out cy);
+
+ if (cx != rx) {
+ cx++; cy++;
+ ch-=2; cw-=2;
+ Move (cx, cy);
+ Resize (cw, ch);
+ return true;
+ }
+ anim = 0;
+ return false;
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/ShadedContainer.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/ShadedContainer.cs
new file mode 100644
index 0000000000..f8d20a906e
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/ShadedContainer.cs
@@ -0,0 +1,314 @@
+//
+// ShadedContainer.cs
+//
+// Author:
+// Lluis Sanchez Gual <lluis@novell.com>
+//
+// Copyright (c) 2010 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using Gtk;
+using MonoDevelop.Components;
+
+namespace MonoDevelop.Components.Docking
+{
+ public class ShadedContainer
+ {
+ struct Section {
+ public int Offset;
+ public int Size;
+ }
+
+ Gdk.Color lightColor;
+ Gdk.Color darkColor;
+ int shadowSize = 2;
+
+ List<Widget> widgets = new List<Widget> ();
+ Dictionary<Widget, Gdk.Rectangle[]> allocations = new Dictionary<Widget, Gdk.Rectangle[]> ();
+
+ public ShadedContainer ()
+ {
+ }
+
+ public int ShadowSize {
+ get { return this.shadowSize; }
+ set { this.shadowSize = value; RedrawAll (); }
+ }
+
+ public Gdk.Color LightColor {
+ get { return this.lightColor; }
+ set { this.lightColor = value; RedrawAll (); }
+ }
+
+ public Gdk.Color DarkColor {
+ get { return this.darkColor; }
+ set { this.darkColor = value; RedrawAll (); }
+ }
+
+ public void Add (Gtk.Widget w)
+ {
+ widgets.Add (w);
+ UpdateAllocation (w);
+ w.Destroyed += HandleWDestroyed;
+ w.Shown += HandleWShown;
+ w.Hidden += HandleWHidden;
+ w.SizeAllocated += HandleWSizeAllocated;
+ IShadedWidget sw = w as IShadedWidget;
+ if (sw != null)
+ sw.AreasChanged += HandleSwAreasChanged;
+ RedrawAll ();
+ }
+
+ public void Remove (Widget w)
+ {
+ widgets.Remove (w);
+ allocations.Remove (w);
+ w.Destroyed -= HandleWDestroyed;
+ w.Shown -= HandleWShown;
+ w.Hidden -= HandleWHidden;
+ IShadedWidget sw = w as IShadedWidget;
+ if (sw != null)
+ sw.AreasChanged -= HandleSwAreasChanged;
+ RedrawAll ();
+ }
+
+ void UpdateAllocation (Widget w)
+ {
+ if (w.IsRealized) {
+ int x, y;
+ w.GdkWindow.GetOrigin (out x, out y);
+ IShadedWidget sw = w as IShadedWidget;
+ if (sw != null) {
+ List<Gdk.Rectangle> rects = new List<Gdk.Rectangle> ();
+ foreach (Gdk.Rectangle ar in sw.GetShadedAreas ()) {
+ Gdk.Rectangle r = new Gdk.Rectangle (x + ar.X, y + ar.Y, ar.Width, ar.Height);
+ rects.Add (r);
+ }
+ allocations [w] = rects.ToArray ();
+ } else {
+ Gdk.Rectangle r = new Gdk.Rectangle (x + w.Allocation.X, y + w.Allocation.Y, w.Allocation.Width, w.Allocation.Height);
+ allocations [w] = new Gdk.Rectangle [] { r };
+ }
+ }
+ else {
+ allocations.Remove (w);
+ }
+ }
+
+ void HandleSwAreasChanged (object sender, EventArgs e)
+ {
+ UpdateAllocation ((Gtk.Widget)sender);
+ RedrawAll ();
+ }
+
+ void HandleWSizeAllocated (object o, SizeAllocatedArgs args)
+ {
+ UpdateAllocation ((Widget) o);
+ RedrawAll ();
+ }
+
+ void HandleWHidden (object sender, EventArgs e)
+ {
+ RedrawAll ();
+ }
+
+ void HandleWShown (object sender, EventArgs e)
+ {
+ RedrawAll ();
+ }
+
+ void HandleWDestroyed (object sender, EventArgs e)
+ {
+ Remove ((Widget)sender);
+ }
+
+ void RedrawAll ()
+ {
+ foreach (Widget w in widgets)
+ w.QueueDraw ();
+ }
+
+ public void DrawBackground (Gtk.Widget w)
+ {
+ DrawBackground (w, w.Allocation);
+ }
+
+ public void DrawBackground (Gtk.Widget w, Gdk.Rectangle allocation)
+ {
+ if (shadowSize == 0) {
+ Gdk.Rectangle wr = new Gdk.Rectangle (allocation.X, allocation.Y, allocation.Width, allocation.Height);
+ using (Cairo.Context ctx = Gdk.CairoHelper.Create (w.GdkWindow)) {
+ ctx.Rectangle (wr.X, wr.Y, wr.Width, wr.Height);
+ ctx.Color = GtkUtil.ToCairoColor (lightColor);
+ ctx.Fill ();
+ }
+ return;
+ }
+
+ List<Section> secsT = new List<Section> ();
+ List<Section> secsB = new List<Section> ();
+ List<Section> secsR = new List<Section> ();
+ List<Section> secsL = new List<Section> ();
+
+ int x, y;
+ w.GdkWindow.GetOrigin (out x, out y);
+ Gdk.Rectangle rect = new Gdk.Rectangle (x + allocation.X, y + allocation.Y, allocation.Width, allocation.Height);
+
+ Section s = new Section ();
+ s.Size = rect.Width;
+ secsT.Add (s);
+ secsB.Add (s);
+ s.Size = rect.Height;
+ secsL.Add (s);
+ secsR.Add (s);
+
+ foreach (var rects in allocations.Values) {
+ foreach (Gdk.Rectangle sr in rects) {
+ if (sr == rect)
+ continue;
+
+ if (sr.Right == rect.X)
+ RemoveSection (secsL, sr.Y - rect.Y, sr.Height);
+ if (sr.Bottom == rect.Y)
+ RemoveSection (secsT, sr.X - rect.X, sr.Width);
+ if (sr.X == rect.Right)
+ RemoveSection (secsR, sr.Y - rect.Y, sr.Height);
+ if (sr.Y == rect.Bottom)
+ RemoveSection (secsB, sr.X - rect.X, sr.Width);
+ }
+ }
+
+ Gdk.Rectangle r = new Gdk.Rectangle (allocation.X, allocation.Y, allocation.Width, allocation.Height);
+ using (Cairo.Context ctx = Gdk.CairoHelper.Create (w.GdkWindow)) {
+ ctx.Rectangle (r.X, r.Y, r.Width, r.Height);
+ ctx.Color = GtkUtil.ToCairoColor (lightColor);
+ ctx.Fill ();
+
+ DrawShadow (ctx, r, PositionType.Left, secsL);
+ DrawShadow (ctx, r, PositionType.Top, secsT);
+ DrawShadow (ctx, r, PositionType.Right, secsR);
+ DrawShadow (ctx, r, PositionType.Bottom, secsB);
+ }
+ }
+
+ void DrawShadow (Cairo.Context ctx, Gdk.Rectangle ar, PositionType pos, List<Section> secs)
+ {
+ foreach (Section s in secs) {
+ Cairo.Gradient pat = null;
+ Gdk.Rectangle r = ar;
+ switch (pos) {
+ case PositionType.Top:
+ r.Height = shadowSize > r.Height ? r.Height / 2 : shadowSize;
+ r.X += s.Offset;
+ r.Width = s.Size;
+ pat = new Cairo.LinearGradient (r.X, r.Y, r.X, r.Bottom);
+ break;
+ case PositionType.Bottom:
+ r.Y = r.Bottom - shadowSize;
+ r.Height = shadowSize > r.Height ? r.Height / 2 : shadowSize;
+ r.X = r.X + s.Offset;
+ r.Width = s.Size;
+ pat = new Cairo.LinearGradient (r.X, r.Bottom, r.X, r.Y);
+ break;
+ case PositionType.Left:
+ r.Width = shadowSize > r.Width ? r.Width / 2 : shadowSize;
+ r.Y += s.Offset;
+ r.Height = s.Size;
+ pat = new Cairo.LinearGradient (r.X, r.Y, r.Right, r.Y);
+ break;
+ case PositionType.Right:
+ r.X = r.Right - shadowSize;
+ r.Width = shadowSize > r.Width ? r.Width / 2 : shadowSize;
+ r.Y += s.Offset;
+ r.Height = s.Size;
+ pat = new Cairo.LinearGradient (r.Right, r.Y, r.X, r.Y);
+ break;
+ }
+ Cairo.Color c = GtkUtil.ToCairoColor (darkColor);
+ pat.AddColorStop (0, c);
+ c.A = 0;
+ pat.AddColorStop (1, c);
+ ctx.NewPath ();
+ ctx.Rectangle (r.X, r.Y, r.Width, r.Height);
+ ctx.Pattern = pat;
+ ctx.Fill ();
+ }
+ }
+
+ void RemoveSection (List<Section> secs, int offset, int size)
+ {
+ if (offset < 0) {
+ size += offset;
+ offset = 0;
+ }
+ if (size <= 0 || secs.Count == 0)
+ return;
+ Section last = secs [secs.Count - 1];
+ int rem = (last.Offset + last.Size) - (offset + size);
+ if (rem < 0) {
+ size += rem;
+ if (size <= 0)
+ return;
+ }
+ for (int n=0; n<secs.Count; n++) {
+ Section s = secs [n];
+ if (s.Offset >= offset + size)
+ continue;
+ if (offset >= s.Offset + s.Size)
+ continue;
+ if (offset <= s.Offset && offset + size >= s.Offset + s.Size) {
+ // Remove the whole section
+ secs.RemoveAt (n);
+ n--;
+ continue;
+ }
+ if (offset <= s.Offset) {
+ int newOfs = offset + size;
+ s.Size = s.Size - (newOfs - s.Offset);
+ s.Offset = newOfs;
+ secs [n] = s;
+ // Nothing else to remove
+ return;
+ }
+ if (offset + size >= s.Offset + s.Size) {
+ s.Size = offset - s.Offset;
+ secs [n] = s;
+ continue;
+ }
+ // Split section
+ Section s2 = new Section ();
+ s2.Offset = offset + size;
+ s2.Size = (s.Offset + s.Size) - (offset + size);
+ secs.Insert (n + 1, s2);
+ s.Size = offset - s.Offset;
+ secs [n] = s;
+ }
+ }
+ }
+
+ public interface IShadedWidget
+ {
+ IEnumerable<Gdk.Rectangle> GetShadedAreas ();
+ event EventHandler AreasChanged;
+ }
+}
+
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/TabStrip.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/TabStrip.cs
new file mode 100644
index 0000000000..67976a6ee5
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/TabStrip.cs
@@ -0,0 +1,407 @@
+//
+// TabStrip.cs
+//
+// Author:
+// Lluis Sanchez Gual
+//
+
+//
+// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using Gtk;
+
+using System;
+
+namespace MonoDevelop.Components.Docking
+{
+ class TabStrip: Notebook
+ {
+ int currentTab = -1;
+ bool ellipsized = true;
+ HBox box = new HBox ();
+ DockFrame frame;
+ Label bottomFiller = new Label ();
+
+ public TabStrip (DockFrame frame)
+ {
+ this.frame = frame;
+ frame.ShadedContainer.Add (this);
+ VBox vbox = new VBox ();
+ box = new HBox ();
+ vbox.PackStart (box, false, false, 0);
+ vbox.PackStart (bottomFiller, false, false, 0);
+ AppendPage (vbox, null);
+ ShowBorder = false;
+ ShowTabs = false;
+ ShowAll ();
+ bottomFiller.Hide ();
+ BottomPadding = 3;
+ }
+
+ public int BottomPadding {
+ get { return bottomFiller.HeightRequest; }
+ set {
+ bottomFiller.HeightRequest = value;
+ bottomFiller.Visible = value > 0;
+ }
+ }
+
+ public void AddTab (Gtk.Widget page, Gdk.Pixbuf icon, string label)
+ {
+ Tab tab = new Tab ();
+ tab.SetLabel (page, icon, label);
+ tab.ShowAll ();
+ box.PackStart (tab, true, true, 0);
+ if (currentTab == -1)
+ CurrentTab = box.Children.Length - 1;
+ else {
+ tab.Active = false;
+ page.Hide ();
+ }
+
+ tab.ButtonPressEvent += OnTabPress;
+ }
+
+ public void SetTabLabel (Gtk.Widget page, Gdk.Pixbuf icon, string label)
+ {
+ foreach (Tab tab in box.Children) {
+ if (tab.Page == page) {
+ tab.SetLabel (page, icon, label);
+ UpdateEllipsize (Allocation);
+ break;
+ }
+ }
+ }
+
+ public int TabCount {
+ get { return box.Children.Length; }
+ }
+
+ public int CurrentTab {
+ get { return currentTab; }
+ set {
+ if (currentTab == value)
+ return;
+ if (currentTab != -1) {
+ Tab t = (Tab) box.Children [currentTab];
+ t.Page.Hide ();
+ t.Active = false;
+ }
+ currentTab = value;
+ if (currentTab != -1) {
+ Tab t = (Tab) box.Children [currentTab];
+ t.Active = true;
+ t.Page.Show ();
+ }
+ }
+ }
+
+ new public Gtk.Widget CurrentPage {
+ get {
+ if (currentTab != -1) {
+ Tab t = (Tab) box.Children [currentTab];
+ return t.Page;
+ } else
+ return null;
+ }
+ set {
+ if (value != null) {
+ Gtk.Widget[] tabs = box.Children;
+ for (int n = 0; n < tabs.Length; n++) {
+ Tab tab = (Tab) tabs [n];
+ if (tab.Page == value) {
+ CurrentTab = n;
+ return;
+ }
+ }
+ }
+ CurrentTab = -1;
+ }
+ }
+
+ public void Clear ()
+ {
+ ellipsized = true;
+ currentTab = -1;
+ foreach (Widget w in box.Children) {
+ box.Remove (w);
+ w.Destroy ();
+ }
+ }
+
+ void OnTabPress (object s, Gtk.ButtonPressEventArgs args)
+ {
+ CurrentTab = Array.IndexOf (box.Children, s);
+ Tab t = (Tab) s;
+ DockItem.SetFocus (t.Page);
+ QueueDraw ();
+ }
+
+ protected override void OnSizeAllocated (Gdk.Rectangle allocation)
+ {
+ UpdateEllipsize (allocation);
+ base.OnSizeAllocated (allocation);
+ }
+
+ void UpdateEllipsize (Gdk.Rectangle allocation)
+ {
+ int tsize = 0;
+ foreach (Tab tab in box.Children)
+ tsize += tab.LabelWidth;
+
+ bool ellipsize = tsize > allocation.Width;
+ if (ellipsize != ellipsized) {
+ foreach (Tab tab in box.Children) {
+ tab.SetEllipsize (ellipsize);
+ Gtk.Box.BoxChild bc = (Gtk.Box.BoxChild) box [tab];
+ bc.Expand = bc.Fill = ellipsize;
+ }
+ ellipsized = ellipsize;
+ }
+ }
+
+ public Gdk.Rectangle GetTabArea (int ntab)
+ {
+ Gtk.Widget[] tabs = box.Children;
+ Tab tab = (Tab) tabs[ntab];
+ Gdk.Rectangle rect = GetTabArea (tab, ntab);
+ int x, y;
+ tab.GdkWindow.GetRootOrigin (out x, out y);
+ rect.X += x;
+ rect.Y += y;
+ return rect;
+ }
+
+ protected override bool OnExposeEvent (Gdk.EventExpose evnt)
+ {
+ frame.ShadedContainer.DrawBackground (this);
+
+ Gtk.Widget[] tabs = box.Children;
+ for (int n=tabs.Length - 1; n>=0; n--) {
+ Tab tab = (Tab) tabs [n];
+ if (n != currentTab)
+ DrawTab (evnt, tab, n);
+ }
+ if (currentTab != -1) {
+ Tab ctab = (Tab) tabs [currentTab];
+// GdkWindow.DrawLine (Style.DarkGC (Gtk.StateType.Normal), Allocation.X, Allocation.Y, Allocation.Right, Allocation.Y);
+ DrawTab (evnt, ctab, currentTab);
+ }
+ return base.OnExposeEvent (evnt);
+ }
+
+ public Gdk.Rectangle GetTabArea (Tab tab, int pos)
+ {
+ Gdk.Rectangle rect = tab.Allocation;
+
+ int xdif = 0;
+ if (pos > 0)
+ xdif = 2;
+
+ int reqh;
+// StateType st;
+
+ if (tab.Active) {
+// st = StateType.Normal;
+ reqh = tab.Allocation.Height;
+ }
+ else {
+ reqh = tab.Allocation.Height - 3;
+// st = StateType.Active;
+ }
+
+ if (DockFrame.IsWindows) {
+ rect.Height = reqh - 1;
+ rect.Width--;
+ if (pos > 0) {
+ rect.X--;
+ rect.Width++;
+ }
+ return rect;
+ }
+ else {
+ rect.X -= xdif;
+ rect.Width += xdif;
+ rect.Height = reqh;
+ return rect;
+ }
+ }
+
+ void DrawTab (Gdk.EventExpose evnt, Tab tab, int pos)
+ {
+ Gdk.Rectangle rect = GetTabArea (tab, pos);
+ StateType st;
+ if (tab.Active)
+ st = StateType.Normal;
+ else
+ st = StateType.Active;
+
+ if (DockFrame.IsWindows) {
+ GdkWindow.DrawRectangle (Style.DarkGC (Gtk.StateType.Normal), false, rect);
+ rect.X++;
+ rect.Width--;
+ if (tab.Active) {
+ GdkWindow.DrawRectangle (Style.LightGC (Gtk.StateType.Normal), true, rect);
+ }
+ else {
+ using (Cairo.Context cr = Gdk.CairoHelper.Create (evnt.Window)) {
+ cr.NewPath ();
+ cr.MoveTo (rect.X, rect.Y);
+ cr.RelLineTo (rect.Width, 0);
+ cr.RelLineTo (0, rect.Height);
+ cr.RelLineTo (-rect.Width, 0);
+ cr.RelLineTo (0, -rect.Height);
+ cr.ClosePath ();
+ Cairo.Gradient pat = new Cairo.LinearGradient (rect.X, rect.Y, rect.X, rect.Y + rect.Height);
+ Cairo.Color color1 = DockFrame.ToCairoColor (Style.Mid (Gtk.StateType.Normal));
+ pat.AddColorStop (0, color1);
+ color1.R *= 1.2;
+ color1.G *= 1.2;
+ color1.B *= 1.2;
+ pat.AddColorStop (1, color1);
+ cr.Pattern = pat;
+ cr.FillPreserve ();
+ }
+ }
+ }
+ else
+ Gtk.Style.PaintExtension (Style, GdkWindow, st, ShadowType.Out, evnt.Area, this, "tab", rect.X, rect.Y, rect.Width, rect.Height, Gtk.PositionType.Top);
+ }
+ }
+
+ class Tab: Gtk.EventBox
+ {
+ bool active;
+ Gtk.Widget page;
+ Gtk.Label labelWidget;
+ int labelWidth;
+
+ const int TopPadding = 2;
+ const int BottomPadding = 4;
+ const int TopPaddingActive = 3;
+ const int BottomPaddingActive = 5;
+ const int HorzPadding = 5;
+
+ public Tab ()
+ {
+ this.VisibleWindow = false;
+ }
+
+ public void SetLabel (Gtk.Widget page, Gdk.Pixbuf icon, string label)
+ {
+ Pango.EllipsizeMode oldMode = Pango.EllipsizeMode.End;
+
+ this.page = page;
+ if (Child != null) {
+ if (labelWidget != null)
+ oldMode = labelWidget.Ellipsize;
+ Gtk.Widget oc = Child;
+ Remove (oc);
+ oc.Destroy ();
+ }
+
+ Gtk.HBox box = new HBox ();
+ box.Spacing = 2;
+
+ if (icon != null)
+ box.PackStart (new Gtk.Image (icon), false, false, 0);
+
+ if (!string.IsNullOrEmpty (label)) {
+ labelWidget = new Gtk.Label (label);
+ labelWidget.UseMarkup = true;
+ box.PackStart (labelWidget, true, true, 0);
+ } else {
+ labelWidget = null;
+ }
+
+ Add (box);
+
+ // Get the required size before setting the ellipsize property, since ellipsized labels
+ // have a width request of 0
+ ShowAll ();
+ labelWidth = SizeRequest ().Width;
+
+ if (labelWidget != null)
+ labelWidget.Ellipsize = oldMode;
+ }
+
+ public void SetEllipsize (bool elipsize)
+ {
+ if (labelWidget != null) {
+ if (elipsize)
+ labelWidget.Ellipsize = Pango.EllipsizeMode.End;
+ else
+ labelWidget.Ellipsize = Pango.EllipsizeMode.None;
+ }
+ }
+
+ public int LabelWidth {
+ get { return labelWidth; }
+ }
+
+ public bool Active {
+ get {
+ return active;
+ }
+ set {
+ active = value;
+ this.QueueResize ();
+ QueueDraw ();
+ }
+ }
+
+ public Widget Page {
+ get {
+ return page;
+ }
+ }
+
+ protected override void OnSizeRequested (ref Gtk.Requisition req)
+ {
+ req = Child.SizeRequest ();
+ req.Width += HorzPadding * 2;
+ if (active)
+ req.Height += TopPaddingActive + BottomPaddingActive;
+ else
+ req.Height += TopPadding + BottomPadding;
+ }
+
+ protected override void OnSizeAllocated (Gdk.Rectangle rect)
+ {
+ base.OnSizeAllocated (rect);
+
+ rect.X += HorzPadding;
+ rect.Width -= HorzPadding * 2;
+
+ if (active) {
+ rect.Y += TopPaddingActive;
+ rect.Height = Child.SizeRequest ().Height;
+ }
+ else {
+ rect.Y += TopPadding;
+ rect.Height = Child.SizeRequest ().Height;
+ }
+ Child.SizeAllocate (rect);
+ }
+ }
+}
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-auto-hide.png b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-auto-hide.png
new file mode 100644
index 0000000000..e31a471569
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-auto-hide.png
Binary files differ
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-close-12.png b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-close-12.png
new file mode 100644
index 0000000000..71016e2f06
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-close-12.png
Binary files differ
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-dock.png b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-dock.png
new file mode 100644
index 0000000000..225c2abfc7
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-dock.png
Binary files differ
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-menu-left-12.png b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-menu-left-12.png
new file mode 100644
index 0000000000..c1d3befddc
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-menu-left-12.png
Binary files differ
diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-menu-right-12.png b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-menu-right-12.png
new file mode 100644
index 0000000000..df945cd85f
--- /dev/null
+++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/stock-menu-right-12.png
Binary files differ