[Lazarus] Dynamic Library in Linux

Andrew Brunner andrew.t.brunner at gmail.com
Tue Dec 16 06:53:40 CET 2008


Martin Friebe schrieb:

> The only reason I did skip the "grid" in the name is that a generic 
> painter base class will not define a griod (or maybe it will but based 
> on pixels). So it does not block anyone from implementing a proportional 
> painter

Okay, but a proportional representation will have a very different 
coordinate mapping, so that most of the basic functions (mouse, cursor 
movements) are very different. My approach addressed exactly those low 
level tasks, with the CharGrid already being a specialized grid class, 
with cells containing characters, and added font and text properties.

My primary goal was a stable base component, that can be turned into any 
text viewer or editor, by adding specialized document interfaces in 
derived classes. For a proportional representation the design will have 
to be turned upside down, and the base class will have to be specialized 
and follow the design of the related content handler(s).


> That canvas/handle holder does not replace the (Grid)Painter. It is used 
> by the GridPainter(s), and used by the GutterPainter(s). It may even be 
> thyat it does not need to exist, and canvas and handle can be passed to 
> all the Painters in Form of their LCL classes.

Then my CharGrid is kind of a canvas holder, which performs the mapping 
between document (content) and viewport (painting) space. The painters 
do not have to know about the organization of the canvas, they only have 
to paint given information within their actual clipping area (part of a 
display line). The content holder (source file) can be switched at any 
time, whereupon the CharGrid adjusts the viewport (window) to the new 
content extent.


> As It currently stands all the info about everything is hold by the Main 
> SynEdit Class, and all other classes need to ask the central SynEdit 
> Class. That is undesirable.

ACK. A MVC (model-view-controller) approach migth be better. The model 
holds the source files, the view manages painting and user interface 
(mouse and keyboard), and the controller updates the document upon input 
or other commands, and synchronizes the related view(s) afterwards.

> I extracted 2 classes already (but the ove isn't complete)
> - TSynEditCaret:
>    Storing all info about the caret. It will obviously need help from 
> other modules, to deal with tabs, double-width chars, wrapped lines 
> (that will probably be a specialized subclass, completely replacing the 
> original), and other things
> -TSynEditSelection:
>   To deal with the selected block. This one is not very related to this 
> discussion. But it has the same needs as the Caret

The caret is private to every view, the outer world only has to retrieve 
or modify the logical (content based) caret position. The same for the 
selection, with content based row/col coordinates; the view will manage 
the display of either a sequential or column based block hightlighting, 
and merge the text attributes of all "block" sources (syntax, 
hyperlinks, selection).

BTW, just the requirement for column-based blocks discourages the use of 
an proportional font. Elastic tabs may allow for blocks with consistent 
left/right margins, but then the text will look strange in any other 
editor or viewer, what's not desireable with shareable source code.


> I will have to add a TSynEditViewPortClass:
>  This will at least store the Coordinates of the screen in the text (as 
> in TopLine/LeftChar - LinesInWindow/CharWidthOfScreen), maybe a bit 
> more.  To do so, it will need access to the Painter to get information 
> about the grid (LineHeight, SingleCharWidth)

This were my CharGrid, that translates everything between document 
(model) and view space. The interface between document and view can be a 
simple record, containing the document row count. My CharGrid then can 
determine everything else from the text itself. I delegated that mapping 
to the syntax highlighter, that already has the task of parsing the 
text. It also will be involved in the determination of foldable blocks, 
so that folding (list of blocks and their state) can be implemented 
inside that class.

TopLine and LeftChar are not of any interest outside the view. A 
ScrollIntoView method will be sufficient for the outer world, with 
document based coordinates, perhaps with an anchor (alTop, alBottom, 
alCenter).



>>> - the highlighter
>>> - the MarkUpManager
>>>     
>> In my solution the highlighting (including hyperlinks) is implemented in 
>> derived classes, by overriding the line-painting method. I ended up in a 
>> single array, holding the scanner start state for every line - required 
>>   
> If I understand your description correct: This special array is 
> currently part of SynEditCodeBuffer? In any case this is information for 
> the highlighter. The (Grid)Drawer should never access this info 
> directly. The grid drawer will ask the highlighter (In the current 
> Synedit there may be a need to clean up the way the Highlighter is 
> handled...)

My hiliter has several purposes:
- it parses a new document for it's line count, multi-line comments, 
longest line (maybe for foldable blocks as well).
- with folding, it translates between document line and visible row 
numbers (not yet implemented).
- it parses a given line for syntactic elements, setting the text 
attributes in the display line buffer.

Painting a line requires multiple actions:
- the viewport row is mapped into a document line (or vice versa).
- the according text is retrieved and stored in the line buffer, with 
tab expansion, special character substitution and UTF translation if 
required, bookmarks etc.
- the syntax highlighter fills in character attributes.
- hyperlink attributes are updated, according to the mouse position.
- the visible part of the line buffer is determined, depending on the 
viewport margins and wrapped lines.

Then the text and gutter painters are invoked for the supplied line 
buffer, if their painting area is not clipped. The text painter 
determines sequences of same text attributes, initializes the canvas 
(DC) and paints the according characters.

The prepared line buffers can be kept in an cache, so that a quick 
refresh can be made when the mouse moves over the hyperlinks in the 
current view.

BTW, the top gutter can hold file tabs, or an ruler with column numbers, 
tab and margin markers. It must not exist at all, but when such an 
object is assigned to the grid, it's invoked in the appropriate situations.

Multiple edit windows deserve an application wide (non-visual) file 
pool. A visual notebook can contain any subset of source files, so that 
both cannot be combined into one component.

So much for now
   DoDi




More information about the Lazarus mailing list