5
// Lluis Sanchez Gual <lluis@xamarin.com>
7
// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com)
8
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
10
// Permission is hereby granted, free of charge, to any person obtaining a copy
11
// of this software and associated documentation files (the "Software"), to deal
12
// in the Software without restriction, including without limitation the rights
13
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
// copies of the Software, and to permit persons to whom the Software is
15
// furnished to do so, subject to the following conditions:
17
// The above copyright notice and this permission notice shall be included in
18
// all copies or substantial portions of the Software.
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
31
using MonoDevelop.Ide.Gui;
33
using MonoDevelop.Core;
34
using MonoDevelop.Ide;
35
using Mono.TextEditor;
36
using MonoDevelop.Components;
38
namespace MonoDevelop.Components.Docking
41
class DockItemTitleTab: Gtk.EventBox
45
ExtendedLabel labelWidget;
47
DockVisualStyle visualStyle;
54
bool allowPlaceholderDocking;
57
static Gdk.Cursor fleurCursor = new Gdk.Cursor (Gdk.CursorType.Fleur);
59
static Gdk.Pixbuf pixClose;
60
static Gdk.Pixbuf pixAutoHide;
61
static Gdk.Pixbuf pixDock;
63
const int TopPadding = 5;
64
const int BottomPadding = 7;
65
const int TopPaddingActive = 5;
66
const int BottomPaddingActive = 7;
67
const int LeftPadding = 11;
68
const int RightPadding = 9;
70
static DockItemTitleTab ()
72
pixClose = Gdk.Pixbuf.LoadFromResource ("stock-close-12.png");
73
pixAutoHide = Gdk.Pixbuf.LoadFromResource ("stock-auto-hide.png");
74
pixDock = Gdk.Pixbuf.LoadFromResource ("stock-dock.png");
77
public DockItemTitleTab (DockItem item, DockFrame frame)
81
this.VisibleWindow = false;
86
Events |= Gdk.EventMask.EnterNotifyMask | Gdk.EventMask.LeaveNotifyMask | Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask;
87
KeyPressEvent += HeaderKeyPress;
88
KeyReleaseEvent += HeaderKeyRelease;
90
this.SubscribeLeaveEvent (OnLeave);
93
public DockVisualStyle VisualStyle {
94
get { return visualStyle; }
102
void UpdateVisualStyle ()
104
if (labelWidget != null && label != null) {
105
if (visualStyle.UppercaseTitles.Value)
106
labelWidget.Text = label.ToUpper ();
108
labelWidget.Text = label;
109
labelWidget.UseMarkup = true;
110
if (visualStyle.ExpandedTabs.Value)
111
labelWidget.Xalign = 0.5f;
113
if (!(Parent is TabStrip.TabStripBox))
114
labelWidget.Xalign = 0;
118
tabIcon.Visible = visualStyle.ShowPadTitleIcon.Value;
120
if (labelWidget != null)
121
labelWidget.ModifyFg (StateType.Normal, visualStyle.PadTitleLabelColor.Value);
123
var r = WidthRequest;
125
labelWidth = SizeRequest ().Width + 1;
128
if (visualStyle != null)
129
HeightRequest = visualStyle.PadTitleHeight != null ? visualStyle.PadTitleHeight.Value : -1;
132
public void SetLabel (Gtk.Widget page, Gdk.Pixbuf icon, string label)
137
Gtk.Widget oc = Child;
142
Gtk.HBox box = new HBox ();
146
tabIcon = new Gtk.Image (icon);
148
box.PackStart (tabIcon, false, false, 0);
152
if (!string.IsNullOrEmpty (label)) {
153
labelWidget = new ExtendedLabel (label);
154
labelWidget.DropShadowVisible = true;
155
labelWidget.UseMarkup = true;
156
box.PackStart (labelWidget, true, true, 0);
161
btnDock = new ImageButton ();
162
btnDock.Image = pixAutoHide;
163
btnDock.TooltipText = GettextCatalog.GetString ("Auto Hide");
164
btnDock.CanFocus = false;
165
// btnDock.WidthRequest = btnDock.HeightRequest = 17;
166
btnDock.Clicked += OnClickDock;
167
btnDock.ButtonPressEvent += (o, args) => args.RetVal = true;
168
btnDock.WidthRequest = btnDock.SizeRequest ().Width;
170
btnClose = new ImageButton ();
171
btnClose.Image = pixClose;
172
btnClose.TooltipText = GettextCatalog.GetString ("Close");
173
btnClose.CanFocus = false;
174
// btnClose.WidthRequest = btnClose.HeightRequest = 17;
175
btnClose.WidthRequest = btnDock.SizeRequest ().Width;
176
btnClose.Clicked += delegate {
177
item.Visible = false;
179
btnClose.ButtonPressEvent += (o, args) => args.RetVal = true;
181
Gtk.Alignment al = new Alignment (0, 0, 1, 1);
182
HBox btnBox = new HBox (false, 3);
183
btnBox.PackStart (btnDock, false, false, 0);
184
btnBox.PackStart (btnClose, false, false, 0);
188
box.PackEnd (al, false, false, 0);
192
// Get the required size before setting the ellipsize property, since ellipsized labels
193
// have a width request of 0
198
UpdateVisualStyle ();
201
void OnClickDock (object s, EventArgs a)
203
if (item.Status == DockItemStatus.AutoHide || item.Status == DockItemStatus.Floating)
204
item.Status = DockItemStatus.Dockable;
206
item.Status = DockItemStatus.AutoHide;
209
public int LabelWidth {
210
get { return labelWidth; }
218
if (active != value) {
233
public void UpdateBehavior ()
235
if (btnClose == null)
238
btnClose.Visible = (item.Behavior & DockItemBehavior.CantClose) == 0;
239
btnDock.Visible = (item.Behavior & DockItemBehavior.CantAutoHide) == 0;
241
if (active || mouseOver) {
242
if (btnClose.Image == null)
243
btnClose.Image = pixClose;
244
if (item.Status == DockItemStatus.AutoHide || item.Status == DockItemStatus.Floating) {
245
btnDock.Image = pixDock;
246
btnDock.TooltipText = GettextCatalog.GetString ("Dock");
248
btnDock.Image = pixAutoHide;
249
btnDock.TooltipText = GettextCatalog.GetString ("Auto Hide");
252
btnDock.Image = null;
253
btnClose.Image = null;
257
bool tabPressed, tabActivated;
258
double pressX, pressY;
260
protected override bool OnButtonPressEvent (Gdk.EventButton evnt)
262
if (evnt.TriggersContextMenu ()) {
263
item.ShowDockPopupMenu (evnt.Time);
265
} else if (evnt.Button == 1) {
266
if (evnt.Type == Gdk.EventType.ButtonPress) {
270
} else if (evnt.Type == Gdk.EventType.TwoButtonPress) {
274
return base.OnButtonPressEvent (evnt);
277
protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt)
280
tabActivated = false;
281
if (item.Status == DockItemStatus.AutoHide)
282
item.Status = DockItemStatus.Dockable;
284
item.Status = DockItemStatus.AutoHide;
286
else if (!evnt.TriggersContextMenu () && evnt.Button == 1) {
287
frame.DockInPlaceholder (item);
288
frame.HidePlaceholder ();
289
if (GdkWindow != null)
290
GdkWindow.Cursor = null;
291
frame.Toplevel.KeyPressEvent -= HeaderKeyPress;
292
frame.Toplevel.KeyReleaseEvent -= HeaderKeyRelease;
295
return base.OnButtonReleaseEvent (evnt);
298
protected override bool OnMotionNotifyEvent (Gdk.EventMotion evnt)
300
if (tabPressed && Math.Abs (evnt.X - pressX) > 3 && Math.Abs (evnt.Y - pressY) > 3) {
301
frame.ShowPlaceholder (item);
302
GdkWindow.Cursor = fleurCursor;
303
frame.Toplevel.KeyPressEvent += HeaderKeyPress;
304
frame.Toplevel.KeyReleaseEvent += HeaderKeyRelease;
305
allowPlaceholderDocking = true;
308
frame.UpdatePlaceholder (item, Allocation.Size, allowPlaceholderDocking);
309
return base.OnMotionNotifyEvent (evnt);
312
protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt)
316
return base.OnEnterNotifyEvent (evnt);
325
[GLib.ConnectBeforeAttribute]
326
void HeaderKeyPress (object ob, Gtk.KeyPressEventArgs a)
328
if (a.Event.Key == Gdk.Key.Control_L || a.Event.Key == Gdk.Key.Control_R) {
329
allowPlaceholderDocking = false;
330
frame.UpdatePlaceholder (item, Allocation.Size, false);
332
if (a.Event.Key == Gdk.Key.Escape) {
333
frame.HidePlaceholder ();
334
frame.Toplevel.KeyPressEvent -= HeaderKeyPress;
335
frame.Toplevel.KeyReleaseEvent -= HeaderKeyRelease;
336
Gdk.Pointer.Ungrab (0);
340
[GLib.ConnectBeforeAttribute]
341
void HeaderKeyRelease (object ob, Gtk.KeyReleaseEventArgs a)
343
if (a.Event.Key == Gdk.Key.Control_L || a.Event.Key == Gdk.Key.Control_R) {
344
allowPlaceholderDocking = true;
345
frame.UpdatePlaceholder (item, Allocation.Size, true);
349
protected override void OnRealized ()
352
UpdateVisualStyle ();
355
protected override void OnSizeRequested (ref Gtk.Requisition req)
358
req = Child.SizeRequest ();
359
req.Width += LeftPadding + RightPadding;
361
req.Height += TopPaddingActive + BottomPaddingActive;
363
req.Height += TopPadding + BottomPadding;
367
protected override void OnSizeAllocated (Gdk.Rectangle rect)
369
base.OnSizeAllocated (rect);
371
int leftPadding = LeftPadding;
372
int rightPadding = RightPadding;
373
if (rect.Width < labelWidth) {
374
int red = (labelWidth - rect.Width) / 2;
377
if (leftPadding < 2) leftPadding = 2;
378
if (rightPadding < 2) rightPadding = 2;
381
rect.X += leftPadding;
382
rect.Width -= leftPadding + rightPadding;
386
rect.Y += TopPaddingActive;
387
rect.Height = Child.SizeRequest ().Height;
390
rect.Y += TopPadding;
391
rect.Height = Child.SizeRequest ().Height;
393
Child.SizeAllocate (rect);
397
protected override bool OnExposeEvent (Gdk.EventExpose evnt)
399
if (VisualStyle.TabStyle == DockTabStyle.Normal)
400
DrawAsBrowser (evnt);
403
return base.OnExposeEvent (evnt);
406
void DrawAsBrowser (Gdk.EventExpose evnt)
408
var alloc = Allocation;
410
Gdk.GC bgc = new Gdk.GC (GdkWindow);
411
var c = new HslColor (VisualStyle.PadBackgroundColor.Value);
416
TabStrip tabStrip = null;
417
if (Parent is TabStrip.TabStripBox) {
418
var tsb = (TabStrip.TabStripBox) Parent;
419
var cts = tsb.Children;
420
first = cts[0] == this;
421
last = cts[cts.Length - 1] == this;
422
tabStrip = tsb.TabStrip;
425
if (Active || (first && last)) {
426
Gdk.GC gc = new Gdk.GC (GdkWindow);
427
gc.RgbFgColor = VisualStyle.PadBackgroundColor.Value;
428
evnt.Window.DrawRectangle (gc, true, alloc);
430
evnt.Window.DrawLine (bgc, alloc.X, alloc.Y, alloc.X, alloc.Y + alloc.Height - 1);
431
if (!(last && first) && !(tabStrip != null && tabStrip.VisualStyle.ExpandedTabs.Value && last))
432
evnt.Window.DrawLine (bgc, alloc.X + alloc.Width - 1, alloc.Y, alloc.X + alloc.Width - 1, alloc.Y + alloc.Height - 1);
436
Gdk.GC gc = new Gdk.GC (GdkWindow);
437
gc.RgbFgColor = tabStrip != null ? tabStrip.VisualStyle.InactivePadBackgroundColor.Value : frame.DefaultVisualStyle.InactivePadBackgroundColor.Value;
438
evnt.Window.DrawRectangle (gc, true, alloc);
440
evnt.Window.DrawLine (bgc, alloc.X, alloc.Y + alloc.Height - 1, alloc.X + alloc.Width - 1, alloc.Y + alloc.Height - 1);
445
void DrawNormal (Gdk.EventExpose evnt)
447
using (var ctx = Gdk.CairoHelper.Create (GdkWindow)) {
448
var x = Allocation.X;
449
var y = Allocation.Y;
451
ctx.Rectangle (x, y + 1, Allocation.Width, Allocation.Height - 1);
452
using (var g = new Cairo.LinearGradient (x, y + 1, x, y + Allocation.Height - 1)) {
453
g.AddColorStop (0, Styles.DockTabBarGradientStart);
454
g.AddColorStop (1, Styles.DockTabBarGradientEnd);
459
ctx.MoveTo (x + 0.5, y + 0.5);
460
ctx.LineTo (x + Allocation.Width - 0.5d, y + 0.5);
461
ctx.Color = Styles.DockTabBarGradientTop;
466
ctx.Rectangle (x, y + 1, Allocation.Width, Allocation.Height - 1);
467
using (var g = new Cairo.LinearGradient (x, y + 1, x, y + Allocation.Height - 1)) {
468
g.AddColorStop (0, new Cairo.Color (0, 0, 0, 0.01));
469
g.AddColorStop (0.5, new Cairo.Color (0, 0, 0, 0.08));
470
g.AddColorStop (1, new Cairo.Color (0, 0, 0, 0.01));
475
/* double offset = Allocation.Height * 0.25;
476
var rect = new Cairo.Rectangle (x - Allocation.Height + offset, y, Allocation.Height, Allocation.Height);
477
var cg = new Cairo.RadialGradient (rect.X + rect.Width / 2, rect.Y + rect.Height / 2, 0, rect.X, rect.Y + rect.Height / 2, rect.Height / 2);
478
cg.AddColorStop (0, Styles.DockTabBarShadowGradientStart);
479
cg.AddColorStop (1, Styles.DockTabBarShadowGradientEnd);
481
ctx.Rectangle (rect);
484
rect = new Cairo.Rectangle (x + Allocation.Width - offset, y, Allocation.Height, Allocation.Height);
485
cg = new Cairo.RadialGradient (rect.X + rect.Width / 2, rect.Y + rect.Height / 2, 0, rect.X, rect.Y + rect.Height / 2, rect.Height / 2);
486
cg.AddColorStop (0, Styles.DockTabBarShadowGradientStart);
487
cg.AddColorStop (1, Styles.DockTabBarShadowGradientEnd);
489
ctx.Rectangle (rect);