From 833cb6e4d330027d4bb53c1a62deb82a66e5013a Mon Sep 17 00:00:00 2001
From: Patrick Simpson 
Date: Mon, 19 Jun 2017 15:51:23 +0200
Subject: [PATCH] Added edit and button portion of custom combo box.
---
 .../AcaciaZPushPlugin.csproj                  |   8 +-
 .../AcaciaZPushPlugin/Controls/KComboBox.cs   | 168 ++++++++++
 .../AcaciaZPushPlugin/Controls/KUIUtil.cs     |  51 +++
 .../Controls/KVisualStateTracker.cs           | 299 ++++++++++++++++++
 .../Controls/KVisualStyle.cs                  | 141 +++++++++
 .../SharedFoldersDialog.Designer.cs           |   1 -
 .../AcaciaZPushPlugin/Native/UXTheme.cs       |  24 ++
 7 files changed, 690 insertions(+), 2 deletions(-)
 create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs
 create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KVisualStateTracker.cs
 create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KVisualStyle.cs
 create mode 100644 src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/UXTheme.cs
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj
index 51e22ce..eee1c65 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/AcaciaZPushPlugin.csproj
@@ -220,6 +220,9 @@
       KBusyIndicator.cs
     
     
+    
+      UserControl
+    
     
       Component
     
@@ -251,6 +254,8 @@
     
     
     
+    
+    
     
     
     
@@ -319,6 +324,7 @@
     
     
     
+    
     
     
     
@@ -403,7 +409,7 @@
       UserControl
     
     
