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

« back to all changes in this revision

Viewing changes to src/core/MonoDevelop.Ide/MonoDevelop.Components/DropDownBoxListWindow.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:
30
30
using Gtk;
31
31
using Mono.TextEditor;
32
32
using MonoDevelop.Ide.TypeSystem;
 
33
using System.Text;
33
34
 
34
35
namespace MonoDevelop.Components
35
36
{
36
37
        public class DropDownBoxListWindow : Window
37
38
        {
38
 
                HBox hBox;
39
 
                VScrollbar vScrollbar;
 
39
                ScrolledWindow vScrollbar;
40
40
                internal ListWidget list;
41
41
                
42
42
                public IListDataProvider DataProvider {
51
51
                        this.TypeHint = Gdk.WindowTypeHint.Menu;
52
52
                        this.BorderWidth = 1;
53
53
                        this.Events |= Gdk.EventMask.KeyPressMask;
54
 
                        hBox = new HBox ();
55
54
                        list = new ListWidget (this);
56
55
                        list.SelectItem += delegate {
57
56
                                var sel = list.Selection;
60
59
                                        Destroy ();
61
60
                                }
62
61
                        };
63
 
                        
64
 
                        list.ScrollEvent += HandleListScrollEvent;
65
 
                        list.SizeAllocated += delegate {
66
 
                                QueueResize ();
67
 
                        };
68
 
                        list.PageChanged += HandleListPageChanged;
69
 
                        hBox.PackStart (list, true, true, 0);
70
 
                        
71
 
                        vScrollbar = new VScrollbar (null);
72
 
                        vScrollbar.ValueChanged += delegate {
73
 
                                list.ForcePage ((int)vScrollbar.Value);
74
 
                        };
75
 
                        
76
 
                        hBox.PackStart (vScrollbar, false, false, 0);
77
 
                        Add (hBox);
78
 
                        ShowAll ();
79
 
                }
80
 
 
81
 
                void HandleListScrollEvent (object o, ScrollEventArgs args)
82
 
                {
83
 
                        if (!vScrollbar.Visible)
84
 
                                return;
85
 
                        
86
 
                        var adj = vScrollbar.Adjustment;
87
 
                        var alloc = Allocation;
88
 
                        
89
 
                        //This widget is a special case because it's always aligned to items as it scrolls.
90
 
                        //Although this means we can't use the pixel deltas for true smooth scrolling, we 
91
 
                        //can still make use of the effective scrolling velocity by basing the calculation 
92
 
                        //on pixels and rounding to the nearest item.
93
 
                        
94
 
                        double dx, dy;
95
 
                        args.Event.GetPageScrollPixelDeltas (0, alloc.Height, out dx, out dy);
96
 
                        if (dy == 0)
97
 
                                return;
98
 
                        
99
 
                        var itemDelta = dy / (alloc.Height / adj.PageSize);
100
 
                        double discreteItemDelta = System.Math.Round (itemDelta);
101
 
                        if (discreteItemDelta == 0.0 && dy != 0.0)
102
 
                                discreteItemDelta = dy > 0? 1.0 : -1.0;
103
 
                        
104
 
                        adj.AddValueClamped (discreteItemDelta);
105
 
                        args.RetVal = true;
106
 
                }
107
 
 
108
 
                void HandleListPageChanged (object sender, EventArgs e)
109
 
                {
110
 
                        vScrollbar.Value = list.Page;
111
 
                }
112
 
                
 
62
                        SetSizeRequest (list.WidthRequest, list.HeightRequest);
 
63
                        vScrollbar = new ScrolledWindow ();
 
64
                        vScrollbar.VScrollbar.SizeAllocated += (object o, SizeAllocatedArgs args) => {
 
65
                                var minWidth = list.WidthRequest + args.Allocation.Width;
 
66
                                if (this.Allocation.Width < minWidth)
 
67
                                        SetSizeRequest (minWidth, list.HeightRequest);
 
68
                        };
 
69
                        vScrollbar.Child = list;
 
70
                        var vbox = new VBox ();
 
71
                        vbox.PackStart (vScrollbar, true, true, 0);
 
72
                        Add (vbox);
 
73
                }
 
74
 
113
75
                public void SelectItem (object item)
114
76
                {
115
77
                        for (int i = 0; i < DataProvider.IconCount; i++) {
116
78
                                if (DataProvider.GetTag (i) == item) {
117
79
                                        list.Selection = i;
118
 
                                        list.Page = Math.Max (0, i - list.VisibleRows / 2);
119
 
                                        vScrollbar.Value = list.Page;
120
 
                                        QueueDraw ();
 
80
                                        vScrollbar.Vadjustment.Value = Math.Max (0, i * list.RowHeight - vScrollbar.Vadjustment.PageSize / 2);
121
81
                                        break;
122
82
                                }
123
83
                        }
136
96
                        Gdk.Pointer.Ungrab (Gtk.Global.CurrentEventTime);
137
97
                        base.OnUnmapped ();
138
98
                }
