DockItem.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2004 Todd Berman <tberman@off.net>
  5. * Copyright (C) 2004 Jeroen Zwartepoorte <jeroen@xs4all.nl>
  6. * Copyright (C) 2005 John Luke <john.luke@gmail.com>
  7. *
  8. * based on work by:
  9. * Copyright (C) 2002 Gustavo Giráldez <gustavo.giraldez@gmx.net>
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 59 Temple Place - Suite 330,
  24. * Boston, MA 02111-1307, USA.
  25. */
  26. using System;
  27. using System.Xml;
  28. using Gtk;
  29. namespace Gdl
  30. {
  31. public delegate void DockItemMotionHandler (DockItem o, int x, int y);
  32. public delegate void DockItemDragBeginHandler (DockItem o);
  33. public delegate void DockItemDragEndHandler (DockItem o, bool cancelled);
  34. public class DockItem : DockObject
  35. {
  36. private const float SplitRatio = 0.4f;
  37. private Widget child = null;
  38. private DockItemBehavior behavior = DockItemBehavior.Normal;
  39. private Orientation orientation = Orientation.Vertical;
  40. private bool resize = false;
  41. private int dragoffX = 0;
  42. private int dragoffY = 0;
  43. private Menu menu = null;
  44. private DockItemGrip grip;
  45. private DockBar dockBar;
  46. private DockBarButton dockButton;
  47. private Widget tabLabel = null;
  48. private int preferredWidth = -1;
  49. private int preferredHeight = -1;
  50. private DockPlaceholder dockPlaceHolder = null;
  51. private int startX;
  52. private int startY;
  53. public event DockItemMotionHandler DockItemMotion;
  54. public event DockItemDragBeginHandler DockItemDragBegin;
  55. public event DockItemDragEndHandler DockItemDragEnd;
  56. static DockItem ()
  57. {
  58. Rc.ParseString ("style \"gdl-dock-item-default\" {\n" +
  59. "xthickness = 0\n" +
  60. "ythickness = 0\n" +
  61. "}\n" +
  62. "class \"Gdl_DockItem\" " +
  63. "style : gtk \"gdl-dock-item-default\"\n");
  64. }
  65. protected DockItem ()
  66. {
  67. // remove NoWindow flag
  68. WidgetFlags &= ~(WidgetFlags.NoWindow);
  69. DockObjectFlags &= ~(DockObjectFlags.Automatic);
  70. if (HasGrip) {
  71. grip = new DockItemGrip (this);
  72. grip.Parent = this;
  73. grip.Show ();
  74. }
  75. }
  76. protected DockItem (IntPtr raw) : base (raw) { }
  77. public DockItem (string name, string longName, DockItemBehavior behavior) : this ()
  78. {
  79. Name = name;
  80. LongName = longName;
  81. Behavior = behavior;
  82. ((Label) TabLabel).Markup = longName;
  83. }
  84. public DockItem (string name, string longName, string stockid,
  85. DockItemBehavior behavior) : this (name, longName, behavior)
  86. {
  87. StockId = stockid;
  88. }
  89. public DockItemBehavior Behavior {
  90. get {
  91. return behavior;
  92. }
  93. set {
  94. DockItemBehavior oldBehavior = behavior;
  95. behavior = value;
  96. if (((oldBehavior ^ behavior) & DockItemBehavior.Locked) != 0) {
  97. if (Master != null)
  98. Master.EmitLayoutChangedEvent ();
  99. }
  100. EmitPropertyEvent ("Behavior");
  101. }
  102. }
  103. public bool CantClose {
  104. get { return ((Behavior & DockItemBehavior.CantClose) != 0) || Locked; }
  105. }
  106. public bool CantIconify {
  107. get { return ((Behavior & DockItemBehavior.CantIconify) != 0) || Locked; }
  108. }
  109. public new Widget Child {
  110. get { return child; }
  111. set { child = value; }
  112. }
  113. public DockBar DockBar {
  114. get { return dockBar; }
  115. set { dockBar = value; }
  116. }
  117. public DockBarButton DockBarButton {
  118. get { return dockButton; }
  119. set { dockButton = value; }
  120. }
  121. public int DragOffX {
  122. get { return dragoffX; }
  123. set { dragoffX = value; }
  124. }
  125. public int DragOffY {
  126. get { return dragoffY; }
  127. set { dragoffY = value; }
  128. }
  129. public bool GripShown {
  130. get { return HasGrip; }
  131. }
  132. public virtual bool HasGrip {
  133. get { return !NoGrip; }
  134. }
  135. public bool Iconified {
  136. get { return ((DockObjectFlags & DockObjectFlags.Iconified) != 0); }
  137. }
  138. public bool InDrag {
  139. get { return ((DockObjectFlags & DockObjectFlags.InDrag) != 0); }
  140. }
  141. public bool InPreDrag {
  142. get { return ((DockObjectFlags & DockObjectFlags.InPreDrag) != 0); }
  143. }
  144. public override bool IsCompound {
  145. get { return false; }
  146. }
  147. [Export]
  148. public bool Locked {
  149. get {
  150. return ((behavior & DockItemBehavior.Locked) != 0);
  151. }
  152. set {
  153. DockItemBehavior oldBehavior = behavior;
  154. if (value)
  155. behavior |= DockItemBehavior.Locked;
  156. else
  157. behavior &= ~(DockItemBehavior.Locked);
  158. if ((oldBehavior ^ behavior) != 0) {
  159. ShowHideGrip ();
  160. if (Master != null)
  161. Master.EmitLayoutChangedEvent ();
  162. EmitPropertyEvent ("Locked");
  163. }
  164. }
  165. }
  166. public bool NoGrip {
  167. get { return ((behavior & DockItemBehavior.NoGrip) != 0); }
  168. set {
  169. if (value)
  170. behavior |= DockItemBehavior.NoGrip;
  171. else
  172. behavior &= ~(DockItemBehavior.NoGrip);
  173. }
  174. }
  175. [Export]
  176. public Orientation Orientation {
  177. get { return orientation; }
  178. set { SetOrientation (value); }
  179. }
  180. public int PreferredHeight {
  181. get { return preferredHeight; }
  182. set { preferredHeight = value; }
  183. }
  184. public int PreferredWidth {
  185. get { return preferredWidth; }
  186. set { preferredWidth = value; }
  187. }
  188. public Requisition PreferredSize {
  189. get {
  190. Requisition req = new Requisition ();
  191. req.Width = Math.Max (preferredWidth, Allocation.Width);
  192. req.Height = Math.Max (preferredHeight, Allocation.Height);
  193. return req;
  194. }
  195. }
  196. public bool Resize {
  197. get { return resize; }
  198. set {
  199. resize = value;
  200. QueueResize ();
  201. EmitPropertyEvent ("Resize");
  202. }
  203. }
  204. public Widget TabLabel {
  205. get {
  206. if (tabLabel == null)
  207. tabLabel = new Label ();
  208. return tabLabel;
  209. }
  210. set { tabLabel = value; }
  211. }
  212. public bool UserAction {
  213. get { return ((DockObjectFlags & DockObjectFlags.UserAction) != 0); }
  214. }
  215. protected override void OnAdded (Widget widget)
  216. {
  217. if (widget is DockObject) {
  218. Console.WriteLine ("You can't add a DockObject to a DockItem");
  219. return;
  220. }
  221. if (Child != null) {
  222. Console.WriteLine ("This DockItem already has a child");
  223. return;
  224. }
  225. widget.Parent = this;
  226. Child = widget;
  227. }
  228. protected override void OnRemoved (Widget widget)
  229. {
  230. bool wasVisible = widget.Visible;
  231. if (grip == widget) {
  232. widget.Unparent ();
  233. grip = null;
  234. if (wasVisible)
  235. QueueResize ();
  236. return;
  237. } else if (widget != Child) {
  238. return;
  239. }
  240. if (InDrag)
  241. EndDrag (true);
  242. widget.Unparent ();
  243. Child = null;
  244. if (wasVisible)
  245. QueueResize ();
  246. }
  247. protected override void ForAll (bool include_internals, Callback cb)
  248. {
  249. if (include_internals && grip != null)
  250. cb (grip);
  251. if (Child != null)
  252. cb (Child);
  253. }
  254. protected override void OnSizeRequested (ref Requisition requisition)
  255. {
  256. requisition.Width = ((int)BorderWidth + Style.XThickness) * 2;
  257. requisition.Height = ((int)BorderWidth + Style.YThickness) * 2;
  258. Requisition childReq;
  259. // If our child is not visible, we still request its size, since
  260. // we won't have any useful hint for our size otherwise.
  261. if (Child != null) {
  262. childReq = Child.SizeRequest ();
  263. } else {
  264. childReq.Width = 0;
  265. childReq.Height = 0;
  266. }
  267. Requisition gripReq;
  268. gripReq.Width = gripReq.Height = 0;
  269. if (Orientation == Orientation.Horizontal) {
  270. if (GripShown) {
  271. gripReq = grip.SizeRequest ();
  272. requisition.Width = gripReq.Width;
  273. }
  274. if (Child != null) {
  275. requisition.Width += childReq.Width;
  276. requisition.Height = Math.Max (childReq.Height,
  277. gripReq.Height);
  278. }
  279. } else {
  280. if (GripShown) {
  281. gripReq = grip.SizeRequest ();
  282. requisition.Height = gripReq.Height;
  283. }
  284. if (Child != null) {
  285. requisition.Width = childReq.Width;
  286. requisition.Height += childReq.Height;
  287. }
  288. }
  289. requisition.Width += (int) (this.BorderWidth + this.Style.XThickness) * 2;
  290. requisition.Height += (int) (this.BorderWidth + this.Style.XThickness) * 2;
  291. }
  292. protected override void OnSizeAllocated (Gdk.Rectangle allocation)
  293. {
  294. base.OnSizeAllocated (allocation);
  295. if (IsRealized) {
  296. GdkWindow.MoveResize (allocation.X, allocation.Y,
  297. allocation.Width, allocation.Height);
  298. }
  299. if (Child != null && Child.Visible) {
  300. int bw = (int)BorderWidth;
  301. Gdk.Rectangle childAlloc;
  302. childAlloc.X = bw + Style.XThickness;
  303. childAlloc.Y = bw + Style.YThickness;
  304. childAlloc.Width = allocation.Width - 2 * (bw + Style.XThickness);
  305. childAlloc.Height = allocation.Height - 2 * (bw + Style.YThickness);
  306. if (GripShown) {
  307. Gdk.Rectangle gripAlloc = childAlloc;
  308. Requisition gripReq = grip.SizeRequest ();
  309. if (Orientation == Orientation.Horizontal) {
  310. childAlloc.X += gripReq.Width;
  311. childAlloc.Width -= gripReq.Width;
  312. gripAlloc.Width = gripReq.Width;
  313. } else {
  314. childAlloc.Y += gripReq.Height;
  315. childAlloc.Height -= gripReq.Height;
  316. gripAlloc.Height = gripReq.Height;
  317. }
  318. grip.SizeAllocate (gripAlloc);
  319. }
  320. Child.SizeAllocate (childAlloc);
  321. }
  322. }
  323. protected override void OnMapped ()
  324. {
  325. SetFlag (WidgetFlags.Mapped);
  326. GdkWindow.Show ();
  327. if (Child != null && Child.Visible && !Child.IsMapped)
  328. Child.Map ();
  329. if (grip != null && grip.Visible && !grip.IsMapped)
  330. grip.Map ();
  331. }
  332. protected override void OnUnmapped ()
  333. {
  334. ClearFlag (WidgetFlags.Mapped);
  335. GdkWindow.Hide ();
  336. if (grip != null)
  337. grip.Unmap ();
  338. }
  339. protected override void OnRealized ()
  340. {
  341. WidgetFlags |= WidgetFlags.Realized;
  342. Gdk.WindowAttr attributes = new Gdk.WindowAttr ();
  343. attributes.X = Allocation.X;
  344. attributes.Y = Allocation.Y;
  345. attributes.Height = Allocation.Height;
  346. attributes.Width = Allocation.Width;
  347. attributes.WindowType = Gdk.WindowType.Child;
  348. attributes.Wclass = Gdk.WindowClass.InputOutput;
  349. attributes.Visual = Visual;
  350. attributes.Colormap = Colormap;
  351. attributes.EventMask = (int)(Events |
  352. Gdk.EventMask.ExposureMask |
  353. Gdk.EventMask.Button1MotionMask |
  354. Gdk.EventMask.ButtonPressMask |
  355. Gdk.EventMask.ButtonReleaseMask);
  356. Gdk.WindowAttributesType attributes_mask =
  357. Gdk.WindowAttributesType.X |
  358. Gdk.WindowAttributesType.Y |
  359. Gdk.WindowAttributesType.Colormap |
  360. Gdk.WindowAttributesType.Visual;
  361. GdkWindow = new Gdk.Window (ParentWindow, attributes, (int)attributes_mask);
  362. GdkWindow.UserData = Handle;
  363. Style = Style.Attach (GdkWindow);
  364. Style.SetBackground (GdkWindow, State);
  365. GdkWindow.SetBackPixmap (null, true);
  366. if (Child != null)
  367. Child.ParentWindow = GdkWindow;
  368. if (grip != null)
  369. grip.ParentWindow = GdkWindow;
  370. }
  371. protected override void OnStyleSet (Style style)
  372. {
  373. if (IsRealized && !IsNoWindow) {
  374. Style.SetBackground (GdkWindow, State);
  375. if (IsDrawable)
  376. GdkWindow.Clear ();
  377. }
  378. }
  379. protected override void OnDestroyed ()
  380. {
  381. if (tabLabel != null)
  382. tabLabel = null;
  383. if (menu != null) {
  384. menu.Detach ();
  385. menu = null;
  386. }
  387. if (grip != null) {
  388. Remove (grip);
  389. grip = null;
  390. }
  391. if (dockPlaceHolder != null) {
  392. dockPlaceHolder = null;
  393. }
  394. base.OnDestroyed ();
  395. }
  396. protected override bool OnExposeEvent (Gdk.EventExpose evnt)
  397. {
  398. if (IsDrawable && evnt.Window == GdkWindow) {
  399. /* TODO this crashes win32 at the moment...
  400. Style.PaintBox (Style, GdkWindow, State,
  401. ShadowType.None, evnt.Area, this,
  402. "dockitem", 0, 0, -1, -1);
  403. */
  404. base.OnExposeEvent (evnt);
  405. }
  406. return false;
  407. }
  408. protected override bool OnButtonPressEvent (Gdk.EventButton evnt)
  409. {
  410. if (!EventInGripWindow (evnt))
  411. return false;
  412. bool eventHandled = false;
  413. bool inHandle;
  414. Gdk.Cursor cursor = null;
  415. /* Check if user clicked on the drag handle. */
  416. switch (Orientation) {
  417. case Orientation.Horizontal:
  418. inHandle = evnt.X < grip.Allocation.Width;
  419. break;
  420. case Orientation.Vertical:
  421. inHandle = evnt.Y < grip.Allocation.Height;
  422. break;
  423. default:
  424. inHandle = false;
  425. break;
  426. }
  427. /* Left mousebutton click on dockitem. */
  428. if (!Locked && evnt.Button == 1 && evnt.Type == Gdk.EventType.ButtonPress) {
  429. /* Set in_drag flag, grab pointer and call begin drag operation. */
  430. if (inHandle) {
  431. startX = (int)evnt.X;
  432. startY = (int)evnt.Y;
  433. DockObjectFlags |= DockObjectFlags.InPreDrag;
  434. cursor = new Gdk.Cursor (Display, Gdk.CursorType.Fleur);
  435. grip.TitleWindow.Cursor = cursor;
  436. eventHandled = true;
  437. }
  438. } else if (!Locked && evnt.Type == Gdk.EventType.ButtonRelease && evnt.Button == 1) {
  439. if (InDrag) {
  440. /* User dropped widget somewhere. */
  441. EndDrag (false);
  442. eventHandled = true;
  443. } else if (InPreDrag) {
  444. DockObjectFlags &= ~(DockObjectFlags.InPreDrag);
  445. eventHandled = true;
  446. }
  447. /* we check the window since if the item was redocked it's
  448. been unrealized and maybe it's not realized again yet */
  449. if (grip.TitleWindow != null) {
  450. cursor = new Gdk.Cursor (Display, Gdk.CursorType.Hand2);
  451. grip.TitleWindow.Cursor = cursor;
  452. }
  453. } else if (evnt.Button == 3 && evnt.Type == Gdk.EventType.ButtonPress && inHandle) {
  454. DockPopupMenu (evnt.Button, evnt.Time);
  455. eventHandled = true;
  456. }
  457. return eventHandled;
  458. }
  459. protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt)
  460. {
  461. return OnButtonPressEvent (evnt);
  462. }
  463. protected override bool OnMotionNotifyEvent (Gdk.EventMotion evnt)
  464. {
  465. if (!EventInGripWindow (evnt))
  466. return false;
  467. if (InPreDrag) {
  468. if (Drag.CheckThreshold (this, startX, startY,
  469. (int)evnt.X, (int)evnt.Y)) {
  470. DockObjectFlags &= ~(DockObjectFlags.InPreDrag);
  471. dragoffX = startX;
  472. dragoffY = startY;
  473. StartDrag ();
  474. }
  475. }
  476. if (!InDrag)
  477. return false;
  478. int newX = (int)evnt.XRoot;
  479. int newY = (int)evnt.YRoot;
  480. OnDragMotion (newX, newY);
  481. DockItemMotionHandler handler = DockItemMotion;
  482. if (handler != null)
  483. handler (this, newX, newY);
  484. return true;
  485. }
  486. protected override bool OnKeyPressEvent (Gdk.EventKey evnt)
  487. {
  488. if (InDrag && evnt.Key == Gdk.Key.Escape) {
  489. EndDrag (false);
  490. return true;
  491. }
  492. return base.OnKeyPressEvent (evnt);
  493. }
  494. public override bool OnDockRequest (int x, int y, ref DockRequest request)
  495. {
  496. /* we get (x,y) in our allocation coordinates system */
  497. /* Get item's allocation. */
  498. Gdk.Rectangle alloc = Allocation;
  499. /* Get coordinates relative to our window. */
  500. int relX = x - alloc.X;
  501. int relY = y - alloc.Y;
  502. /* Location is inside. */
  503. if (relX > 0 && relX < alloc.Width &&
  504. relY > 0 && relY < alloc.Height) {
  505. int divider = -1;
  506. /* these are for calculating the extra docking parameter */
  507. Requisition other = ((DockItem)request.Applicant).PreferredSize;
  508. Requisition my = PreferredSize;
  509. /* Calculate location in terms of the available space (0-100%). */
  510. float rx = (float) relX / alloc.Width;
  511. float ry = (float) relY / alloc.Height;
  512. /* Determine dock location. */
  513. if (rx < SplitRatio) {
  514. request.Position = DockPlacement.Left;
  515. divider = other.Width;
  516. } else if (rx > (1 - SplitRatio)) {
  517. request.Position = DockPlacement.Right;
  518. rx = 1 - rx;
  519. divider = Math.Max (0, my.Width - other.Width);
  520. } else if (ry < SplitRatio && ry < rx) {
  521. request.Position = DockPlacement.Top;
  522. divider = other.Height;
  523. } else if (ry > (1 - SplitRatio) && (1 - ry) < rx) {
  524. request.Position = DockPlacement.Bottom;
  525. divider = Math.Max (0, my.Height - other.Height);
  526. } else {
  527. request.Position = DockPlacement.Center;
  528. }
  529. /* Reset rectangle coordinates to entire item. */
  530. request.X = 0;
  531. request.Y = 0;
  532. request.Width = alloc.Width;
  533. request.Height = alloc.Height;
  534. /* Calculate docking indicator rectangle size for new locations.
  535. Only do this when we're not over the item's current location. */
  536. if (request.Applicant != this) {
  537. switch (request.Position) {
  538. case DockPlacement.Top:
  539. request.Height = (int)(request.Height * SplitRatio);
  540. break;
  541. case DockPlacement.Bottom:
  542. request.Y += (int)(request.Height * (1 - SplitRatio));
  543. request.Height = (int)(request.Height * SplitRatio);
  544. break;
  545. case DockPlacement.Left:
  546. request.Width = (int)(request.Width * SplitRatio);
  547. break;
  548. case DockPlacement.Right:
  549. request.X += (int)(request.Width * (1 - SplitRatio));
  550. request.Width = (int)(request.Width * SplitRatio);
  551. break;
  552. case DockPlacement.Center:
  553. request.X = (int)(request.Width * SplitRatio / 2);
  554. request.Y = (int)(request.Height * SplitRatio / 2);
  555. request.Width = (int)(request.Width * (1 - SplitRatio / 2)) - request.X;
  556. request.Height = (int)(request.Height * (1 - SplitRatio / 2)) - request.Y;
  557. break;
  558. default:
  559. break;
  560. }
  561. }
  562. /* adjust returned coordinates so they have the same
  563. origin as our window */
  564. request.X += alloc.X;
  565. request.Y += alloc.Y;
  566. /* Set possible target location and return true. */
  567. request.Target = this;
  568. /* fill-in other dock information */
  569. if (request.Position != DockPlacement.Center && divider >= 0)
  570. request.Extra = divider;
  571. return true;
  572. } else { /* No docking possible at this location. */
  573. return false;
  574. }
  575. }
  576. public override void OnDocked (DockObject requestor, DockPlacement position, object data)
  577. {
  578. DockObject parent = ParentObject;
  579. DockObject newParent = null;
  580. bool addOurselvesFirst;
  581. switch (position) {
  582. case DockPlacement.Top:
  583. case DockPlacement.Bottom:
  584. newParent = new DockPaned (Orientation.Vertical);
  585. addOurselvesFirst = (position == DockPlacement.Bottom);
  586. break;
  587. case DockPlacement.Left:
  588. case DockPlacement.Right:
  589. newParent = new DockPaned (Orientation.Horizontal);
  590. addOurselvesFirst = (position == DockPlacement.Right);
  591. break;
  592. case DockPlacement.Center:
  593. newParent = new DockNotebook ();
  594. addOurselvesFirst = true;
  595. break;
  596. default:
  597. Console.WriteLine ("Unsupported docking strategy");
  598. return;
  599. }
  600. if (parent != null)
  601. parent.Freeze ();
  602. DockObjectFlags |= DockObjectFlags.InReflow;
  603. Detach (false);
  604. newParent.Freeze ();
  605. newParent.Bind (Master);
  606. if (addOurselvesFirst) {
  607. newParent.Add (this);
  608. newParent.Add (requestor);
  609. } else {
  610. newParent.Add (requestor);
  611. newParent.Add (this);
  612. }
  613. if (parent != null)
  614. parent.Add (newParent);
  615. if (Visible)
  616. newParent.Show ();
  617. if (position != DockPlacement.Center && data != null && data is System.Int32) {
  618. if (newParent is DockPaned)
  619. ((DockPaned) newParent).Position = (int) data;
  620. }
  621. DockObjectFlags &= ~(DockObjectFlags.InReflow);
  622. newParent.Thaw ();
  623. if (parent != null)
  624. parent.Thaw ();
  625. }
  626. protected virtual void OnDragBegin ()
  627. {
  628. }
  629. protected virtual void OnDragEnd (bool cancelled)
  630. {
  631. }
  632. protected virtual void OnDragMotion (int x, int y)
  633. {
  634. }
  635. private void DetachMenu (Widget item, Menu menu)
  636. {
  637. if (item is DockItem)
  638. ((DockItem)item).menu = null;
  639. }
  640. public void DockPopupMenu (uint button, uint time)
  641. {
  642. if (menu == null) {
  643. // Create popup menu and attach it to the dock item
  644. menu = new Menu ();
  645. menu.AttachToWidget (this, new MenuDetachFunc (DetachMenu));
  646. // Hide menuitem
  647. MenuItem mitem = new MenuItem ("Hide");
  648. mitem.Activated += new EventHandler (ItemHideCb);
  649. menu.Append (mitem);
  650. // Lock menuitem
  651. CheckMenuItem citem = new CheckMenuItem ("Lock");
  652. citem.Active = this.Locked;
  653. citem.Toggled += new EventHandler (ItemLockCb);
  654. menu.Append (citem);
  655. }
  656. menu.ShowAll ();
  657. menu.Popup (null, null, null, button, time);
  658. }
  659. private void ItemHideCb (object o, EventArgs e)
  660. {
  661. HideItem ();
  662. }
  663. private void ItemLockCb (object sender, EventArgs a)
  664. {
  665. this.Locked = ((CheckMenuItem)sender).Active;
  666. }
  667. private void StartDrag ()
  668. {
  669. if (!IsRealized)
  670. Realize ();
  671. DockObjectFlags |= DockObjectFlags.InDrag;
  672. /* grab the pointer so we receive all mouse events */
  673. //Gdk.Cursor fleur = new Gdk.Cursor (Gdk.CursorType.Fleur);
  674. /* grab the keyboard & pointer */
  675. Grab.Add (this);
  676. OnDragBegin ();
  677. DockItemDragBeginHandler handler = DockItemDragBegin;
  678. if (handler != null)
  679. handler (this);
  680. }
  681. private void EndDrag (bool cancel)
  682. {
  683. /* Release pointer & keyboard. */
  684. Grab.Remove (Grab.Current);
  685. OnDragEnd (cancel);
  686. DockItemDragEndHandler handler = DockItemDragEnd;
  687. if (handler != null)
  688. handler (this, cancel);
  689. DockObjectFlags &= ~(DockObjectFlags.InDrag);
  690. }
  691. private void ShowHideGrip ()
  692. {
  693. DetachMenu (this, null);
  694. if (grip != null) {
  695. Gdk.Cursor cursor = null;
  696. if (GripShown && !Locked)
  697. cursor = new Gdk.Cursor (Display, Gdk.CursorType.Hand2);
  698. if (grip.TitleWindow != null)
  699. grip.TitleWindow.Cursor = cursor;
  700. if (GripShown)
  701. grip.Show ();
  702. else
  703. grip.Hide ();
  704. }
  705. QueueResize ();
  706. }
  707. public void DockTo (DockItem target, DockPlacement position)
  708. {
  709. if (target == null && position != DockPlacement.Floating)
  710. return;
  711. if (position == DockPlacement.Floating || target == null) {
  712. if (!IsBound) {
  713. Console.WriteLine ("Attempting to bind an unbound item");
  714. return;
  715. }
  716. // FIXME: save previous docking position for later re-docking?
  717. dragoffX = dragoffY = 0;
  718. ((Dock)Master.Controller).AddFloatingItem (this, 0, 0, -1, -1);
  719. } else {
  720. target.Dock (this, position, null);
  721. }
  722. }
  723. public virtual void SetOrientation (Orientation orientation)
  724. {
  725. if (Orientation != orientation) {
  726. this.orientation = orientation;
  727. if (IsDrawable)
  728. QueueDraw ();
  729. QueueResize ();
  730. EmitPropertyEvent ("orientation");
  731. }
  732. }
  733. public void HideGrip ()
  734. {
  735. if (GripShown)
  736. ShowHideGrip ();
  737. }
  738. public void ShowGrip ()
  739. {
  740. if (!GripShown)
  741. ShowHideGrip ();
  742. }
  743. public void Bind (Dock dock)
  744. {
  745. if (dock == null)
  746. return;
  747. Bind (dock.Master);
  748. }
  749. public void HideItem ()
  750. {
  751. if (!IsAttached)
  752. /* already hidden/detached */
  753. return;
  754. /* if the object is manual, create a new placeholder to be
  755. able to restore the position later */
  756. if (!IsAutomatic)
  757. dockPlaceHolder = new DockPlaceholder (this, false);
  758. Freeze ();
  759. /* hide our children first, so they can also set placeholders */
  760. if (IsCompound)
  761. Foreach (new Callback (HideChildItem));
  762. Detach (true);
  763. Thaw ();
  764. }
  765. private void HideChildItem (Widget widget)
  766. {
  767. if (!(widget is DockItem))
  768. return;
  769. DockItem item = widget as DockItem;
  770. item.HideItem ();
  771. }
  772. public void IconifyItem ()
  773. {
  774. DockObjectFlags |= DockObjectFlags.Iconified;
  775. HideItem ();
  776. }
  777. public void ShowItem ()
  778. {
  779. DockObjectFlags &= ~(DockObjectFlags.Iconified);
  780. if (dockPlaceHolder != null) {
  781. dockPlaceHolder.Add (this);
  782. dockPlaceHolder = null;
  783. } else if (IsBound) {
  784. if (Master.Controller != null) {
  785. Master.Controller.Dock (this, DockPlacement.Floating, null);
  786. }
  787. }
  788. }
  789. public virtual void SetDefaultPosition (DockObject reference)
  790. {
  791. dockPlaceHolder = null;
  792. if (reference != null && reference.IsAttached) {
  793. if (reference is DockPlaceholder) {
  794. dockPlaceHolder = (DockPlaceholder)reference;
  795. } else {
  796. dockPlaceHolder = new DockPlaceholder (reference, true);
  797. }
  798. }
  799. }
  800. public DockPlaceholder DefaultPosition {
  801. get { return dockPlaceHolder; }
  802. }
  803. private bool EventInGripWindow (Gdk.Event evnt)
  804. {
  805. if (grip != null && grip.TitleWindow == evnt.Window)
  806. return true;
  807. else
  808. return false;
  809. }
  810. }
  811. }