• 0

ScribBox - Line Numbered RichTextBox


Question

hey, all, i remember a long time ago, i posted asking if someone knew how to apply line-numbering using pure win32 api to modify the non-client area.

i have finally done it. of course, there are some menial performance drawbacks, but if anyone is willing to help fix them, please pm or email me.

this control inherits from .net's richtextbox and is named ScribBox for the program for which it was made (Scrib).

attached is a picture, and, yes, there are 20 lines in the client area.

post-72514-1128815937.png

Edited by Ianmac45
Link to comment
https://www.neowin.net/forum/topic/382661-scribbox-line-numbered-richtextbox/
Share on other sites

6 answers to this question

Recommended Posts

  • 0

here's a quick rundown of the problems i have with it.

+ you can turn the line numbering on and off, but it doesn't clear the side bar when turning it off.

+ painting performance

here's a quick rundown of what awesome cool features this control has

+ a premade working context menu

+ extra properties such as FirstVisibleLine, LastVisibleLine, CurrentLine

+ Delete functionality (as if you pressed the Delete key)

+ Go To Line functionality

it's really awesome.

  • 0

ok, since no one has actually replied to this post. i'm simply going to post the main part of the code. the only things i know are missing are some properties/variables and all win32 objects/methods. this exact code produced the picture above.

protected override void WndProc(ref Message m)
{
	//this method mainly controls how the line numbers are painted
	//so we gotta skip it if it's not wanted or if it's designtime
	if(this.DesignMode || !showNumbers)// || !System.Diagnostics.Debugger.IsAttached)
	{
  base.WndProc(ref m);
  return;
	}


	switch(m.Msg)
	{
  case (int)Win32.WM.NCCALCSIZE:
  	if(m.WParam.ToInt32() != 0)
  	{
    Win32.NCCALCSIZE_PARAMS p = (Win32.NCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(Win32.NCCALCSIZE_PARAMS));
    p.rgrc0.Left = sideWidth;
    Marshal.StructureToPtr(p, m.LParam, true);
  	}

  	break;

  case (int)Win32.WM.NCPAINT:
  	IntPtr hDC = Win32.GetWindowDC(m.HWnd);
  	Graphics g = Graphics.FromHdc(hDC);

  	PaintLineNumbers(g);

  	//cleanup
  	g.Dispose();
  	Win32.ReleaseDC(m.HWnd, hDC);

  	//need to redraw client area, because sometimes it simply disappears
  	base.Refresh();

  	break;
	}

	base.WndProc(ref m);
}

private void PaintLineNumbers(Graphics g)
{
	//set graphics environment
	g.Clear(this.BackColor);

	//init drawing utensils
	Color numColor = Color.FromArgb(0, 128, 128);
	Brush br = new SolidBrush(numColor);
	Pen pen = new Pen(numColor);
	int height = 3;

	//draw visible line numbers only
	for(int i = FirstVisibleLine; i <= LastVisibleLine; i++)
	{
  //gets line number as right-justified string
  string text = " " + (i + 1).ToString().PadLeft(this.Lines.Length.ToString().Length);
  g.DrawString(text, this.Font, br, 0, height);
  height += this.Font.Height;

  //if there is more than one line, this statement is necessary 
  //to prevent printing one more line number than needed
  if(i == LastVisibleLine - 1)
  	break;
	}

	//draw line seperating numbers from text
	pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
	g.DrawLine(pen, sideWidth - 1, 1, sideWidth - 1, this.Height);
}

anyway, i really need help with debugging and improving it's speed. i'd also like to implement some other features, but if anyone is willing to help, i'd really appreciate it.

  • 0

Speed improvements:

+ use the bounding box of the HRGN that you'll get thru the WM_NCPAINT to only update the necessary parts.

+ fall back to plain old GDI calls.

+ don't do an invalidate on the whole clientarea in the WM_NCPAINT, but figure out what's going wrong (might need to not pass the WM_NCPAINT to the old WNDPROC).

+ check if caching makes things faster (could also raise a costly active pagefault).

  • 0

i still have to look at the first two, but i think the first item kinda ties in with the third item

excluding the call to the old wndproc for ncpaint did speed it up a bit, but then the scrollbars weren't painted properly. also, just like the code says, i need the base.Refresh() call so it works with the rest of my app.

  • 0

WM_NCPAINT:

a) clip your update rectangle with the HRGN being passed, creating a new HRGN.

b) pass that new to base.wndProc(WM_NCPAINT, reinterpret_cast<WPARAM>(yourNewHrgn), 0L);

c) do your painting.

GDI calls:

