// This is a part of the Smart PropertyGrid Library
// Copyright (C) 2001-2006 VisualHint
// All rights reserved.
//
// This source code can be used, distributed or modified
// only under terms and conditions 
// of the accompanying license agreement.

#region Using directives

using System.Windows.Forms;
using System.Security.Permissions;

#endregion

namespace VisualHint.SmartPropertyGrid
{
    internal class InternalTrackBar : TrackBar
    {
        /// <summary>
        /// Because Control.OnLostFocus and Control.OnGotFocus doesn't provide a reference to the
        /// window that lost or gained the focus, this variable will contain this missing information.
        /// It is initialized in WndProc when processing WM_FILLFOCUS and WM_SETFOCUS messages.
        /// It is also embedded in a FocusEventArgs instance for event listeners.
        /// </summary>
        private Control _wmFocusMissingArg;

        /// <summary>
        /// True when the focus is lost because of typing Return or Escape, false otherwise.
        /// </summary>
        private bool _leaveKey = false;

        private PropertyEnumerator _ownerPropertyEnum;

        public PropertyEnumerator OwnerPropertyEnumerator
        {
            set
            {
                _ownerPropertyEnum = value;

                PropertyValidatorMinMax<int> validator = (_ownerPropertyEnum.Property.Value.Validator as PropertyValidatorMinMax<int>);

                if (validator != null)
                {
                    Minimum = validator.Min;
                    Maximum = validator.Max;
                }
                else
                {
                    Minimum = 0;
                    Maximum = 100;
                }
            }
        }

        public InternalTrackBar()
        {
            AutoSize = false;
            TickStyle = TickStyle.None;
        }

        [UIPermission(SecurityAction.LinkDemand, Window = UIPermissionWindow.AllWindows)]
        protected override bool ProcessDialogKey(Keys keyData)
        {
            Keys key = (keyData & Keys.KeyCode);

            if (key == Keys.Return)
            {
                _leaveKey = true;
                Parent.Focus();
                return true;
            }
            else if (key == Keys.Escape)
            {
                // Restore the old string in the edit box
                PropertyValue value = _ownerPropertyEnum.Property.Value;
                if (value != null)
                    Value = (int)_ownerPropertyEnum.Property.Value.GetValue();

                _leaveKey = true;
                Parent.Focus();
                return true;
            }

            return base.ProcessDialogKey(keyData);
        }

        protected override void OnLostFocus(System.EventArgs e)
        {
            base.OnLostFocus(new FocusEventArgs(_wmFocusMissingArg, _leaveKey));

            _leaveKey = false;
        }

        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == Win32Calls.WM_SETFOCUS)
            {
                // The window that lose the focus is stored for future reference
                // in OnGotFocus. if the handle is in another application, the stored
                // value will be null.
                _wmFocusMissingArg = FromHandle(m.WParam);
            }
            else if (m.Msg == Win32Calls.WM_KILLFOCUS)
            {
                // The window that gained the focus is stored for future reference
                // in OnLostFocus. if the handle is in another application, the stored
                // value will be null.
                _wmFocusMissingArg = FromHandle(m.WParam);
            }
            else if (m.Msg == Win32Calls.WM_ERASEBKGND)
            {
                // If I don't intercept this message, the control flickers
                return;
            }

            base.WndProc(ref m);
        }
    }
}
