From e0e82b6905707050525ea9eeedb176c8ec8012e3 Mon Sep 17 00:00:00 2001 From: Xanfre Date: Sat, 18 May 2019 11:19:37 -0500 Subject: [PATCH 1/2] Reader mode and scrolling work -Added new reader mode to RichTextBox using the new scrolling method -Added ability to scroll horizontally on DataGridView by tilting the mouse wheel --- .../CustomControls/DataGridViewCustom.cs | 39 ++++ .../CustomControls/RichTextBoxCustom.cs | 185 +++++++++++++++++- 2 files changed, 220 insertions(+), 4 deletions(-) diff --git a/AngelLoader/CustomControls/DataGridViewCustom.cs b/AngelLoader/CustomControls/DataGridViewCustom.cs index 459aa614c..012770ed2 100644 --- a/AngelLoader/CustomControls/DataGridViewCustom.cs +++ b/AngelLoader/CustomControls/DataGridViewCustom.cs @@ -532,6 +532,45 @@ internal void FillColumns(List columnDataList) #endregion + #region Horizontal scrolling + + public const int WM_MOUSEHWHEEL = 0x020E; + + protected override void WndProc(ref Message m) + { + base.WndProc(ref m); + if (m.HWnd != Handle) + { + return; + } + else + { + if (m.Msg == WM_MOUSEHWHEEL) + { + int delta = (int)m.WParam; + if (delta < 0) + { + if (HorizontalScrollingOffset > 14) + { + HorizontalScrollingOffset -= 15; + } + else + { + HorizontalScrollingOffset = 0; + } + m.Result = (IntPtr)1; + } + if (delta > 0) + { + HorizontalScrollingOffset += 15; + m.Result = (IntPtr)1; + } + } + } + } + + #endregion + protected override void Dispose(bool disposing) { if (disposing) diff --git a/AngelLoader/CustomControls/RichTextBoxCustom.cs b/AngelLoader/CustomControls/RichTextBoxCustom.cs index 35d4ecaa1..eaf3d522e 100644 --- a/AngelLoader/CustomControls/RichTextBoxCustom.cs +++ b/AngelLoader/CustomControls/RichTextBoxCustom.cs @@ -1,6 +1,9 @@ using System; +using System.ComponentModel; +using System.Drawing; using System.Globalization; using System.IO; +using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; @@ -29,6 +32,14 @@ public RichTextBoxCustom() // Make sure this is valid right from the start _scrollInfo.cbSize = (uint)Marshal.SizeOf(_scrollInfo); _scrollInfo.fMask = (uint)ScrollInfoMask.SIF_ALL; + ReaderModeEnabled = true; + tmrAutoScroll = new Timer(); + tmrAutoScroll.Interval = AUTO_SCROLL_TICK_INTERVAL; + tmrAutoScroll.Tick += new EventHandler(tmrAutoScroll_Tick); + pbGlyph = new PictureBox(); + pbGlyph.Size = new Size(26, 26); + pbGlyph.Visible = false; + Controls.Add(pbGlyph); } #region Zoom stuff @@ -388,6 +399,152 @@ private void InterceptMousewheel(ref Message m) #endregion + #region Better reader mode + + const int AUTO_SCROLL_TICK_INTERVAL = 25; + const int AUTO_SCROLL_DISTANCE_MULTIPLIER = 2; + + private class NativeMethods + { + [DllImport("comctl32.dll", SetLastError = true, EntryPoint = "#383")] + public static extern void DoReaderMode(ref InteropTypes.READERMODEINFO prmi); + } + + private class InteropTypes + { + public const int WM_MBUTTONDOWN = 0x0207; + public const int WM_MBUTTONUP = 0x0208; + public const int WM_XBUTTONDOWN = 0x020B; + public const int WM_LBUTTONDOWN = 0x0201; + public const int WM_RBUTTONDOWN = 0x0204; + public const int WM_MOUSELEAVE = 0x02A3; + public const int WM_MOUSEWHEEL = 0x020A; + public const int WM_MOUSEHWHEEL = 0x020E; + public const int WM_KEYDOWN = 0x0100; + public delegate bool TranslateDispatchCallbackDelegate(ref Message lpmsg); + public delegate bool ReaderScrollCallbackDelegate(ref READERMODEINFO prmi, int dx, int dy); + [Flags] + public enum ReaderModeFlags + { + None = 0x00, + ZeroCursor = 0x01, + VerticalOnly = 0x02, + HorizontalOnly = 0x04 + } + + [StructLayout(LayoutKind.Sequential)] + public struct READERMODEINFO + { + public int cbSize; + public IntPtr hwnd; + public ReaderModeFlags fFlags; + public IntPtr prc; + public ReaderScrollCallbackDelegate pfnScroll; + public TranslateDispatchCallbackDelegate fFlags2; + public IntPtr lParam; + } + } + + Timer tmrAutoScroll; + int scrollIncrementY; + PictureBox pbGlyph; + bool endOnMouseUp; + + [DefaultValue(true), Category("Behavior"), Description("Enables reader mode for the control.")] + public bool ReaderModeEnabled + { + get; + set; + } + + void tmrAutoScroll_Tick(object sender, EventArgs e) + { + //Scroll RichTextBox using pixels rather than lines + BetterScroll(Handle, scrollIncrementY); + } + + private bool TranslateDispatchCallback(ref Message msg) + { + bool isMouseDown = false; + switch (msg.Msg) + { + case InteropTypes.WM_LBUTTONDOWN: + case InteropTypes.WM_MBUTTONDOWN: + case InteropTypes.WM_RBUTTONDOWN: + case InteropTypes.WM_XBUTTONDOWN: + case InteropTypes.WM_MOUSEWHEEL: + case InteropTypes.WM_MOUSEHWHEEL: + case InteropTypes.WM_KEYDOWN: + isMouseDown = true; + break; + } + + if (isMouseDown || (endOnMouseUp && (msg.Msg == InteropTypes.WM_MBUTTONUP))) + { + // exit reader mode + tmrAutoScroll.Stop(); + } + + if ((!endOnMouseUp && (msg.Msg == InteropTypes.WM_MBUTTONUP)) || (msg.Msg == InteropTypes.WM_MOUSELEAVE)) + { + return true; + } + + if (isMouseDown) + { + msg.Msg = InteropTypes.WM_MBUTTONDOWN; + } + + return false; + } + + private bool ReaderScrollCallback(ref InteropTypes.READERMODEINFO prmi, int dx, int dy) + { + scrollIncrementY = dy * AUTO_SCROLL_DISTANCE_MULTIPLIER; + + if (dy != 0) endOnMouseUp = true; + + return true; + } + + private InteropTypes.ReaderModeFlags GetReaderModeFlags() + { + return InteropTypes.ReaderModeFlags.VerticalOnly; + } + + private void EnterReaderMode() + { + // bounds to get the scrolling sensitivity + Rectangle scrollBounds = new Rectangle(pbGlyph.Left, pbGlyph.Top, pbGlyph.Right, pbGlyph.Bottom); + IntPtr rectPtr = Marshal.AllocHGlobal(Marshal.SizeOf(scrollBounds)); + + try + { + Marshal.StructureToPtr(scrollBounds, rectPtr, true); + + InteropTypes.READERMODEINFO readerInfo = new InteropTypes.READERMODEINFO + { + hwnd = Handle, + fFlags = GetReaderModeFlags(), + prc = rectPtr, + lParam = IntPtr.Zero, + fFlags2 = new InteropTypes.TranslateDispatchCallbackDelegate(TranslateDispatchCallback), + pfnScroll = new InteropTypes.ReaderScrollCallbackDelegate(ReaderScrollCallback) + }; + + readerInfo.cbSize = Marshal.SizeOf(readerInfo); + + // enable reader mode + NativeMethods.DoReaderMode(ref readerInfo); + } + finally + { + Marshal.FreeHGlobal(rectPtr); + } + } + + #endregion + [DllImport("user32.dll")] public static extern IntPtr SetCursor(HandleRef hcursor); @@ -430,13 +587,23 @@ protected override void WndProc(ref Message m) case InteropMisc.WM_MOUSEWHEEL: InterceptMousewheel(ref m); break; - // Fix the flickering that is present when reader mode is entered + // Intercept the middle mouse button and direct it to use the fixed reader mode case InteropMisc.WM_MBUTTONDOWN: case InteropMisc.WM_MBUTTONUP: case InteropMisc.WM_MBUTTONDBLCLK: - SetStyle(ControlStyles.Selectable, false); - DefWndProc(ref m); - SetStyle(ControlStyles.Selectable, true); + if ((ReaderModeEnabled)) + { + if (VerticalScrollBarVisible(this)) + { + // Enter reader mode + pbGlyph.Location = Point.Subtract(this.PointToClient(Control.MousePosition), new Size(13, 13)); + SetCursor(new HandleRef(Cursors.NoMoveVert, Cursors.NoMoveVert.Handle)); + m.Result = (IntPtr)1; + tmrAutoScroll.Start(); + endOnMouseUp = false; + EnterReaderMode(); + } + } break; // The below DefWndProc() call essentially "calls" this section, and this section "returns" whether // the cursor was over a link (via LinkCursor) @@ -798,5 +965,15 @@ private static string GLMLToRTF(string text) } #endregion + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (tmrAutoScroll != null) tmrAutoScroll.Dispose(); + if (pbGlyph != null) pbGlyph.Dispose(); + } + base.Dispose(disposing); + } } } From de73e09619864e92d299e7afb089bd66eee9791c Mon Sep 17 00:00:00 2001 From: Xanfre Date: Sat, 18 May 2019 17:55:38 -0500 Subject: [PATCH 2/2] Tweak reader mode values --- AngelLoader/CustomControls/RichTextBoxCustom.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/AngelLoader/CustomControls/RichTextBoxCustom.cs b/AngelLoader/CustomControls/RichTextBoxCustom.cs index eaf3d522e..13a8d69ee 100644 --- a/AngelLoader/CustomControls/RichTextBoxCustom.cs +++ b/AngelLoader/CustomControls/RichTextBoxCustom.cs @@ -34,7 +34,7 @@ public RichTextBoxCustom() _scrollInfo.fMask = (uint)ScrollInfoMask.SIF_ALL; ReaderModeEnabled = true; tmrAutoScroll = new Timer(); - tmrAutoScroll.Interval = AUTO_SCROLL_TICK_INTERVAL; + tmrAutoScroll.Interval = 10; tmrAutoScroll.Tick += new EventHandler(tmrAutoScroll_Tick); pbGlyph = new PictureBox(); pbGlyph.Size = new Size(26, 26); @@ -401,9 +401,6 @@ private void InterceptMousewheel(ref Message m) #region Better reader mode - const int AUTO_SCROLL_TICK_INTERVAL = 25; - const int AUTO_SCROLL_DISTANCE_MULTIPLIER = 2; - private class NativeMethods { [DllImport("comctl32.dll", SetLastError = true, EntryPoint = "#383")] @@ -500,7 +497,7 @@ private bool TranslateDispatchCallback(ref Message msg) private bool ReaderScrollCallback(ref InteropTypes.READERMODEINFO prmi, int dx, int dy) { - scrollIncrementY = dy * AUTO_SCROLL_DISTANCE_MULTIPLIER; + scrollIncrementY = dy; if (dy != 0) endOnMouseUp = true;