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 to a library providing the needed information. We then only need to concern ourself at which point we need to access this information.

[ column mode block ]
Again we can open a thread with implementation details


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.
    

Just for clarification: I assume kind of a DocumentSource property in 
the editor (CharGrid) component, that is initialized with the 
appropriate object reference, by the controller (in MVC terms). In the 
simplest case the DocumentSource is kind of a TStringList, or it can be 
a FoldedView, or whatever is appropriate for the file type and context.
  
I would like to see see folded view to be "part of" the TextDrawer (char-grid ?) 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)
  - 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
- 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 could either be internal part of the component or be given to it. Which one is the case should not matter for the design of the component.

The component then retrieves the correct part(s) of the raw source, transforms it and paints it to the canvas

Does this description makes sense?
And we open other mail-threads for other topics?

Even if Undo functionality is added to the document source, this is 
nothing what the visual component should have to know or care about. In 
the MVC model it's the task of the controller, to submit user actions to 
the right place (object and method), where Undo, Folding, Insert etc. is 
implemented. The controller must know about all those details, but the 
viewer component only has to know how to obtain the text to display. It 
even must *not* know, whether the text can be edited by the user at all 
- it only must be aware of a Change message, indicating that the text 
has been changed, somehow.
  
Undo definitely is an editor feature since it modifies the Model.

Folding I believe can be part of the Display-Component. (This is application of the folding info stored in the model)
It has certain similarities with the Grid.

The Grids purpos is to: Select text from the RawSource, and transform it in certain ways, like: Display whitespace, after a newline; or adjust position in the grid, after tabs

Similar work is done by Folding or Wrapping. The change the selection (selection of what is visible), and transform it (wrapping may transform a logical line into several physical lines)
The same applies for Tab expansion, The handling of DoubleDisplayWidth Char or merging of multicode points (provided they are known by access to a library)

The component should also concern the application of highlighting or Markup information, provided it can retrieve it from the appropriate classes. (This will allow multiply Components to display the same Model , using different highlighters)

The controller reference can become another property of the final 
component, but for the first steps I left it to an OnKeyPress handler, 
to translate keystrokes into actions. E.g. my test application 
translates the cursor keys into scroll actions, and calls the according 
methods of the CharGrid.
  
The Keypress should be on the controller, the Display-Component does not need to be concerned with this.

Probably both approaches have their benefits. In order to compare them 
we would have to deeply analyse both of them.
    

I still don't understand your stack. Exchanging the document (file) only 
requires to change the DocumentSource property of the control. Writing 
to that property will trigger all actions, required to display the new 
text source.

Can you please explain what you have in mind, when you introduce the 
term "stack"? I associate an stack with push/pop actions, what seems not 
to make sense to me, in the context of an text editor.
  
