[Oberon] Locate/identify Char at cursor ?

eas lab lab.eas at gmail.com
Thu Feb 28 06:49:40 CET 2013

Sorry that I've lost the mail-subject-thread.
In this failed-state-location, my ISP has forced me to use gmail, which
can only fetch ONE mail per expensive login session.

 Paul Reed wrote:
 > ] TextFrames.Edit is in turn called from the TextFrames message handler
 > ] TextFrames.Handle().
 > ----
> > OK, but I still can't see how to get the char at the CURSOR.
> > Is this correct:--
>>   Oberon.GetSelection(text, beg, end, time);
> >   char := <Scan 'text' from 'beg'>
 >> would get the char of mouse: RM.
> >
>  > But the RECORD in Oberon.Mod which holds 'text' and 'beg'
>  >  has been Set by a process, which runs in the background,
>  >  which is not published.
>  It is! :)

AFAIK Display.Mod sets the RECORD which Oberon.Mod reads.
Are you saying that the code of Display.Mod IS published?
AFAIK Display.Mod does the difficult job of finding the index in the
text-stream of 'beg' and 'end', for possible later GetSelection.

>  The current (latest) selection is a conceptually-global
>  property of the system, which is obtained by Oberon.Mod using a
>  SelectionMsg broadcast in GetSelection().  Each viewer (e.g. a TextViewer)
>  with a selection will respond to this message in its handler and update
>  the selection in the message (as long as the selection time is later than
>  any selection already there).  See TextFrames.GetSelection().

 Yes, but TextFrames.GetSelection() like Oberon.GetSelection
 wouldn't *set* the RECORD.

>  > I want the CURSOR-chars, to be returned, for various keys, like they
>  > can be, for mouse: RM, via < Scan(GetSelected(args)) >.
>  There's a convention for many Oberon commands that in fact, only the
>  beginning of the text need be selected.  A simple example to look at would
>  be Edit.Locate, at the end of Chapter 5 of Project Oberon, page 174 (or
>  page 139 of the PDF), which:

I'm not yet fluent in Chapter*.Text so I don't want to take other medicine.

>  1. finds the marked (starred) viewer, typically a source file being compiled
>  2. gets the current selection (usually in another viewer, the log viewer,
>  a pos of a compile error)
>  3. opens a scanner S at the start of the current selection (after this,
>  what text is *actually* selected is ignored)
>  4. scans until it finds an integer (a position), returned in S.i   <--*?
>  5. shows that position in the marked viewer, by repositioning the Text
>  frame (found in 1.) to 200 characters beforehand
>  6. puts the focus and the caret in the marked viewer at position S.i

Without looking at the code [yet], I'll confidentially say this is the
reverse of my problem. So it's also interesting.
The compiler KNOWS the index of the char/token and needs to position
the cursor/caret there.
In a non-ETHO system it could merely step the cursor to char N.
The concept of X,Y coordinates are not even needed.

