| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898 | using PaintDotNet.SystemLayer;using System;using System.Collections;using System.Collections.Generic;using System.Diagnostics;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;namespace PaintDotNet.Annotation.Other{    /// <summary>    /// 没用到,先放着    /// </summary>    public class OtherTool : IDisposable    {        private ImageResource toolBarImage;        private Cursor cursor;        private int mouseDown = 0; // incremented for every MouseDown, decremented for every MouseUp        private int ignoreMouseMove = 0; // when >0, MouseMove is ignored and then this is decremented        protected Cursor handCursor;        protected Cursor handCursorMouseDown;        protected Cursor handCursorInvalid;        private Cursor panOldCursor;        private Point lastMouseXY;        private Point lastPanMouseXY;        private bool panMode = false; // 'true' when the user is holding down the spacebar        private bool panTracking = false; // 'true' when panMode is true, and when the mouse is down (which is when MouseMove should do panning)                private ISurfaceBox documentWorkspace;        private bool active = false;        protected bool autoScroll = true;        private Hashtable keysThatAreDown = new Hashtable();        private MouseButtons lastButton = MouseButtons.None;        private int mouseEnter; // increments on MouseEnter, decrements on MouseLeave. The MouseLeave event is ONLY raised when this value decrements to 0, and MouseEnter is ONLY raised when this value increments to 1        public ISurfaceBox DocumentWorkspace        {            get            {                return this.documentWorkspace;            }        }        private sealed class KeyTimeInfo        {            public DateTime KeyDownTime;            public DateTime LastKeyPressPulse;            private int repeats = 0;            public int Repeats            {                get                {                    return repeats;                }                set                {                    repeats = value;                }            }            public KeyTimeInfo()            {                KeyDownTime = DateTime.Now;                LastKeyPressPulse = KeyDownTime;            }        }        /// <summary>        /// Tells you whether the tool is "active" or not. If the tool is not active        /// it is not safe to call any other method besides PerformActivate. All        /// properties are safe to get values from.        /// </summary>        public bool Active        {            get            {                return this.active;            }        }        public bool IsMouseDown        {            get            {                return this.mouseDown > 0;            }        }        /// <summary>        /// Gets a flag that determines whether the Tool is deactivated while the current        /// layer is changing, and then reactivated afterwards.        /// </summary>        /// <remarks>        /// This property is queried every time the ActiveLayer property of DocumentWorkspace        /// is changed. If false is returned, then the tool is not deactivated during the        /// layer change and must manually maintain coherency.        /// </remarks>        public virtual bool DeactivateOnLayerChange        {            get            {                return true;            }        }        /// <summary>        /// Tells you which keys are pressed        /// </summary>        public Keys ModifierKeys        {            get            {                return Control.ModifierKeys;            }        }        /// <summary>        /// Represents the Image that is displayed in the toolbar.        /// </summary>        public ImageResource Image        {            get            {                return this.toolBarImage;            }        }        public event EventHandler CursorChanging;        protected virtual void OnCursorChanging()        {            if (CursorChanging != null)            {                CursorChanging(this, EventArgs.Empty);            }        }        public event EventHandler CursorChanged;        protected virtual void OnCursorChanged()        {            if (CursorChanged != null)            {                CursorChanged(this, EventArgs.Empty);            }        }        /// <summary>        /// The Cursor that is displayed when this Tool is active and the        /// mouse cursor is inside the document view.        /// </summary>        public Cursor Cursor        {            get            {                return this.cursor;            }            set            {                OnCursorChanging();                this.cursor = value;                OnCursorChanged();            }        }        /// <summary>        /// Specifies whether or not an inherited tool should take Ink commands        /// </summary>        protected virtual bool SupportsInk        {            get            {                return false;            }        }        // Methods to send messages to this class        public void PerformActivate()        {            Activate();        }        public void PerformDeactivate()        {            Deactivate();        }        private bool IsOverflow(MouseEventArgs e)        {            PointF clientPt = DocumentWorkspace.DocumentToClient(new PointF(e.X, e.Y));            return clientPt.X < -16384 || clientPt.Y < -16384;        }        public bool IsMouseEntered        {            get            {                return this.mouseEnter > 0;            }        }        public void PerformMouseEnter()        {            MouseEnter();        }        private void MouseEnter()        {            ++this.mouseEnter;            if (this.mouseEnter == 1)            {                OnMouseEnter();            }        }        protected virtual void OnMouseEnter()        {        }        public void PerformMouseLeave()        {            MouseLeave();        }        private void MouseLeave()        {            if (this.mouseEnter == 1)            {                this.mouseEnter = 0;                OnMouseLeave();            }            else            {                this.mouseEnter = Math.Max(0, this.mouseEnter - 1);            }        }        protected virtual void OnMouseLeave()        {        }        public void PerformMouseMove(MouseEventArgs e)        {            if (IsOverflow(e))            {                return;            }            MouseMove(e);        }        public void PerformMouseDown(MouseEventArgs e)        {            if (IsOverflow(e))            {                return;            }            MouseDown(e);        }        public void PerformMouseUp(MouseEventArgs e)        {            if (IsOverflow(e))            {                return;            }            MouseUp(e);        }        public void PerformKeyUp(KeyEventArgs e)        {            KeyUp(e);        }        public void PerformKeyDown(KeyEventArgs e)        {            KeyDown(e);        }        public void PerformClick()        {            Click();        }        public void PerformPulse()        {            Pulse();        }        public void PerformPaste(IDataObject data, out bool handled)        {            Paste(data, out handled);        }        public void PerformPasteQuery(IDataObject data, out bool canHandle)        {            PasteQuery(data, out canHandle);        }        private void Activate()        {            Debug.Assert(this.active != true, "already active!");            this.active = true;            this.handCursor = new Cursor(PdnResources.GetResourceStream("Cursors.PanToolCursor.cur"));            this.handCursorMouseDown = new Cursor(PdnResources.GetResourceStream("Cursors.PanToolCursorMouseDown.cur"));            this.handCursorInvalid = new Cursor(PdnResources.GetResourceStream("Cursors.PanToolCursorInvalid.cur"));            this.panTracking = false;            this.panMode = false;            this.mouseDown = 0;            OnActivate();        }        void FinishedHistoryStepGroup(object sender, EventArgs e)        {            OnFinishedHistoryStepGroup();        }        protected virtual void OnFinishedHistoryStepGroup()        {        }        /// <summary>        /// This method is called when the tool is being activated; that is, when the        /// user has chosen to use this tool by clicking on it on a toolbar.        /// </summary>        protected virtual void OnActivate()        {        }        private void Deactivate()        {            this.active = false;            OnDeactivate();            if (this.handCursor != null)            {                this.handCursor.Dispose();                this.handCursor = null;            }            if (this.handCursorMouseDown != null)            {                this.handCursorMouseDown.Dispose();                this.handCursorMouseDown = null;            }            if (this.handCursorInvalid != null)            {                this.handCursorInvalid.Dispose();                this.handCursorInvalid = null;            }        }        /// <summary>        /// This method is called when the tool is being deactivated; that is, when the        /// user has chosen to use another tool by clicking on another tool on a        /// toolbar.        /// </summary>        protected virtual void OnDeactivate()        {        }        private void MouseMove(MouseEventArgs e)        {            if (this.ignoreMouseMove > 0)            {                --this.ignoreMouseMove;            }            else if (this.panTracking && e.Button == MouseButtons.Left)            {                // Pan the document, using Stylus coordinates. This is done in                // MouseMove instead of StylusMove because StylusMove is                // asynchronous, and would not 'feel' right (pan motions would                // stack up)                Point position = new Point(e.X, e.Y);                RectangleF visibleRect = DocumentWorkspace.GetVisibleDocumentRectangleF();                PointF visibleCenterPt = new PointF((visibleRect.Left + visibleRect.Right) / 2, (visibleRect.Top + visibleRect.Bottom) / 2);                PointF delta = new PointF(e.X - lastPanMouseXY.X, e.Y - lastPanMouseXY.Y);                PointF newScroll = DocumentWorkspace.GetDocumentScrollPositionF();                if (delta.X != 0 || delta.Y != 0)                {                    newScroll.X -= delta.X;                    newScroll.Y -= delta.Y;                    lastPanMouseXY = new Point(e.X, e.Y);                    lastPanMouseXY.X -= (int)Math.Truncate(delta.X);                    lastPanMouseXY.Y -= (int)Math.Truncate(delta.Y);                    ++this.ignoreMouseMove; // setting DocumentScrollPosition incurs a MouseMove event. ignore it prevents 'jittering' at non-integral zoom levels (like, say, 743%)                    DocumentWorkspace.SetDocumentScrollPositionF(newScroll);                    Update();                }            }            else if (!this.panMode)            {                OnMouseMove(e);            }            this.lastMouseXY = new Point(e.X, e.Y);            this.lastButton = e.Button;        }        /// <summary>        /// This method is called when the Tool is active and the mouse is moving within        /// the document canvas area.        /// </summary>        /// <param name="e">Contains information about where the mouse cursor is, in document coordinates.</param>        public virtual void OnMouseMove(MouseEventArgs e)        {            if (this.panMode || this.mouseDown > 0)            {                ScrollIfNecessary(new PointF(e.X, e.Y));            }        }        private void MouseDown(MouseEventArgs e)        {            ++this.mouseDown;            if (this.panMode)            {                this.panTracking = true;                this.lastPanMouseXY = new Point(e.X, e.Y);                if (this.CanPan())                {                    this.Cursor = this.handCursorMouseDown;                }            }            else            {                OnMouseDown(e);            }            this.lastMouseXY = new Point(e.X, e.Y);        }        /// <summary>        /// This method is called when the Tool is active and a mouse button has been        /// pressed within the document area.        /// </summary>        /// <param name="e">Contains information about where the mouse cursor is, in document coordinates, and which mouse buttons were pressed.</param>        public virtual void OnMouseDown(MouseEventArgs e)        {            this.lastButton = e.Button;        }        public void MouseUp(MouseEventArgs e)        {            --this.mouseDown;            if (!this.panMode)            {                OnMouseUp(e);            }            this.lastMouseXY = new Point(e.X, e.Y);        }        /// <summary>        /// This method is called when the Tool is active and a mouse button has been        /// released within the document area.        /// </summary>        /// <param name="e">Contains information about where the mouse cursor is, in document coordinates, and which mouse buttons were released.</param>        public virtual void OnMouseUp(MouseEventArgs e)        {            this.lastButton = e.Button;        }        private void Click()        {            OnClick();        }        /// <summary>        /// This method is called when the Tool is active and a mouse button has been        /// clicked within the document area. If you need more specific information,        /// such as where the mouse was clicked and which button was used, respond to        /// the MouseDown/MouseUp events.        /// </summary>        protected virtual void OnClick()        {        }        private static DateTime lastToolSwitch = DateTime.MinValue;        // if we are pressing 'S' to switch to the selection tools, then consecutive        // presses of 'S' should switch to the next selection tol in the list. however,        // if we wait awhile then pressing 'S' should go to the *first* selection        // tool. 'awhile' is defined by this variable.        private static readonly TimeSpan toolSwitchReset = new TimeSpan(0, 0, 0, 2, 0);        private const char decPenSizeShortcut = '[';        private const char decPenSizeBy5Shortcut = (char)27; // Ctrl [ but must also test that Ctrl is down        private const char incPenSizeShortcut = ']';        private const char incPenSizeBy5Shortcut = (char)29; // Ctrl ] but must also test that Ctrl is down        private const char swapColorsShortcut = 'x';        private const char swapPrimarySecondaryChoice = 'c';        private char[] wildShortcuts = new char[] { ',', '.', '/' };        // Return true if the key is handled, false if not.        protected virtual bool OnWildShortcutKey(int ordinal)        {            return false;        }        private DateTime lastKeyboardMove = DateTime.MinValue;        private void KeyPress(Keys key)        {            OnKeyPress(key);        }        /// <summary>        /// This method is called when the tool is active and a keyboard key is pressed        /// and released that is not representable with a regular Unicode chararacter.        /// An example would be the arrow keys.        /// </summary>        protected virtual void OnKeyPress(Keys key)        {            /**            Point dir = Point.Empty;            if (key != lastKey)            {                lastKeyboardMove = DateTime.MinValue;            }            lastKey = key;            switch (key)            {                case Keys.Left:                    --dir.X;                    break;                case Keys.Right:                    ++dir.X;                    break;                case Keys.Up:                    --dir.Y;                    break;                case Keys.Down:                    ++dir.Y;                    break;            }            if (!dir.Equals(Point.Empty))            {                long span = DateTime.Now.Ticks - lastKeyboardMove.Ticks;                if ((span * 4) > TimeSpan.TicksPerSecond)                {                    keyboardMoveRepeats = 0;                    keyboardMoveSpeed = 1;                }                else                {                    keyboardMoveRepeats++;                    if (keyboardMoveRepeats > 15 && (keyboardMoveRepeats % 4) == 0)                    {                        keyboardMoveSpeed++;                    }                }                lastKeyboardMove = DateTime.Now;                int offset = (int)(Math.Ceiling(DocumentWorkspace.GetRatio()) * (double)keyboardMoveSpeed);//ScaleFactor.                Cursor.Position = new Point(Cursor.Position.X + offset * dir.X, Cursor.Position.Y + offset * dir.Y);                Point location = DocumentWorkspace.PointToScreenFromTool(Point.Truncate(DocumentWorkspace.DocumentToClient(PointF.Empty)));                PointF stylusLocF = new PointF((float)Cursor.Position.X - (float)location.X, (float)Cursor.Position.Y - (float)location.Y);                Point stylusLoc = new Point(Cursor.Position.X - location.X, Cursor.Position.Y - location.Y);                stylusLoc = DocumentWorkspace.UnscalePoint(stylusLoc);                stylusLocF = DocumentWorkspace.UnscalePoint(stylusLocF);                DocumentWorkspace.PerformDocumentMouseMove(new MouseEventArgs(lastButton, 1, stylusLoc.X, stylusLoc.Y, 0));            }**/        }        public static Rectangle RoundRectangle(RectangleF rectF)        {            float left = (float)Math.Floor(rectF.Left);            float top = (float)Math.Floor(rectF.Top);            float right = (float)Math.Ceiling(rectF.Right);            float bottom = (float)Math.Ceiling(rectF.Bottom);            return Rectangle.Truncate(RectangleF.FromLTRB(left, top, right, bottom));        }        private bool CanPan()        {            //Rectangle vis = RoundRectangle(DocumentWorkspace.GetVisibleDocumentRectangleF());            //vis.Intersect(Document.Bounds);            //if (vis == Document.Bounds)            //{            //    return false;            //}            //else            {                return true;            }        }        private void KeyUp(KeyEventArgs e)        {            if (this.panMode)            {                this.panMode = false;                this.panTracking = false;                this.Cursor = this.panOldCursor;                this.panOldCursor = null;                e.Handled = true;            }            OnKeyUp(e);        }        /// <summary>        /// This method is called when the tool is active and a keyboard key is pressed.        /// If you respond to the keyboard key, set e.Handled to true.        /// </summary>        protected virtual void OnKeyUp(KeyEventArgs e)        {            keysThatAreDown.Clear();        }        private void KeyDown(KeyEventArgs e)        {            OnKeyDown(e);        }        /// <summary>        /// This method is called when the tool is active and a keyboard key is released        /// Before responding, check that e.Handled is false, and if you then respond to         /// the keyboard key, set e.Handled to true.        /// </summary>        protected virtual void OnKeyDown(KeyEventArgs e)        {            if (!e.Handled)            {                if (!keysThatAreDown.Contains(e.KeyData))                {                    keysThatAreDown.Add(e.KeyData, new KeyTimeInfo());                }                if (!this.IsMouseDown &&                    !this.panMode &&                    e.KeyCode == Keys.Space)                {                    this.panMode = true;                    this.panOldCursor = this.Cursor;                    if (CanPan())                    {                        this.Cursor = this.handCursor;                    }                    else                    {                        this.Cursor = this.handCursorInvalid;                    }                }                // arrow keys are processed in another way                // we get their KeyDown but no KeyUp, so they can not be handled                // by our normal methods                OnKeyPress(e.KeyData);            }        }        private void SelectionChanging()        {            OnSelectionChanging();        }        /// <summary>        /// This method is called when the Tool is active and the selection area is        /// about to be changed.        /// </summary>        protected virtual void OnSelectionChanging()        {        }        private void SelectionChanged()        {            OnSelectionChanged();        }        /// <summary>        /// This method is called when the Tool is active and the selection area has        /// been changed.        /// </summary>        protected virtual void OnSelectionChanged()        {        }        private void PasteQuery(IDataObject data, out bool canHandle)        {            OnPasteQuery(data, out canHandle);        }        /// <summary>        /// This method is called when the system is querying a tool as to whether        /// it can handle a pasted object.        /// </summary>        /// <param name="data">        /// The clipboard data that was pasted by the user that should be inspected.        /// </param>        /// <param name="canHandle">        /// <b>true</b> if the data can be handled by the tool, <b>false</b> if not.        /// </param>        /// <remarks>        /// If you do not set canHandle to <b>true</b> then the tool will not be        /// able to respond to the Edit menu's Paste item.        /// </remarks>        protected virtual void OnPasteQuery(IDataObject data, out bool canHandle)        {            canHandle = false;        }        private void Paste(IDataObject data, out bool handled)        {            OnPaste(data, out handled);        }        /// <summary>        /// This method is called when the user invokes a paste operation. Tools get        /// the first chance to handle this data.        /// </summary>        /// <param name="data">        /// The data that was pasted by the user.        /// </param>        /// <param name="handled">        /// <b>true</b> if the data was handled and pasted, <b>false</b> if not.        /// </param>        /// <remarks>        /// If you do not set handled to <b>true</b> the event will be passed to the         /// global paste handler.        /// </remarks>        protected virtual void OnPaste(IDataObject data, out bool handled)        {            handled = false;        }        private void Pulse()        {            OnPulse();        }        /// <summary>        /// This method is called many times per second, called by the DocumentWorkspace.        /// </summary>        protected virtual void OnPulse()        {            if (this.panTracking && this.lastButton == MouseButtons.Right)            {                /**                Point position = this.lastMouseXY;                RectangleF visibleRect = DocumentWorkspace.GetVisibleDocumentRectangleF();                PointF visibleCenterPt = new PointF((visibleRect.Left + visibleRect.Right) / 2, (visibleRect.Top + visibleRect.Bottom) / 2);                PointF delta = new PointF(position.X - visibleCenterPt.X, position.Y - visibleCenterPt.Y);                PointF newScroll = DocumentWorkspace.GetDocumentScrollPositionF();                if (delta.X != 0 || delta.Y != 0)                {                    newScroll.X += delta.X;                    newScroll.Y += delta.Y;                    ++this.ignoreMouseMove; // setting DocumentScrollPosition incurs a MouseMove event. ignore it prevents 'jittering' at non-integral zoom levels (like, say, 743%)                    UI.SuspendControlPainting(DocumentWorkspace.GetThis());                    DocumentWorkspace.SetDocumentScrollPositionF(newScroll);                                        this.trackingNub.Location = Utility.GetRectangleCenter(DocumentWorkspace.GetVisibleDocumentRectangleF());                    UI.ResumeControlPainting(DocumentWorkspace.GetThis());                    DocumentWorkspace.InvalidateFromTool(true);                    Update();                }**/            }        }        protected bool ScrollIfNecessary(PointF position)        {            if (!autoScroll || !CanPan())            {                return false;            }            RectangleF visible = DocumentWorkspace.GetVisibleDocumentRectangleF();            PointF lastScrollPosition = DocumentWorkspace.GetDocumentScrollPositionF();            PointF delta = PointF.Empty;            PointF zoomedPoint = PointF.Empty;                        zoomedPoint.X = ((visible.Left + visible.Right) / 2.0f + 1.02f * (position.X - (visible.Left + visible.Right) / 2.0f));            zoomedPoint.Y = ((visible.Top + visible.Bottom) / 2.0f + 1.02f * (position.Y - (visible.Top + visible.Bottom) / 2.0f));            if (zoomedPoint.X < visible.Left)            {                delta.X = zoomedPoint.X - visible.Left;            }            else if (zoomedPoint.X > visible.Right)            {                delta.X = zoomedPoint.X - visible.Right;            }            if (zoomedPoint.Y < visible.Top)            {                delta.Y = zoomedPoint.Y - visible.Top;            }            else if (zoomedPoint.Y > visible.Bottom)            {                delta.Y = zoomedPoint.Y - visible.Bottom;            }            if (!delta.IsEmpty)            {                PointF newScrollPosition = new PointF(lastScrollPosition.X + delta.X, lastScrollPosition.Y + delta.Y);                DocumentWorkspace.SetDocumentScrollPositionF(newScrollPosition);                Update();                return true;            }            else            {                return false;            }        }        private void SelectionChangingHandler(object sender, EventArgs e)        {            OnSelectionChanging();        }        private void SelectionChangedHandler(object sender, EventArgs e)        {            OnSelectionChanged();        }        protected void Update()        {            DocumentWorkspace.Update();        }        // NOTE: Your constructor must be able to run successfully with a documentWorkspace        //       of null. This is sent in while the DocumentControl static constructor         //       class is building a list of ToolInfo instances, so that it may construct        //       the list without having to also construct a DocumentControl.        public OtherTool(ISurfaceBox documentWorkspace,                    ImageResource toolBarImage,                    string name,                    string helpText,                    char hotKey,                    bool skipIfActiveOnHotKey)        {            this.documentWorkspace = documentWorkspace;            this.toolBarImage = toolBarImage;        }        public event EventHandler Disposed;        private void OnDisposed()        {            if (Disposed != null)            {                Disposed(this, EventArgs.Empty);            }        }        public void Dispose()        {                    }    }}
 |