Stack refers to an implementation similar to a protocol stack (http://en.wikipedia.org/wiki/Protocol_stack)

In this case the painter would talk to the lowest end of the stack, and the top end of the stack would access the Model.
The Stack can have any amount of elements depending on which transformations are needed.

The different to a list of transformers is:
- in a list 2 neighbours would not necessarily know each others (they could, but that would almost make it a stack)
- a list controller would be needed.

The TSynEditMarkup* classes are an example of a list.
In a list (as I see it) you ask the controller do to the task, the controller hands the request to the first list-member, then the controller takes the result to the next list member and so on.

In a stack each element directly asks the next higher level for the information required. this allows each element to ask any (and any amount of) questions to the next higher level

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.
    

It may help to leave the "physical view" as a view (output only), and to 
consider the "logical view" as a model+view+controller (data + painter + 
edit functions). While a "typical" edit control also holds (owns) the 
displayed text, the SynEdit text resides in the Lazarus notebook (file 
pool) - that's why I think that a separation into MVC makes sense.
  
All we need is  access to the Model. Origination, Location or Ownership can be left to implementation, and should be easy to change.

As for the logical view. this does (in my description) not contain the controller. It describes what the class or classes that are concerned with the transformation of the RawSourceText into the a format suitable to the Painter (The grid in this case).

Please see the attached Image, it's just a rough Idea, without much detailed design. (It only covers the TextDrawer (View in MVC), it does not cover Model or Controller)

The "decorated TextDrawer would then have access to the Model. And the controller has access to all of this


The 2 classes go hand in hand. The desired output of the logical-view is 
a grid-matrix, for the kind of physical-view we currently have in mind. 
(It may slightly differ for a reader (text to voice)).
    

It should be 3 classes, according to MVC. The view (painter...) reads 
from the model, which holds the information (text), and the controller 
translates user interaction into commands for editing, scrolling etc. 
User actions can come from the view (mouse and keyboard input), but also 
from a menu, notebook tabs etc., or from the application code (after 
init, before shutdown).
  
I was referring to the internals of the TextDrawer. I left model and Controller out of the game here.
As you can see in the image, I divide the TextDrawer into 2 sets of classes.

In terms of MVC this needs more clarification.

I did put folding into the LogicalView (and therefore into the TextDrawer, which is the View of the MVC)

Now of course, The TextDrawer does not store any of the data (model). Folding consists of 2 parts:
- The information what is folded, which is part of the model (and modified by the controller)
- The application of this data, to provide the correct output.

It is the concern of the TextDrawer to apply this information.

Ideally the logical-view should be divided into a part that is 
independent of the physical-view, and a part that is allowed to depend.
    

 From the designer viewpoint, the component palette should contain 
multiple related components: at least a general editor component, and a 
(non-visual) component representing the file pool. The current 
integration of the file pool into the SynEdit notebook is inappropriate 
for multiple edit windows - the current notebook (tabs) can be 
integrated into the editor/viewer component, or can become a slightly 
specialized derivate of the common tab control.
  
This gets as outside the Display-Model.  A solution could be to have a ModularSynEdit (which has SourceModel Property) and an integrated SynEdit (which has it's own Model for compatibility with existing code)

In my initial description I spoke of views (meaning logical views, not 
the painter). I also included the actual raw-text (file-provider) in the 
list of views. Because in my stacked organization they share some part 
in their interface. A logical view reads it's input from either another 
logical view or from the file provider (hence the file provider must be 
able to look like a logical view)
    

This structure is incompatible with MVC. The model (your file provider) 
doesn't know about or interact with anything else. It may include a list 
of active views, so that changes to the data can be made known to the 
views. I implemented a chain (linked list) of views, with the list 
header in the document (file provider) object, and every view containing 
a link to the next view of the same document. A separate controller 
becomes important, as soon as multiple views can send edit commands for 
the same source file, and must be notified of all changes to their 
shared data source.
  
Seems we were discussing different things. I only discussed the internals of the TextDrawer.

The file provider is seen in a special way from within each TextDrawer that accesses it. That should not limit it's interaction with any amount of Controllers.

It also may be that your linked list, is what I refer to as stack?

The controller receives commands from a view or other source. From 
"other" source means that the command applies to the view in the active 
window. Then the controller sends scroll commands etc. (affecting only 
the view) immediately back to the view, translated into logical actions 
(scroll a page ahead, copy selection etc.). Edit commands 
(insert/delete) are sent to View.DataSource, or are performed immediatly 
  
Can you please give me an example where an edit command is sent to the view? This is strictly between the Controller and the Model.

The only exception, is that any edit command that is relative to the current display (such as a vertical block operation) does need feedback from the View. This is because the View determines which chars are vertically aligned. (This information is not available from the model)

on that document, and after completion the active views of the updated 
document are notified of the changes. When the controller is invoked 
with keyboard input, then it must look for the according action in the 
key-map, and if no action is associated, inserts the character into the 
file, at the current (caret) position of the view.

Do you understand now, why a multi-window editor deserves some strict 
logical (re)structuring of the current SynEdit component?

  
I think we were not so far apart in our solutions. Only we used different terminology.

For some clarification (now that I got this as "user view across 2 
windows). Each "user-view" will have it's complete own stack of logical 
views. But each stack reading the same instance of the the file-buffer
    

Right :-)

But file-buffer is not the best term, because it must include shared 
bookmarks, foldable blocks and more. All that has to be separated in the 
current implementation of the SynEdit, i.e. must be removed from the 
(physical and logical) view, and has to be encapsulated within the MVC 
"model".
  
Correct. No problem with that.




Best regards
Martin

<<inline: textdrawer.gif>>

_______________________________________________
Lazarus mailing list
[email protected]
http://www.lazarus.freepascal.org/mailman/listinfo/lazarus

Reply via email to