Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
In some places below, I am unsure what you meant by component: - the view (as in MVC) - the overall editor (as in SynEdit) Hans-Peter Diettrich wrote: Martin Friebe schrieb: Model shall contain - the raw text - bookmarks, and other marks - foldable secitions - ... Other information can be local to a specific Component (in case multiply component display the same model in more than one window). An example would be which sections are folded. This info may or may not be part of the model Right. We should start with the persistent information, stored together with the text on disk, then add all information that is common to all (multiple) Views. Serializing the Model for storage purposes (such as saving to a file or many files) for me comes after the decision how the model looks. There may be more than one way to serialize the model. As there are many ways to use SynEdit. - In Lazarus it is used a SourceEditor, so serializing should write the Text information into one file, and other information into another file. - In User Applications, people may wish to serialize the model into just one file (which can not be edited by other editors) We could differ between a public and a private model. (Probably not needed) Most probably not needed in this form, default is the public Model. Actually we may need. Example folding. Having the same model displayed in many Windows, the user may want to fold different nodes in each Window. Or even use different highlighters, leading to different nodes being available. The design of this must leave the choice to the user, which information is hold in the public, and which in the private model. The private Model can store the same info as the public. The private model only stores info the user whises to be different from the public model, all other info will be forwarded. However concerning the design of the other Classes (Controller/View), the differentation between private or public model is not relevant. They access one Model. This Model knows what to do. Folding has to be reflected in a component, both as a structure (block tree in the gutter) and as currently visible lines (for the text painter), so that a helper object/class is appropriate for retrieving all the information in an synchronized way. Then one instance can reside in the Model, holding the shared definition of the blocks, and another instance can be part of the Views, doing individual folding - that's only a matter of how a new View is initialized. Ack View.Folding := Model.Folding; //object reference if FoldingPerView then begin PrivateFolding := TFoldingState.Create(View.Folding); View.Folding := PrivateFolding; end; [This is what you would consider as pushing another item on the stack, see below] My implementation probably looks slightly different. There will be no dedicated properties (on the View) for dedicated features. View.Model := TheModel; Then the View can internally distribute this. The Model can be a Private Model, which acts as a wrapper to the public Model. This way it is easier to add features, without the need to change the way the view is set up. In this terms if you wish to implement new feature (which are not covered by the set of existing properties), an component that inherits from the original is the most likely way. This inherited component can either implement the features itself, or create additional ( or substitute existing) helper classes to archive the new functionality Isn't LazSynEdit such a customized version of a SynEdit? yes and no. SynLazarus is a fork off, of an early Synedit. Not done by inheritance. But in the following I would like to look at the details of a Component that provides the following functionality (and can be used by any editor, Memo or anything else): A component that has: - a Model (was: RawSource) property - For ease of access an extended TStrings interface can be assumed (this simplifies the case, as it already implements the text to be organized into lines) ACK. UTF-8 encoding, I suppose? Access should be routed through the folding object. For SynEdit in Lazarus, currently UTF8. Ideally most of the code should be agnostic to the encoding, and the remainder exchangeable. The design of the Classes involved most not be based on an encoding. (except maybe the design of the model) - A Tab is a normal character that does has no information about it's later display properties. - Highlighting information is not part of the model. (Displaying the same model in 2 windows can be done with different Highlighters selected) - Markup (such as the selected block, if any) is not part of the model - This Text has information where it can be folded, but is *not* yet folded or wrapped Wordwrap should be implemented in the component, because it depends on the width of the window. Folding should
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Martin Friebe schrieb: In some places below, I am unsure what you meant by component: - the view (as in MVC) - the overall editor (as in SynEdit) Now that you mention it, I'm also unsure. I meant the implementation of the component, without thinking of the embedding/outsorcing of the controller, or whether the control should include an default controller for a default (new text file) data source. Serializing the Model for storage purposes (such as saving to a file or many files) for me comes after the decision how the model looks. But we can decide in advance, which properties are to be stored at all, or will have to be saved and restored when the data source (file) is exchanged. We could differ between a public and a private model. (Probably not needed) Most probably not needed in this form, default is the public Model. Actually we may need. Example folding. Having the same model displayed in many Windows, the user may want to fold different nodes in each Window. Or even use different highlighters, leading to different nodes being available. All that IMO is configurable, using according stacks. The component code uses a given helper object, without knowing whether it's private or shared. The design of this must leave the choice to the user, which information is hold in the public, and which in the private model. The private Model can store the same info as the public. The private model only stores info the user whises to be different from the public model, all other info will be forwarded. Or the private Model is independent from outside data, and all shared properties have to be transferred into the View, by the (application wide) Controller. The public Model cannot know what a View has to do, when settings change, so that all changes must be signaled to the Views. In an stack, we need an back-channel for propagating such configuration changes to the other end. This may be related to what I called characteristic data. The View contains an set of properties, for private use, and the Model contains another set of shared properties. When the shared properties change, a single change notification is sent to each View, with the changed property set, and every View has to check for changes and react as appropriate. That's easier to implement, and doesn't leave an View in an inconsistent state, when one of more related settings change. I remember FontChanged and other methods in SynEdit, which may have to be embedded in a wider scope, e.g. guarded by BeginChange/EndChange calls. All intermediate changes are stored, but are recognized only on the final EndChange. When all acutal changes are collected in an set of ChangeFlags, the receiver can know which settings actually have changed, and which (other) ones may deserve an according readjustment. I already planned to open another thread, on my design for such synchronizations, in detail for synchronizing scrolls and caret moves. However concerning the design of the other Classes (Controller/View), the differentation between private or public model is not relevant. They access one Model. This Model knows what to do. IMO the Model has to know nothing, except that it holds data, and possibly how to load/store these data in a customized class (overridden methods). View.Folding := Model.Folding; //object reference if FoldingPerView then begin PrivateFolding := TFoldingState.Create(View.Folding); View.Folding := PrivateFolding; end; [This is what you would consider as pushing another item on the stack, see below] My implementation probably looks slightly different. There will be no dedicated properties (on the View) for dedicated features. View.Model := TheModel; Then the View can internally distribute this. The Model can be a Private Model, which acts as a wrapper to the public Model. I should have used Self instead of View, to indicate that my code resides inside the View, in the View.Model property setter. Then we agree again, I assume? [encoding] For SynEdit in Lazarus, currently UTF8. Ideally most of the code should be agnostic to the encoding, and the remainder exchangeable. The design of the Classes involved most not be based on an encoding. (except maybe the design of the model) The data exchange between the classes IMO should use fixed data types. When TStrings are used, an agreement must exist whether the strings are Ansi or UTF-8 encoded. In the CharGrid I used WideString in the interface (assuming UCS-2), and left it to the Model to translate the string encoding, between file format, internal storage, and viewer/contoller interface. Wordwrap should be implemented in the component, because it depends on the width of the window. Folding should be reflected in a helper object, that allows to retrieve the visible lines. In the simplest case (source not foldable at all) that object does a 1:1 mapping of the unfolded lines. Which
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Hans-Peter Diettrich wrote: Martin Friebe schrieb: Maybe for clarifications. I started this using the word "view". But I can see there are 2 ways to read this word. - "physical view": Like a painter. The final output of the combined text/style information. Most common drawing it to a canvas. But it could be a reader too. - "logical view": (I guess what you called the grid?). A module that takes the raw-text, and converts it into a structure suitable for the "physical view", applying style/highlight info on the way. In the model-view-controller context, the view is the logical aspect. Best to always specify the context (logical / physical ). The painter is no separate itme in MVC, so it resides within the "View" too. You also pointed out correctly (at the end of the mail) that TextBuffer/lineBuffer/SourceText/etc are inappropriate names. (Unfortunately I came to read this after I wrote most of my response) I will revise my text to use Model instead. In cases were I overlooked the old term, please assume it as a reference to Model. Model shall contain - the raw text - bookmarks, and other marks - foldable secitions - ... Other information can be local to a specific Component (in case multiply component display the same model in more than one window). An example would be which sections are folded. This info may or may not be part of the model Information like the (logical) caret position are specific to each Component. This information is not part of the model. We could differ between a public and a private model. (Probably not needed) Let me add another clarification: My primary viewpoint is that of an component writer, designing components for general use, i.e. not bound to a specific application or context, unless specific to the functionality of the component itself. Consequently my CharGrid is a general component, whose use in Lazarus may deserve extensions to the general functionality. The basic component has certain capabilities, and a specific implementation. Take it both as a general model, and a specific implementation as a proof of the concept. This should apply to both (your grid and LazSynEdit). To the user it will present itself as one whole component. It should not expose it's inner structure. In the case where it is implemented using a structure of internal classes, it will act as Facade and have a single interface. In this terms if you wish to implement new feature (which are not covered by the set of existing properties), an component that inherits from the original is the most likely way. This inherited component can either implement the features itself, or create additional ( or substitute existing) helper classes to archive the new functionality The original class could also expose some of it helper classes (in the same way that a data aware class depends on a data-provider), and allow the end user to provide a class with the desired functionality. This I believe can be discussed in implementation details. Now we can discuss in general, *whether* it's possible to achive the Lazarus-specific functionality, based on the given component design. This was my context in the preceding discussion. I wanted to prove that my approach is suitable for that specific use, and find out where the implementation may deserve a redesign. The result only can be go/nogo. Let's try to stick to the abstracts in this part. We may open a new subthread to this mail and discuss implementation details in parallel. I would also try to stick to the "display/presentation" part of the discussion here. For the edit part a new sub thread may be created? So the below will concern itself with the View of the MVC I do use the word "view" to describe the logical-view of a source-file transformed into a grid. I do not use the word "view" to describe the painter. ( I propose "physical view") I do not use the word "view" to describe the high level dual visibility of the same source-file in 2 windows (or a splitted window) ( I propose "user view" ?? imho a weak description, not good) When it comes to implementation details, like painting, then I'd prefer "component" for the overall (TLazEdit or TCharGrid) component. That component can consist of, or use, dedicated sub-components, wich we should address as text and gutter painters, syntax highlighters etc. We roughly look at a component (I call it TextDrawer to avoid confusion with the word View), that will cover the following functionality: - access to a model - logical presentation of this model (folding, tabs, grid) - painter (gutter, text area, possible others) I believe we can leave details such as scrollbars for a higher level? This could be done using a decorator. [.] [ discussion about double-display-width and multi-code-point chars ] Let's move it to a different thread for details. For discussing the abstracts it should be enough to assume we have access
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Martin Friebe schrieb: Model shall contain - the raw text - bookmarks, and other marks - foldable secitions - ... Other information can be local to a specific Component (in case multiply component display the same model in more than one window). An example would be which sections are folded. This info may or may not be part of the model Right. We should start with the persistent information, stored together with the text on disk, then add all information that is common to all (multiple) Views. Folding has to be reflected in a component, both as a structure (block tree in the gutter) and as currently visible lines (for the text painter), so that a helper object/class is appropriate for retrieving all the information in an synchronized way. Then one instance can reside in the Model, holding the shared definition of the blocks, and another instance can be part of the Views, doing individual folding - that's only a matter of how a new View is initialized. View.Folding := Model.Folding; //object reference if FoldingPerView then begin PrivateFolding := TFoldingState.Create(View.Folding); View.Folding := PrivateFolding; end; [This is what you would consider as pushing another item on the stack, see below] Information like the (logical) caret position are specific to each Component. This information is not part of the model. ACK We could differ between a public and a private model. (Probably not needed) Most probably not needed in this form, default is the public Model. This should apply to both (your grid and LazSynEdit). To the user it will present itself as one whole component. It should not expose it's inner structure. In the case where it is implemented using a structure of internal classes, it will act as Facade and have a single interface. Right, that's why I addressed the component view. In this terms if you wish to implement new feature (which are not covered by the set of existing properties), an component that inherits from the original is the most likely way. This inherited component can either implement the features itself, or create additional ( or substitute existing) helper classes to archive the new functionality Isn't LazSynEdit such a customized version of a SynEdit? So the below will concern itself with the View of the MVC [...] We roughly look at a component (I call it TextDrawer to avoid confusion with the word View), that will cover the following functionality: - access to a model - logical presentation of this model (folding, tabs, grid) - painter (gutter, text area, possible others) I believe we can leave details such as scrollbars for a higher level? This could be done using a decorator. Right. We now should agree about what to discuss, for what purpose. The need for refactoring should be clear by now, when multiple edit windows shall become possible. I should know more about editing lcl code, so that it is at least syntax-checked in the IDE, and in the next step how to test the modifications, perhaps with a test application, or by rebuilding the IDE. [ discussion about double-display-width and multi-code-point chars ] [ column mode block ] Again we can open a thread with implementation details I would like to see see folded view to be part of the TextDrawer (char-grid ?) component. See above. That's only a matter of the initialization and finalization of the component. But in the following I would like to look at the details of a Component that provides the following functionality (and can be used by any editor, Memo or anything else): A component that has: - a Model (was: RawSource) property - For ease of access an extended TStrings interface can be assumed (this simplifies the case, as it already implements the text to be organized into lines) ACK. UTF-8 encoding, I suppose? Access should be routed through the folding object. - A Tab is a normal character that does has no information about it's later display properties. - Highlighting information is not part of the model. (Displaying the same model in 2 windows can be done with different Highlighters selected) - Markup (such as the selected block, if any) is not part of the model - This Text has information where it can be folded, but is *not* yet folded or wrapped Wordwrap should be implemented in the component, because it depends on the width of the window. Folding should be reflected in a helper object, that allows to retrieve the visible lines. In the simplest case (source not foldable at all) that object does a 1:1 mapping of the unfolded lines. - properties to define the ViewPort - The controller can change attributes such as topline or display area according to the users action. - The component is not concerned where those changes originate from - (The decorated TextDrawer (with scrollbars) can send info to the controller, about required Viewport changes) - A canvas. This
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Zitat von Hans-Peter Diettrich drdiettri...@aol.com: Martin Friebe schrieb: Then how to you handle double width chars? This si one of the problems I still have to address. Even in a proportional font, some chars (Chinese, and other) have twice the width of a normal char. They will 2 positions in the grid. Actually it is the same issue as tabs. Are these characters inside the Unicode BMP? AFAIK: yes. All chinese characters are in some fonts double wide characters. [...] That's why keep both the characters and their text attributes in the line buffer, passed to the painter. I started with separate regions, describing the begin and length of tokens, selection etc., but it turned out that the handling of overlapping regions is accomplished easier by a direct mapping of the text attributes to every single character. The text attributes then can be used to e.g. determine, whether the mouse is over a (character in a) hyperlink. What means 'text attributes to every single character'? How much memory is needed for a 10mb text? [...] One such case is the docking manager, where I still don't see a chance to implement an different manager separately from Controls.pp. The anchor docking sample in fact lacks the drag-dock functionality, because the implementation would require access to and modification of the existing code base, hidden in the implementation section of Controls.pp. An extraction of the hidden classes leads to circular unit references all over, protected methods are inaccessible from other classes etc. The anchor docking lacks dd because my plan is: first finish the restore layout and get manual things stable. Then implement dd. But at the moment I have other priorities than docking. If the dd properties/methods are not sufficient in the LCL then they can be extended. [...] Mattias ___ Lazarus mailing list Lazarus@lazarus.freepascal.org http://www.lazarus.freepascal.org/mailman/listinfo/lazarus
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Zitat von Hans-Peter Diettrich drdiettri...@aol.com: Mattias Gärtner schrieb: Even in a proportional font, some chars (Chinese, and other) have twice the width of a normal char. They will 2 positions in the grid. Actually it is the same issue as tabs. Are these characters inside the Unicode BMP? AFAIK: yes. All chinese characters are in some fonts double wide characters. What double, 4 bytes or double display width? double display width. The font is called 'monospace' but has two different widths. chinese characters are twice the width as the other characters in the font. Double width on the display could be fixed by simply doubling their indicated width, if it applies to all characters in that codepage. Monospaced doesn't mean quadratic ;-) [...] What means 'text attributes to every single character'? How much memory is needed for a 10mb text? The text attributes only are stored in the line buffer of the line to be painted, nowhere else. ok [...] The anchor docking lacks dd because my plan is: first finish the restore layout and get manual things stable. Then implement dd. But at the moment I have other priorities than docking. Oh, that's you, too? :-) Yes, the world is small. Mattias ___ Lazarus mailing list Lazarus@lazarus.freepascal.org http://www.lazarus.freepascal.org/mailman/listinfo/lazarus
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
There are several meanings by the word view I have tried to put some clarification into this. Having finished this mail, I thought I copy 2 fragments up here to the top. If they are not clear in itself, please read on first. And let us find a common approach to name those things Maybe for clarifications. I started this using the word view. But I can see there are 2 ways to read this word. - physical view: Like a painter. The final output of the combined text/style information. Most common drawing it to a canvas. But it could be a reader too. - logical view: (I guess what you called the grid?). A module that takes the raw-text, and converts it into a structure suitable for the physical view, applying style/highlight info on the way. I do use the word view to describe the logical-view of a source-file transformed into a grid. I do not use the word view to describe the painter. ( I propose physical view) I do not use the word view to describe the high level dual visibility of the same source-file in 2 windows (or a splitted window) ( I propose user view ?? imho a weak description, not good) Some of the answers where given before I understood that view in your text sometimes refers to multi window display. I tried to amend them in a 2nd run through my answer. I hope I didn't miss any. If my answers do not seem to match your text, I probably read view in a different way from what you meant Hans-Peter Diettrich wrote: Martin Friebe schrieb: Then how to you handle double width chars? This si one of the problems I still have to address. Even in a proportional font, some chars (Chinese, and other) have twice the width of a normal char. They will 2 positions in the grid. Actually it is the same issue as tabs. Are these characters inside the Unicode BMP? Yes, and there are quite a few Lazarus users waiting for a solution. In utf16 they occupy 1 code point ( they are encoded in a single 16 bit word), but need display twice the display width. Actually it seems they are called full width, while all others (like western chars) are called half width. Full Unicode requires assistance by some sophisticated library, that can deal with all the oddities of character sequences (ligatures...), and True, and so far we only talk about the display, it also needs to be edited. Anyway there is much other work before I get there, so I think I defer the details on this part. Column Blocks, as well as horizontal caret movement have to deal with this anyway, since you may allow to be in the middle of a tab. But you can not permit to have the caret in the middle of a chinese char. No problem, my tabs have a special display encoding, that forces the caret to move to the next ordinary character cell. Is it really still a column block, when a double-width character hangs out on it's right boundary? Well it is the users option (with tabs) to either have ragged column blocks, or cut tabs into spaces or With Chinese (and I believe Arabic, and a few other language) there are no options (the char can not be cut). The question still is how do your painters to all that. IMHO the mapping into a grid requires a lot of info (folded/ word wrapped/ tabs,...) as well as highlighting info. The painter as I see it collects all this info, but the info is provided by other objects. Right, I left the implementation of the highlighters and folding to dedicated objects. The classes have to implement only the very slim interface of the base class, everything else is open end. Right that sounds similar to my plans. The folded info is stored in a FoldTree (well at the moment it is split, and some is still stored on the raw-text-lines, work in progress) The mapping is done in FoldedView. From all I read the difference is, that I put a viewer-class into a stack. You seem to have this in your grid-class, or a specialized inherited grid-class. Probably both approaches have their benefits. In order to compare them we would have to deeply analyse both of them. BTW, I stored characteristic info in fixed size records, which can easily saved and exchanged together with the source file or the global settings. No encapsulation, but easy to use, and little chances for coding errors. You are speaking of the highlighting info? Maybe easiest to give a usecase or example? Also when you say characteristic, do you mean: the details of the characteristics (e.g. numbers are blue or comments are bold), or do you mean whih characteristic apply to a char/group of chars (e.g. format the next 3 chars with the format for numbers). The View port for example does not do the painting, it is a helper class to map the right code into the grid. It is used by the painters, but also used outside. It allows (without accessing the painter) to check if a char or the caret is in the visible area. ( There still is the question if it will be
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Martin Friebe schrieb: Maybe for clarifications. I started this using the word view. But I can see there are 2 ways to read this word. - physical view: Like a painter. The final output of the combined text/style information. Most common drawing it to a canvas. But it could be a reader too. - logical view: (I guess what you called the grid?). A module that takes the raw-text, and converts it into a structure suitable for the physical view, applying style/highlight info on the way. In the model-view-controller context, the view is the logical aspect. Let me add another clarification: My primary viewpoint is that of an component writer, designing components for general use, i.e. not bound to a specific application or context, unless specific to the functionality of the component itself. Consequently my CharGrid is a general component, whose use in Lazarus may deserve extensions to the general functionality. The basic component has certain capabilities, and a specific implementation. Take it both as a general model, and a specific implementation as a proof of the concept. Now we can discuss in general, *whether* it's possible to achive the Lazarus-specific functionality, based on the given component design. This was my context in the preceding discussion. I wanted to prove that my approach is suitable for that specific use, and find out where the implementation may deserve a redesign. The result only can be go/nogo. Then we can discuss in detail, *how* the desired functionality can be achieved (implemented). In this part I can explain how I implemented certain functionalities, and how I would use and extend the functionality in general. Others can explain their model, how to implement and extend the functionality in their design and implementation, so that we can find out about the specific advantages and disadvantages of the different approaches. We seem to have just entered this part of the discussion. I do use the word view to describe the logical-view of a source-file transformed into a grid. I do not use the word view to describe the painter. ( I propose physical view) I do not use the word view to describe the high level dual visibility of the same source-file in 2 windows (or a splitted window) ( I propose user view ?? imho a weak description, not good) When it comes to implementation details, like painting, then I'd prefer component for the overall (TLazEdit or TCharGrid) component. That component can consist of, or use, dedicated sub-components, wich we should address as text and gutter painters, syntax highlighters etc. Some of the answers where given before I understood that view in your text sometimes refers to multi window display. I tried to amend them in a 2nd run through my answer. I hope I didn't miss any. If my answers do not seem to match your text, I probably read view in a different way from what you meant IMO we should restrict the term view to any unspecific visual representation of a model (document), in the abstract MVC context. Distinct from the context of a specific component or viewer. [...] Is it really still a column block, when a double-width character hangs out on it's right boundary? Well it is the users option (with tabs) to either have ragged column blocks, or cut tabs into spaces or The user selects an column block with the mouse, as a rectangle from top/left to bottom/right. Then we have to specify how to deal with unaligned double-width characters, at the left and right margins of that rectangle, in block highlighting and copy/paste operations. With Chinese (and I believe Arabic, and a few other language) there are no options (the char can not be cut). There exist more such language and Unicode specific restrictions. Take the more familiar case of an Ä (A-umlaut), which in Unicode can be represented as either a single code point Ä or as two code points for umlaut and A. Both encodings are displayed as the same glyph, by a true Unicode painter. Now we have a problem, because the internal representation of that glyph can consist of one or two code points, so what should happen when the user deletes that character from the text? In an Unicode editor the first delete may delete the umlaut, so that the glyph is not removed on screen, but instead is converted into the remaining A. That's why I dislike the use of Unicode with all related hazzles. Either we need a Unicode library, that implements everything, including the painting, and implement something like an text processor - or we deal with code points and display above umlaut-A combination as two adjacent glyphs. In my approach I assumed (willingly) that there exists a 1:1 correspondence between stored code units (WideChar) and visible glyphs, and all glyphs are displayed left-to-right. For all unhandled cases I expect a detailed specification, from somebody really familiar with the handling of those
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Hans-Peter Diettrich wrote: 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). Then how to you handle double width chars? This si one of the problems I still have to address. Even in a proportional font, some chars (Chinese, and other) have twice the width of a normal char. They will 2 positions in the grid. Actually it is the same issue as tabs. Each char needs to have an info, how many cells it will allocate. Now if that is the case then to display proportional fonts, all I need to to make the grid size 1 pixel. -- I do *not* encourage that. I do not say this is a good thing for a source editor. But given how close SynEdit comes to proportional display anyway, I keep at least an open mind about a structure that would allow to implement it. -- Column Blocks, as well as horizontal caret movement have to deal with this anyway, since you may allow to be in the middle of a tab. But you can not permit to have the caret in the middle of a chinese char. 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. The question still is how do your painters to all that. IMHO the mapping into a grid requires a lot of info (folded/ word wrapped/ tabs,...) as well as highlighting info. The painter as I see it collects all this info, but the info is provided by other objects. The View port for example does not do the painting, it is a helper class to map the right code into the grid. It is used by the painters, but also used outside. It allows (without accessing the painter) to check if a char or the caret is in the visible area. ( There still is the question if it will be the painter or the viewport who defines the size of each grid cell (basically the font size)) 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. The view IMHO is more than one class, that gradually apply the mapping from a Source-Holder (TStringList) to a char-grid. The Painter then transfers each char to from the grid to the canvas. That is what I am currently trying to do the painter looks at a grid-provider, a grid provider may read either the source or another grid-provider as input. I currently call those grid-provider View. One thing must change, currently the PaintLines code, combines the highlight info with the grid-view result. But that means mapping the highlight info. The highlight info must be applied to the unmodified source, and then share the way through the grid-providers (That's actually something I realized from this discussion = good) So If I display a text that has no tabs, no double width chars, no folds, no , then all I need is: -source-buffer -highlight info (does not re-organize the layout) -viewport-grid -painter The view port grid, selects the correct lines, and within each line the correct substring. So if the text is horizontaly scrolled it cuts the beginning of each line, and in any case, it cuts any line that is to long. There a 2 objects: - The TViewPort = which defines the corner points /
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Martin Friebe schrieb: Then how to you handle double width chars? This si one of the problems I still have to address. Even in a proportional font, some chars (Chinese, and other) have twice the width of a normal char. They will 2 positions in the grid. Actually it is the same issue as tabs. Are these characters inside the Unicode BMP? Actually I did a translation into WideChar, so that only characters from the Unicode BMP can be processed. In this model I'd insert a dummy character into the output string, that is not displayed but compensates for the width of the preceding double-width character. And what about RTL text? IMO there exist limits for the task of an source code editor, where it's easier to use or port some existing text processing component, instead of reinventing the wheel. Full Unicode requires assistance by some sophisticated library, that can deal with all the oddities of character sequences (ligatures...), and that should be provided and maintained by the platform. Windows has such a Uniscribe library, see http://www.catch22.net/tuts/neatpad/11 This editor tutorial convinced me to either stay with truly monospaced characters, or let an according library do all drawing. Nothing half-baked in between. The same for the *input* of Chinese or other exceptional character sets (IME editors...). Column Blocks, as well as horizontal caret movement have to deal with this anyway, since you may allow to be in the middle of a tab. But you can not permit to have the caret in the middle of a chinese char. No problem, my tabs have a special display encoding, that forces the caret to move to the next ordinary character cell. Is it really still a column block, when a double-width character hangs out on it's right boundary? The question still is how do your painters to all that. IMHO the mapping into a grid requires a lot of info (folded/ word wrapped/ tabs,...) as well as highlighting info. The painter as I see it collects all this info, but the info is provided by other objects. Right, I left the implementation of the highlighters and folding to dedicated objects. The classes have to implement only the very slim interface of the base class, everything else is open end. BTW, I stored characteristic info in fixed size records, which can easily saved and exchanged together with the source file or the global settings. No encapsulation, but easy to use, and little chances for coding errors. The View port for example does not do the painting, it is a helper class to map the right code into the grid. It is used by the painters, but also used outside. It allows (without accessing the painter) to check if a char or the caret is in the visible area. ( There still is the question if it will be the painter or the viewport who defines the size of each grid cell (basically the font size)) In my model nobody has to know about the painting, all required information resides in the line buffer and viewport outline. Apart from the basic client and gutter size (in pixels) and the font size, the viewport outline contains the overall grid dimension, corresponding to the line/row count of the document after block folding, the visible area is described by a scrollable offset within the grid, or (0,0) for painting in client address space, and the current extent of the viewport (client area of the control), in both fully and partially visible characters. The separation into fully (page size) and partially visible (viewport size) characters allows to e.g. scroll by (fully visible) pages in both directions, while painting and display of the caret stops only at the viewport margins - the latter (caret display) is not properly implemented in the current LazEdit! 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. The view IMHO is more than one class, that gradually apply the mapping from a Source-Holder (TStringList) to a char-grid. The Painter then transfers each char to from the grid to the canvas. All that has to be encapsulated in every single view(er). When the code explorer is a view, it's internals have almost nothing in common with the text viewer. A gutter also is kind of an viewer, coupled with the text viewer only by a common TopLine, but independent otherwise. Of course the various viewers are related to a distinct document and helper objects, from which they obtain all the information to be displayed, but the kind of required information depends on their individual tasks. The document base class has (virtual) functions for the conversion between stored (file based) and visible (possibly folded) coordinates, so that the details of folding are encapsulated. When the gutter painter/viewer
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Hans-Peter Diettrich wrote: Martin Friebe schrieb: A couple of remarks: -Individual drawer objects fro Gutter and TextArea (I will avoid Grid in the name, Grid is a specialization) The Grid is a hint on the organisation of the canvas, in rectangular cells. I've spent a lot of time in the various coordinate systems and their mapping, for drawing purposes (relative to the window), document view (rows/columns, scrolling, line wrapping), and document storage (folding, tab expansion, UTF encoding). The need for properly anchored bookmarks was a big challenge. Similar, but finally easy to implement, was the preservation of the cursor column, when scrolling across lines of shorter lenght. 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 This has been started for the Gutter. It does need a lot of clean up still. It would also benefit from the Os-Handle and canvas being moved into a wrapper class. This would: - avoid the need to callback synedit for Invalidates - allow a Handle/Canvas of another Component being passed to SynEdit, and SynEdit painting the other component (e.g. SourceEditor) Here we may have quite different viewpoints, on the delegation of the responsibilities. 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. 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. 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 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) Similar considerations for the Textarea. However the textdrawer will have to access a lot of other objects, and need ways to merge the result. there are - 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...) for proper handling of multi-line comments. Hyperlinks are implemented as special highlighting information. When the mouse pointer moves, the according characters and attributes are obtained for the current line, from the document, then the line eventually is repainted when the active state of a hyperlink has changed. For Hyper links, had you have a look at the MarkUp class? (SynEditMarkupCtrlMouseLink in components\synedit\syneditmarkupctrlmouselink.pp; there is stil some remains in central Synedit that need moving) Again this class does not replace the GridDrawer. It is to be used as a helper class by any GridDrawer. I have no information about the internals of you r grid drawer, and how it delegates work and responsibilities, so I can not really comment on it. I don't know how your grid drawer deals with all the different tasks/responsibilities, it has to meet (especially within the LineDrawing Class). You talk a lot of sub classes that implement the individual bits. This may be needed (and probably is at least for WordWrapping). But I believe that the Griddrawer (and it's LineDrawer) should solve a lot by delegate to helper classes? Of course this is easily said. And I haven't yet got the full design for how I will/would do the GridDrawer. - The TextLines itself (e.g. Highlighter token will return a tab as a tab, but the TestLines need to translate this into displayable chars. Either -- spaces -- show special chars (and if tab is only one char, then maybe there is only one followe by spaces? Right, tab expansion is
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
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
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Hans-Peter Diettrich wrote: Martin Friebe schrieb: Well I am in the process of breaking it up into smaller bits. - The gutter drawing moved to its own class. - Folding is partly abstracted - Trim Trailing spaces has been abstracted into a class of its own. (a view of SynEditLines) - Caret and block have been started I've a TCharGrid component, developed in the time when the SynEdit was too instable and unreliable. It handles all cursor moves, scrolling, selecting text (also in columns), tab widths, (syntax) coloring, and also has provisions for both vertical and horizontal gutters. It was intended as a more reliable base for e.g. SynEdit, in general for representing text in a monospaced font, as is convenient for source code. It was developed and tested with Delphi 7, i.e. for Windows, but should be widely platform independent. If somebody is interested in the source code... DoDi Looking at your signature, you are the Author of http://wiki.lazarus.freepascal.org/Redesign_of_the_SynEdit_component ? A couple of remarks: -Individual drawer objects fro Gutter and TextArea (I will avoid Grid in the name, Grid is a specialization) This has been started for the Gutter. It does need a lot of clean up still. It would also benefit from the Os-Handle and canvas being moved into a wrapper class. This would: - avoid the need to callback synedit for Invalidates - allow a Handle/Canvas of another Component being passed to SynEdit, and SynEdit painting the other component (e.g. SourceEditor) Similar considerations for the Textarea. However the textdrawer will have to access a lot of other objects, and need ways to merge the result. there are - the highlighter - the MarkUpManager - The TextLines itself (e.g. Highlighter token will return a tab as a tab, but the TestLines need to translate this into displayable chars. Either -- spaces -- show special chars (and if tab is only one char, then maybe there is only one followe by spaces? This can only be done by the Lines, as they know the layout/tabwidth (see concept of Views/ TabView below) The storage and view of the TextLines: I think TSynEditCodeBuffer is a good start for this. Yet tabs are a specialisation, that should go into a ViewClass. ViewClasses TSynEditStrings themself, that will modify how the stored text is seen. (TrimTrailingSpaces is an example. FoldedView too, so FoldedFiew does not yet fully follow the concept) The following Views (and others) can apply to the text - WordWrapView - FoldView - TabView or ElasticTabView (http://bugs.freepascal.org/view.php?id=9650) modifies Logical(byte) to Phisical (char on screen) calculations. probably still returns tabs, but offers conversation methods. - replacing tabs with spaces in the Strings[] property, may complicate Highlighting and MarkUp and show special chars It would also impact the ability of keeping the caret from being placed in the middle of a tab (which currently can be done) - TrimSpaceView - TSynEditStringBuffer (holding the actual text) Martin ___ Lazarus mailing list Lazarus@lazarus.freepascal.org http://www.lazarus.freepascal.org/mailman/listinfo/lazarus
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Martin Friebe schrieb: Looking at your signature, you are the Author of http://wiki.lazarus.freepascal.org/Redesign_of_the_SynEdit_component ? Right, this was the draft for the subsequent implementation. A couple of remarks: -Individual drawer objects fro Gutter and TextArea (I will avoid Grid in the name, Grid is a specialization) The Grid is a hint on the organisation of the canvas, in rectangular cells. I've spent a lot of time in the various coordinate systems and their mapping, for drawing purposes (relative to the window), document view (rows/columns, scrolling, line wrapping), and document storage (folding, tab expansion, UTF encoding). The need for properly anchored bookmarks was a big challenge. Similar, but finally easy to implement, was the preservation of the cursor column, when scrolling across lines of shorter lenght. This has been started for the Gutter. It does need a lot of clean up still. It would also benefit from the Os-Handle and canvas being moved into a wrapper class. This would: - avoid the need to callback synedit for Invalidates - allow a Handle/Canvas of another Component being passed to SynEdit, and SynEdit painting the other component (e.g. SourceEditor) Here we may have quite different viewpoints, on the delegation of the responsibilities. Similar considerations for the Textarea. However the textdrawer will have to access a lot of other objects, and need ways to merge the result. there are - 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 for proper handling of multi-line comments. Hyperlinks are implemented as special highlighting information. When the mouse pointer moves, the according characters and attributes are obtained for the current line, from the document, then the line eventually is repainted when the active state of a hyperlink has changed. - The TextLines itself (e.g. Highlighter token will return a tab as a tab, but the TestLines need to translate this into displayable chars. Either -- spaces -- show special chars (and if tab is only one char, then maybe there is only one followe by spaces? Right, tab expansion is highly configurable in my solution :-) This can only be done by the Lines, as they know the layout/tabwidth (see concept of Views/ TabView below) Right, the handling of wrapped lines also was a challenge :-) The storage and view of the TextLines: I think TSynEditCodeBuffer is a good start for this. Yet tabs are a specialisation, that should go into a ViewClass. ViewClasses TSynEditStrings themself, that will modify how the stored text is seen. (TrimTrailingSpaces is an example. FoldedView too, so FoldedFiew does not yet fully follow the concept) I've left folding to the document management, for any convenient implementation. The visual component manages visible lines only, the mapping between stored and visible lines must be implemented outside of it. Including notifications of the changed line count, when text blocks are collapsed or expanded. If desired, multiple views can have different blocks collapsed, different tab width, wrapping on different screen boundaries etc. The consideration of multiple views reveals clear frontiers for the various responsibilities (what feature to implement where). The following Views (and others) can apply to the text - WordWrapView - FoldView - TabView or ElasticTabView (http://bugs.freepascal.org/view.php?id=9650) modifies Logical(byte) to Phisical (char on screen) calculations. probably still returns tabs, but offers conversation methods. - replacing tabs with spaces in the Strings[] property, may complicate Highlighting and MarkUp and show special chars It would also impact the ability of keeping the caret from being placed in the middle of a tab (which currently can be done) - TrimSpaceView - TSynEditStringBuffer (holding the actual text) IMO all this is already perfectly implemented in my CharGrid. With regards to the ElasticTabView, I have my own opinion on a mix of an source code editor with a text processor or page layouter - it stinks :-( I neither like subroutine arguments indented to the ( of the call, nor block comments to the right of source code, sensitive to insertion or deletion of lines of code. I don't want to open a can of worms for people who put more emphasis on the appearance of their(?) source code, than on its functionality. It's more annoying when the caret disappears in the last line or column of the window, as I observed in the current SynEdit implementation. DoDi ___ Lazarus mailing list Lazarus@lazarus.freepascal.org http://www.lazarus.freepascal.org/mailman/listinfo/lazarus
[Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Mattias Gärtner wrote: Zitat von Alexander Klenin kle...@gmail.com: I should note that I was horrified by the amount of glue code needed to route an event through main form, source notebook, source editor and SynEdit. The IDE is structured in a hierarchy. mainide: the top level of the IDE and the central nerve system. Because of its size it's splitted into several units. This is the 'integrated' in IDE. It connects the various modules like debugger, package system, codetools, designer, etc. source notebook: the whole source editor source editor: one single editor (at the moment in the same unit with source notebook, but should eventually split up) synedit: visual control Reading this, I just had an idea. (Nothing that would be done anytime soon, as it would be a major project) In The current structure SynEdit is the Visual control, and therefore also the control that takes all events such as mouse/key down/up/move. Often it is SynEdits work to react to this, but often it also needs to call back to SourceEditor. It is at least worth reviewing if this order could/should be changed (I am not sure about it): - SourceEditor could be a visual component with all the Key/Mouse event handlers. - It would *not* inherit from SynEdit, but same as now it would have a SynEdit instance that it can make calls to. This SynEdit would not paint on it's own canvas, but rather paint on the SourceEditors canvas - Instead of SynEdit making all the callbacks to SourceEditor, now all events go to SourceEditor first, and SourceEditor can decide what to forward. On the other hand, it is probably not worth the amount of work. Well the future will show, if there is a use case for it... Best Regards Martin ___ Lazarus mailing list Lazarus@lazarus.freepascal.org http://www.lazarus.freepascal.org/mailman/listinfo/lazarus
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
On Fri, Dec 12, 2008 at 21:37, Martin Friebe laza...@mfriebe.de wrote: In The current structure SynEdit is the Visual control, and therefore also the control that takes all events such as mouse/key down/up/move. Often it is SynEdits work to react to this, but often it also needs to call back to SourceEditor. It is at least worth reviewing if this order could/should be changed (I am not sure about it): - SourceEditor could be a visual component with all the Key/Mouse event handlers. - It would *not* inherit from SynEdit, but same as now it would have a SynEdit instance that it can make calls to. This SynEdit would not paint on it's own canvas, but rather paint on the SourceEditors canvas - Instead of SynEdit making all the callbacks to SourceEditor, now all events go to SourceEditor first, and SourceEditor can decide what to forward. Sigh, if we are dreaming anyway, here is my dream: 1) Logic should be separated from the presentation, so first there should be 'TAbstractSynEdit' class, concerning itself purely with text manipulations, such as text insertion/deletion, cursor position changes, text attribute calculation, save/loading, codetools etc. TAbstractSynEdit should not depend on any visual code, in partucular it should descend from TObject/TPersistent, not TControl. 2) Logic should be covered by automated tests, e.g. using fpcunit framework. 3) Presentation and user interaction should be the concern of TSynEdit class, aggregating TAbstractSynEdit and delegating all actual logic to the latter. 4) SourceEditor should be removed (or converted into a trivial wrapper), TSourceNotebook should reference TSynEdit directly. On the other hand, it is probably not worth the amount of work. Well the future will show, if there is a use case for it... True. Proper design requires lots of effort, and (especially short-term) benefits might not outweight the costs. -- Alexander S. Klenin Insight Experts Ltd. ___ Lazarus mailing list Lazarus@lazarus.freepascal.org http://www.lazarus.freepascal.org/mailman/listinfo/lazarus
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Alexander Klenin wrote: On Fri, Dec 12, 2008 at 21:37, Martin Friebe laza...@mfriebe.de wrote: In The current structure SynEdit is the Visual control, and therefore also the control that takes all events such as mouse/key down/up/move. Often it is SynEdits work to react to this, but often it also needs to call back to SourceEditor. It is at least worth reviewing if this order could/should be changed (I am not sure about it): - SourceEditor could be a visual component with all the Key/Mouse event handlers. - It would *not* inherit from SynEdit, but same as now it would have a SynEdit instance that it can make calls to. This SynEdit would not paint on it's own canvas, but rather paint on the SourceEditors canvas - Instead of SynEdit making all the callbacks to SourceEditor, now all events go to SourceEditor first, and SourceEditor can decide what to forward. Sigh, if we are dreaming anyway, here is my dream: 1) Logic should be separated from the presentation, so first there should be 'TAbstractSynEdit' class, concerning itself purely with text manipulations, such as text insertion/deletion, cursor position changes, text attribute calculation, save/loading, codetools etc. TAbstractSynEdit should not depend on any visual code, in partucular it should descend from TObject/TPersistent, not TControl. Well I am in the process of breaking it up into smaller bits. - The gutter drawing moved to its own class. - Folding is partly abstracted - Trim Trailing spaces has been abstracted into a class of its own. (a view of SynEditLines) - Caret and block have been started Of course, they do still have heavy dependencies. But those can not easily be removed yet, other parts have to be broken free first. 2) Logic should be covered by automated tests, e.g. using fpcunit framework. Also started (mainly folding), so they need heavy cleanup. I cam from other test frame-works and forcefully attempted to abuse fpcunit... But as far as I am concerned, you can not write code without having automated tests. 3) Presentation and user interaction should be the concern of TSynEdit class, aggregating TAbstractSynEdit and delegating all actual logic to the latter. 4) SourceEditor should be removed (or converted into a trivial wrapper), TSourceNotebook should reference TSynEdit directly. On the other hand, it is probably not worth the amount of work. Well the future will show, if there is a use case for it... True. Proper design requires lots of effort, and (especially short-term) benefits might not outweight the costs. ___ Lazarus mailing list Lazarus@lazarus.freepascal.org http://www.lazarus.freepascal.org/mailman/listinfo/lazarus
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
Martin Friebe wrote: Mattias Gärtner wrote: Zitat von Alexander Klenin kle...@gmail.com: I should note that I was horrified by the amount of glue code needed to route an event through main form, source notebook, source editor and SynEdit. The IDE is structured in a hierarchy. mainide: the top level of the IDE and the central nerve system. Because of its size it's splitted into several units. This is the 'integrated' in IDE. It connects the various modules like debugger, package system, codetools, designer, etc. source notebook: the whole source editor source editor: one single editor (at the moment in the same unit with source notebook, but should eventually split up) synedit: visual control Reading this, I just had an idea. (Nothing that would be done anytime soon, as it would be a major project) In The current structure SynEdit is the Visual control, and therefore also the control that takes all events such as mouse/key down/up/move. Often it is SynEdits work to react to this, but often it also needs to call back to SourceEditor. It is at least worth reviewing if this order could/should be changed (I am not sure about it): - SourceEditor could be a visual component with all the Key/Mouse event handlers. - It would *not* inherit from SynEdit, but same as now it would have a SynEdit instance that it can make calls to. This SynEdit would not paint on it's own canvas, but rather paint on the SourceEditors canvas - Instead of SynEdit making all the callbacks to SourceEditor, now all events go to SourceEditor first, and SourceEditor can decide what to forward. On the other hand, it is probably not worth the amount of work. Well the future will show, if there is a use case for it... It would make the design more pure then as it is now. I have too been wondering why synedit needs all the knowledge of ide events. Marc ___ Lazarus mailing list Lazarus@lazarus.freepascal.org http://www.lazarus.freepascal.org/mailman/listinfo/lazarus
Re: [Lazarus] Code Structure / SourceEdit and SyneEdit [Re: Mouse Link in SynEdit (only link-able items)]
On Sat, Dec 13, 2008 at 06:26, Flávio Etrusco flavio.etru...@gmail.com wrote: My vision deviates a bit from this in the sense that TAbstractSynEdit would just be an abstraction (or dedicated implementation) of a cleaner text manipulation interface (as TStrings won't cut it), which would also implement transparent/automatic/implicit 'undo' handling. Then each command would be a class, probably inheriting from TAction. It is not a deviation as much as detalization ;-) However, it is also important not to overdo abstractions -- perhaps a separate class for every command is too much. Anyway, I am glad that you (and Martin) agree with the general concept. -- Alexander S. Klenin Insight Experts Ltd. ___ Lazarus mailing list Lazarus@lazarus.freepascal.org http://www.lazarus.freepascal.org/mailman/listinfo/lazarus