[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