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

« back to all changes in this revision

Viewing changes to src/core/MonoDevelop.Ide/MonoDevelop.Ide.Gui.Components/ExtensibleTreeView.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:
49
49
using MonoDevelop.Ide.Gui.Pads;
50
50
using MonoDevelop.Projects.Extensions;
51
51
using Mono.TextEditor;
 
52
using System.Linq;
52
53
 
53
54
namespace MonoDevelop.Ide.Gui.Components
54
55
{
60
61
                internal const int DataItemColumn     = 3;
61
62
                internal const int BuilderChainColumn = 4;
62
63
                internal const int FilledColumn       = 5;
63
 
                
 
64
                internal const int ShowPopupColumn    = 6;
 
65
 
64
66
                NodeBuilder[] builders;
65
67
                Dictionary<Type, NodeBuilder[]> builderChains = new Dictionary<Type, NodeBuilder[]> ();
66
68
                NodeHashtable nodeHash = new NodeHashtable ();
67
69
                
68
70
                ExtensibleTreeViewTree tree;
69
71
                Gtk.TreeStore store;
70
 
                internal Gtk.TreeViewColumn complete_column;
71
 
                internal ZoomableCellRendererPixbuf pix_render;
72
 
                internal Gtk.CellRendererText text_render;
 
72
                Gtk.TreeViewColumn complete_column;
 
73
                ZoomableCellRendererPixbuf pix_render;
 
74
                CustomCellRendererText text_render;
73
75
                TreeBuilderContext builderContext;
74
76
                Hashtable callbacks = new Hashtable ();
75
77
                bool editingText = false;
76
 
                int customFontSize = -1;
77
 
                
 
78
                bool showSelectionPopupButton;
 
79
                Gtk.TreeIter? lastPopupButtonIter;
 
80
 
78
81
                TreePadOption[] options;
79
82
                TreeOptions globalOptions;
80
83
 
90
93
                int updateLockCount;
91
94
                string contextMenuPath;
92
95
                IDictionary<string,string> contextMenuTypeNameAliases;
93
 
                
 
96
 
94
97
                public IDictionary<string,string> ContextMenuTypeNameAliases {
95
98
                        get { return contextMenuTypeNameAliases; }
96
99
                        set { contextMenuTypeNameAliases = value; }
120
123
                        Initialize (builders, options);
121
124
                }
122
125
                
123
 
                void CustomFontPropertyChanged (object sender, MonoDevelop.Core.PropertyChangedEventArgs prop)
 
126
                void CustomFontPropertyChanged (object sender, EventArgs a)
124
127
                {
125
 
                        string val = (string)prop.NewValue;
126
 
                        string name = !string.IsNullOrEmpty (val) ? val : tree.Style.FontDescription.ToString ();
127
 
                        UpdateCustomFont (name);
 
128
                        UpdateFont ();
128
129
                }
129
130
                
130
 
                void UpdateCustomFont (string name)
 
131
                void UpdateFont ()
131
132
                {
132
 
                        Pango.FontDescription customFont = Pango.FontDescription.FromString (name);
133
 
                        customFontSize = customFont.Size;
134
 
                        if (Zoom != 1)
135
 
                                customFont.Size = (int) (((double) customFont.Size) * Zoom);
136
 
                        text_render.Family = customFont.Family;
137
 
                        text_render.Size = customFont.Size;
138
 
                        customFont.Dispose ();
 
133
                        text_render.CustomFont = IdeApp.Preferences.CustomPadFont ?? tree.Style.FontDescription;
139
134
                        tree.ColumnsAutosize ();
140
135
                }
141
136
                
142
137
                protected override void OnStyleSet (Gtk.Style previous_style)
143
138
                {
144
139
                        base.OnStyleSet (previous_style);
145
 
                        UpdateCustomFont (IdeApp.Preferences.CustomPadFont ?? tree.Style.FontDescription.ToString ());
 
140
                        UpdateFont ();
146
141
                }
147
142
                
148
143
                public void Initialize (NodeBuilder[] builders, TreePadOption[] options)
164
159
                        4 -- Builder chain
165
160
                        5 -- Expanded
166
161
                        */
167
 
                        store = new Gtk.TreeStore (typeof(string), typeof(Gdk.Pixbuf), typeof(Gdk.Pixbuf), typeof(object), typeof(object), typeof(bool));
 
162
                        store = new Gtk.TreeStore (typeof(string), typeof(Gdk.Pixbuf), typeof(Gdk.Pixbuf), typeof(object), typeof(object), typeof(bool), typeof(bool));
168
163
                        tree.Model = store;
169
164
                        tree.Selection.Mode = Gtk.SelectionMode.Multiple;
170
165
                        
183
178
                        complete_column.AddAttribute (pix_render, "image-expander-open", OpenIconColumn);
184
179
                        complete_column.AddAttribute (pix_render, "image-expander-closed", ClosedIconColumn);
185
180
                        
186
 
                        text_render = new Gtk.CellRendererText ();
187
 
                        var customFontName = IdeApp.Preferences.CustomPadFont;
188
 
                        if (customFontName != null) {
189
 
                                Pango.FontDescription customFont = Pango.FontDescription.FromString (customFontName);
190
 
                                text_render.Family = customFont.Family;
191
 
                                text_render.Size = customFont.Size;
192
 
                                customFontSize = customFont.Size;
193
 
                                customFont.Dispose ();
194
 
                        }
 
181
                        text_render = new CustomCellRendererText (this);
195
182
                        text_render.Ypad = 0;
196
183
                        IdeApp.Preferences.CustomPadFontChanged += CustomFontPropertyChanged;;
197
184
                        text_render.EditingStarted += HandleEditingStarted;
199
186
                        text_render.EditingCanceled += HandleOnEditCancelled;
200
187
                        
201
188
                        complete_column.PackStart (text_render, true);
202
 
                        complete_column.AddAttribute (text_render, "markup", TextColumn);
203
 
                        
 
189
                        complete_column.AddAttribute (text_render, "text-markup", TextColumn);
 
190
                        complete_column.AddAttribute (text_render, "show-popup-button", ShowPopupColumn);
 
191
 
204
192
                        tree.AppendColumn (complete_column);
205
193
                        
206
194
                        tree.TestExpandRow += OnTestExpandRow;
212
200
                        
213
201
                        tree.CursorChanged += OnSelectionChanged;
214
202
                        tree.KeyPressEvent += OnKeyPress;
 
203
                        tree.ButtonPressEvent += HandleButtonPressEvent;
 
204
                        tree.MotionNotifyEvent += HandleMotionNotifyEvent;
 
205
                        tree.LeaveNotifyEvent += HandleLeaveNotifyEvent;
215
206
 
216
207
                        if (GtkGestures.IsSupported) {
217
208
                                tree.AddGestureMagnifyHandler ((sender, args) => {
234
225
                        GLib.Timeout.Add (3000, Checker);
235
226
#endif
236
227
                }
237
 
        
238
228
#if TREE_VERIFY_INTEGRITY
239
229
                // Verifies the consistency of the tree view. Disabled by default
240
230
                HashSet<object> ochecked = new HashSet<object> ();
404
394
                        return foundHandler;
405
395
                }
406
396
 
 
397
                [GLib.ConnectBefore]
 
398
                void HandleButtonPressEvent (object o, Gtk.ButtonPressEventArgs args)
 
399
                {
 
400
                        if (ShowSelectionPopupButton && text_render.PointerInButton ((int)args.Event.XRoot, (int)args.Event.YRoot)) {
 
401
                                text_render.Pushed = true;
 
402
                                args.RetVal = true;
 
403
                                var menu = CreateContextMenu ();
 
404
                                if (menu != null) {
 
405
                                        menu.Hidden += HandleMenuHidden;
 
406
                                        GtkWorkarounds.ShowContextMenu (menu, tree, text_render.PopupAllocation);
 
407
                                }
 
408
                        }
 
409
                }
 
410
 
 
411
                [GLib.ConnectBefore]
 
412
                void HandleMotionNotifyEvent (object o, Gtk.MotionNotifyEventArgs args)
 
413
                {
 
414
                        if (ShowSelectionPopupButton) {
 
415
                                text_render.PointerPosition = new Gdk.Point ((int)args.Event.XRoot, (int)args.Event.YRoot);
 
416
                                Gtk.TreePath path;
 
417
                                if (tree.GetPathAtPos ((int)args.Event.X, (int)args.Event.Y, out path)) {
 
418
                                        var area = tree.GetCellArea (path, tree.Columns[0]);
 
419
                                        tree.QueueDrawArea (area.X, area.Y, area.Width, area.Height);
 
420
                                }
 
421
                        }
 
422
                }
 
423
 
 
424
                [GLib.ConnectBefore]
 
425
                void HandleLeaveNotifyEvent (object o, Gtk.LeaveNotifyEventArgs args)
 
426
                {
 
427
                        
 
428
                }
 
429
 
 
430
                void HandleMenuHidden (object sender, EventArgs e)
 
431
                {
 
432
                        ((Gtk.Menu)sender).Hidden -= HandleMenuHidden;
 
433
                        text_render.Pushed = false;
 
434
                        QueueDraw ();
 
435
                }
 
436
                
407
437
                internal void LockUpdates ()
408
438
                {
409
439
                        if (++updateLockCount == 1)
748
778
                        else
749
779
                                return null;
750
780
                }
751
 
                
 
781
 
752
782
                void ExpandCurrentItem ()
753
783
                {
754
784
                        try {
755
785
                                LockUpdates ();
756
 
                                foreach (SelectionGroup grp in GetSelectedNodesGrouped ()) {
 
786
 
 
787
                                IEnumerable<SelectionGroup> nodeGroups = GetSelectedNodesGrouped ();
 
788
                                if (nodeGroups.Count () == 1) {
 
789
                                        SelectionGroup grp = nodeGroups.First ();
 
790
 
 
791
                                        if (grp.Nodes.Count () == 1) {
 
792
                                                ITreeNavigator node = grp.Nodes.First ();
 
793
                                                if (node.Expanded) {
 
794
                                                        grp.SavePositions ();
 
795
                                                        node.Selected = false;
 
796
                                                        if (node.MoveToFirstChild ())
 
797
                                                                node.Selected = true;
 
798
 
 
799
                                                        // This exit statement is so that it doesn't do 2 actions at a time.
 
800
                                                        // As in, navigate, then expand.
 
801
                                                        return;
 
802
                                                }
 
803
                                        }
 
804
                                }
 
805
 
 
806
                                foreach (SelectionGroup grp in nodeGroups) {
757
807
                                        grp.SavePositions ();
 
808
 
758
809
                                        foreach (var node in grp.Nodes) {
759
810
                                                node.Expanded = true;
760
811
                                        }
768
819
                {
769
820
                        try {
770
821
                                LockUpdates ();
771
 
                                foreach (SelectionGroup grp in GetSelectedNodesGrouped ()) {
 
822
 
 
823
                                IEnumerable<SelectionGroup> nodeGroups = GetSelectedNodesGrouped ();
 
824
                                if (nodeGroups.Count () == 1) {
 
825
                                        SelectionGroup grp = nodeGroups.First ();
 
826
 
 
827
                                        if (grp.Nodes.Count () == 1)
 
828
                                        {
 
829
                                                ITreeNavigator node = grp.Nodes.First ();
 
830
                                                if (!node.HasChildren () || !node.Expanded) {
 
831
                                                        grp.SavePositions ();
 
832
                                                        node.Selected = false;
 
833
                                                        if (node.MoveToParent ())
 
834
                                                                node.Selected = true;
 
835
 
 
836
                                                        // This exit statement is so that it doesn't do 2 actions at a time.
 
837
                                                        // As in, navigate, then collapse.
 
838
                                                        return;
 
839
                                                }
 
840
                                        }
 
841
                                }
 
842
 
 
843
                                foreach (SelectionGroup grp in nodeGroups) {
772
844
                                        grp.SavePositions ();
 
845
 
773
846
                                        foreach (var node in grp.Nodes) {
774
847
                                                node.Expanded = false;
775
848
                                        }
844
917
                        return false;
845
918
                }
846
919
                
 
920
                [CommandHandler (ViewCommands.RefreshTree)]
 
921
                public virtual void RefreshCurrentItem ()
 
922
                {
 
923
                        try {
 
924
                                LockUpdates ();
 
925
                                foreach (SelectionGroup grp in GetSelectedNodesGrouped ()) {
 
926
                                        NodeBuilder[] chain = grp.BuilderChain;
 
927
                                        grp.SavePositions ();
 
928
                                        foreach (NodeBuilder b in chain) {
 
929
                                                NodeCommandHandler handler = b.CommandHandler;
 
930
                                                handler.SetCurrentNodes (grp.Nodes.ToArray ());
 
931
                                                if (!grp.RestorePositions ())
 
932
                                                        return;
 
933
                                                handler.RefreshMultipleItems ();
 
934
                                                if (!grp.RestorePositions ())
 
935
                                                        return;
 
936
                                        }
 
937
                                }
 
938
                        } finally {
 
939
                                UnlockUpdates ();
 
940
                        }
 
941
                        RefreshTree ();
 
942
                }
 
943
                
847
944
                protected virtual void OnCurrentItemActivated (EventArgs args)
848
945
                {
849
946
                        if (CurrentItemActivated != null)
883
980
                void OnZoomChanged (double value)
884
981
                {
885
982
                        pix_render.Zoom = value;
886
 
                        if (customFontSize != -1) {
887
 
                                int newSize = customFontSize;
888
 
                                if (value != 1)
889
 
                                        newSize = (int) (((double) customFontSize) * value);
890
 
                                text_render.Size = newSize;
891
 
                        }
 
983
                        text_render.Zoom = value;
 
984
 
892
985
                        int expanderSize = (int) (12 * Zoom);
893
986
                        if (expanderSize < 3) expanderSize = 3;
894
987
                        if (expanderSize > 15) expanderSize = 15;
1157
1250
                                editable.SelectRegion (selectionStart, selectionStart + selectionLength);
1158
1251
                                return false;
1159
1252
                        });
 
1253
                        // Ensure we set all our state variables before calling SetCursor
 
1254
                        // as this may directly invoke HandleOnEditCancelled
1160
1255
                        text_render.Editable = true;
 
1256
                        editingText = true;
1161
1257
                        tree.SetCursor (store.GetPath (iter), complete_column, true);
1162
 
                        
1163
 
                        editingText = true;
1164
1258
                }
1165
1259
 
1166
1260
                Gtk.Editable currentLabelEditable;
1193
1287
                                                                handler.SetCurrentNode (nav);
1194
1288
                                                                handler.RenameItem (e.NewText);
1195
1289
                                                        } catch (Exception ex) {
 
1290
                                                                MessageService.ShowException (ex);
1196
1291
                                                                LoggingService.LogError (ex.ToString ());
1197
1292
                                                        }
1198
1293
                                                        nav.MoveToPosition (pos);
1669
1764
 
1670
1765
                void ShowPopup (Gdk.EventButton evt)
1671
1766
                {
 
1767
                        var menu = CreateContextMenu ();
 
1768
                        if (menu != null)
 
1769
                                IdeApp.CommandService.ShowContextMenu (this, evt, menu, this);
 
1770
                }
 
1771
 
 
1772
                protected Gtk.Menu CreateContextMenu ()
 
1773
                {
1672
1774
                        ITreeNavigator tnav = GetSelectedNode ();
1673
1775
                        if (tnav == null)
1674
 
                                return;
 
1776
                                return null;
1675
1777
                        TypeNodeBuilder nb = GetTypeNodeBuilder (tnav.CurrentPosition._iter);
1676
1778
                        string menuPath = nb != null && nb.ContextMenuAddinPath != null ? nb.ContextMenuAddinPath : contextMenuPath;
1677
1779
                        if (menuPath == null) {
1680
1782
                                        opset.AddItem (ViewCommands.TreeDisplayOptionList);
1681
1783
                                        opset.AddItem (Command.Separator);
1682
1784
                                        opset.AddItem (ViewCommands.ResetTreeDisplayOptions);
1683
 
                                        IdeApp.CommandService.ShowContextMenu (this, evt, opset, this);
 
1785
                                        return IdeApp.CommandService.CreateMenu (opset, this);
1684
1786
                                }
 
1787
                                return null;
1685
1788
                        } else {
1686
1789
                                ExtensionContext ctx = AddinManager.CreateExtensionContext ();
1687
1790
                                ctx.RegisterCondition ("ItemType", new ItemTypeCondition (tnav.DataItem.GetType (), contextMenuTypeNameAliases));
1688
1791
                                CommandEntrySet eset = IdeApp.CommandService.CreateCommandEntrySet (ctx, menuPath);
1689
1792
                                
1690
1793
                                eset.AddItem (Command.Separator);
1691
 
                                CommandEntrySet opset = eset.AddItemSet (GettextCatalog.GetString ("Display Options"));
1692
 
                                opset.AddItem (ViewCommands.TreeDisplayOptionList);
1693
 
                                opset.AddItem (Command.Separator);
1694
 
                                opset.AddItem (ViewCommands.ResetTreeDisplayOptions);
1695
 
                                opset.AddItem (ViewCommands.RefreshTree);
1696
 
                                opset.AddItem (ViewCommands.CollapseAllTreeNodes);
1697
 
                                IdeApp.CommandService.ShowContextMenu (this, evt, eset, this);
 
1794
                                if (!tnav.Clone ().MoveToParent ()) {
 
1795
                                        CommandEntrySet opset = eset.AddItemSet (GettextCatalog.GetString ("Display Options"));
 
1796
                                        opset.AddItem (ViewCommands.TreeDisplayOptionList);
 
1797
                                        opset.AddItem (Command.Separator);
 
1798
                                        opset.AddItem (ViewCommands.ResetTreeDisplayOptions);
 
1799
                                //      opset.AddItem (ViewCommands.CollapseAllTreeNodes);
 
1800
                                }
 
1801
                                eset.AddItem (ViewCommands.RefreshTree);
 
1802
                                return IdeApp.CommandService.CreateMenu (eset, this);
1698
1803
                        }
1699
1804
                }
1700
1805
                
1701
1806
                [CommandUpdateHandler (ViewCommands.TreeDisplayOptionList)]
1702
1807
                protected void BuildTreeOptionsMenu (CommandArrayInfo info)
1703
1808
                {
1704
 
                        ITreeNavigator tnav = GetSelectedNode ();
1705
1809
                        foreach (TreePadOption op in options) {
1706
1810
                                CommandInfo ci = new CommandInfo (op.Label);
1707
1811
                                ci.Checked = globalOptions [op.Id];
1713
1817
                protected void OptionToggled (string optionId)
1714
1818
                {
1715
1819
                        globalOptions [optionId] = !globalOptions [optionId];
1716
 
                        RefreshTree ();
 
1820
                        RefreshRoots ();
1717
1821
                }
1718
 
                
 
1822
 
1719
1823
                [CommandHandler (ViewCommands.ResetTreeDisplayOptions)]
1720
1824
                protected void ResetOptions ()
1721
1825
                {
1722
 
                        foreach (TreeNodeNavigator node in GetSelectedNodes ()) {
1723
 
                                Gtk.TreeIter it = node.CurrentPosition._iter;
1724
 
                                if (store.IterIsValid (it)) {
1725
 
                                        ITreeBuilder tb = CreateBuilder (it);
1726
 
                                        tb.UpdateAll ();
1727
 
                                }
1728
 
                        }
1729
 
                }
1730
 
 
1731
 
                [CommandHandler (ViewCommands.RefreshTree)]
 
1826
                        foreach (TreePadOption op in options)
 
1827
                                globalOptions [op.Id] = op.DefaultValue;
 
1828
 
 
1829
                        RefreshRoots ();
 
1830
                }
 
1831
 
 
1832
                void RefreshRoots ()
 
1833
                {
 
1834
                        Gtk.TreeIter it;
 
1835
                        if (!store.GetIterFirst (out it))
 
1836
                                return;
 
1837
                        do {
 
1838
                                ITreeBuilder tb = CreateBuilder (it);
 
1839
                                tb.UpdateAll ();
 
1840
                        } while (store.IterNext (ref it));
 
1841
                }
 
1842
 
1732
1843
                protected void RefreshTree ()
1733
1844
                {
1734
1845
                        foreach (TreeNodeNavigator node in GetSelectedNodes ()) {
1745
1856
                {
1746
1857
                        tree.CollapseAll();
1747
1858
                }
1748
 
                
 
1859
 
 
1860
                public bool ShowSelectionPopupButton {
 
1861
                        get { return showSelectionPopupButton; }
 
1862
                        set {
 
1863
                                showSelectionPopupButton = value;
 
1864
                                UpdateSelectionPopupButton ();
 
1865
                        }
 
1866
                }
 
1867
 
1749
1868
                [GLib.ConnectBefore]
1750
1869
                void OnKeyPress (object o, Gtk.KeyPressEventArgs args)
1751
1870
                {
1785
1904
                                return;
1786
1905
                        }
1787
1906
 
1788
 
                        if (args.Event.Key == Gdk.Key.Return || args.Event.Key == Gdk.Key.KP_Enter) {
 
1907
                        if (args.Event.Key == Gdk.Key.Return || args.Event.Key == Gdk.Key.KP_Enter || args.Event.Key == Gdk.Key.ISO_Enter) {
1789
1908
                                ActivateCurrentItem ();
1790
1909
                                args.RetVal = true;
1791
1910
                                return;
1825
1944
                {
1826
1945
                        ActivateCurrentItem ();
1827
1946
                }
 
1947
 
 
1948
                void UpdateSelectionPopupButton ()
 
1949
                {
 
1950
                        if (editingText)
 
1951
                                return;
 
1952
 
 
1953
                        if (lastPopupButtonIter != null) {
 
1954
                                if (store.IterIsValid (lastPopupButtonIter.Value))
 
1955
                                        tree.Model.SetValue (lastPopupButtonIter.Value, ShowPopupColumn, false);
 
1956
                                lastPopupButtonIter = null;
 
1957
                        }
 
1958
 
 
1959
                        if (showSelectionPopupButton) {
 
1960
                                var sel = Tree.Selection.GetSelectedRows ();
 
1961
                                if (sel.Length > 0) {
 
1962
                                        Gtk.TreeIter it;
 
1963
                                        if (store.GetIter (out it, sel[0])) {
 
1964
                                                lastPopupButtonIter = it;
 
1965
                                                tree.Model.SetValue (it, ShowPopupColumn, true);
 
1966
                                        }
 
1967
                                }
 
1968
                        }
 
1969
                }
1828
1970
                
1829
1971
                protected virtual void OnSelectionChanged (object sender, EventArgs args)
1830
1972
                {
 
1973
                        UpdateSelectionPopupButton ();
 
1974
 
1831
1975
                        TreeNodeNavigator node = (TreeNodeNavigator) GetSelectedNode ();
1832
1976
                        if (node != null) {
1833
1977
                                NodeBuilder[] chain = node.NodeBuilderChain;
1881
2025
                        
1882
2026
                        base.OnDestroyed ();
1883
2027
                }
 
2028
 
 
2029
                class PopupButton: Gtk.EventBox
 
2030
                {
 
2031
                        public event EventHandler Clicked;
 
2032
 
 
2033
                        public PopupButton ()
 
2034
                        {
 
2035
                                Gtk.Button b = new Gtk.Button ("...");
 
2036
                                b.CanFocus = false;
 
2037
                                Add (b);
 
2038
 
 
2039
                                b.Clicked += delegate {
 
2040
                                        if (Clicked != null)
 
2041
                                                Clicked (this, EventArgs.Empty);
 
2042
                                };
 
2043
                                ShowAll ();
 
2044
                        }
 
2045
                }
1884
2046
                
1885
2047
                internal class PadCheckMenuItem: Gtk.CheckMenuItem
1886
2048
                {
2075
2237
                                }
2076
2238
                        }
2077
2239
                }
 
2240
 
 
2241
                class CustomCellRendererText: Gtk.CellRendererText
 
2242
                {
 
2243
                        double zoom;
 
2244
                        Pango.Layout layout;
 
2245
                        Pango.FontDescription scaledFont, customFont;
 
2246
 
 
2247
                        static Gdk.Pixbuf popupIcon;
 
2248
                        static Gdk.Pixbuf popupIconDown;
 
2249
                        static Gdk.Pixbuf popupIconHover;
 
2250
                        bool bound;
 
2251
                        ExtensibleTreeView parent;
 
2252
                        Gdk.Rectangle buttonScreenRect;
 
2253
                        Gdk.Rectangle buttonAllocation;
 
2254
                        string markup;
 
2255
 
 
2256
                        public bool Pushed { get; set; }
 
2257
 
 
2258
                        //using this instead of FontDesc property, FontDesc seems to be broken
 
2259
                        public Pango.FontDescription CustomFont {
 
2260
                                get {
 
2261
                                        return customFont;
 
2262
                                }
 
2263
                                set {
 
2264
                                        if (scaledFont != null) {
 
2265
                                                scaledFont.Dispose ();
 
2266
                                                scaledFont = null;
 
2267
                                        }
 
2268
                                        customFont = value;
 
2269
                                }
 
2270
                        }
 
2271
 
 
2272
                        static CustomCellRendererText ()
 
2273
                        {
 
2274
                                popupIcon = Gdk.Pixbuf.LoadFromResource ("tree-popup-button.png");
 
2275
                                popupIconDown = Gdk.Pixbuf.LoadFromResource ("tree-popup-button-down.png");
 
2276
                                popupIconHover = Gdk.Pixbuf.LoadFromResource ("tree-popup-button-hover.png");
 
2277
                        }
 
2278
 
 
2279
                        [GLib.Property ("text-markup")]
 
2280
                        public string TextMarkup {
 
2281
                                get { return markup; }
 
2282
                                set { Markup = markup = value; }
 
2283
                        }
 
2284
 
 
2285
                        [GLib.Property ("show-popup-button")]
 
2286
                        public bool ShowPopupButton { get; set; }
 
2287
                        
 
2288
                        public CustomCellRendererText (ExtensibleTreeView parent)
 
2289
                        {
 
2290
                                this.parent = parent;
 
2291
                        }
 
2292
 
 
2293
                        protected override void Render (Gdk.Drawable window, Gtk.Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gdk.Rectangle expose_area, Gtk.CellRendererState flags)
 
2294
                        {
 
2295
                                Gtk.StateType st = Gtk.StateType.Normal;
 
2296
                                if ((flags & Gtk.CellRendererState.Prelit) != 0)
 
2297
                                        st = Gtk.StateType.Prelight;
 
2298
                                if ((flags & Gtk.CellRendererState.Focused) != 0)
 
2299
                                        st = Gtk.StateType.Normal;
 
2300
                                if ((flags & Gtk.CellRendererState.Insensitive) != 0)
 
2301
                                        st = Gtk.StateType.Insensitive;
 
2302
                                if ((flags & Gtk.CellRendererState.Selected) != 0)
 
2303
                                        st = widget.HasFocus ? Gtk.StateType.Selected : Gtk.StateType.Active;
 
2304
 
 
2305
                                if (scaledFont == null) {
 
2306
                                        if (scaledFont != null)
 
2307
                                                scaledFont.Dispose ();
 
2308
                                        scaledFont = (customFont ?? parent.Style.FontDesc).Copy ();
 
2309
                                        scaledFont.Size = (int)(customFont.Size * Zoom);
 
2310
                                        if (layout != null)
 
2311
                                                layout.FontDescription = scaledFont;
 
2312
                                }
 
2313
 
 
2314
                                if (layout == null || layout.Context != widget.PangoContext) {
 
2315
                                        if (layout != null)
 
2316
                                                layout.Dispose ();
 
2317
                                        layout = new Pango.Layout (widget.PangoContext);
 
2318
                                        layout.FontDescription = scaledFont;
 
2319
                                }
 
2320
 
 
2321
                                layout.SetMarkup (TextMarkup);
 
2322
 
 
2323
                                int w, h;
 
2324
                                layout.GetPixelSize (out w, out h);
 
2325
 
 
2326
                                int tx = cell_area.X + (int) Xpad;
 
2327
                                int ty = cell_area.Y + (cell_area.Height - h) / 2;
 
2328
 
 
2329
                                window.DrawLayout (widget.Style.TextGC (st), tx, ty, layout);
 
2330
 
 
2331
                                if (ShowPopupButton) {
 
2332
                                        if (!bound) {
 
2333
                                                bound = true;
 
2334
                                                ((Gtk.ScrolledWindow)widget.Parent).Hadjustment.ValueChanged += delegate {
 
2335
                                                        foreach (var r in parent.Tree.Selection.GetSelectedRows ()) {
 
2336
                                                                var rect = parent.Tree.GetCellArea (r, parent.Tree.Columns[0]);
 
2337
                                                                parent.Tree.QueueDrawArea (rect.X, rect.Y, rect.Width, rect.Height);
 
2338
                                                        }
 
2339
                                                };
 
2340
                                        }
 
2341
 
 
2342
                                        if ((flags & Gtk.CellRendererState.Selected) != 0) {
 
2343
                                                var icon = Pushed ? popupIconDown : popupIcon;
 
2344
                                                var dy = (cell_area.Height - icon.Height) / 2;
 
2345
                                                var y = cell_area.Y + dy;
 
2346
                                                var x = cell_area.X + cell_area.Width - icon.Width - dy;
 
2347
 
 
2348
                                                var sw = (Gtk.ScrolledWindow) widget.Parent;
 
2349
                                                int ox, oy, ow, oh;
 
2350
                                                sw.GdkWindow.GetOrigin (out ox, out oy);
 
2351
                                                sw.GdkWindow.GetSize (out ow, out oh);
 
2352
                                                ox += sw.Allocation.X;
 
2353
                                                oy += sw.Allocation.Y;
 
2354
                                                if (sw.VScrollbar.Visible)
 
2355
                                                        ow -= sw.VScrollbar.Allocation.Width;
 
2356
 
 
2357
                                                int cx, cy, cw, ch;
 
2358
                                                ((Gdk.Window)window).GetOrigin (out cx, out cy);
 
2359
                                                ((Gdk.Window)window).GetSize (out cw, out ch);
 
2360
                                                cx += widget.Allocation.X;
 
2361
                                                cy += widget.Allocation.Y;
 
2362
 
 
2363
                                                int rp = ox + ow;
 
2364
                                                int diff = rp - (cx + cw);
 
2365
 
 
2366
                                                if (diff < 0) {
 
2367
                                                        x += diff;
 
2368
                                                        if (x < cell_area.X + 20)
 
2369
                                                                x = cell_area.X + 20;
 
2370
                                                }
 
2371
 
 
2372
                                                buttonScreenRect = new Gdk.Rectangle (cx + x, cy + y, popupIcon.Width, popupIcon.Height);
 
2373
 
 
2374
                                                buttonAllocation = new Gdk.Rectangle (x, y, popupIcon.Width, popupIcon.Height);
 
2375
                                                buttonAllocation = GtkUtil.ToScreenCoordinates (widget, ((Gdk.Window)window), buttonAllocation);
 
2376
                                                buttonAllocation = GtkUtil.ToWindowCoordinates (widget, widget.GdkWindow, buttonAllocation);
 
2377
 
 
2378
                                                bool mouseOver = (flags & Gtk.CellRendererState.Prelit) != 0 && buttonScreenRect.Contains (PointerPosition);
 
2379
                                                if (mouseOver && !Pushed)
 
2380
                                                        icon = popupIconHover;
 
2381
 
 
2382
                                                using (var ctx = Gdk.CairoHelper.Create (window)) {
 
2383
                                                        Gdk.CairoHelper.SetSourcePixbuf (ctx, icon, x, y);
 
2384
                                                        ctx.Paint ();
 
2385
                                                }
 
2386
                                        }
 
2387
                                }
 
2388
                        }
 
2389
 
 
2390
                        public double Zoom {
 
2391
                                get {
 
2392
                                        return zoom;
 
2393
                                }
 
2394
                                set {
 
2395
                                        if (scaledFont != null) {
 
2396
                                                scaledFont.Dispose ();
 
2397
                                                scaledFont = null;
 
2398
                                        }
 
2399
                                        zoom = value;
 
2400
                                }
 
2401
                        }
 
2402
 
 
2403
                        public bool PointerInButton (int px, int py)
 
2404
                        {
 
2405
                                return buttonScreenRect.Contains (px, py);
 
2406
                        }
 
2407
 
 
2408
                        public Gdk.Point PointerPosition { get; set; }
 
2409
 
 
2410
                        public Gdk.Rectangle PopupAllocation {
 
2411
                                get { return buttonAllocation; }
 
2412
                        }
 
2413
 
 
2414
                        protected override void OnDestroyed ()
 
2415
                        {
 
2416
                                base.OnDestroyed ();
 
2417
                                if (scaledFont != null)
 
2418
                                        scaledFont.Dispose ();
 
2419
                                if (layout != null)
 
2420
                                        layout.Dispose ();
 
2421
                        }
 
2422
                }
2078
2423
        }
2079
2424
 
2080
2425
        class NodeCommandTargetChain: ICommandDelegatorRouter