-      Component
+      UserControl
     
     
       GABLookupControl.cs
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs
new file mode 100644
index 0000000..7b9bc8b
--- /dev/null
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KComboBox.cs
@@ -0,0 +1,168 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace Acacia.Controls
+{
+    public class KComboBox : UserControl
+    {
+        #region Properties
+
+        public ComboBoxStyle DropDownStyle
+        {
+            get;
+            set;
+        }
+
+        public string DisplayMember
+        {
+            get;
+            set;
+        }
+
+        #endregion
+
+        #region Components
+
+        private TextBox _edit;
+
+        #endregion
+
+        #region Init
+
+        public KComboBox()
+        {
+            SetupRenderer();
+
+            _edit = new TextBox();
+            _edit.BorderStyle = BorderStyle.None;
+            Controls.Add(_edit);
+            _state.AddControl(_edit);
+        }
+
+        #endregion
+
+        #region Drop down
+
+        private void Button_Clicked()
+        {
+
+        }
+
+        #endregion
+
+        #region Rendering
+
+        private enum State
+        {
+            // Values match those defined in vsstyles.h so no conversion is needed.
+            Normal = 1, Hot = 2, Pressed = 3, Disabled = 4
+        }
+
+        private KVisualStyle _style = new KVisualStyle("COMBOBOX");
+
+        // Enum from vsstyles.h
+        enum COMBOBOXPARTS
+        {
+            CP_DROPDOWNBUTTON = 1,
+            CP_BACKGROUND = 2,
+            CP_TRANSPARENTBACKGROUND = 3,
+            CP_BORDER = 4,
+            CP_READONLY = 5,
+            CP_DROPDOWNBUTTONRIGHT = 6,
+            CP_DROPDOWNBUTTONLEFT = 7,
+            CP_CUEBANNER = 8,
+        };
+        
+        private KVisualStateTracker _state;
+        private KVisualStateTracker.Part _stateButton;
+
+        public void SetupRenderer(bool enableVisualStyles = true)
+        {
+            SetStyle(ControlStyles.AllPaintingInWmPaint, true);
+            SetStyle(ControlStyles.ContainerControl, true);
+            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
+            SetStyle(ControlStyles.ResizeRedraw, true);
+            SetStyle(ControlStyles.Selectable, true);
+            SetStyle(ControlStyles.SupportsTransparentBackColor, true);
+            SetStyle(ControlStyles.UserMouse, true);
+            SetStyle(ControlStyles.UserPaint, true);
+            SetStyle(ControlStyles.Selectable, true);
+
+            _style[COMBOBOXPARTS.CP_DROPDOWNBUTTON].SetPadding(COMBOBOXPARTS.CP_DROPDOWNBUTTONLEFT,
+                                                               COMBOBOXPARTS.CP_DROPDOWNBUTTONRIGHT);
+
+            _state = new KVisualStateTracker(this, State.Normal, State.Disabled);
+            _state.Root.WithHot(State.Hot);
+            _state.Root.WithFocus(State.Hot);
+
+            _stateButton = _state.Root.AddPart().WithPressed(State.Pressed);
+            _stateButton.Clicked += Button_Clicked;
+
+            // TODO if (enableVisualStyles && Application.RenderWithVisualStyles)
+        }
+
+        protected override void OnPaint(PaintEventArgs e)
+        {
+            _style[COMBOBOXPARTS.CP_BORDER]?.DrawBackground(e.Graphics, _state.Root.State, ClientRectangle);
+            _style[COMBOBOXPARTS.CP_DROPDOWNBUTTON]?.DrawBackground(e.Graphics, _stateButton.State, _stateButton.Rectangle);
+        }
+
+        #endregion
+
+        #region Layout
+
+        protected override void OnLayout(LayoutEventArgs e)
+        {
+            base.OnLayout(e);
+
+            using (Graphics graphics = CreateGraphics())
+            {
+                // Determine the border insets
+                Padding insets = _style[COMBOBOXPARTS.CP_BORDER]?.GetMargins(graphics, _state.Root.State) ?? new Padding();
+
+                // Determine the button size
+                Size? buttonSize = _style[COMBOBOXPARTS.CP_DROPDOWNBUTTON]?.GetPartSize(graphics, _state.Root.State);
+                if (!buttonSize.HasValue)
+                    buttonSize = new Size(ClientRectangle.Height, ClientRectangle.Height);
+
+                Rectangle buttonRect = new Rectangle();
+                buttonRect.X = ClientRectangle.Width - buttonSize.Value.Width;
+                buttonRect.Width = buttonSize.Value.Width;
+                buttonRect.Y = 0;
+                buttonRect.Height = ClientRectangle.Height;
+                _stateButton.Rectangle = buttonRect;
+
+                // Set the edit control
+                Rectangle editRect = new Rectangle(insets.Left, insets.Top, buttonRect.X - insets.Left,
+                                                    ClientRectangle.Height - insets.Vertical);
+                editRect = editRect.CenterVertically(new Size(editRect.Width, _edit.PreferredHeight));
+                _edit.SetBounds(editRect.X, editRect.Y, editRect.Width, editRect.Height);
+            }
+        }
+
+        public override Size GetPreferredSize(Size proposedSize)
+        {
+            // TODO: cache sizes?
+            using (Graphics graphics = CreateGraphics())
+            {
+                Size editSize = _edit.GetPreferredSize(proposedSize);
+                Padding insets = _style[COMBOBOXPARTS.CP_BORDER]?.GetMargins(graphics, _state.Root.State) ?? new Padding();
+
+                Size prefSize = editSize.Expand(insets);
+
+                Size? buttonSize = _style[COMBOBOXPARTS.CP_DROPDOWNBUTTON]?.GetPartSize(graphics, _state.Root.State);
+                if (!buttonSize.HasValue)
+                    buttonSize = new Size(prefSize.Height, prefSize.Height);
+
+                return new Size(prefSize.Width + buttonSize.Value.Width, Math.Max(prefSize.Height, buttonSize.Value.Height));
+            }
+        }
+
+        #endregion
+    }
+}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs
index 9e9eb86..2e4d15f 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KUIUtil.cs
@@ -35,6 +35,12 @@ namespace Acacia.Controls
             return new Rectangle(x, y, size.Width, size.Height);
         }
 
+        public static Rectangle CenterVertically(this Rectangle _this, Size size)
+        {
+            int y = _this.Y + (_this.Height - size.Height) / 2;
+            return new Rectangle(_this.X, y, size.Width, size.Height);
+        }
+
         public static Rectangle Expand(this Rectangle _this, Padding padding)
         {
             Rectangle r = _this;
@@ -75,6 +81,51 @@ namespace Acacia.Controls
             return new Size((int)(_this.Width * graphics.DpiX / 96), (int)(_this.Height * graphics.DpiY / 96));
         }
 
