[Oberon] SystemV - Viewer Scroll
Jörg Straube
joerg.straube at iaeth.ch
Sat Mar 23 08:37:44 CET 2019
Andreas
No I don‘t. I‘m happy with the scroll speed we got. Tomas just asked why the scroll code is asymmtric, and the main reason is: Using standard Texts API it’s easier to find the end of a line than to find the start of a line.
As you demonstrated guessing and forward reading is faster than backward reading.
br
Jörg
Am 22.03.2019 um 22:26 schrieb Andreas Pirklbauer <andreas_pirklbauer at yahoo.com>:
>> My quick hack was only applicable to Files.
>> Assuming you have a frame, initialized a Reader "R" already
>> and want to set this Reader back by one position.
>>
>> Texts.OpenReader(R, f.text, Texts.Pos(R)-1);
>> Texts.Read(R, ch)
>>
>> Jörg
>
>
> Hi Jörg,
>
> just in case ... you are thinking of actually implementing this kind
> of “read backwards” operation, you’ll notice that the resulting code for
> text scrolling will be fast enough (i.e. avoids flickering) *only* if you
> implement it directly *within* modules Files and Texts (been there,
> done that..). But if you implement it outside Files and Texts, i.e.
> write something along the lines of:
>
> PROCEDURE ReadBack (T: Texts.Text; VAR R: Texts.Reader; VAR ch: CHAR; VAR bof: BOOLEAN);
> VAR pos: INTEGER;
> BEGIN pos := Texts.Pos(R);
> IF pos > 0 THEN bof := FALSE;
> Texts.OpenReader(R, T, pos-1); Texts.Read(R, ch); Texts.OpenReader(R, T, pos-1)
> ELSE ch := 0X; bof := TRUE
> END
> END ReadBack;
>
> then text scrolling will simply be too slow, when e.g. used as in:
>
> PROCEDURE Scroll* (F: Frame; dY: INTEGER); (*scroll displayed text dY pixels up or down*)
> VAR R: Texts.Reader; L, L0: Line; bof: BOOLEAN;
> org: LONGINT; dy: INTEGER;
> BEGIN (*dY # 0*)
> IF F.trailer.next # F.trailer THEN
> IF dY < 0 THEN (*move backwards*)
> dY := -dY; org := F.org; Validate(F.text, org);
> IF org > 0 THEN NewLine(F, L); dy := 0;
> REPEAT
> Texts.OpenReader(R, F.text, org-1); ReadBack(F.text, R, nextCh, bof);
> ReadLineBack(L, F.text, R, bof);
> dy := dy + L.lsp; org := org - L.len;
> (*...code that sets up line list to be inserted ...*)
> UNTIL bof OR (dy + F.voff >= dY);
> ScrollDown(F, org, F.voff + dy - dY, dY)
> END
> END
> ELSIF dY > 0 THEN (*move forward*)
> ...
> END
> END
> END Scroll;
>
> where:
>
> PROCEDURE ReadLineBack (L: Line; T: Texts.Text; VAR R: Texts.Reader; VAR bof: BOOLEAN); (*pass 1*)
> VAR maxY, minY, len: INTEGER;
> BEGIN maxY := asr; minY := -dsr; len := 0;
> WHILE ~bof & (nextCh # CR) DO
> IF R.fnt.maxY > maxY THEN maxY := R.fnt.maxY END;
> IF R.fnt.minY < minY THEN minY := R.fnt.minY END;
> INC(len); ReadBack(T, R, nextCh, bof)
> END;
> L.len := len + 1; L.asr := maxY; L.dsr := -minY; L.lsp := maxY - minY;
> L.eot := FALSE
> END ReadLineBack;
>
> So if you want fast enough code for *completely smooth* and flicker-free
> text scrolling, there are two options:
>
> Option #1. Modify Files and Texts to add Files.ReadBack and Texts.ReadBack
>
> Option #2. Find a faster solution than the “natural” code outlined above.
>
> I have done both. In the end I decided to use option #2, as I wanted to leave
> modules Files and Texts untouched. HOWEVER - and unfortunately - I admit
> that I found no better solution than to simply “guess” the right position N times
> until it is “right” (if a good heuristic is chosen, N = 1 or 2 in most cases though)
> and then just read *forward* from there.
>
> This makes the code more complex, but also faster (at least it eliminates flickering):
>
> PROCEDURE Scroll (F: Frame; dY: INTEGER); (*scroll displayed text dY pixels up or down*)
> CONST P = 100; len = 75; (*assumed average line length*)
> VAR R: Texts.Reader; L, L0: Line; done: BOOLEAN;
> org, q: LONGINT; dy, k: INTEGER; p: ARRAY P OF LONGINT; d: ARRAY P OF INTEGER;
> BEGIN (*dY # 0*)
> IF F.trailer.next # F.trailer THEN
> IF dY < 0 THEN dY := -dY;
> IF dY <= F.voff THEN ScrollDown(F, F.org, F.voff - dY, dY)
> ELSE NewLine(F, L); done := FALSE;
> q := Max(F.org - len*((dY + lsp - F.voff - 1) DIV lsp), 0); (*first guess*)
> REPEAT org := q; Validate(F.text, org); k := 0; dy := 0;
> Texts.OpenReader(R, F.text, org); Texts.Read(R, nextCh);
> WHILE (org < F.org) & (k < P) DO PrepareLine(L, R);
> dy := dy + L.lsp; p[k] := org; d[k] := L.lsp; org := org + L.len; INC(k)
> END;
> IF org < F.org THEN q := p[1] (*next guess forward*)
> ELSIF q = 0 THEN (*reached beginning of text*) done := TRUE;
> IF dy + F.voff > 0 THEN ScrollDown(F, 0, 0, dy + F.voff) END
> ELSIF (k = 0) OR (dy + F.voff < dY) THEN q := Max(q - len, 0) (*next guess backward*)
> ELSE (*found, now scroll*) k := 0; done := TRUE;
> WHILE dy - d[k] + F.voff >= dY DO dy := dy - d[k]; INC(k) END;
> ScrollDown(F, p[k], F.voff + dy - dY, dY)
> END
> UNTIL done
> END
> ELSIF dY > 0 THEN
> ...
> END
> END
> END Scroll;
>
> If someone has a more elegant (and equally fast or even faster)
> solution I am a happy taker.
>
> PS: When it is done inside Files and Texts, scrolling is only
> marginally faster than the above code...
>
> -ap
>
>
> --
> Oberon at lists.inf.ethz.ch mailing list for ETH Oberon and related systems
> https://lists.inf.ethz.ch/mailman/listinfo/oberon
More information about the Oberon
mailing list