>  > The difficult part, is that the <text stream viewed on the screen/display>
>  > consists of different sized rectangles.
>  Yes, and each viewer has the choice to lay out text however it wants
>  (there's text in the graphics editor too, for example).
>  > It seems to me that there can be no 'mapping' from X,Y to the
>  > correspondingly
>  > displayed-char. Because eg. if you change the font-size of charN, then the
>  > X,Y of char (n + i) changes.
>  Quite.  Hence the message broadcast, so that each viewer can interpret its
>  own contents.

I've found the code to trace the *gadget* at coordinated x,y.
But, are you saying that each char is an object/gadget ?!

>  > I'm not getting near a solution.
>  Hopefully the above helps a bit.  If you really want the text at the
>  *mouse* cursor, you could add a new message type and add a handler for
>  that message type to each type of window which displays text.  Or perhaps
>  at least add a new message id to ControlMsg.  In later systems YMMV.

No need to add a new message type. I only want a subset of what's already
done, in the 2 cases:
1. on the systems without a MidMouse, <Ctrl> can be used.
    This reads the char at the cursor [plus those before and after, up
to white-char]
2. RM selects a char. I.e. beg=end are set in the RECORD.
    So if RM can set the RECORD, then my privileged-key events can too.
    Eg. <Ctrl> is promoted to a priveleged-key   -- as in A2 too.

>  But you'd be changing the convention on how the system is used, since the
>  selection is the established way to get things like this done.  And in any
>  case I'm not sure what you actually want to do! :)

Well yes, I'm drastically extending the usage:
  you just roam around with a keyless mouse, and pick off various keys
  when the mouse is over various chars/tokens.

OK, I've realised that since you can edit any ascii-char to become
a 'multiply-sized bitmap-image' eg. a bird, so perhps each char
IS a gadget. Then I could try the published code which <finds the
gadget at cursor position: x,y>.

But now I remember, that I had a brain-dump after I though I
was getting there while testing modified Hex.Mod [V4 has similar
code]. Don't bother to study this, but just note that it's a function,
with display-coordinates IN and CharIndexInFrame OUT.
I remember that my tests showed the x-coordinate of where the cursor
was when invoking <Do.Test>.
The problem was that I didn't know how to get from <MarkedDisplay> to
the corresponding Frame, which PROC LocateChar needs.

When I asked on this forum, I was told to 'buy the book'.



== Chris Glur.

==> NO/Hex.Mod HOW2 <LocateChar in Frame @ x,y=cursor>
     Location* = RECORD
             org*, pos*: LONGINT;   <-- output: position of char in text-stream.
             x*, y*, dx*, dy*: INTEGER;   <-- input args: cursor coordinates
             line: TextLine
     END ;
 PROCEDURE LocateChar* (F: Frame; x, y: INTEGER; VAR loc: Location);
         VAR t: TextLine; pat: Display.Pattern; i: LONGINT; n, w, lm,
pw, tw, ddx, cn, dx, xc, yc, wc, hc: INTEGER; nextCh: C
                 P: Parc; pbeg: LONGINT;
         LocateLine(F, y, loc); t := loc.line; w := x - F.X;
AdjustMetrics(F, t, pw, tw, ddx, cn, P, pbeg);
         lm := F.left + SHORT(P.left DIV Unit);
         IF (t # F.trailer) & (w > pw) THEN Texts.OpenReader(R, F.text, t.org);
                 i := 0; n := 0; dx := 0; nextCh := 0X;
                 WHILE (i < t.len) & (pw + dx < w) DO
                         (* i = pos after nextCh; dx = width of
nextCh; pw = line width without nextCh *)
                         Texts.Read(R, nextCh); INC(i); INC(pw, dx);
                         IF nextCh <= " " THEN GetSpecial(R, nextCh,
P, F, n, cn, ddx, pw - lm, dx, xc, yc, wc, hc)
                         ELSE Display.GetChar(R.fnt.raster, nextCh,
dx, xc, yc, wc, hc, pat)
                 END ;
                 IF pw + dx < w THEN INC(i); INC(pw, dx); R.elem := NIL END ;
                 INC(loc.pos, i - 1); loc.x := F.X + pw;
                 IF i < t.len THEN loc.dx := dx; loc.dy :=
R.fnt.height * R.voff DIV 64 ELSE loc.dx := 4 END
         ELSE loc.dx := 4; R.elem := NIL
 END LocateChar;
!! Oh !! It's interesting, that it does LocateLine(F, y, loc) FIRST,
since we know that chars of different height on the same line,
align on a common base, which is related to 'y'. Then it just
needs to step 'x', once the y-coordinate has given the line.
BTW: Chapter5.Text =>
   "Locating a gadget in the display space....There are essentially
three ways of locating gadgets: by position, by state (the current
gadget selection), or by name.
        Given a certain X, Y position on the display, we can ask exactly
what gadget is located at that position. "
OK, but the chars in a Document are normally NOT gadgets.

More information about the Oberon mailing list