[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