// // 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; title.Ellipsize = Pango.EllipsizeMode.End; 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.05; gcol.L = Math.Min (1, gcol.L); 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.SolidPattern solidPattern = new Cairo.SolidPattern (gcol); cr.Pattern = solidPattern; cr.FillPreserve (); solidPattern.Destroy (); } 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 = "" + value + ""; 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) { if (child != null) { requisition = child.SizeRequest (); requisition.Width += leftMargin + rightMargin + leftPadding + rightPadding; requisition.Height += topMargin + bottomMargin + topPadding + bottomPadding; } else { requisition.Width = 0; requisition.Height = 0; } } 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; } if (child != null) 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