139
 
                
 
99
 
 
100
                void SwitchToSeletedWord ()
 
101
                {
 
102
                        string selection = list.WordSelection.ToString ();
 
103
                        for (int i = 0; i < DataProvider.IconCount; i++) {
 
104
                                if (DataProvider.GetMarkup (i).StartsWith (selection, StringComparison.OrdinalIgnoreCase)) {
 
105
                                        list.Selection = i;
 
106
                                        list.WordSelection.Append (selection);
 
107
                                }
 
108
                        } 
 
109
                }
 
110
 
140
111
                public bool ProcessKey (Gdk.Key key, Gdk.ModifierType modifier)
141
112
                {
142
113
                        switch (key) {
143
 
                                case Gdk.Key.Up:
144
 
                                        if (list.SelectionDisabled)
145
 
                                                list.SelectionDisabled = false;
146
 
                                        else
147
 
                                                list.Selection --;
148
 
                                        vScrollbar.Value = list.Page;
149
 
                                        return true;
150
 
                                        
151
 
                                case Gdk.Key.Down:
152
 
                                        if (list.SelectionDisabled)
153
 
                                                list.SelectionDisabled = false;
154
 
                                        else
155
 
                                                list.Selection ++;
156
 
                                        vScrollbar.Value = list.Page;
157
 
                                        return true;
158
 
                                        
159
 
                                case Gdk.Key.Page_Up:
160
 
                                        list.Selection -= list.VisibleRows - 1;
161
 
                                        vScrollbar.Value = list.Page;
162
 
                                        return true;
163
 
                                        
164
 
                                case Gdk.Key.Page_Down:
165
 
                                        list.Selection += list.VisibleRows - 1;
166
 
                                        vScrollbar.Value = list.Page;
167
 
                                        return true;
168
 
                                
169
 
                                case Gdk.Key.Home:
170
 
                                        vScrollbar.Value = list.Selection = (int)vScrollbar.Adjustment.Lower;
171
 
                                        return true;
172
 
                                
173
 
                                case Gdk.Key.End:
174
 
                                        vScrollbar.Value = (int)vScrollbar.Adjustment.Upper;
175
 
                                        list.Selection = DataProvider.IconCount;
176
 
                                        return true;
177
 
                                                                
178
 
                                case Gdk.Key.Return:
179
 
                                case Gdk.Key.ISO_Enter:
180
 
                                case Gdk.Key.Key_3270_Enter:
181
 
                                case Gdk.Key.KP_Enter:
182
 
                                        list.OnSelectItem (EventArgs.Empty);
183
 
                                        return true;
 
114
                        case Gdk.Key.Up:
 
115
                                if (list.SelectionDisabled)
 
116
                                        list.SelectionDisabled = false;
 
117
                                else
 
118
                                        list.Selection --;
 
119
                                return true;
 
120
                                
 
121
                        case Gdk.Key.Down:
 
122
                                if (list.SelectionDisabled)
 
123
                                        list.SelectionDisabled = false;
 
124
                                else
 
125
                                        list.Selection ++;
 
126
                                return true;
 
127
                                
 
128
                        case Gdk.Key.Page_Up:
 
129
                                list.Selection -= list.VisibleRows - 1;
 
130
                                return true;
 
131
                                
 
132
                        case Gdk.Key.Page_Down:
 
133
                                list.Selection += list.VisibleRows - 1;
 
134
                                return true;
 
135
 
 
136
                        case Gdk.Key.Home:
 
137
                                list.Selection = (int)0;
 
138
                                return true;
 
139
                        
 
140
                        case Gdk.Key.End:
 
141
                                list.Selection = DataProvider.IconCount;
 
142
                                return true;
 
143
                                                        
 
144
                        case Gdk.Key.Escape:
 
145
                                Destroy ();
 
146
                                return true;
 
147
                                
 
148
                        case Gdk.Key.Return:
 
149
                        case Gdk.Key.ISO_Enter:
 
150
                        case Gdk.Key.Key_3270_Enter:
 
151
                        case Gdk.Key.KP_Enter:
 
152
                                list.OnSelectItem (EventArgs.Empty);
 
153
                                return true;
 
154
                        default:
 
155
                                char ch = (char)key;
 
156
                                if (char.IsLetterOrDigit (ch)) {
 
157
                                        list.WordSelection.Append (ch);
 
158
                                        SwitchToSeletedWord ();
 
159
                                }
 
160
                                break;
184
161
                        }
185
162
                        
186
163
                        return false;
187
164
                }
