PDA

View Full Version : Common problem: implementing a text editor area/box



cronodragon
15-12-2006, 04:05 AM
I think this is a universal problem of GUIs, but I have no idea how to look for the algorithm.

The idea is simple, making from ground up an optimal edit area (like a TMemo, a TEdit, or the Delphi's editor).

The first problem that must be optimized is drawing the text lines in a way that consumes as little time as possible. For example, if a document of 100,000 lines is being edited in the text box, the idea is to show only the (let's say) 80 lines the user is watching. And not only that, if the content of that huge document is distributed in those 80 lines, to show only the characters inside the showable area.

That brings us to the second problem is which dealing with variable font widths. And later on dealing with styles...

Is out there any function in Pascal that can do most of this work in a general way? I mean, the function could have callback functions to get the document text, size font, cursor position, scrolling position, etc, etc, and then just order to draw each text line from one point to another.

Does something like that exist? :?

JernejL
15-12-2006, 09:08 AM
I've implemented half stage (no editing yet, but it has scrolling) of such memo control in my tdc gui, let me describe it a bit and how it works:

what the gui renders in my game is currently not being cached and is created at runtime, and rendered in immediate mode each frame, this could be improved with a display list per control or window, but i havent done any testing yet and could as well be slower with such little elements.

I've wrote a flexible text drawing and measuring routines that support WORD WRAP (i posted them on this forum as well). the rendering function has a almost same function, which instead of rendering, calculates amout of lines (line returns and wraps), text extents and also stores index of characters at which the specific line starts (in a dynamic array) - this is very important.

The same measuring routine is also capable of telling you the string character index at specific XY coordinates. this is for locating the caret and text editing.

Now say you need multi-line scrolling text you just calculate text extents, and then you figure out the scrollbar range (get it from amout of line breaks from text calculating routine), so say you want to start rendering text at line 5 to line 10, you get those indexes from line start character indexes and cut the string, and render just that portion of it ;) it is not smooth way like windows does it, but it works pretty well! it also works with different text sizes as long as the rendering and calculating routines are written to digest it ;)






I think this is a universal problem of GUIs, but I have no idea how to look for the algorithm.

The idea is simple, making from ground up an optimal edit area (like a TMemo, a TEdit, or the Delphi's editor).

The first problem that must be optimized is drawing the text lines in a way that consumes as little time as possible. For example, if a document of 100,000 lines is being edited in the text box, the idea is to show only the (let's say) 80 lines the user is watching. And not only that, if the content of that huge document is distributed in those 80 lines, to show only the characters inside the showable area.

That brings us to the second problem is which dealing with variable font widths. And later on dealing with styles...

Is out there any function in Pascal that can do most of this work in a general way? I mean, the function could have callback functions to get the document text, size font, cursor position, scrolling position, etc, etc, and then just order to draw each text line from one point to another.

Does something like that exist? :?

jdarling
15-12-2006, 01:54 PM
To add to what Delfi said, this depends on your source. If your using a TStrings descendent as your source, then finding line 5 really isn't that big of a problem. BUT if your loading from disk and wanting to keep your overhead down, then you have another problem to deal with. The way that I handle it is to keep a PChar that points to a TFileStream position. This way I can "scroll" the text rather quickly. I have another PChar that keeps the last space that I came across, and if I need word wrapping I use that to decide when to break the line (if (p+1)^<>#32 then begin srcPos:=srcLastSpace; newline; end;).

Now on your rendering side of things. Create a lookup table of ALL font character vectors (Height, Width, KerningX, KerningY, OffsetY). Kerning is a way of having characters placed on the screen in a more readiable fassion (its easy to find out about on the web) while offset is to handle dangeling letters (such as y or g).

Next render your text as you read it from your PChar to an intermediate surface. Draw the surface. On your next render loop, check to see if any of the properties that would force a re-draw has changed (a flag when they change works well for this), if it hasn't then simply re-render you existing surface, if it has then use your lookup table, clear the existing surface, and render with the table yet again.

Once you get this working, things such as startpos, endpos, highlighting, and even code highlighting become alot easier. Then comes editing, this can be a very tricky topic, but if you have the above working I think you can figure it out. its just another PChar for the caret position and proper handeling of the keystrokes when focused.

In case your curious, this is pretty much the way that all of the edits work in windows and linux. Sure there are optimizations, and they use generic pointers instead of file stream pointers (you could do that easily enough), but the general concept is the same.

cronodragon
15-12-2006, 02:37 PM
Thanks ppl! Well it seems it's mostly a problem related to lookup tables. I'll start doing something... 8)