~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to src/addins/MonoDevelop.SourceEditor2/MonoDevelop.SourceEditor/DropDownBox.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// 
2
 
// DropDownBox.cs
3
 
//  
4
 
// Author:
5
 
//       Mike KrĆ¼ger <mkrueger@novell.com>
6
 
// 
7
 
// Copyright (c) 2009 Novell, Inc (http://www.novell.com)
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
 
using System.ComponentModel;
29
 
using Gtk;
30
 
 
31
 
namespace MonoDevelop.SourceEditor
32
 
{
33
 
        [Category ("Widgets")]
34
 
        [ToolboxItem (true)]
35
 
        public class DropDownBox : Gtk.Button
36
 
        {
37
 
                Pango.Layout layout;
38
 
                const int pixbufSpacing = 2;
39
 
                const int leftSpacing   = 2;
40
 
                const int ySpacing   = 1;
41
 
                
42
 
                public string Text {
43
 
                        get {
44
 
                                return layout.Text;
45
 
                        }
46
 
                        set {
47
 
                                layout.SetText (value);
48
 
//                              QueueResize ();
49
 
                        }
50
 
                }
51
 
                
52
 
                public DropDownBoxListWindow.IListDataProvider DataProvider {
53
 
                        get;
54
 
                        set;
55
 
                }
56
 
                
57
 
                public bool DrawRightBorder {
58
 
                        get;
59
 
                        set;
60
 
                }
61
 
                
62
 
                public Gdk.Pixbuf Pixbuf {
63
 
                        get;
64
 
                        set;
65
 
                }
66
 
                
67
 
                public object CurrentItem {
68
 
                        get;
69
 
                        set;
70
 
                }
71
 
                
72
 
                int defaultIconHeight, defaultIconWidth;
73
 
                
74
 
                /// <summary>
75
 
                /// This is so that the height doesn't jump around depending whether there's an icon assigned or not.
76
 
                /// </summary>
77
 
                public int DefaultIconHeight {
78
 
                        get { return defaultIconHeight; }
79
 
                        set {
80
 
                                defaultIconHeight = value;
81
 
                        }
82
 
                }
83
 
                
84
 
                public int DefaultIconWidth  {
85
 
                        get { return defaultIconWidth; }
86
 
                        set {
87
 
                                defaultIconWidth = value;
88
 
                        }
89
 
                }
90
 
                
91
 
                public DropDownBox ()
92
 
                {
93
 
                        layout = new Pango.Layout (this.PangoContext);
94
 
                        this.Events = Gdk.EventMask.KeyPressMask | Gdk.EventMask.FocusChangeMask | Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask | Gdk.EventMask.LeaveNotifyMask;
95
 
                        this.CanFocus = true;
96
 
                        BorderWidth = 0;
97
 
                }
98
 
                
99
 
                void PositionListWindow ()
100
 
                {
101
 
                        if (window == null)
102
 
                                return;
103
 
                        int ox, oy;
104
 
                        ParentWindow.GetOrigin (out ox, out oy);
105
 
                        int dx = ox + this.Allocation.X;
106
 
                        int dy = oy + this.Allocation.Bottom;
107
 
                        window.WidthRequest = Allocation.Width;
108
 
                        int width, height;
109
 
                        window.GetSizeRequest (out width, out height);
110
 
                        Gdk.Rectangle geometry = Screen.GetMonitorGeometry (Screen.GetMonitorAtPoint (dx, dy));
111
 
                        
112
 
                        if (dy + height > geometry.Bottom)
113
 
                                dy = oy + this.Allocation.Y - height;
114
 
                        if (dx + width > geometry.Right)
115
 
                                dx = geometry.Right - width;
116
 
                        
117
 
                        window.Move (dx, dy);
118
 
                        window.GetSizeRequest (out width, out height);
119
 
                        window.GrabFocus ();
120
 
                }
121
 
                
122
 
                public void SetItem (string text, Gdk.Pixbuf icon, object currentItem)
123
 
                {
124
 
                        if (currentItem != CurrentItem) {// don't update when the same item is set.
125
 
                                this.Text = text;
126
 
                                this.CurrentItem = currentItem;
127
 
                                this.Pixbuf = icon;
128
 
                                this.QueueDraw ();
129
 
                        }
130
 
                        
131
 
                        if (ItemSet != null)
132
 
                                ItemSet (this, EventArgs.Empty);
133
 
                }
134
 
                
135
 
                public void SetItem (int i)
136
 
                {
137
 
                        SetItem (DataProvider.GetText (i), DataProvider.GetIcon (i), DataProvider.GetTag (i));
138
 
                }
139
 
                
140
 
                protected override void OnDestroyed ()
141
 
                {
142
 
                        DestroyWindow ();
143
 
                        if (layout != null) {
144
 
                                layout.Dispose ();
145
 
                                layout = null;
146
 
                        }
147
 
                        base.OnDestroyed ();
148
 
                }
149
 
                
150
 
                
151
 
                protected override void OnSizeRequested (ref Requisition requisition)
152
 
                {
153
 
                        int width, height;
154
 
                        layout.GetPixelSize (out width, out height);
155
 
                        
156
 
                        if (Pixbuf != null) {
157
 
                                width += Pixbuf.Width + pixbufSpacing * 2;
158
 
                                height = System.Math.Max (height, Pixbuf.Height);
159
 
                        } else {
160
 
                                height = System.Math.Max (height, defaultIconHeight);
161
 
                        }
162
 
                        
163
 
                        if (DrawRightBorder)
164
 
                                width += 2;
165
 
                        int arrowHeight = height / 2; 
166
 
                        int arrowWidth = arrowHeight + 1;
167
 
                        
168
 
                        requisition.Width = width + arrowWidth + leftSpacing;
169
 
                        requisition.Height = height + ySpacing * 2;
170
 
                }
171
 
                
172
 
                protected override bool OnFocusOutEvent (Gdk.EventFocus evnt)
173
 
                {
174
 
                        DestroyWindow ();
175
 
                        return base.OnFocusOutEvent (evnt);
176
 
                }
177
 
 
178
 
                
179
 
                DropDownBoxListWindow window = null;
180
 
                internal void DestroyWindow ()
181
 
                {
182
 
                        if (window != null) {
183
 
                                window.Destroy ();
184
 
                                window = null;
185
 
                                QueueDraw ();
186
 
                        }
187
 
                }
188
 
                
189
 
                protected override bool OnKeyPressEvent (Gdk.EventKey evnt)
190
 
                {
191
 
                        if (evnt.Key == Gdk.Key.Escape) {
192
 
                                DestroyWindow (); 
193
 
                                return true;
194
 
                        }
195
 
                        if (window != null && window.ProcessKey (evnt.Key, evnt.State))
196
 
                                return true;
197
 
                        return base.OnKeyPressEvent (evnt);
198
 
                }
199
 
                
200
 
                protected override bool OnLeaveNotifyEvent (Gdk.EventCrossing evnt)
201
 
                {
202
 
                        QueueDraw ();
203
 
                        return base.OnLeaveNotifyEvent (evnt);
204
 
                }
205
 
                
206
 
                protected override bool OnButtonPressEvent (Gdk.EventButton e)
207
 
                {
208
 
                        if (e.Button == 3) {
209
 
                                StatusBox.ShowNavigationBarContextMenu ();
210
 
                                return true;
211
 
                        }
212
 
                        if (e.Type == Gdk.EventType.ButtonPress) {
213
 
                                if (window != null) {
214
 
                                        DestroyWindow ();
215
 
                                } else {
216
 
                                        this.GrabFocus ();
217
 
                                        if (DataProvider != null) {
218
 
                                                DataProvider.Reset ();
219
 
                                                if (DataProvider.IconCount > 0) {
220
 
                                                        window = new DropDownBoxListWindow (this);
221
 
                                                        PositionListWindow ();
222
 
                                                        window.SelectItem (CurrentItem);
223
 
                                                }
224
 
                                        }
225
 
                                }
226
 
                        }
227
 
                        return base.OnButtonPressEvent (e);
228
 
                }
229
 
                
230
 
                protected override void OnStateChanged (StateType previous_state)
231
 
                {
232
 
                        base.OnStateChanged (previous_state);
233
 
                }
234
 
 
235
 
                protected override bool OnButtonReleaseEvent (Gdk.EventButton e)
236
 
                {
237
 
                        return base.OnButtonReleaseEvent (e);
238
 
                }
239
 
                
240
 
                protected override bool OnMotionNotifyEvent (Gdk.EventMotion e)
241
 
                {
242
 
                        QueueDraw ();
243
 
                        return base.OnMotionNotifyEvent (e);
244
 
                }
245
 
        
246
 
                protected override bool OnExposeEvent (Gdk.EventExpose args)
247
 
                {
248
 
                        Gdk.Drawable win = args.Window;
249
 
                
250
 
                        int width, height;
251
 
                        layout.GetPixelSize (out width, out height);
252
 
                        
253
 
                        int arrowHeight = height / 2; 
254
 
                        int arrowWidth = arrowHeight + 1;
255
 
                        int arrowXPos = this.Allocation.X + this.Allocation.Width - arrowWidth;
256
 
                        if (DrawRightBorder)
257
 
                                arrowXPos -= 2;
258
 
                        
259
 
                        //HACK: don't ever draw insensitive, only active/prelight/normal, because insensitive generally looks really ugly
260
 
                        //this *might* cause some theme issues with the state of the text/arrows rendering on top of it
261
 
                        var state = window != null? StateType.Active
262
 
                                : State == StateType.Insensitive? StateType.Normal : State;
263
 
                        
264
 
                        //HACK: paint the button background as if it were bigger, but it stays clipped to the real area,
265
 
                        // so we get the content but not the border. This might break with crazy themes.
266
 
                        //FIXME: we can't use the style's actual internal padding because GTK# hasn't wrapped GtkBorder AFAICT
267
 
                        // (default-border, inner-border, default-outside-border, etc - see http://git.gnome.org/browse/gtk+/tree/gtk/gtkbutton.c)
268
 
                        const int padding = 4;
269
 
                        Style.PaintBox (Style, args.Window, state, ShadowType.None, args.Area, this, "button", 
270
 
                                        Allocation.X - padding, Allocation.Y - padding, Allocation.Width + padding * 2, Allocation.Height + padding * 2);
271
 
                        
272
 
                        int xPos = Allocation.Left;
273
 
                        if (Pixbuf != null) {
274
 
                                win.DrawPixbuf (this.Style.BaseGC (StateType.Normal), Pixbuf, 0, 0, xPos + pixbufSpacing, Allocation.Y + (Allocation.Height - Pixbuf.Height) / 2, Pixbuf.Width, Pixbuf.Height, Gdk.RgbDither.None, 0, 0);
275
 
                                xPos += Pixbuf.Width + pixbufSpacing * 2;
276
 
                        }
277
 
                        
278
 
                        //constrain the text area so it doesn't get rendered under the arrows
279
 
                        var textArea = new Gdk.Rectangle (xPos, Allocation.Y + ySpacing, arrowXPos - xPos - 2, Allocation.Height - ySpacing);
280
 
                        Style.PaintLayout (Style, win, state, true, textArea, this, "", textArea.X, textArea.Y, layout);
281
 
                        
282
 
                        state = Sensitive ? StateType.Normal : StateType.Insensitive;
283
 
                        Gtk.Style.PaintArrow (this.Style, win, state, ShadowType.None, args.Area, this, "", ArrowType.Up, true, arrowXPos, Allocation.Y + (Allocation.Height) / 2 - arrowHeight, arrowWidth, arrowHeight);
284
 
                        Gtk.Style.PaintArrow (this.Style, win, state, ShadowType.None, args.Area, this, "", ArrowType.Down, true, arrowXPos, Allocation.Y + (Allocation.Height) / 2, arrowWidth, arrowHeight);
285
 
                        if (DrawRightBorder)
286
 
                                win.DrawLine (this.Style.DarkGC (StateType.Normal), Allocation.X + Allocation.Width - 1, Allocation.Y, Allocation.X + Allocation.Width - 1, Allocation.Y + Allocation.Height);                  
287
 
                        return false;
288
 
                }
289
 
                
290
 
                public EventHandler ItemSet;
291
 
        }
292
 
}