+        /// 
+        /// Adds the sizes horizontally. The height is the maximum of any of the elements' height.
+        /// Any of the heights may be null.
+        /// 
+        /// 
+        /// The added sizes. Null is returned only if all sizes are null.
+        /// 
+        public static Size? AddHorizontally(this Size? _this, params Size?[] add)
+        {
+            Size? s = _this;
+
+            foreach(Size? s2 in add)
+            {
+                if (s2.HasValue)
+                {
+                    if (!s.HasValue)
+                        s = s2;
+                    else
+                        s = new Size(s.Value.Width + s2.Value.Width, Math.Max(s.Value.Height, s2.Value.Height));
+                }
+            }
+
+            return s;
+        }
+        public static Size? AddHorizontally(this Size _this, params Size?[] add)
+        {
+            return AddHorizontally((Size?)_this, add);
+        }
+
+        public static Size Expand(this Size _this, Padding padding)
+        {
+            Size r = _this;
+            r.Width += padding.Horizontal;
+            r.Height += padding.Vertical;
+            return r;
+        }
+
+        public static Size Shrink(this Size _this, Padding padding)
+        {
+            Size r = _this;
+            r.Width -= padding.Horizontal;
+            r.Height -= padding.Vertical;
+            return r;
+        }
+
         #endregion
     }
 }
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KVisualStateTracker.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KVisualStateTracker.cs
new file mode 100644
index 0000000..a281619
--- /dev/null
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KVisualStateTracker.cs
@@ -0,0 +1,299 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace Acacia.Controls
+{
+    internal class KVisualStateTracker
+        where StateTypeId: struct, IConvertible
+    {
+        public class Part
+        {
+            private KVisualStateTracker _tracker;
+            private readonly StateTypeId? _normalState;
+            private readonly StateTypeId? _disabledState;
+            private StateTypeId? _hotState;
+            private StateTypeId? _pressedState;
+            private StateTypeId? _focusState;
+            private bool _mouseOver;
+            private bool _mousePressed;
+            private bool _focused;
+            private readonly Part _parent;
+            private readonly List _children = new List();
+            private Rectangle? _rectangle;
+
+            public Action Clicked { get; set; }
+
+            public Part(KVisualStateTracker tracker, StateTypeId? normalState, StateTypeId? disabledState)
+            {
+                this._tracker = tracker;
+                this._normalState = normalState;
+                this._disabledState = disabledState;
+            }
+
+            public Part(KVisualStateTracker tracker, Part parent)
+            {
+                this._tracker = parent._tracker;
+                this._parent = parent;
+            }
+
+            public StateTypeId State
+            {
+                get
+                {
+                    if (_parent != null && !_mouseOver)
+                    {
+                        return _parent.State;
+                    }
+
+                    if (!_tracker._control.Enabled)
+                    {
+                        return DisabledState;
+                    }
+
+                    if (_focused && FocusedState.HasValue)
+                        return FocusedState.Value;
+
+                    if (_mouseOver && _mousePressed)
+                        return _pressedState.Value;
+
+                    if (_mouseOver && HotState.HasValue)
+                        return HotState.Value;
+
+                    return NormalState;
+                }
+            }
+
+            public Rectangle Rectangle
+            {
+                get
+                {
+                    if (_rectangle.HasValue)
+                        return _rectangle.Value;
+
+                    return _tracker._control.ClientRectangle;
+                }
+
+                set
+                {
+                    if (_parent == null)
+                        throw new InvalidOperationException("Cannot set rectangle on root element");
+                    _rectangle = value;
+                }
+
+            }
+
+            private StateTypeId DisabledState
+            {
+                get
+                {
+                    if (_disabledState.HasValue)
+                        return _disabledState.Value;
+                    return _parent.DisabledState;
+                }
+            }
+
+            private StateTypeId NormalState
+            {
+                get
+                {
+                    if (_normalState.HasValue)
+                        return _normalState.Value;
+                    return _parent.NormalState;
+                }
+            }
+
+            private StateTypeId? HotState
+            {
+                get
+                {
+                    if (_hotState.HasValue)
+                        return _hotState.Value;
+                    return _parent.HotState;
+                }
+            }
+
+            private StateTypeId? FocusedState
+            {
+                get
+                {
+                    if (_focusState.HasValue)
+                        return _focusState.Value;
+                    return _parent.FocusedState;
+                }
+            }
+
+            private bool MouseOver
+            {
+                get { return _mouseOver; }
+                set
+                {
+                    if (_mouseOver != value)
+                    {
+                        _mouseOver = value;
+                        Invalidate();
+                    }
+                }
+            }
+
+            private bool MousePressed
+            {
+                get { return _mousePressed; }
+                set
+                {
+                    if (_mousePressed != value)
+                    {
+                        _mousePressed = value;
+                        Invalidate();
+                    }
+                }
+            }
+
+            private bool Focused
+            {
+                get { return _focused; }
+                set
+                {
+                    if (_focused != value)
+                    {
+                        _focused = value;
+                        Invalidate();
+                    }
+                }
+            }
+
+            private void Invalidate()
+            {
+                _tracker.Invalidate();
+            }
+
+            internal void GotFocus(object sender, EventArgs e)
+            {
+                Focused = true;
+            }
+
+            internal void LostFocus(object sender, EventArgs e)
+            {
+                Focused = false;
+            }
+
+            internal void MouseDown(object sender, MouseEventArgs e)
+            {
+                if (_pressedState != null && e.Button.HasFlag(MouseButtons.Left))
+                {
+                    MousePressed = Rectangle.Contains(e.Location);
+                }
+
+                foreach (Part child in _children)
+                {
+                    child.MouseDown(sender, e);
+                }
+            }
+
+            internal void MouseUp(object sender, MouseEventArgs e)
+            {
+                foreach (Part child in _children)
+                {
+                    child.MouseUp(sender, e);
+                }
+
+                if (e.Button.HasFlag(MouseButtons.Left))
+                {
+                    if (_pressedState != null)
+                    {
+                        MousePressed = false;
+                    }
+
+                    if (MouseOver && Clicked != null)
+                    {
+                        Clicked();
+                    }
+                }
+            }
+
+            internal void MouseMove(object sender, MouseEventArgs e)
+            {
+                MouseOver = Rectangle.Contains(e.Location);
+
+                foreach(Part child in _children)
+                {
+                    child.MouseMove(sender, e);
+                }
+            }
+
+            internal void MouseLeave(object sender, EventArgs e)
+            {
+                MouseOver = false;
+                foreach (Part child in _children)
+                {
+                    child.MouseLeave(sender, e);
+                }
+            }
+
+            public Part AddPart()
+            {
+                Part child = new Part(_tracker, this);
+                _children.Add(child);
+                return child;
+            }
+
+            public Part WithPressed(StateTypeId? pressedState)
+            {
+                this._pressedState = pressedState;
+                return this;
+            }
+
+            public Part WithHot(StateTypeId? hotState)
+            {
+                this._hotState = hotState;
+                return this;
+            }
+
+            public Part WithFocus(StateTypeId? focusState)
+            {
+                this._focusState = focusState;
+                return this;
+            }
+        }
+
+        private readonly Control _control;
+        private readonly List _additionalControls = new List();
+        public readonly Part Root;
+
+        public KVisualStateTracker(Control control, StateTypeId normalState, StateTypeId disabledState)
+        {
+            this._control = control;
+            Root = new Part(this, normalState, disabledState);
+            AddControl(_control);
+            _control.EnabledChanged += Control_EnabledChanged;
+        }
+
+        public void AddControl(Control child)
+        {
+            if (child != _control)
+            {
+                _additionalControls.Add(child);
+            }
+            child.MouseLeave += Root.MouseLeave;
+            child.MouseMove += Root.MouseMove;
+            child.MouseDown += Root.MouseDown;
+            child.MouseUp += Root.MouseUp;
+            child.GotFocus += Root.GotFocus;
+            child.LostFocus += Root.LostFocus;
+        }
+
+        private void Control_EnabledChanged(object sender, EventArgs e)
+        {
+            Invalidate();
+        }
+
+        private void Invalidate()
+        {
+            _control.Invalidate();
+        }
+    }
+}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KVisualStyle.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KVisualStyle.cs
new file mode 100644
index 0000000..6137b42
--- /dev/null
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Controls/KVisualStyle.cs
@@ -0,0 +1,141 @@
+using Acacia.Native;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Windows.Forms.VisualStyles;
+
+namespace Acacia.Controls
+{
+    internal class KVisualStyle
+        where PartTypeId : struct, IConvertible
+        where StateTypeId : struct, IConvertible
+    {
+        public class Part
+        {
+            private readonly KVisualStyle _style;
+            private readonly PartTypeId _partId;
+            private Dictionary _renderers;
+            private Part _paddingLeft;
+            private Part _paddingRight;
+
+            public Part(KVisualStyle style, PartTypeId id)
+            {
+                this._style = style;
+                this._partId = id;
+            }
+
+            public void DrawBackground(Graphics graphics, StateTypeId state, Rectangle rect)
+            {
+                VisualStyleRenderer r = GetRenderer(state);
+                if (r != null)
+                {
+                    r.DrawBackground(graphics, rect);
+                }
+            }
+
+            public void DrawText(Graphics graphics, StateTypeId state, Rectangle rect, string text)
+            {
+                VisualStyleRenderer r = GetRenderer(state);
+                if (r != null)
+                {
+                    r.DrawText(graphics, rect, text); // TODO: disabled
+                }
+            }
+
+            private VisualStyleRenderer GetRenderer(StateTypeId state)
+            {
+                InitRenderers();
+                VisualStyleRenderer renderer;
+                _renderers.TryGetValue(state, out renderer);
+                return renderer;
+            }
+
+            private void InitRenderers()
+            {
+                if (_renderers == null)
+                {
+                    _renderers = new Dictionary();
+                    foreach (StateTypeId entry in Enum.GetValues(typeof(StateTypeId)))
+                    {
+                        try
+                        {
+                            int id = _partId.ToInt32(null);
+                            int entryId = entry.ToInt32(null);
+                            _renderers.Add(entry, new VisualStyleRenderer(_style.ClassName, id, entryId));
+                        }
+                        catch (Exception e) { Logger.Instance.Trace(this, "Renderer not supported: {0}", e); }
+                    }
+                }
+            }
+
+            public Size? GetPartSize(Graphics graphics, StateTypeId state)
+            {
+                VisualStyleRenderer renderer = GetRenderer(state);
+                if (renderer == null)
+                    return null;
+
+                Size size = renderer.GetPartSize(graphics, ThemeSizeType.True);
+                return size.AddHorizontally(_paddingLeft?.GetPartSize(graphics, state),
+                                            _paddingRight?.GetPartSize(graphics, state));
+            }
+
+            public Padding? GetMargins(Graphics graphics, StateTypeId state)
+            {
+                VisualStyleRenderer renderer = GetRenderer(state);
+                if (renderer == null)
+                    return null;
+
+
+                // VisualStyleRenderer.GetMargins always throws an exception, make an explicit API call
+                int stateId = state.ToInt32(null);
+                UXTheme.MARGINS margins;
+                IntPtr hdc = graphics.GetHdc();
+                try
+                {
+                    UXTheme.GetThemeMargins(renderer.Handle, hdc, this._partId.ToInt32(null), stateId,
+                                        (int)MarginProperty.SizingMargins, IntPtr.Zero, out margins);
+                    // TODO: include padding
+                    return new Padding(margins.cxLeftWidth, margins.cyTopHeight, margins.cxRightWidth, margins.cyBottomHeight);
+                }
+                finally
+                {
+                    graphics.ReleaseHdc(hdc);
+                }
+            }
+
+
+            public void SetPadding(PartTypeId paddingLeft, PartTypeId paddingRight)
+            {
+                this._paddingLeft = _style[paddingLeft];
+                this._paddingRight = _style[paddingRight];
+            }
+
+        }
+
+        private readonly string ClassName;
+        private readonly Dictionary _parts = new Dictionary();
+
+        public KVisualStyle(string name)
+        {
+            this.ClassName = name;
+        }
+
+        public Part this[PartTypeId index]
+        {
+            get
+            {
+                Part part;
+                if (!_parts.TryGetValue(index, out part))
+                {
+                    part = new Part(this, index);
+                    _parts.Add(index, part);
+                }
+                return part;
+            }
+        }
+    }
+}
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs
index f93a21e..4268118 100644
--- a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Features/SharedFolders/SharedFoldersDialog.Designer.cs
@@ -111,7 +111,6 @@
             // 
             this.gabLookup.DisplayMember = "DisplayName";
             resources.ApplyResources(this.gabLookup, "gabLookup");
-            this.gabLookup.FormattingEnabled = true;
             this.gabLookup.GAB = null;
             this.gabLookup.Name = "gabLookup";
             this.gabLookup.SelectedUserChanged += new Acacia.UI.GABLookupControl.SelectedUserEventHandler(this.gabLookup_SelectedUserChanged);
diff --git a/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/UXTheme.cs b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/UXTheme.cs
new file mode 100644
index 0000000..34887e0
--- /dev/null
+++ b/src/AcaciaZPushPlugin/AcaciaZPushPlugin/Native/UXTheme.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Acacia.Native
+{
+    public static class UXTheme
+    {
+        [StructLayout(LayoutKind.Sequential, Pack = 1)]
+        public struct MARGINS
+        {
+            public int cxLeftWidth;
+            public int cxRightWidth;
+            public int cyTopHeight;
+            public int cyBottomHeight;
+        }
+
+        [DllImport("uxtheme.dll")]
+        public static extern int GetThemeMargins(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, int iPropId, IntPtr prc, out MARGINS pMargins);
+    }
+}