~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/xwt/Xwt.Gtk/Xwt.GtkBackend/PopoverBackend.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// PopoverBackend.cs
 
3
//
 
4
// Author:
 
5
//       JĆ©rĆ©mie Laval <jeremie.laval@xamarin.com>
 
6
//
 
7
// Copyright (c) 2012 Xamarin, Inc.
 
8
//
 
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
 
10
// of this software and associated documentation files (the "Software"), to deal
 
11
// in the Software without restriction, including without limitation the rights
 
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
13
// copies of the Software, and to permit persons to whom the Software is
 
14
// furnished to do so, subject to the following conditions:
 
15
//
 
16
// The above copyright notice and this permission notice shall be included in
 
17
// all copies or substantial portions of the Software.
 
18
//
 
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
25
// THE SOFTWARE.
 
26
 
 
27
using System;
 
28
 
 
29
using Xwt.Backends;
 
30
 
 
31
using Gtk;
 
32
using Cairo;
 
33
 
 
34
namespace Xwt.GtkBackend
 
35
{
 
36
        public class PopoverBackend : IPopoverBackend
 
37
        {
 
38
                class PopoverWindow : Gtk.Window
 
39
                {
 
40
                        const int arrowPadding = 10;
 
41
                        const int radius = 6;
 
42
                        
 
43
                        bool supportAlpha;
 
44
                        Xwt.Popover.Position arrowPosition;
 
45
                        Gtk.Alignment alignment;
 
46
                        
 
47
                        public PopoverWindow (Gtk.Widget child, Xwt.Popover.Position orientation) : base (WindowType.Toplevel)
 
48
                        {
 
49
                                this.AppPaintable = true;
 
50
                                this.Decorated = false;
 
51
                                this.SkipPagerHint = true;
 
52
                                this.SkipTaskbarHint = true;
 
53
                                this.TypeHint = Gdk.WindowTypeHint.PopupMenu;
 
54
                                //this.TransientFor = (Gtk.Window)child.Toplevel;
 
55
                                this.AddEvents ((int)Gdk.EventMask.FocusChangeMask);
 
56
                                //this.DefaultHeight = this.DefaultWidth = 400;
 
57
                                this.arrowPosition = orientation;
 
58
                                this.alignment = new Gtk.Alignment (0, 0, 1, 1);
 
59
                                this.Add (alignment);
 
60
                                this.alignment.Add (child);
 
61
                                this.FocusOutEvent += HandleFocusOutEvent;
 
62
                                OnScreenChanged (null);
 
63
                        }
 
64
                        
 
65
                        public Xwt.Popover.Position ArrowPosition {
 
66
                                get {
 
67
                                        return arrowPosition;
 
68
                                }
 
69
                        }
 
70
                        
 
71
                        public void ReleaseInnerWidget ()
 
72
                        {
 
73
                                alignment.Remove (alignment.Child);
 
74
                        }
 
75
                        
 
76
                        void HandleFocusOutEvent (object o, FocusOutEventArgs args)
 
77
                        {
 
78
                                this.HideAll ();
 
79
                        }
 
80
                        
 
81
                        public void SetPadding (WidgetSpacing spacing)
 
82
                        {
 
83
                                alignment.LeftPadding = radius + (uint) spacing.Left;
 
84
                                alignment.RightPadding = radius + (uint) spacing.Right;
 
85
                                if (arrowPosition == Xwt.Popover.Position.Top) {
 
86
                                        alignment.TopPadding = radius + arrowPadding + (uint) spacing.Top;
 
87
                                        alignment.BottomPadding = radius + (uint) spacing.Bottom;
 
88
                                } else {
 
89
                                        alignment.BottomPadding = radius + arrowPadding + (uint) spacing.Bottom;
 
90
                                        alignment.TopPadding = radius + (uint) spacing.Top;
 
91
                                }
 
92
                        }
 
93
                        
 
94
                        protected override void OnScreenChanged (Gdk.Screen previous_screen)
 
95
                        {
 
96
                                // To check if the display supports alpha channels, get the colormap
 
97
                                var colormap = this.Screen.RgbaColormap;
 
98
                                if (colormap == null) {
 
99
                                        colormap = this.Screen.RgbColormap;
 
100
                                        supportAlpha = false;
 
101
                                } else {
 
102
                                        supportAlpha = true;
 
103
                                }
 
104
                                this.Colormap = colormap;
 
105
                                base.OnScreenChanged (previous_screen);
 
106
                        }
 
107
                        
 
108
                        protected override bool OnExposeEvent (Gdk.EventExpose evnt)
 
109
                        {
 
110
                                int w, h;
 
111
                                this.GdkWindow.GetSize (out w, out h);
 
112
                                var bounds = new Xwt.Rectangle (0.5, 0.5, w - 1, h - 1);
 
113
                                var backgroundColor = Xwt.Drawing.Color.FromBytes (230, 230, 230, 230);
 
114
                                var black = Xwt.Drawing.Color.FromBytes (60, 60, 60);
 
115
                                
 
116
                                using (Context ctx = Gdk.CairoHelper.Create (this.GdkWindow)) {
 
117
                                        // We clear the surface with a transparent color if possible
 
118
                                        if (supportAlpha)
 
119
                                                ctx.Color = new Color (1.0, 1.0, 1.0, 0.0);
 
120
                                        else
 
121
                                                ctx.Color = new Color (1.0, 1.0, 1.0);
 
122
                                        ctx.Operator = Operator.Source;
 
123
                                        ctx.Paint ();
 
124
                                        
 
125
                                        var calibratedRect = RecalibrateChildRectangle (bounds);
 
126
                                        // Fill it with one round rectangle
 
127
                                        RoundRectangle (ctx, calibratedRect, radius);
 
128
                                        ctx.LineWidth = 1;
 
129
                                        ctx.Color = new Color (black.Red, black.Green, black.Blue, black.Alpha);
 
130
                                        ctx.StrokePreserve ();
 
131
                                        ctx.Color = new Color (backgroundColor.Red, backgroundColor.Green, backgroundColor.Blue, backgroundColor.Alpha);
 
132
                                        ctx.Fill ();
 
133
                                        
 
134
                                        // Triangle
 
135
                                        // We first begin by positionning ourselves at the top-center or bottom center of the previous rectangle
 
136
                                        var arrowX = bounds.Center.X;
 
137
                                        var arrowY = arrowPosition == Xwt.Popover.Position.Top ? calibratedRect.Top + ctx.LineWidth : calibratedRect.Bottom - ctx.LineWidth;
 
138
                                        ctx.NewPath ();
 
139
                                        ctx.MoveTo (arrowX, arrowY);
 
140
                                        // We draw the rectangle path
 
141
                                        DrawTriangle (ctx);
 
142
                                        // We use it
 
143
                                        ctx.Color = new Color (black.Red, black.Green, black.Blue, black.Alpha);
 
144
                                        ctx.StrokePreserve ();
 
145
                                        ctx.ClosePath ();
 
146
                                        ctx.Color = new Color (backgroundColor.Red, backgroundColor.Green, backgroundColor.Blue, backgroundColor.Alpha);
 
147
                                        ctx.Fill ();
 
148
                                }
 
149
                                
 
150
                                base.OnExposeEvent (evnt);
 
151
                                return false;
 
152
                        }
 
153
                        
 
154
                        void DrawTriangle (Context ctx)
 
155
                        {
 
156
                                var triangleSide = 2 * arrowPadding / Math.Sqrt (3);
 
157
                                var halfSide = triangleSide / 2;
 
158
                                var verticalModifier = arrowPosition == Xwt.Popover.Position.Top ? -1 : 1;
 
159
                                // Move to the left
 
160
                                ctx.RelMoveTo (-halfSide, 0);
 
161
                                ctx.RelLineTo (halfSide, verticalModifier * arrowPadding);
 
162
                                ctx.RelLineTo (halfSide, verticalModifier * -arrowPadding);
 
163
                        }
 
164
                        
 
165
                        void RoundRectangle (Context ctx, Rectangle rect, double radius)
 
166
                        {
 
167
                                double degrees = Math.PI / 180;
 
168
                                var x = rect.X;
 
169
                                var y = rect.Y;
 
170
                                var height = rect.Height;
 
171
                                var width = rect.Width;
 
172
                                
 
173
                                ctx.NewSubPath ();
 
174
                                ctx.Arc (x + width - radius, y + radius, radius, -90 * degrees, 0 * degrees);
 
175
                                ctx.Arc (x + width - radius, y + height - radius, radius, 0 * degrees, 90 * degrees);
 
176
                                ctx.Arc (x + radius, y + height - radius, radius, 90 * degrees, 180 * degrees);
 
177
                                ctx.Arc (x + radius, y + radius, radius, 180 * degrees, 270 * degrees);
 
178
                                ctx.ClosePath ();
 
179
                        }
 
180
                        
 
181
                        Xwt.Rectangle RecalibrateChildRectangle (Xwt.Rectangle bounds)
 
182
                        {
 
183
                                switch (arrowPosition) {
 
184
                                case Xwt.Popover.Position.Top:
 
185
                                        return new Rectangle (bounds.X, bounds.Y + arrowPadding, bounds.Width, bounds.Height - arrowPadding);
 
186
                                case Xwt.Popover.Position.Bottom:
 
187
                                        return new Rectangle (bounds.X, bounds.Y, bounds.Width, bounds.Height - arrowPadding);
 
188
                                }
 
189
                                return bounds;
 
190
                        }
 
191
                }
 
192
                
 
193
                PopoverWindow popover;
 
194
                IPopoverEventSink sink;
 
195
                Popover frontend;
 
196
 
 
197
                public void Initialize (IPopoverEventSink sink)
 
198
                {
 
199
                        this.sink = sink;
 
200
                }
 
201
 
 
202
                public void InitializeBackend (object frontend)
 
203
                {
 
204
                        this.frontend = (Popover) frontend;
 
205
                }
 
206
                
 
207
                public void EnableEvent (object eventId)
 
208
                {
 
209
                }
 
210
                
 
211
                public void DisableEvent (object eventId)
 
212
                {
 
213
                }
 
214
 
 
215
                public void Show (Xwt.Popover.Position orientation, Xwt.Widget reference, Xwt.Rectangle positionRect, Widget child)
 
216
                {
 
217
                        var parent = reference.ParentWindow;
 
218
                        popover = new PopoverWindow ((Gtk.Widget)((WidgetBackend)Xwt.Engine.WidgetRegistry.GetBackend (child)).NativeWidget, orientation);
 
219
                        popover.SetPadding (frontend.Padding);
 
220
                        popover.TransientFor = ((WindowFrameBackend)Xwt.Engine.WidgetRegistry.GetBackend (parent)).Window;
 
221
                        popover.DestroyWithParent = true;
 
222
                        popover.Hidden += (o, args) => {
 
223
                                popover.ReleaseInnerWidget ();
 
224
                                sink.OnClosed ();
 
225
                                popover.Destroy ();
 
226
                        };
 
227
                        
 
228
                        var position = new Point (reference.ScreenBounds.Center.X, popover.ArrowPosition == Popover.Position.Top ? reference.ScreenBounds.Bottom : reference.ScreenBounds.Top);
 
229
                        popover.ShowAll ();
 
230
                        popover.GrabFocus ();
 
231
                        int w, h;
 
232
                        popover.GetSize (out w, out h);
 
233
                        popover.Move ((int)position.X - w / 2, (int)position.Y);
 
234
                        popover.SizeAllocated += (o, args) => { popover.Move ((int)position.X - args.Allocation.Width / 2, (int)position.Y); popover.GrabFocus (); };
 
235
                }
 
236
 
 
237
                public void Hide ()
 
238
                {
 
239
                        popover.Hide ();
 
240
                }
 
241
                
 
242
                public void Dispose ()
 
243
                {
 
244
                }
 
245
        }
 
246
}
 
 
b'\\ No newline at end of file'