• 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

    • The 2025 Complete Splunk Beginner Bundle is now 25% off by Steven Parker Today's highlighted deal comes via Neowin Deals store, where you can save 75% on The 2025 Complete Splunk Beginner Bundle. Splunk is a powerful data platform used to gather information from multiple sources and index it for efficient access. You can then use collected data to create visualizations, analytics, and a variety of automated and security-related functions. With its web-style interface, Splunk is easy to use and is utilized by many companies worldwide. What's Included: Splunk Fundamentals for Effective Management of SOC and SIEM Oak Academy 38 Lessons (3.5h) Lifetime $20.00 Value Splunk | Splunk Core Certified User Certification Prep Lab Oak Academy, 63 Lessons (6h),Lifetime, $20.00 Value Splunk | Splunk Core Certified Power User SPLK 1002 Prep Oak Academy, 53 Lessons (5.5h), Lifetime, $20.00 Value Splunk| Splunk Enterprise Certified Admin Certification Prep Oak Academy, 68 Lessons (8.5h), Lifetime, $20.00 Value Requirements Basic understanding of IT and networking concepts Familiarity with Linux and Windows operating systems A computer with internet access for hands-on practice Good to Know Length of time users can access this course: lifetime Access options: desktop or mobile Redemption deadline: redeem your code within 30 days of purchase Experience level required: all levels Certificate of Completion ONLY Updates included Closed captioning NOT available NOT downloadable for offline viewing Learn more about our Lifetime deals here! Lifetime access to this 2025 Complete Splunk Beginner Bundle normally costs $80, but this deal can be yours for just $19.99, that's a saving of $60. For full terms, specifications, and info, click the link below. Get the 2025 Complete Splunk Beginner Bundle for just $19.99 (75% off MSRP: $80) Although priced in U.S. dollars, this deal is available for digital purchase worldwide. We post these because we earn commission on each sale so as not to rely solely on advertising, which many of our readers block. It all helps toward paying staff reporters, servers and hosting costs. Other ways to support Neowin Whitelist Neowin by not blocking our ads Create a free member account to see fewer ads Make a donation to support our day to day running costs Subscribe to Neowin - for $14 a year, or $28 a year for an ad-free experience Disclosure: Neowin benefits from revenue of each sale made through our branded deals site powered by StackCommerce.
    • and you got scammed because 2077 launch its one of the worse thing i ever remember and even to this day the game never reached its potential
    • Basic Auth needs to die especially for anything internet bound and exchange in the office 365 suite is extremely internet bound as the cloud service it is. Microsoft has been announcing it for years now. There is always a balance between security and usability, in this case it should be glaringly obvious.
    • the more they want to charge more the more people won't buy anything at launch and wait until its reduced price or discount, hell i even waited until its free on epic game store. and smoke pass model its not viable and having others to pay 80 dollars to subside it wont help
    • Pandemic of 2020, AKA justification to "print" 10 trillion $$$ and keep the Ponzi scheme alive for another while. Until the next one.
  • Recent Achievements

    • Apprentice
      Wireless wookie went up a rank
      Apprentice
    • Week One Done
      bukro earned a badge
      Week One Done
    • One Year In
      Wulle earned a badge
      One Year In
    • One Month Later
      Wulle earned a badge
      One Month Later
    • One Month Later
      Simmo3D earned a badge
      One Month Later
  • Popular Contributors

    1. 1
      +primortal
      558
    2. 2
      ATLien_0
      258
    3. 3
      +FloatingFatMan
      182
    4. 4
      Michael Scrip
      124
    5. 5
      Steven P.
      100
  • Tell a friend

    Love Neowin? Tell a friend!