3
// Copyright (C) 2008 GNOME Do
5
// This program is free software: you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation, either version 3 of the License, or
8
// (at your option) any later version.
10
// This program is distributed in the hope that it will be useful,
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
// GNU General Public License for more details.
15
// You should have received a copy of the GNU General Public License
16
// along with this program. If not, see <http://www.gnu.org/licenses/>.
20
using System.Collections.Generic;
28
using Do.Interface.CairoUtils;
31
using Docky.Utilities;
33
namespace Docky.Interface.Menus
37
public class DockPopupMenu : Gtk.Window
39
public static readonly Cairo.Color BackgroundColor = new Cairo.Color (0.13, 0.13, 0.13, .95);
41
const int TailHeight = 20;
42
const int TailWidth = 25;
43
new const int BorderWidth = 2;
44
const int HeaderSize = 20;
46
const int Width = 180;
47
const double Curviness = .05;
48
const string FormatString = "<b>{0}</b>";
50
int horizontal_offset;
57
public Gtk.VBox Container { get; private set; }
59
// we are making a new one here for speed reasons
60
public new bool Visible { get; private set; }
62
int HeaderTextOffset {
64
if (DockPreferences.Orientation == DockOrientation.Bottom)
65
return (HeaderSize + 10) / 2;
67
return (TailHeight + 3) + (HeaderSize + 10) / 2;
71
public DockPopupMenu() : base (Gtk.WindowType.Popup)
78
SkipTaskbarHint = true;
81
TypeHint = WindowTypeHint.PopupMenu;
85
this.SetCompositeColormap ();
87
AddEvents ((int) EventMask.PointerMotionMask |
88
(int) EventMask.LeaveNotifyMask |
89
(int) EventMask.ButtonPressMask |
90
(int) EventMask.ButtonReleaseMask |
91
(int) EventMask.FocusChangeMask);
93
Container = new Gtk.VBox ();
96
DockPreferences.OrientationChanged += SetAlignment;
99
protected virtual void Build ()
101
align = new Gtk.Alignment (0.5f, 0.5f, 1, 1);
104
align.Add (Container);
111
align.LeftPadding = 4;
112
align.RightPadding = 3;
113
align.TopPadding = align.BottomPadding = 7;
114
align.TopPadding += HeaderSize;
116
switch (DockPreferences.Orientation) {
117
case DockOrientation.Bottom:
118
align.BottomPadding += TailHeight + 3;
120
case DockOrientation.Top:
121
align.TopPadding += TailHeight + 3;
126
public virtual void PopUp (string description, IEnumerable<AbstractMenuArgs> args, int x, int y)
128
header = description;
129
vertical_offset = horizontal_offset = 0;
131
Gdk.Rectangle geo = LayoutUtils.MonitorGeometry ();
132
Gtk.Requisition req = SizeRequest ();
135
switch (DockPreferences.Orientation) {
136
case DockOrientation.Bottom:
137
postion = new Gdk.Point (x - req.Width / 2, y - req.Height);
139
case DockOrientation.Top:
140
postion = new Gdk.Point (x - req.Width / 2, y);
143
postion = new Gdk.Point (0, 0);
147
if (postion.X < geo.X) {
148
horizontal_offset = geo.X - postion.X;
149
} else if (postion.X + req.Width > geo.X + geo.Width) {
150
horizontal_offset = (geo.X + geo.Width) - (postion.X + req.Width);
153
postion.X += horizontal_offset;
154
postion.Y += vertical_offset;
155
Move (postion.X, postion.Y);
157
Do.Interface.Windowing.PresentWindow (this);
160
protected override bool OnExposeEvent (Gdk.EventExpose evnt)
162
using (Context cr = Gdk.CairoHelper.Create (GdkWindow)) {
167
return base.OnExposeEvent (evnt);
170
protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt)
173
GetSize (out rect.Width, out rect.Height);
175
if (evnt.X < 0 || evnt.Y < 0 || evnt.X > rect.Width || evnt.Y > rect.Height) {
176
Do.Interface.Windowing.UnpresentWindow (this);
179
return base.OnButtonReleaseEvent (evnt);
182
protected override bool OnKeyReleaseEvent (Gdk.EventKey evnt)
184
if (evnt.Key == Gdk.Key.Escape) {
185
Do.Interface.Windowing.UnpresentWindow (this);
188
return base.OnKeyReleaseEvent (evnt);
191
protected override void OnShown ()
197
protected override void OnHidden ()
203
void DrawBackground (Context cr)
206
GetSize (out rect.Width, out rect.Height);
208
SetBackgroundPath (cr);
210
cr.Color = BackgroundColor;
213
LinearGradient lg = (DockPreferences.Orientation == DockOrientation.Bottom) ?
214
new LinearGradient (0, rect.Height - TailHeight, 0, rect.Height) : new LinearGradient (0, TailHeight, 0, 0);
215
lg.AddColorStop (0, BackgroundColor);
216
lg.AddColorStop (1, new Cairo.Color (BackgroundColor.R, BackgroundColor.G, BackgroundColor.B, 0));
219
cr.StrokePreserve ();
222
lg = (DockPreferences.Orientation == DockOrientation.Bottom) ?
223
new LinearGradient (0, rect.Height - TailHeight, 0, rect.Height) : new LinearGradient (0, TailHeight, 0, 0);
224
lg.AddColorStop (0, new Cairo.Color (1, 1, 1, .25));
225
lg.AddColorStop (1, new Cairo.Color (1, 1, 1, 0));
232
TextRenderContext context = new TextRenderContext (cr, string.Format (FormatString, header), Width - 16);
233
context.LeftCenteredPoint = new Gdk.Point (8, HeaderTextOffset);
234
context.Alignment = Pango.Alignment.Center;
236
Core.DockServices.DrawingService.TextPathAtPoint (context);
237
cr.Color = new Cairo.Color (1, 1, 1);
241
void SetBackgroundPath (Context context)
244
GetSize (out size.Width, out size.Height);
246
Gdk.Rectangle mainArea = new Gdk.Rectangle (0, 0, 0, 0);
247
switch (DockPreferences.Orientation) {
248
case DockOrientation.Bottom:
249
mainArea = new Gdk.Rectangle (BorderWidth,
251
size.Width - 2 * BorderWidth,
252
size.Height - 2 * BorderWidth - TailHeight);
254
case DockOrientation.Top:
255
mainArea = new Gdk.Rectangle (BorderWidth,
256
BorderWidth + TailHeight,
257
size.Width - 2 * BorderWidth,
258
size.Height - 2 * BorderWidth - TailHeight);
262
context.Translate (.5, .5);
264
mainArea.Height -= 1;
266
PointD topLeftRadialCenter = new PointD (mainArea.X + Radius, mainArea.Y + Radius);
267
PointD topRightRadialCenter = new PointD (mainArea.X + mainArea.Width - Radius, mainArea.Y + Radius);
268
PointD bottomRightRadialCenter = new PointD (mainArea.X + mainArea.Width - Radius, mainArea.Y + mainArea.Height - Radius);
269
PointD bottomLeftRadialCenter = new PointD (mainArea.X + Radius, mainArea.Y + mainArea.Height - Radius);
271
context.MoveTo (mainArea.X, mainArea.Y + Radius);
273
context.Arc (topLeftRadialCenter.X, topLeftRadialCenter.Y, Radius, Math.PI, Math.PI * 1.5);
274
if (DockPreferences.Orientation == DockOrientation.Top) {
275
Gdk.Point vertex = new Gdk.Point ();
276
vertex.X = mainArea.X + mainArea.Width / 2;
277
vertex.Y = mainArea.Y - TailHeight;
278
vertex.X -= horizontal_offset;
280
Gdk.Point top = new Gdk.Point (vertex.X, vertex.Y + TailHeight);
282
context.LineTo (top.X - TailWidth, top.Y);
283
context.CurveTo (top.X - TailWidth * Curviness, top.Y, vertex.X, vertex.Y, vertex.X, vertex.Y);
284
context.CurveTo (vertex.X, vertex.Y, top.X + TailWidth * Curviness, top.Y, top.X + TailWidth, top.Y);
286
context.Arc (topRightRadialCenter.X, topRightRadialCenter.Y, Radius, Math.PI * 1.5, Math.PI * 2);
287
context.Arc (bottomRightRadialCenter.X, bottomRightRadialCenter.Y, Radius, 0, Math.PI * .5);
288
if (DockPreferences.Orientation == DockOrientation.Bottom) {
289
Gdk.Point vertex = new Gdk.Point ();
290
vertex.X = mainArea.X + mainArea.Width / 2;
291
vertex.Y = mainArea.Y + mainArea.Height + TailHeight;
292
vertex.X -= horizontal_offset;
294
Gdk.Point top = new Gdk.Point (vertex.X, vertex.Y - TailHeight);
296
context.LineTo (top.X + TailWidth, top.Y);
297
context.CurveTo (top.X + TailWidth * Curviness, top.Y, vertex.X, vertex.Y, vertex.X, vertex.Y);
298
context.CurveTo (vertex.X, vertex.Y, top.X - TailWidth * Curviness, top.Y, top.X - TailWidth, top.Y);
300
context.Arc (bottomLeftRadialCenter.X, bottomLeftRadialCenter.Y, Radius, Math.PI * .5, Math.PI);
303
context.ClosePath ();
305
context.Translate (-.5, -.5);
308
public override void Dispose ()
310
DockPreferences.OrientationChanged -= SetAlignment;