188
 
                
189
 
                protected override void OnSizeRequested (ref Requisition requisition)
190
 
                {
191
 
                        base.OnSizeRequested (ref requisition);
192
 
                        var upper = Math.Max (0, DataProvider.IconCount);
193
 
                        var pageStep = list.VisibleRows;
194
 
                        vScrollbar.Adjustment.SetBounds (0, upper, 1, pageStep, pageStep);
195
 
                        
196
 
                        if (list.VisibleRows >= DataProvider.IconCount && vScrollbar.Parent == hBox)
197
 
                                hBox.Remove (vScrollbar);
198
 
                
199
 
                        requisition.Height = this.list.HeightRequest + 2;
200
 
                        int width;
201
 
                        if (WidthRequest >= 0) {
202
 
                                width = WidthRequest;
203
 
                        } else {
204
 
                                width = this.list.CalcWidth ();
205
 
                                if (list.VisibleRows < DataProvider.IconCount)
206
 
                                        width += vScrollbar.Allocation.Width;
207
 
                        }
208
 
                        requisition.Width = width;
209
 
                }
210
 
 
211
 
                protected override bool OnExposeEvent (Gdk.EventExpose args)
212
 
                {
213
 
                        bool result = base.OnExposeEvent (args);
214
 
                        args.Window.DrawRectangle (Style.MidGC (Gtk.StateType.Normal), false, 0, 0, this.Allocation.Width - 1, this.Allocation.Height - 1);
215
 
                        return result;
216
 
                }
217
165
 
218
166
                protected override bool OnFocusOutEvent (Gdk.EventFocus evnt)
219
167
                {
223
171
                
224
172
                protected override bool OnButtonPressEvent (Gdk.EventButton evnt)
225
173
                {
226
 
                        Destroy ();
 
174
                        if (left)
 
175
                                Destroy ();
227
176
                        return base.OnButtonPressEvent (evnt);
228
177
                }
229
178
 
 
179
 
 
180
                bool left = true;
 
181
                protected override bool OnLeaveNotifyEvent (Gdk.EventCrossing evnt)
 
182
                {
 
183
                        left = true;
 
184
                        return base.OnLeaveNotifyEvent (evnt);
 
185
                }
 
186
 
 
187
                protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt)
 
188
                {
 
189
                        if (evnt.Window == this.GdkWindow)
 
190
                                left = false;
 
191
                        return base.OnEnterNotifyEvent (evnt);
 
192
                }
 
193
 
230
194
                protected override bool OnKeyPressEvent (Gdk.EventKey evnt)
231
195
                {
232
196
                        ProcessKey (evnt.Key, evnt.State);
242
206
                        Pango.Layout layout;
243
207
                        DropDownBoxListWindow win;
244
208
                        int selection = 0;
245
 
                        int page = 0;
246
 
                        
 
209
 
247
210
                        int rowHeight;
 
211
 
 
212
                        public int RowHeight {
 
213
                                get {
 
214
                                        return rowHeight;
 
215
                                }
 
216
                        }
 
217
 
248
218
                //      bool buttonPressed;
249
219
                        bool disableSelection;
250
220
        
256
226
                                this.Events = Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask | Gdk.EventMask.LeaveNotifyMask;
257
227
                                layout = new Pango.Layout (this.PangoContext);
258
228
                                CalcRowHeight ();
 
229
                                CalcVisibleRows ();
259
230
                        }
260
231
                        
261
232
                        void CalcRowHeight ()
264
235
                                int rowWidth;
265
236
                                layout.GetPixelSize (out rowWidth, out rowHeight);
266
237
                                rowHeight += padding;
 
238
                                SetBounds (Allocation);
267
239
                        }
268
240
                        
269
241
                        protected override bool OnLeaveNotifyEvent (Gdk.EventCrossing evnt)
294
266
                                        selection = -1;
295
267
                                else
296
268
                                        selection = 0;
297
 
        
298
 
                                page = 0;
 
269
                                CalcVisibleRows ();
299
270
                                disableSelection = false;
300
271
                                if (IsRealized) {
301
272
                                        UpdateStyle ();
303
274
                                }
304
275
                                if (SelectionChanged != null) SelectionChanged (this, EventArgs.Empty);
305
276
                        }
306
 
                        
 
277
                        StringBuilder wordSelection = new StringBuilder ();
 
