diff options
Diffstat (limited to 'main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/TabStrip.cs')
-rw-r--r-- | main/src/core/MonoDevelop.Ide/MonoDevelop.Components.Docking/TabStrip.cs | 407 |
1 files changed, 407 insertions, 0 deletions
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); + } + } +} |