123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619 |
- /*
- * $Id$
- *
- * Copyright (C) 2004 Todd Berman <tberman@off.net>
- * Copyright (C) 2004 Jeroen Zwartepoorte <jeroen@xs4all.nl>
- * Copyright (C) 2005 John Luke <john.luke@gmail.com>
- *
- * based on work by:
- * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
- using System;
- using System.Collections;
- using System.Xml;
- using Gtk;
- namespace Gdl
- {
- public class Dock : DockObject
- {
- private readonly float SplitRatio = 0.3f;
- private DockObject root = null;
- private bool floating;
- private Widget window;
- private bool autoTitle;
- private int floatX;
- private int floatY;
- private int width = -1;
- private int height = -1;
- private Gdk.GC xorGC;
- private string title;
- protected Dock (IntPtr raw) : base (raw) { }
- public Dock () : this (null, false)
- {
- }
- public Dock (Dock original, bool floating)
- : this (original, floating, 0, 0, -1, -1)
- {
- }
- public Dock (Dock original, bool floating, int x, int y, int width, int height)
- {
- floatX = x;
- floatY = y;
- this.width = width;
- this.height = height;
- this.floating = floating;
- SetFlag (WidgetFlags.NoWindow);
- if (original != null)
- Bind (original.Master);
- /* create a master for the dock if none was provided */
- if (Master == null) {
- DockObjectFlags &= ~(DockObjectFlags.Automatic);
- Bind (new DockMaster ());
- }
- if (floating) {
- /* create floating window for this dock */
- window = new Window (WindowType.Toplevel);
- Window wnd = window as Window;
- /* set position and default size */
- wnd.WindowPosition = WindowPosition.Mouse;
- wnd.SetDefaultSize (width, height);
- wnd.TypeHint = Gdk.WindowTypeHint.Normal;
- /* metacity ignores this */
- wnd.Move (floatX, floatY);
- /* connect to the configure event so we can track down window geometry */
- wnd.ConfigureEvent += new ConfigureEventHandler (OnFloatingConfigure);
- /* set the title */
- SetWindowTitle ();
- /* set transient for the first dock if that is a non-floating dock */
- DockObject controller = Master.Controller;
- if (controller != null && controller is Dock) {
- if (!((Dock)controller).Floating) {
- if (controller.Toplevel != null && controller.Toplevel is Window) {
- wnd.TransientFor = (Window)controller.Toplevel;
- }
- }
- }
- wnd.Add (this);
- wnd.DeleteEvent += new DeleteEventHandler (OnFloatingDelete);
- }
- DockObjectFlags |= DockObjectFlags.Attached;
- }
- [Export]
- public bool Floating {
- get {
- return floating;
- }
- set {
- floating = value;
- }
- }
- [Export]
- public int FloatX {
- get {
- return floatX;
- }
- set {
- floatX = value;
- if (floating && window != null && window is Window)
- ((Window)window).Resize (width, height);
- }
- }
- [Export]
- public int FloatY {
- get {
- return floatY;
- }
- set {
- floatY = value;
- if (floating && window != null && window is Window)
- ((Window)window).Resize (width, height);
- }
- }
- [Export]
- public int Height {
- get {
- return height;
- }
- set {
- height = value;
- if (floating && window != null && window is Window)
- ((Window)window).Resize (width, height);
- }
- }
- private bool IsController {
- get {
- if (Master == null)
- return false;
- return Master.Controller == this;
- }
- }
- public ICollection NamedItems {
- get {
- return Master.DockObjects;
- }
- }
- public DockObject Root {
- get {
- return root;
- }
- set {
- root = value;
- }
- }
- public string Title {
- get {
- return title;
- }
- set {
- title = value;
- }
- }
- [Export]
- public int Width {
- get { return width; }
- set {
- width = value;
- if (floating && window != null && window is Window)
- ((Window)window).Resize (width, height);
- }
- }
- protected override void OnSizeRequested (ref Requisition requisition)
- {
- // make request to root
- if (root != null && root.Visible)
- requisition = root.SizeRequest ();
- else
- requisition.Width = requisition.Height = 0;
- requisition.Width += 2 * (int)BorderWidth;
- requisition.Height += 2 * (int)BorderWidth;
- }
- protected override void OnSizeAllocated (Gdk.Rectangle allocation)
- {
- base.OnSizeAllocated (allocation);
- // reduce allocation by border width
- int bw = (int)BorderWidth;
- allocation.X += bw;
- allocation.Y += bw;
- allocation.Width = Math.Max (1, allocation.Width - 2 * bw);
- allocation.Height = Math.Max (1, allocation.Height - 2 * bw);
- if (root != null && root.Visible)
- root.SizeAllocate (allocation);
- }
- protected override void OnMapped ()
- {
- base.OnMapped ();
- if (root != null && root.Visible && !root.IsMapped)
- root.Map ();
- }
- protected override void OnUnmapped ()
- {
- base.OnUnmapped ();
- if (root != null && root.Visible && root.IsMapped)
- root.Unmap ();
- if (window != null)
- window.Unmap ();
- }
- protected override void OnShown ()
- {
- base.OnShown ();
- if (floating && window != null)
- window.ShowAll ();
- if (IsController) {
- foreach (DockObject item in Master.TopLevelDocks) {
- if (item == this)
- continue;
- if (item.IsAutomatic)
- item.Show ();
- }
- }
- }
- protected override void OnHidden ()
- {
- base.OnHidden ();
- if (floating && window != null)
- window.Hide ();
- if (IsController) {
- foreach (DockObject item in Master.TopLevelDocks) {
- if (item == this)
- continue;
- if (item.IsAutomatic)
- item.Hide ();
- }
- }
- }
- protected override void OnDestroyed ()
- {
- if (window != null) {
- window.Destroy ();
- floating = false;
- window = null;
- }
- // destroy the xor gc
- if (xorGC != null)
- xorGC = null;
- base.OnDestroyed ();
- }
- protected override void OnAdded (Widget widget)
- {
- DockItem child = widget as DockItem;
- AddItem (child, DockPlacement.Top);
- }
- protected override void OnRemoved (Widget widget)
- {
- bool wasVisible = widget.Visible;
- if (root == widget) {
- root.DockObjectFlags &= ~(DockObjectFlags.Attached);
- root = null;
- widget.Unparent ();
- if (wasVisible && Visible)
- QueueResize ();
- }
- }
- protected override void ForAll (bool include_internals, Callback cb)
- {
- if (root != null)
- cb (root);
- }
- public override void OnDetached (bool recursive)
- {
- if (recursive && root != null)
- root.Detach (recursive);
- DockObjectFlags &= ~(DockObjectFlags.Attached);
- }
- public override void OnReduce ()
- {
- if (root != null)
- return;
- if (IsAutomatic) {
- Destroy ();
- } else if (!IsAttached) {
- if (floating)
- Hide ();
- else if (Parent != null && Parent is Container)
- ((Container)Parent).Remove (this);
- }
- }
- public override bool OnDockRequest (int x, int y, ref DockRequest request)
- {
- bool mayDock = false;
- /* we get (x,y) in our allocation coordinates system */
- /* Get dock size. */
- Gdk.Rectangle alloc = Allocation;
- int bw = (int)BorderWidth;
- /* Get coordinates relative to our allocation area. */
- int relX = x - alloc.X;
- int relY = y - alloc.Y;
- /* Check if coordinates are in GdlDock widget. */
- if (relX > 0 && relX < alloc.Width &&
- relY > 0 && relY < alloc.Height) {
- /* It's inside our area. */
- mayDock = true;
- /* Set docking indicator rectangle to the Dock size. */
- request.X = alloc.X + bw;
- request.Y = alloc.Y + bw;
- request.Width = alloc.Width - 2 * bw;
- request.Height = alloc.Height - 2 * bw;
- /* If Dock has no root item yet, set the dock
- itself as possible target. */
- if (root == null) {
- request.Position = DockPlacement.Top;
- request.Target = this;
- } else {
- request.Target = root;
- /* See if it's in the BorderWidth band. */
- if (relX < bw) {
- request.Position = DockPlacement.Left;
- request.Width = (int)(request.Width * SplitRatio);
- } else if (relX > alloc.Width - bw) {
- request.Position = DockPlacement.Right;
- request.X += (int)(request.Width * (1 - SplitRatio));
- request.Width = (int)(request.Width * SplitRatio);
- } else if (relY < bw) {
- request.Position = DockPlacement.Top;
- request.Height = (int)(request.Height * SplitRatio);
- } else if (relY > alloc.Height - bw) {
- request.Position = DockPlacement.Bottom;
- request.Y += (int)(request.Height * (1 - SplitRatio));
- request.Height = (int)(request.Height * SplitRatio);
- } else {
- /* Otherwise try our children. */
- /* give them allocation coordinates
- (we are a NoWindow widget) */
- mayDock = root.OnDockRequest (x, y, ref request);
- }
- }
- }
- return mayDock;
- }
- public override void OnDocked (DockObject requestor, DockPlacement position, object data)
- {
- /* only dock items allowed at this time */
- if (!(requestor is DockItem))
- return;
- if (position == DockPlacement.Floating) {
- int x = 0, y = 0, width = -1, height = -1;
- if (data != null && data is Gdk.Rectangle) {
- Gdk.Rectangle rect = (Gdk.Rectangle)data;
- x = rect.X;
- y = rect.Y;
- width = rect.Width;
- height = rect.Height;
- }
- AddFloatingItem ((DockItem)requestor, x, y, width, height);
- } else if (root != null) {
- /* This is somewhat a special case since we know
- which item to pass the request on because we only
- have one child */
- root.Dock (requestor, position, null);
- SetWindowTitle ();
- } else { /* Item about to be added is root item. */
- root = requestor;
- root.DockObjectFlags |= DockObjectFlags.Attached;
- root.Parent = this;
- ((DockItem)root).ShowGrip ();
- /* Realize the item (create its corresponding GdkWindow)
- when the Dock has been realized. */
- if (IsRealized)
- root.Realize ();
- /* Map the widget if it's visible and the parent is
- visible and has been mapped. This is done to make
- sure that the GdkWindow is visible. */
- if (Visible && root.Visible) {
- if (IsMapped)
- root.Map ();
- /* Make the widget resize. */
- root.QueueResize ();
- }
- SetWindowTitle ();
- }
- }
- public override bool OnReorder (DockObject requestor, DockPlacement position, object data)
- {
- if (Floating && position == DockPlacement.Floating && root == requestor) {
- if (window != null && data != null && data is Gdk.Rectangle) {
- Gdk.Rectangle rect = (Gdk.Rectangle)data;
- ((Window)window).Move (rect.X, rect.Y);
- return true;
- }
- }
- return false;
- }
- public override bool OnChildPlacement (DockObject child, ref DockPlacement placement)
- {
- if (root == child) {
- if (placement == DockPlacement.None ||
- placement == DockPlacement.Floating)
- placement = DockPlacement.Top;
- return true;
- }
- return false;
- }
- public override void OnPresent (DockObject child)
- {
- if (Floating && window != null && window is Window)
- ((Window)window).Present ();
- }
- public void AddItem (DockItem item, DockPlacement placement)
- {
- if (item == null)
- return;
- if (placement == DockPlacement.Floating)
- AddFloatingItem (item, 0, 0, -1, -1);
- else
- Dock (item, placement, null);
- }
- public void AddFloatingItem (DockItem item, int x, int y, int width, int height)
- {
- Dock dock = new Dock (this, true, x, y, width, height);
- if (Visible) {
- dock.Show ();
- if (IsMapped)
- dock.Map ();
- dock.QueueResize ();
- }
- dock.AddItem (item, DockPlacement.Top);
- }
- public DockItem GetItemByName (string name)
- {
- if (name == null)
- return null;
- DockObject found = Master.GetObject (name);
- if (found != null && found is DockItem)
- return (DockItem)found;
- else
- return null;
- }
- public DockPlaceholder GetPlaceholderByName (string name)
- {
- if (name == null)
- return null;
- DockObject found = Master.GetObject (name);
- if (found != null && found is DockPlaceholder)
- return (DockPlaceholder)found;
- else
- return null;
- }
- public static Dock GetTopLevel (DockObject obj)
- {
- DockObject parent = obj;
- while (parent != null && !(parent is Dock))
- parent = parent.ParentObject;
- return parent != null ? (Dock)parent : null;
- }
- public void XorRect (Gdk.Rectangle rect)
- {
- if (xorGC == null) {
- if (IsRealized) {
- Gdk.GCValues values = new Gdk.GCValues ();
- values.Function = Gdk.Function.Invert;
- values.SubwindowMode = Gdk.SubwindowMode.IncludeInferiors;
- xorGC = new Gdk.GC (GdkWindow);
- xorGC.SetValues (values, Gdk.GCValuesMask.Function |
- Gdk.GCValuesMask.Subwindow);
- } else {
- return;
- }
- }
- xorGC.SetLineAttributes (1, Gdk.LineStyle.OnOffDash,
- Gdk.CapStyle.NotLast,
- Gdk.JoinStyle.Bevel);
- xorGC.SetDashes (1, new sbyte[] { 1, 1}, 2);
- GdkWindow.DrawRectangle (xorGC, false, rect.X, rect.Y,
- rect.Width, rect.Height);
- xorGC.SetDashes (0, new sbyte[] { 1, 1}, 2);
- GdkWindow.DrawRectangle (xorGC, false, rect.X + 1,
- rect.Y + 1, rect.Width - 2,
- rect.Height - 2);
- }
- private void SetWindowTitle ()
- {
- if (window == null)
- return;
- if (!autoTitle && LongName != null)
- title = LongName;
- else if (Master != null)
- title = Master.DefaultTitle;
- if (title == null && root != null)
- title = root.LongName;
- if (title == null) {
- autoTitle = true;
- title = "Dock " + Master.DockNumber++;
- LongName = title;
- }
- ((Window)window).Title = title;
- }
- [GLib.ConnectBefore]
- private void OnFloatingConfigure (object o, ConfigureEventArgs e)
- {
- floatX = e.Event.X;
- floatY = e.Event.Y;
- width = e.Event.Width;
- height = e.Event.Height;
- e.RetVal = false;
- }
- private void OnFloatingDelete (object o, DeleteEventArgs e)
- {
- if (root != null)
- /* this will call reduce on ourselves, hiding
- the window if appropriate */
- ((DockItem)root).HideItem ();
- e.RetVal = true;
- }
- }
- }
|