Let me start an thread about the internal design of such components. Martin Friebe schrieb: [...] >>> In terms of MVC this needs more clarification. >>> >> You mean, when MVC is applied to the internal structure of the >> TextDrawer, in contrast to the application viewpoint? >> > No, the MVC has no idea about those internals. This line was only to > indicate that some of my considerations (including most of my > considerations in previous emails) where not made in the context of the > "View" only. (Meaning I was exploring the internals of a MVC View and > not the Model or Controller / The presence or need of I was taking for > granted at that time, leaving it out of discussion)
IMO it makes sense to apply MVC also to the internals of a visual component. [...] > In the current implementation, if something changes, this something > often knows about everyone else who needs to react to this change, and > makes direct calls to all of them. That's real bad. > I' d like to revert that. Individual elements know, on who's changes > they need to react, and register a callback handler. If the other one > changes, it just makes all the callbacks. It has no need to know who > receives the callback. I deny the usability of callbacks here, and present a different (proven) model, as I implemented in the CharGrid. > Example: > Interaction between Caret and Viewport. > - If the caret moves, the viewpoer may have to move, so currently the > caret calls the viewport. > Better: the Viewport just registers on the carets OnChange callback List. Even better: Scrolling, folding, or caret movements (hyperlink or bookmark jumps...) can affect both the caret position and the viewport origin. In order to synchronize both, a centralized dispatcher comes into mind. Every event is translated into a primary action, by the controller. The action e.g. describes whether the viewport should follow the caret move, or the caret should follow the viewport move, or should stay where it is. The dispatcher (or local controller) then determines all *consequential* changes, required to reflect the *intended* effect. It initializes an set of flags, indicating what has to be done, what already has been considered, and what remains to do, to reflect the new state (display refresh). Everything starts with a BeginUpdate, preventing premature operations. When the caret shall be moved, or the viewport shall be scrolled, then according flags prevent a later re-adjustment of these values. Then all further checks and adjustments are made, like clipping the caret and viewport to the extent of the actual text, scrolling the caret into view, or moving the caret into the new viewport, and how to adjust the scrollbars, when a block has been collapsed or expanded. Also dependencies between vertical and horizontal moves are checked. The sequence of the checks and adjustments can be fixed, at least in case of the CharGrid, so that it's easy to debug and re-order the various steps, if required. A recursion into already invoked methods does no harm, so that a vertical scroll check can invoke an horizontal scroll check and vice vera, because already performed checks simply do nothing. Each procedure only must know about related checks, to be triggered, but must not assume anything about which other checks may have to be bypassed under certain circumstances. This makes a significant difference vs. setting individual properties one by one, where the setter methods might invoke each other, possibly causing infinite loops, or producing unintended inappropriate results. When the new state has been determined, the last EndUpdate triggers the required refresh of all components (caption, scrollbars, status bar, text and gutter areas etc.), based on the flags in the action/state flag set. In that execution state some internal properties can be re-adjusted or updated, e.g. the physical (visible) caret position can be forced to the end of a short line, while the logical caret position stays in the the same column as before a vertical move. The affected display area is determined and invalidated, with chances for optimizations, as far as the OS and widget set allow. One such optimization (Win32) were scrolling the canvas immediately, and repainting only the uncovered client area. Such a strict separation between initial commands, state changes, and final response, centralized in kind of an local Controller, will result in an almost bullet proof implementation. All modifications to the remaining code in the component class are allowed to use only the predefined dedicated methods. DoDi _______________________________________________ Lazarus mailing list [email protected] http://www.lazarus.freepascal.org/mailman/listinfo/lazarus
