• 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

    • LibreOffice narrows gap with Microsoft Office in 25.8 Beta 1 by David Uzondu The Document Foundation has released LibreOffice 25.8 Beta 1 for public testing on Linux, macOS, and Windows. This is the second pre-release for the 25.8 cycle and the foundation says that the final, stable version of LibreOffice 25.8 is expected to land at the end of August 2025. Starting off with Writer, LibreOffice's Word, the developers have finally addressed some long-standing annoyances, including a new command to easily insert a paragraph break right before a table. This beta also introduces a useful privacy feature in its Auto-Redact tool, letting you strip all images from a document with a single option. To use it, go to Tools and select the Auto-Redact option: The application has improved its ability to handle different languages for punctuation, preventing mix-ups in multilingual documents. Other notable improvements have also been made. A new hyphenation rule lets you choose to prevent a word from splitting at the end of a page, moving the whole line to the next page instead. Microsoft Word has had this feature for years now. The Navigator now displays a handy tooltip with word and character counts for headings and their sub-outlines. Scrolling behavior when selecting text has been improved, making it less erratic. A new command with a keyboard shortcut was added for converting fields into plain text. Calc gets a lot of new functions that bring it closer to its competitors like Excel, including TEXTSPLIT, VSTACK, and WRAPROWS. Impress now properly supports embedded fonts in PPTX files, which should reduce headaches when sharing presentations with PowerPoint users. Alongside these additions, the project is also cleaning house; support for Windows 7, 8, and 8.1 has been completely dropped. There are also smaller UI tweaks across the suite, like allowing a single click to enter rotation mode for objects in Writer and Calc. macOS users get better integration, with proper support for native full screen mode and new window management features from the Sequoia update. In terms of performance, the team has optimized everything from loading huge DOC files and XLSX spreadsheets with tons of conditional formatting to simply switching between sheets in Calc. These improvements should be noticeable, especially when working with complex documents. A new application-wide "Viewer mode" has also been implemented, which opens all files in a read-only state for quick, safe viewing. On a related note, The Document Foundation has joined efforts by the likes of KDE to encourage Windows 10 users to switch to Linux. Also, you might have heard that Denmark, in a bid to lessen its reliance on Microsoft, has decided to make a full switch to LibreOffice, with plans to begin phasing out Office 365 in certain ministries as early as next month. If you're interested in this release, you can read the full release notes and download the binaries for your platform: Windows, macOS (Intel | Apple Silicon), or Linux (DEB | RPM). You can also get the latest stable version from our software stories page.
    • Until it can be used 100% offline (ie: PST file support or equiv) not even considering it. I'll jump to Thunderbird first which has gotten a LOT better since the last time I looked at it.
  • Recent Achievements

    • Explorer
      Case_f went up a rank
      Explorer
    • Conversation Starter
      Jamie Smith earned a badge
      Conversation Starter
    • First Post
      NeoToad777 earned a badge
      First Post
    • Week One Done
      JoeV earned a badge
      Week One Done
    • One Month Later
      VAT Services in UAE earned a badge
      One Month Later
  • Popular Contributors

    1. 1
      +primortal
      545
    2. 2
      ATLien_0
      227
    3. 3
      +FloatingFatMan
      159
    4. 4
      Michael Scrip
      113
    5. 5
      +Edouard
      105
  • Tell a friend

    Love Neowin? Tell a friend!