278
 
 
279
                        public StringBuilder WordSelection {
 
280
                                get {
 
281
                                        return wordSelection;
 
282
                                }
 
283
                        }
 
284
 
307
285
                        public int Selection
308
286
                        {
309
287
                                get {
311
289
                                }
312
290
                                
313
291
                                set {
 
292
                                        wordSelection.Length = 0;
314
293
                                        var newValue = Math.Max (0, Math.Min (value, win.DataProvider.IconCount - 1));
315
294
                                        
316
295
                                        if (newValue != selection) {
330
309
                        
331
310
                        void UpdatePage ()
332
311
                        {
333
 
                                if (!IsRealized) {
334
 
                                        page = 0;
 
312
                                var area = GetRowArea (selection);
 
313
                                if (area.Y < vadj.Value) {
 
314
                                        vadj.Value = area.Y;
335
315
                                        return;
336
316
                                }
337
 
                                
338
 
                                if (selection < page || selection >= page + VisibleRows) {
339
 
                                        page = selection - (VisibleRows / 2);
340
 
                                        if (page < 0) 
341
 
                                                page = 0;
 
317
                                if (vadj.Value + Allocation.Height < area.Bottom) {
 
318
                                        vadj.Value = System.Math.Max (0, area.Bottom - vadj.PageSize + 1);
342
319
                                }
343
 
                                Page = System.Math.Max (0, System.Math.Min (page, win.DataProvider.IconCount - VisibleRows));
344
320
                        }
345
321
                        
346
322
                        public bool SelectionDisabled {
350
326
                                        this.QueueDraw ();
351
327
                                }
352
328
                        }
353
 
                        
354
 
                        public int Page {
355
 
                                get { 
356
 
                                        return page; 
357
 
                                }
358
 
                                set {
359
 
                                        if (page == value)
360
 
                                                return;
361
 
                                        page = value;
362
 
                                        UpdatePage ();
363
 
                                        OnPageChanged (EventArgs.Empty);
364
 
                                        this.QueueDraw ();
365
 
                                }
366
 
                        }
367
 
                        
368
 
                        internal void ForcePage (int page)
369
 
                        {
370
 
                                this.page = System.Math.Max (0, System.Math.Min (page, win.DataProvider.IconCount - VisibleRows));
371
 
                                OnPageChanged (EventArgs.Empty);
372
 
                                this.QueueDraw ();
373
 
                        }
374
 
                        
375
 
                        protected virtual void OnPageChanged (EventArgs e)
376
 
                        {
377
 
                                EventHandler handler = this.PageChanged;
378
 
                                if (handler != null)
379
 
                                        handler (this, e);
380
 
                        }
381
 
                        
382
 
                        public event EventHandler PageChanged;
383
 
                        
 
329
 
384
330
                        protected override bool OnButtonPressEvent (Gdk.EventButton e)
385
331
                        {
386
332
                                Selection = GetRowByPosition ((int) e.Y);
421
367
                        {
422
368
                                base.OnExposeEvent (args);
423
369
                                DrawList ();
424
 
                                return true;
 
370
                                return false;
425
371
                        }
426
372
        
427
373
                        void DrawList ()
433
379
                                int lineWidth = winWidth - margin * 2;
434
380
                                int xpos = margin + padding;
435
381
 
436
 
                                int n = 0;
437
 
                                while (ypos < winHeight - margin && (page + n) < win.DataProvider.IconCount) {
438
 
                                        string text = win.DataProvider.GetMarkup (page + n) ?? "&lt;null&gt;";
 
382
                                int n = (int)(vadj.Value / rowHeight);
 
383
                                while (ypos < winHeight - margin && n < win.DataProvider.IconCount) {
 
384
                                        string text = win.DataProvider.GetMarkup (n) ?? "&lt;null&gt;";
439
385
                                        layout.SetMarkup (text);
440
386
 
441
 
                                        Gdk.Pixbuf icon = win.DataProvider.GetIcon (page + n);
 
387
                                        Gdk.Pixbuf icon = win.DataProvider.GetIcon (n);
442
388
                                        int iconHeight = icon != null ? icon.Height : 24;
443
389
                                        int iconWidth = icon != null ? icon.Width : 0;
444
390
 
462
408
                                        typos = he < rowHeight ? ypos + (rowHeight - he) / 2 : ypos;
463
409
                                        iypos = iconHeight < rowHeight ? ypos + (rowHeight - iconHeight) / 2 : ypos;
464
410
                                        
465
 
                                        if (page + n == selection) {
 
411
                                        if (n == selection) {
466
412
                                                if (!disableSelection) {
467
413
                                                        this.GdkWindow.DrawRectangle (this.Style.BaseGC (StateType.Selected), 
468
414
                                                                                      true, margin, ypos, lineWidth, he + padding);
492
438
                        
493
439
                        int GetRowByPosition (int ypos)
494
440
                        {
495
 
                                return page + (ypos-margin) / rowHeight;
 
441
                                return (int)(vadj.Value + ypos) / rowHeight;
496
442
                        }
497
 
                        
 
443
 
498
444
                        public Gdk.Rectangle GetRowArea (int row)
499
445
                        {
500
 
                                row -= page;
501
 
                                int winWidth, winHeight;
502
 
                                this.GdkWindow.GetSize (out winWidth, out winHeight);
503
 
                                
504
 
                                return new Gdk.Rectangle (margin, margin + rowHeight * row, winWidth, rowHeight);
 
446
                                return new Gdk.Rectangle (0, row * rowHeight, Allocation.Width, rowHeight - 1);
505
447
                        }
506
448
                        
507
449
                        public int VisibleRows {
509
451
                                        return Allocation.Height / rowHeight;
510
452
                                }
511
453
                        }
512
 
                        
 
454
 
 
455
                        const int maxVisibleRows = 8;
513
456
                        void CalcVisibleRows ()
514
457
                        {
515
 
                                Gdk.Rectangle geometry = DesktopService.GetUsableMonitorGeometry (Screen, Screen.GetMonitorAtWindow (GdkWindow));
516
 
                                int winHeight = geometry.Height / 2;
517
458
                                int lvWidth, lvHeight;
518
459
                                this.GetSizeRequest (out lvWidth, out lvHeight);
519
460
                                if (layout == null)
520
461
                                        return;
521
 
                                
522
 
                                int visibleRows = (winHeight + padding - margin * 2) / rowHeight;
 
462
 
523
463
                                int newHeight;
524
 
        
525
 
                                if (this.win.DataProvider.IconCount > visibleRows)
526
 
                                        newHeight = (rowHeight * visibleRows) + margin * 2;
 
464
                                if (this.win.DataProvider.IconCount > maxVisibleRows)
 
465
                                        newHeight = (rowHeight * maxVisibleRows) + margin * 2;
527
466
                                else
528
467
                                        newHeight = (rowHeight * this.win.DataProvider.IconCount) + margin * 2;
529
 
                                
530
 
                                if (lvWidth != listWidth || lvHeight != newHeight) {
531
 
                                        this.SetSizeRequest (listWidth, newHeight);
532
 
                                }
 
468
                                listWidth = Math.Min (450, CalcWidth ());
 
469
                                this.SetSizeRequest (listWidth, newHeight);
533
470
                        } 
534
471
                        internal int CalcWidth ()
535
472
                        {
554
491
                                return w;
555
492
                        }
556
493
 
 
494
                        void SetBounds (Gdk.Rectangle allocation)
 
495
                        {
 
496
                                if (vadj == null)
 
497
                                        return;
 
498
                                var h = allocation.Height;
 
499
                                var height = Math.Max (h, rowHeight * win.DataProvider.IconCount);
 
500
                                if (this.win.DataProvider.IconCount < maxVisibleRows) {
 
501
                                        vadj.SetBounds (0, h, 0, 0, h);
 
502
                                } else {
 
503
                                        vadj.SetBounds (0, height, RowHeight, h, h);
 
504
                                }
 
505
                        }
 
506
 
557
507
                        protected override void OnSizeAllocated (Gdk.Rectangle allocation)
558
508
                        {
559
509
                                base.OnSizeAllocated (allocation);
 
510
 
 
511
                                hadj.SetBounds (0, allocation.Width, 0, 0, allocation.Width);
 
512
 
 
513
                                SetBounds (allocation);
 
514
 
560
515
                                UpdatePage ();
561
516
                        }
562
517
                        
577
532
                                CalcRowHeight ();
578
533
                                CalcVisibleRows ();
579
534
                        }
580
 
                        
 
535
 
 
536
                        Adjustment hadj;
 
537
                        Adjustment vadj;
 
538
 
 
539
                        protected override void OnSetScrollAdjustments (Adjustment hadj, Adjustment vadj)
 
540
                        {
 
541
                                this.hadj = hadj;
 
542
                                this.vadj = vadj;
 
543
                                if (this.vadj != null)
 
544
                                        this.vadj.ValueChanged += (sender, e) => QueueDraw ();
 
545
                                base.OnSetScrollAdjustments (hadj, vadj);
 
546
                        }
 
547
 
581
548
                        internal virtual void OnSelectItem (EventArgs e)
582
549
                        {
583
550
                                if (SelectItem != null)