GDI calls are much faster than GDI+ calls in current implementations. Since GDI is used to draw the richeditbox in the first place, the looks will also be more consistent.

HRGN that you get:

see WM_NCPAINT.

base.Refresh() call:

seems like a fundamental flaw in your application then. There is no reason that you should invalidate the client-area in the non-client area painting proc.

  • 0

ok, i updated the ncpaint case to this (not much change, just a little here and there from msdn and what andreas told me)

case (int)Win32.WM.NCPAINT:
	if((int)m.WParam != 1)
  break;

	//painting
	IntPtr hDC = Win32.GetWindowDC(m.HWnd);
	Graphics g = Graphics.FromHdc(hDC);
	PaintLineNumbers(g);

	//cleanup
	g.Dispose();
	Win32.ReleaseDC(m.HWnd, hDC);
	base.DefWndProc(ref m);

	return;

but, for the plain old GDI calls, is there some sort of reference that i can use to figure out what each function does and how to use it?

i sorta tried the caching of the side bar, but it stole system resources like crazy. maybe i'll try it again later, but definitely not now

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • Really? Do you want it spelled out? Ok: It was a funsies way to say that we can confidently asume that their update servers were shut down years ago already, and no updates have been developed or delivered to any LG phone in years, since, to begin, LG wasn't too well known for their software support.
    • Good afternoon, I have a customer who purchased a Dell laptop last year. One of the latest Inspirons. they are older so it can be a bit hard to see things on the screen. They are using Windows 11 Home 23H2, I have not upgraded them yet to 24H2. What I did was changed the scaling to 150% and that automatically made all the icons on desktop bigger and using in Chrome webpage elements are bigger etc. The thing is I overlooked the Taskbar and the icons most notably hidden within the arrow pointing up. I though by changing to 150% the scaling even the taskbar would get bigger. Again I don't know how I missed seeing that. Is this something that can be fixed? One other thing is I notice in File Explorer things are also small and not larger after the change. Can this be fixed as well?   Thank You.
    • Apple still has two unannounced features for iOS 26 by Hamid Ganji Apple held its WWDC25 event this month to unveil a slew of AI features and its new design for operating systems, known as Liquid Glass. While iOS 26 currently has no shortage of features, the iPhone maker might still have some features under wraps that didn’t make a debut at this month’s WWDC. Bloomberg’s Mark Gurman writes in his weekly Power On newsletter that Apple didn’t announce two iOS 26 features at the WWDC event. The first feature is a live translation of conversations via AirPods, and the latter is the ability to sync your wireless network login information across devices at a hotel or gym. Even though these features were already tipped to arrive in iOS 26, Apple held them from the event, presumably because they’re still not ready to ship. Apple appears to have learned from its experience with Apple Intelligence and aims to break the habit of unveiling new features before they are ready for release. The Live Translation on iOS 26 is currently integrated with popular apps like Messages, FaceTime, and Phone to help users break language barriers and communicate in different languages. The feature is now under development for AirPods, allowing users to hear real-time speech translations. Moreover, the WiFi syncing feature allows you to sync your sign-in information across your entire Apple ecosystem, enabling you to connect to a public WiFi network with ease. This would eliminate the need to sign into a WiFi network separately on each device. While these features haven’t arrived in iOS 26 yet, they’re more likely to be released later this year, in October or December.
    • Intel Level L4 cache has been around for a long time, so AMD Zen 3D Cache is a copy of Intel L4 cache that was introduced with Broadwell i7-5775c, which had 128mb of Level L4 cache. Secondly, Zen 6 is not faster in single-threaded performance than 13900k/14900k. 285k is something new Intel is trying, basically showing us that chiplet design does not work for gaming, just like AMD design does not work for gaming. Throwing more cores at it and having L4 cache won't fix the issue, and that is frame dip and stuttering caused by a very stupid design decision to keep the memory controller outside the compute tile. Might as well put a memory controller by bringing back a south bridge chip. lol
  • Recent Achievements

    • Community Regular
      Primey_ went up a rank
      Community Regular
    • Reacting Well
      Gromvar earned a badge
      Reacting Well
    • Dedicated
      BreakingBenjamin earned a badge
      Dedicated
    • Week One Done
      Hartej earned a badge
      Week One Done
    • One Year In
      TsunadeMama earned a badge
      One Year In
  • Popular Contributors

    1. 1
      +primortal
      518
    2. 2
      +FloatingFatMan
      183
    3. 3
      ATLien_0
      168
    4. 4
      Skyfrog
      98
    5. 5
      Som
      96
  • Tell a friend

    Love Neowin? Tell a friend!