FPGA - OberonV4 Dialogs
Hi,
To have this „Linz GUI“ (= Dialogs) you don’t need Oberon-2. You „only“ have to a) adapt the outer core (mainly ') b) port the relevant Linz modules from Oberon-2 to to Oberon-07
As porting OP2 for RISC5 seems already taken care of. I wish to concentrate on `Dialogs' for FPGA RISC5 1MB machines. I would like to start recoding them to Oberon-7, so far without integration to `Texts/TextFrames', just to make them hover above viewers in their own bound rectangle, taking the whole event loop until quit. Integration to come later. Not having much experience nor knowledge of V4, any guidance or suggestion more then welcome. -- Tomas Kral <thomas.kral@email.cz>
Tomas:
I wish to concentrate on `Dialogs' for FPGA RISC5 1MB machines. I would like to start recoding them to Oberon-7, so far without integration to `Texts/TextFrames', just to make them hover above viewers in their own bound rectangle, taking the whole event loop until quit. Integration to come later.
I suspect that disregarding TextFrames can be difficult because both the original Oberon System and V4 GUI are tightly integrated with TextFrames. System-3 Gadgets departed from the tiled screen layout in that they can "hover over" the desktop. If you really want to move towards the overlapping frames then System-3 is a better bet. An enormous work was put into System-2 over the years. Trying to implement a very simple version of it may not be the best solution because there are many issues which have to be taken care of. Studying System-3 may be very helpful to realize those. Wojtek
Hi, Looking into `Dialogs' code, I can see method procedures are loosely placed in module code, not wrapped within relevant type structures. Do I miss some logic or is it just another style of `OOP' coding in Oberon? -- Tomas Kral <thomas.kral@email.cz>
Hi, Studying V4 further, I have come across this coding Types.NewObj(o, Types.This (Modules.ThisMod (module), name)); type := Types.TypeOf (o); `NewObj', `TypeOf', `BaseOf', `TypeTags' defined in Types.Mod I really need some help in understanding of Linz Oberon better. How does type tags and GC differs in V4 to RISC System5? How can these methods be ported from V4 to RISC5? Many thanks. -- Tomas Kral <thomas.kral@email.cz>
Hi Tomas "Types.Mod" could be ported to ProjectOberon 2013 but there are other ways to do it. Types.Mod is a module used for so called „Meta-programming“. Meta-programming is when one module treats or even modifies data structure of other modules. Not a thing you should normally do! There are some instances where it is useful. Eg module Modules.Mod loads arbitrary modules in memory, and module System.Mod inspects what modules are loaded or even unloads foreign modules from memory. All those low level things you need in an OS are called meta-programming. Handling types that are not owned by you is possible with Types.Mod. Often this is used to load/store (=externalize) arbitrary data structures. I prefer that every data structure that is meant to be externalized should offer its Load and Store procedures. This is a much cleaner way. If you want to have a quite decent GUI for ProjectOberon 2013 , rather try to look into "Elems" than into the more complex "Dialogs". Elems, by the way, have own Load and Store procedures and don‘t need Types.Mod br Jörg -----Original Message----- From: Oberon <oberon-bounces@lists.inf.ethz.ch> On Behalf Of Tomas Kral Sent: Wednesday, November 14, 2018 1:53 PM To: oberon@lists.inf.ethz.ch Subject: Re: [Oberon] FPGA - OberonV4 Dialogs Hi, Studying V4 further, I have come across this coding Types.NewObj(o, Types.This (Modules.ThisMod (module), name)); type := Types.TypeOf (o); `NewObj', `TypeOf', `BaseOf', `TypeTags' defined in Types.Mod I really need some help in understanding of Linz Oberon better. How does type tags and GC differs in V4 to RISC System5? How can these methods be ported from V4 to RISC5? Many thanks. -- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Hi Joerg, Not sure I got the idea of "externalisation" right, but I have tested loading and storing structured data using optimised Read/WriteBytes(). https://github.com/tcat-qldom/Oberon-Read-WriteBytes My understanding is, that I need a way to instantiate run time type data with persistent data on disk? -- Tomas Kral <thomas.kral@email.cz>
Hi Tomas As long as you have an ARRAY or a RECORD with some INTEGER fields or so, WriteBytes is okay. But whenever you have POINTERs in your data structure, you can't just dump the memory to disk. The next time you load that structure into memory again, your heap most probably looks totally different and the stored pointers on disk are not pointing to the correct data again. So, while loading you have to properly allocate your pointer data structure again with NEW. To be able to call NEW you need info on the type you want to allocate on the heap. Either you store the type info you got by the module Type.Mod or - cleaner - you call an instantiation routine of the module where you imported the POINTER from and let that module do its job. br Jörg Am 15.11.18, 10:25 schrieb "Oberon im Auftrag von Tomas Kral" <oberon-bounces@lists.inf.ethz.ch im Auftrag von thomas.kral@email.cz>: Hi Joerg, Not sure I got the idea of "externalisation" right, but I have tested loading and storing structured data using optimised Read/WriteBytes(). https://github.com/tcat-qldom/Oberon-Read-WriteBytes My understanding is, that I need a way to instantiate run time type data with persistent data on disk? -- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Tomas: all these topics of metaprogramming and serialization of data structures were implemented in BlackBox. You will gain a lot of insight from studying BlackBox documentation which is distributed together with BlackBox environment. A spectacular demonstration of metaprogramming is the automatic BlackBox GUI builder which analyzes the compiled module and builds a GUI based on the results of this analysis. Based on my own experience, I dare say that 90% of a GUI project time is devoted to classic GUI programming, which BlackBox can eliminate. Billions of dollars could be saved by adopting BlackBox. (My own claim...) This may be the reson why BB was not successful in the market. Who wants to save? Spending is more lucrative than saving. If you want to explore this topic, download and install BlackBox from the CPC website, and then download and install my graphical package Gr. Compile Gr, and then open the interactive Gr User Guide where I am explaining in great detail how BB metaprogramming is used to quickly assemble impressive GUI packages under BlackBox. Wojtek ________________________________________ From: Oberon [oberon-bounces@lists.inf.ethz.ch] on behalf of Jörg [joerg.straube@iaeth.ch] Sent: Thursday, November 15, 2018 4:52 AM To: ETH Oberon and related systems Subject: Re: [Oberon] FPGA - OberonV4 Dialogs Hi Tomas As long as you have an ARRAY or a RECORD with some INTEGER fields or so, WriteBytes is okay. But whenever you have POINTERs in your data structure, you can't just dump the memory to disk. The next time you load that structure into memory again, your heap most probably looks totally different and the stored pointers on disk are not pointing to the correct data again. So, while loading you have to properly allocate your pointer data structure again with NEW. To be able to call NEW you need info on the type you want to allocate on the heap. Either you store the type info you got by the module Type.Mod or - cleaner - you call an instantiation routine of the module where you imported the POINTER from and let that module do its job. br Jörg Am 15.11.18, 10:25 schrieb "Oberon im Auftrag von Tomas Kral" <oberon-bounces@lists.inf.ethz.ch im Auftrag von thomas.kral@email.cz>: Hi Joerg, Not sure I got the idea of "externalisation" right, but I have tested loading and storing structured data using optimised Read/WriteBytes(). https://urldefense.proofpoint.com/v2/url?u=https-3A__github.com_tcat-2Dqldom_Oberon-2DRead-2DWriteBytes&d=DwIGaQ&c=kbmfwr1Yojg42sGEpaQh5ofMHBeTl9EI2eaqQZhHbOU&r=uUiA_zLpwaGJIlq-_BM9w1wVOuyqPwHi3XzJRa-ybV0&m=yRqK6ugX0wX8EZY_4EMKMUPuEWapL48UNPPlHsonq2I&s=ZFye5Msd5y-5HQbx9gfkhKp55fUoo-otFTW-JYBjYnQ&e= My understanding is, that I need a way to instantiate run time type data with persistent data on disk? -- Tomas Kral <thomas.kral@email.cz>
So, while loading you have to properly allocate your pointer data structure again with NEW.
Hi, I have recoded in revised Oberon so far, Dialogs.Mod, Dialog.Mod, DialogFrames.Mod, Display1.Mod, In.Mod, ... I am testing on `Test.Dlg', trying to understand `Dlg' file structure, just by opening it. Dialog.Open Test.Dlg ~ which fails on `h' TRAP 1 in `Dialogs.Mod', index out of range I guess. PROCEDURE LoadP (p: Panel; VAR r: Files.Rider); (** reads the panel from rider r *) VAR cnt, end1, end2, h: INTEGER; o, prev: Object; module: Modules.ModuleName; name: ARRAY 32 OF CHAR; tab1: ARRAY maxItems OF Modules.ModuleName; tab2: ARRAY maxItems OF ARRAY 32 OF CHAR; pos: LONGINT; BEGIN p.contents := NIL; prev := NIL; Files.ReadInt(r, cnt); (*COPY ("", p.cmd)*) p.cmd[0] := 0X; end1 := 0; end2 := 0; WHILE cnt # 0 DO DEC (cnt); pos := Files.Pos (r); Files.ReadInt (r, h); IF h < end1 THEN module := tab1[h] ELSE Files.Set (r, Files.Base (r), pos); Files.ReadString (r, module); tab1[end1] := module; INC (end1) END; pos := Files.Pos (r); Files.ReadInt (r, h); IF h < end2 THEN (*COPY (tab2[h], name)*) name := tab2[h]; ELSE Files.Set (r, Files.Base (r), pos); Files.ReadString (r, name); (*COPY (name, tab2[end2]);*) tab2[end2] := name; INC (end2) END; (** TODO load module and let it init itself instead using Types.Mod *) (*Types.NewObj (o, Types.This (Modules.ThisMod (module), name)); ASSERT (o # NIL);*) NEW(o); ASSERT (o # NIL); Init(o); o.do.Load (o, r); o.panel := p; IF prev # NIL THEN prev.next := o ELSE p.contents := o END; prev := o END; Files.ReadString (r, p.cmd); p.do.Restore (p) END LoadP; Dumping `Test.Dlg'... 00000000 05 00 44 69 61 6c 6f 67 42 75 74 74 6f 6e 73 00 |..DialogButtons.| 00000010 49 74 65 6d 44 65 73 63 00 50 72 69 6e 74 00 4d |ItemDesc.Print.M| 00000020 79 45 64 69 74 2e 50 72 69 6e 74 00 00 00 81 29 |yEdit.Print....)| 00000030 00 e0 5e f8 ff 80 1a 06 00 40 0d 03 00 00 53 79 |..^......@....Sy| 00000040 6e 74 61 78 31 30 2e 53 63 6e 2e 46 6e 74 00 44 |ntax10.Scn.Fnt.D| 00000050 69 61 6c 6f 67 53 74 61 74 69 63 54 65 78 74 73 |ialogStaticTexts| 00000060 00 49 74 65 6d 44 65 73 63 00 44 72 61 66 74 00 |.ItemDesc.Draft.| 00000070 00 00 30 df 18 00 00 ad f8 ff 80 1a 06 00 40 0d |..0...........@.| 00000080 03 00 00 01 01 00 53 79 6e 74 61 78 31 30 2e 53 |......Syntax10.S| 00000090 63 6e 2e 46 6e 74 00 64 72 61 66 74 00 44 69 61 |cn.Fnt.draft.Dia| 000000a0 6c 6f 67 43 68 65 63 6b 42 6f 78 65 73 00 49 74 |logCheckBoxes.It| 000000b0 65 6d 44 65 73 63 00 64 72 61 66 74 00 00 00 20 |emDesc.draft... | 000000c0 0b 20 00 f0 85 f8 ff 40 0d 03 00 40 0d 03 00 00 |. .....@...@....| 000000d0 01 00 49 74 65 6d 44 65 73 63 00 46 69 6c 65 00 |..ItemDesc.File.| 000000e0 00 00 a0 86 01 00 10 d4 f8 ff 80 1a 06 00 40 0d |..............@.| 000000f0 03 00 00 01 01 00 53 79 6e 74 61 78 31 30 2e 53 |......Syntax10.S| 00000100 63 6e 2e 46 6e 74 00 66 69 6c 65 00 44 69 61 6c |cn.Fnt.file.Dial| 00000110 6f 67 54 65 78 74 73 00 49 74 65 6d 44 65 73 63 |ogTexts.ItemDesc| 00000120 00 66 69 6c 65 00 00 00 40 ef 07 00 00 ad f8 ff |.file...@.......| 00000130 60 ae 0a 00 60 5b 03 00 00 00 |`...`[....| 0000013a -- Tomas Kral <thomas.kral@email.cz>
Possibly you have to take care of the differences of INTEGER in Oberon-2 (two bytes) and Oberon-07 (four bytes) Jörg Am 23.11.2018 um 19:57 schrieb Tomas Kral <thomas.kral@email.cz>:
So, while loading you have to properly allocate your pointer data structure again with NEW.
Hi,
I have recoded in revised Oberon so far, Dialogs.Mod, Dialog.Mod, DialogFrames.Mod, Display1.Mod, In.Mod, ...
I am testing on `Test.Dlg', trying to understand `Dlg' file structure, just by opening it.
Dialog.Open Test.Dlg ~
which fails on `h' TRAP 1 in `Dialogs.Mod', index out of range I guess.
PROCEDURE LoadP (p: Panel; VAR r: Files.Rider); (** reads the panel from rider r *) VAR cnt, end1, end2, h: INTEGER; o, prev: Object; module: Modules.ModuleName; name: ARRAY 32 OF CHAR; tab1: ARRAY maxItems OF Modules.ModuleName; tab2: ARRAY maxItems OF ARRAY 32 OF CHAR; pos: LONGINT; BEGIN p.contents := NIL; prev := NIL; Files.ReadInt(r, cnt); (*COPY ("", p.cmd)*) p.cmd[0] := 0X; end1 := 0; end2 := 0; WHILE cnt # 0 DO DEC (cnt); pos := Files.Pos (r); Files.ReadInt (r, h); IF h < end1 THEN module := tab1[h] ELSE Files.Set (r, Files.Base (r), pos); Files.ReadString (r, module); tab1[end1] := module; INC (end1) END; pos := Files.Pos (r); Files.ReadInt (r, h); IF h < end2 THEN (*COPY (tab2[h], name)*) name := tab2[h]; ELSE Files.Set (r, Files.Base (r), pos); Files.ReadString (r, name); (*COPY (name, tab2[end2]);*) tab2[end2] := name; INC (end2) END; (** TODO load module and let it init itself instead using Types.Mod *) (*Types.NewObj (o, Types.This (Modules.ThisMod (module), name)); ASSERT (o # NIL);*) NEW(o); ASSERT (o # NIL); Init(o); o.do.Load (o, r); o.panel := p; IF prev # NIL THEN prev.next := o ELSE p.contents := o END; prev := o END; Files.ReadString (r, p.cmd); p.do.Restore (p) END LoadP;
Dumping `Test.Dlg'...
00000000 05 00 44 69 61 6c 6f 67 42 75 74 74 6f 6e 73 00 |..DialogButtons.| 00000010 49 74 65 6d 44 65 73 63 00 50 72 69 6e 74 00 4d |ItemDesc.Print.M| 00000020 79 45 64 69 74 2e 50 72 69 6e 74 00 00 00 81 29 |yEdit.Print....)| 00000030 00 e0 5e f8 ff 80 1a 06 00 40 0d 03 00 00 53 79 |..^......@....Sy| 00000040 6e 74 61 78 31 30 2e 53 63 6e 2e 46 6e 74 00 44 |ntax10.Scn.Fnt.D| 00000050 69 61 6c 6f 67 53 74 61 74 69 63 54 65 78 74 73 |ialogStaticTexts| 00000060 00 49 74 65 6d 44 65 73 63 00 44 72 61 66 74 00 |.ItemDesc.Draft.| 00000070 00 00 30 df 18 00 00 ad f8 ff 80 1a 06 00 40 0d |..0...........@.| 00000080 03 00 00 01 01 00 53 79 6e 74 61 78 31 30 2e 53 |......Syntax10.S| 00000090 63 6e 2e 46 6e 74 00 64 72 61 66 74 00 44 69 61 |cn.Fnt.draft.Dia| 000000a0 6c 6f 67 43 68 65 63 6b 42 6f 78 65 73 00 49 74 |logCheckBoxes.It| 000000b0 65 6d 44 65 73 63 00 64 72 61 66 74 00 00 00 20 |emDesc.draft... | 000000c0 0b 20 00 f0 85 f8 ff 40 0d 03 00 40 0d 03 00 00 |. .....@...@....| 000000d0 01 00 49 74 65 6d 44 65 73 63 00 46 69 6c 65 00 |..ItemDesc.File.| 000000e0 00 00 a0 86 01 00 10 d4 f8 ff 80 1a 06 00 40 0d |..............@.| 000000f0 03 00 00 01 01 00 53 79 6e 74 61 78 31 30 2e 53 |......Syntax10.S| 00000100 63 6e 2e 46 6e 74 00 66 69 6c 65 00 44 69 61 6c |cn.Fnt.file.Dial| 00000110 6f 67 54 65 78 74 73 00 49 74 65 6d 44 65 73 63 |ogTexts.ItemDesc| 00000120 00 66 69 6c 65 00 00 00 40 ef 07 00 00 ad f8 ff |.file...@.......| 00000130 60 ae 0a 00 60 5b 03 00 00 00 |`...`[....| 0000013a
-- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
On Fri, 23 Nov 2018 21:16:03 +0100 Jörg Straube <joerg.straube@iaeth.ch> wrote:
Possibly you have to take care of the differences of INTEGER in Oberon-2 (two bytes) and Oberon-07 (four bytes)
Yes, that did it, also reading bools as bytes, ReadByte(r, b); bool := S.VAL(BOOLEAN, b); Drawing and Tracking menus in `GraphicsUtils' exploits the number of procedure params and local variables to the System-V maximum. Compiler gets, `too many parameters', `register stack overflow'. I am splitting the logic into more procedures, while reducing number of VARs. -- Tomas Kral <thomas.kral@email.cz>
Hi, I am now recoding `Dialog Texts' which is one of the item type descendants from `Dialog Objects'. It inherits methods from Dialogs plus it adds some of its own. IMethods* = POINTER TO IMDesc; IMDesc* = RECORD (Dialogs.OMDesc) (*base object method descriptor*) (*Copy*: PROCEDURE(t: Item; VAR dup: Dialogs.Object);*) (*override*) GetText*: PROCEDURE(t: Item): Texts.Text; SetSelection*: PROCEDURE(t: Item; beg, end: LONGINT); RemoveSelection*: PROCEDURE(t: Item); (*Draw*: PROCEDURE(t: Item; x, y: INTEGER; f: Display.Frame);*) (*override*) (*Print*: PROCEDURE(t: Item; x, y: INTEGER);*) (*not implemented*) (*Handle*: PROCEDURE(t: Item; f: Display.Frame; VAR msg: Display.FrameMsg);*) (*override*) END; ItemDesc* = RECORD (Dialogs.ObjectDesc) f: TextFrames.Frame; END; VAR m (*self*), m0 (*base*): IMethods; t: Item; o: Object; ... To call (base) object methods I do e.g. t.do.GetDim (t, x, y, w, h); t.do.Draw (t, f.X + x, f.Y + f.H + y, f); To call (self) item specific methods I do e.g. CASE o OF Item: t1 := o(*Item*).do(IMethods).GetText (o(*Item*)); It seems that without `CASE' I need to do more typeguarding. The above compiles, not sure if alright though. However, I seem unable to clone m and initialise m0, with base methods' pointers. Dialogs.Clone(m:(*self Dialogs.OMethods*)); Dialogs.Get(m0:(*base Dialogs.OMethods*)); I just need `do*:' pointing to a descriptor holding base pointers plus new methods pointers. -- Tomas Kral <thomas.kral@email.cz>
Hi Tomas Every module will have its own local "method" RECORD. A pointer to it will be copied to the "do" field after the instance creation. Dialog Objects will initialize its "method" RECORD with the base procedures. Dialog Texts will call the init procedure of Dialog Objects to initialize its "method" RECORD with the base procedures. Afterwards will overwrite some (or all) of the procedure with the own ones. Jörg -----Original Message----- From: Oberon <oberon-bounces@lists.inf.ethz.ch> On Behalf Of Tomas Kral Sent: Monday, November 26, 2018 12:10 PM To: oberon@lists.inf.ethz.ch Subject: Re: [Oberon] FPGA - OberonV4 Dialogs Hi, I am now recoding `Dialog Texts' which is one of the item type descendants from `Dialog Objects'. It inherits methods from Dialogs plus it adds some of its own. IMethods* = POINTER TO IMDesc; IMDesc* = RECORD (Dialogs.OMDesc) (*base object method descriptor*) (*Copy*: PROCEDURE(t: Item; VAR dup: Dialogs.Object);*) (*override*) GetText*: PROCEDURE(t: Item): Texts.Text; SetSelection*: PROCEDURE(t: Item; beg, end: LONGINT); RemoveSelection*: PROCEDURE(t: Item); (*Draw*: PROCEDURE(t: Item; x, y: INTEGER; f: Display.Frame);*) (*override*) (*Print*: PROCEDURE(t: Item; x, y: INTEGER);*) (*not implemented*) (*Handle*: PROCEDURE(t: Item; f: Display.Frame; VAR msg: Display.FrameMsg);*) (*override*) END; ItemDesc* = RECORD (Dialogs.ObjectDesc) f: TextFrames.Frame; END; VAR m (*self*), m0 (*base*): IMethods; t: Item; o: Object; ... To call (base) object methods I do e.g. t.do.GetDim (t, x, y, w, h); t.do.Draw (t, f.X + x, f.Y + f.H + y, f); To call (self) item specific methods I do e.g. CASE o OF Item: t1 := o(*Item*).do(IMethods).GetText (o(*Item*)); It seems that without `CASE' I need to do more typeguarding. The above compiles, not sure if alright though. However, I seem unable to clone m and initialise m0, with base methods' pointers. Dialogs.Clone(m:(*self Dialogs.OMethods*)); Dialogs.Get(m0:(*base Dialogs.OMethods*)); I just need `do*:' pointing to a descriptor holding base pointers plus new methods pointers. -- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Joerg: Recoding Dialogs from Oberon-2 to Oberon-1 looks like a long and uphill battle. Not entirely unexpected. Now look at all the other V4 software. Recoding all this very valuable stuff and then testing would take months or maybe years. This shows why an Oberon-2 compiler makes much more sense. The Linz V4 software can be then used as a real life test suite for the compiler. Wojtek ________________________________________ Joerg wrote: Every module will have its own local "method" RECORD. .....
On Mon, 26 Nov 2018 16:40:26 +0000 "Skulski, Wojciech" <skulski@pas.rochester.edu> wrote:
This shows why an Oberon-2 compiler makes much more sense.
Alternatively, a parser converting Oberon-2 source text to recommended Oberon-7 code patterns, possibly requiring some further hand editing. Neither within reach of my current capabilities. -- Tomas Kral <thomas.kral@email.cz>
On Mon, 26 Nov 2018 15:22:28 +0100 Jörg <joerg.straube@iaeth.ch> wrote:
Dialog Texts will call the init procedure of Dialog Objects to initialize its "method" RECORD with the base procedures. Afterwards will overwrite some (or all) of the procedure with the own ones.
Hi, Yes this helps. I have revisited `Term' OOP example, in effort to set a good coding template. I added methods to extended `CapTerm' type, that are initialised and called along the base methods. Type guard needed. Is this any good? MODULE Term; (* TK 16.8.2018 / 26.11.2018 revised OOP example *) IMPORT Texts, Oberon; TYPE Term* = POINTER TO TDesc; Methods* = POINTER TO MDesc; (* Base method suite *) MDesc* = RECORD Write*: PROCEDURE(t: Term; ch: CHAR); Refresh*: PROCEDURE(t: Term); Ln*: PROCEDURE(t: Term) (* other methods come here *) END ; (* Base data suite *) TDesc* = RECORD do*: Methods; (* generic terminal data comes here *) END ; VAR W: Texts.Writer; methods: Methods; (* ------ Initialisation for clients ------ *) PROCEDURE Init*(t: Term); BEGIN t.do := methods END Init; PROCEDURE Clone*((*VAR*)m: Methods); BEGIN m^ := methods^ END Clone; PROCEDURE Get*(VAR m: Methods); BEGIN m := methods END Get; (* ------ Term base methods ----- *) PROCEDURE Write(t: Term; ch: CHAR); BEGIN Texts.Write(W, ch) END Write; PROCEDURE Refresh(t: Term); BEGIN Texts.Append(Oberon.Log, W.buf) END Refresh; PROCEDURE Ln(t: Term); BEGIN Texts.WriteLn(W) END Ln; BEGIN Texts.OpenWriter(W); NEW(methods); methods.Write := Write; methods.Refresh := Refresh; methods.Ln := Ln END Term. MODULE CapTerm; IMPORT Term; TYPE CapTerm* = POINTER TO CTDesc; Methods* = POINTER TO MDesc; (* CapTerm specific methods *) MDesc* = RECORD(Term.MDesc) Write0*: PROCEDURE(t: CapTerm); Write1*: PROCEDURE(t: CapTerm); (* other methods come here *) END ; (* CapTerm specific data *) CTDesc* = RECORD (Term.TDesc) (* cap terminal data comes here *) col: INTEGER END ; VAR self: Methods; super: Term.Methods; PROCEDURE Init*(t: CapTerm; color: INTEGER (* other data for the CapTerm if any *) ); BEGIN t.do := self; t.col := color END Init; PROCEDURE CAP(ch: CHAR): CHAR; VAR up: CHAR; BEGIN IF (ch >= "a") & (ch <= "z") THEN up := CHR(ORD(ch) + ORD("A") - ORD("a")) ELSE up := ch END RETURN up END CAP; (* --------- Methods added to CapTerm ------- *) PROCEDURE Write0(t: CapTerm); BEGIN super.Write(t, "0") (* upcalls base Term.Write() *) END Write0; PROCEDURE Write1(t: CapTerm); BEGIN super.Write(t, "1") (* upcalls base Term.Write() *) END Write1; (* --------- Methods overriden from Term base ------- *) PROCEDURE Write(t: Term.Term; ch: CHAR); (* Write method specific for CapTerm *) BEGIN ch := CAP(ch); super.Write(t, ch) (* upcalls base Term.Write() *) END Write; (* Refresh() method not to be overriden *) (* Ln() method not to be overriden *) BEGIN NEW(self); Term.Clone(self); Term.Get(super); self.Write := Write; self.Write0 := Write0; self.Write1 := Write1; END CapTerm. MODULE TestTerm; IMPORT Texts, Term, CapTerm, Oberon; VAR t: Term.Term; c: CapTerm.CapTerm; PROCEDURE Run*; VAR S: Texts.Scanner; BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); WHILE S.class = Texts.Name DO t.do.Write(t, S.s[0]); t.do.Refresh(t); c.do.Write(c, S.s[0]); c.do.Refresh(c); (* calls Term.Refresh() *) Texts.Scan(S) END ; c.do(CapTerm.Methods).Write0(c); c.do(CapTerm.Methods).Write1(c); (* prints 01, note do(typeguard) *) c.do.Ln(c); t.do.Ln(t); c.do.Refresh(c) (* calls Term.Ln() twice *) END Run; BEGIN NEW(t); Term.Init(t); NEW(c); CapTerm.Init(c, 20) END TestTerm. TestTerm.Run a b c ~ -- Tomas Kral <thomas.kral@email.cz>
Tomas Your Term.Get is dangerous; with it you effectively export a pointer to Term‘s internal VAR methods. If your CapTerm is a bad guy, it could do super.Write := NIL and destroy the functionality of Term. Try to work with Clone only. br Jörg
Am 26.11.2018 um 20:17 schrieb Tomas Kral <thomas.kral@email.cz>:
On Mon, 26 Nov 2018 15:22:28 +0100 Jörg <joerg.straube@iaeth.ch> wrote:
Dialog Texts will call the init procedure of Dialog Objects to initialize its "method" RECORD with the base procedures. Afterwards will overwrite some (or all) of the procedure with the own ones.
Hi,
Yes this helps. I have revisited `Term' OOP example, in effort to set a good coding template. I added methods to extended `CapTerm' type, that are initialised and called along the base methods. Type guard needed.
Is this any good?
MODULE Term; (* TK 16.8.2018 / 26.11.2018 revised OOP example *) IMPORT Texts, Oberon;
TYPE Term* = POINTER TO TDesc; Methods* = POINTER TO MDesc;
(* Base method suite *)
MDesc* = RECORD Write*: PROCEDURE(t: Term; ch: CHAR); Refresh*: PROCEDURE(t: Term); Ln*: PROCEDURE(t: Term) (* other methods come here *) END ;
(* Base data suite *)
TDesc* = RECORD do*: Methods; (* generic terminal data comes here *) END ;
VAR W: Texts.Writer; methods: Methods;
(* ------ Initialisation for clients ------ *)
PROCEDURE Init*(t: Term); BEGIN t.do := methods END Init;
PROCEDURE Clone*((*VAR*)m: Methods); BEGIN m^ := methods^ END Clone;
PROCEDURE Get*(VAR m: Methods); BEGIN m := methods END Get;
(* ------ Term base methods ----- *)
PROCEDURE Write(t: Term; ch: CHAR); BEGIN Texts.Write(W, ch) END Write;
PROCEDURE Refresh(t: Term); BEGIN Texts.Append(Oberon.Log, W.buf) END Refresh;
PROCEDURE Ln(t: Term); BEGIN Texts.WriteLn(W) END Ln;
BEGIN Texts.OpenWriter(W); NEW(methods); methods.Write := Write; methods.Refresh := Refresh; methods.Ln := Ln END Term.
MODULE CapTerm; IMPORT Term;
TYPE CapTerm* = POINTER TO CTDesc; Methods* = POINTER TO MDesc;
(* CapTerm specific methods *)
MDesc* = RECORD(Term.MDesc) Write0*: PROCEDURE(t: CapTerm); Write1*: PROCEDURE(t: CapTerm); (* other methods come here *) END ;
(* CapTerm specific data *)
CTDesc* = RECORD (Term.TDesc) (* cap terminal data comes here *) col: INTEGER END ;
VAR self: Methods; super: Term.Methods;
PROCEDURE Init*(t: CapTerm; color: INTEGER (* other data for the CapTerm if any *) ); BEGIN t.do := self; t.col := color END Init;
PROCEDURE CAP(ch: CHAR): CHAR; VAR up: CHAR; BEGIN IF (ch >= "a") & (ch <= "z") THEN up := CHR(ORD(ch) + ORD("A") - ORD("a")) ELSE up := ch END RETURN up END CAP;
(* --------- Methods added to CapTerm ------- *)
PROCEDURE Write0(t: CapTerm); BEGIN super.Write(t, "0") (* upcalls base Term.Write() *) END Write0;
PROCEDURE Write1(t: CapTerm); BEGIN super.Write(t, "1") (* upcalls base Term.Write() *) END Write1;
(* --------- Methods overriden from Term base ------- *)
PROCEDURE Write(t: Term.Term; ch: CHAR); (* Write method specific for CapTerm *) BEGIN ch := CAP(ch); super.Write(t, ch) (* upcalls base Term.Write() *) END Write;
(* Refresh() method not to be overriden *) (* Ln() method not to be overriden *)
BEGIN NEW(self); Term.Clone(self); Term.Get(super); self.Write := Write; self.Write0 := Write0; self.Write1 := Write1; END CapTerm.
MODULE TestTerm; IMPORT Texts, Term, CapTerm, Oberon;
VAR t: Term.Term; c: CapTerm.CapTerm;
PROCEDURE Run*; VAR S: Texts.Scanner; BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); WHILE S.class = Texts.Name DO t.do.Write(t, S.s[0]); t.do.Refresh(t); c.do.Write(c, S.s[0]); c.do.Refresh(c); (* calls Term.Refresh() *) Texts.Scan(S) END ; c.do(CapTerm.Methods).Write0(c); c.do(CapTerm.Methods).Write1(c); (* prints 01, note do(typeguard) *) c.do.Ln(c); t.do.Ln(t); c.do.Refresh(c) (* calls Term.Ln() twice *) END Run;
BEGIN NEW(t); Term.Init(t); NEW(c); CapTerm.Init(c, 20) END TestTerm.
TestTerm.Run a b c ~
-- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
I just realized that the „do“ field has to be outside of the inheritance tree. We should have two inheritance trees: one for the fields (without „do“) and one for the methods. MODULE Term; TYPE Term* = POINTER TO Desc; MethodPtr = POINTER TO Methods; Fields* = RECORD (* generic terminal data comes here *) END; Methods* = RECORD Write*: PROCEDURE(t: Term, ch: CHAR); Refresh*: PROCEDURE(t: Term); Ln*: PROCEDURE(t: Term); END Desc = RECORD (Fields) do*: MethodPtr END MODULE CapTerm; TYPE Term* = POINTER TO Desc; MethodPtr = POINTER TO Methods; Fields* = RECORD (Term.Fields) (* cap terminal data comes here *) col: INTEGER END; Methods* = RECORD (Term.Methods) Write0*: PROCEDURE(ct: Term); Write1*: PROCEDURE (ct: Term) END; Desc = RECORD (Fields) do*: MethodPtr END; By applying this code pattern you don‘t have to use type guards for the „do“ calls. You used c.do(CapTerm.Methods).Write0(c) You now write c.do.Write0(c) as c.do has the correct type Jörg
Am 26.11.2018 um 20:17 schrieb Tomas Kral <thomas.kral@email.cz>:
On Mon, 26 Nov 2018 15:22:28 +0100 Jörg <joerg.straube@iaeth.ch> wrote:
Dialog Texts will call the init procedure of Dialog Objects to initialize its "method" RECORD with the base procedures. Afterwards will overwrite some (or all) of the procedure with the own ones.
Hi,
Yes this helps. I have revisited `Term' OOP example, in effort to set a good coding template. I added methods to extended `CapTerm' type, that are initialised and called along the base methods. Type guard needed.
Is this any good?
MODULE Term; (* TK 16.8.2018 / 26.11.2018 revised OOP example *) IMPORT Texts, Oberon;
TYPE Term* = POINTER TO TDesc; Methods* = POINTER TO MDesc;
(* Base method suite *)
MDesc* = RECORD Write*: PROCEDURE(t: Term; ch: CHAR); Refresh*: PROCEDURE(t: Term); Ln*: PROCEDURE(t: Term) (* other methods come here *) END ;
(* Base data suite *)
TDesc* = RECORD do*: Methods; (* generic terminal data comes here *) END ;
VAR W: Texts.Writer; methods: Methods;
(* ------ Initialisation for clients ------ *)
PROCEDURE Init*(t: Term); BEGIN t.do := methods END Init;
PROCEDURE Clone*((*VAR*)m: Methods); BEGIN m^ := methods^ END Clone;
PROCEDURE Get*(VAR m: Methods); BEGIN m := methods END Get;
(* ------ Term base methods ----- *)
PROCEDURE Write(t: Term; ch: CHAR); BEGIN Texts.Write(W, ch) END Write;
PROCEDURE Refresh(t: Term); BEGIN Texts.Append(Oberon.Log, W.buf) END Refresh;
PROCEDURE Ln(t: Term); BEGIN Texts.WriteLn(W) END Ln;
BEGIN Texts.OpenWriter(W); NEW(methods); methods.Write := Write; methods.Refresh := Refresh; methods.Ln := Ln END Term.
MODULE CapTerm; IMPORT Term;
TYPE CapTerm* = POINTER TO CTDesc; Methods* = POINTER TO MDesc;
(* CapTerm specific methods *)
MDesc* = RECORD(Term.MDesc) Write0*: PROCEDURE(t: CapTerm); Write1*: PROCEDURE(t: CapTerm); (* other methods come here *) END ;
(* CapTerm specific data *)
CTDesc* = RECORD (Term.TDesc) (* cap terminal data comes here *) col: INTEGER END ;
VAR self: Methods; super: Term.Methods;
PROCEDURE Init*(t: CapTerm; color: INTEGER (* other data for the CapTerm if any *) ); BEGIN t.do := self; t.col := color END Init;
PROCEDURE CAP(ch: CHAR): CHAR; VAR up: CHAR; BEGIN IF (ch >= "a") & (ch <= "z") THEN up := CHR(ORD(ch) + ORD("A") - ORD("a")) ELSE up := ch END RETURN up END CAP;
(* --------- Methods added to CapTerm ------- *)
PROCEDURE Write0(t: CapTerm); BEGIN super.Write(t, "0") (* upcalls base Term.Write() *) END Write0;
PROCEDURE Write1(t: CapTerm); BEGIN super.Write(t, "1") (* upcalls base Term.Write() *) END Write1;
(* --------- Methods overriden from Term base ------- *)
PROCEDURE Write(t: Term.Term; ch: CHAR); (* Write method specific for CapTerm *) BEGIN ch := CAP(ch); super.Write(t, ch) (* upcalls base Term.Write() *) END Write;
(* Refresh() method not to be overriden *) (* Ln() method not to be overriden *)
BEGIN NEW(self); Term.Clone(self); Term.Get(super); self.Write := Write; self.Write0 := Write0; self.Write1 := Write1; END CapTerm.
MODULE TestTerm; IMPORT Texts, Term, CapTerm, Oberon;
VAR t: Term.Term; c: CapTerm.CapTerm;
PROCEDURE Run*; VAR S: Texts.Scanner; BEGIN Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(S); WHILE S.class = Texts.Name DO t.do.Write(t, S.s[0]); t.do.Refresh(t); c.do.Write(c, S.s[0]); c.do.Refresh(c); (* calls Term.Refresh() *) Texts.Scan(S) END ; c.do(CapTerm.Methods).Write0(c); c.do(CapTerm.Methods).Write1(c); (* prints 01, note do(typeguard) *) c.do.Ln(c); t.do.Ln(t); c.do.Refresh(c) (* calls Term.Ln() twice *) END Run;
BEGIN NEW(t); Term.Init(t); NEW(c); CapTerm.Init(c, 20) END TestTerm.
TestTerm.Run a b c ~
-- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
On Mon, 26 Nov 2018 15:22:28 +0100 Jörg <joerg.straube@iaeth.ch> wrote:
Dialog Texts .. will overwrite some (or all) of the procedure with the own ones.
Yes, I realised that to overwrite a procedure with another one, both must have the same (signature) parameter types. Inheritance Dialog.Objects -> Dialog.Text.Items. This one from `Objects': Draw*: PROCEDURE(o: Object; x, y: INTEGER; f: Display.Frame); and the one from `Texts': Draw*: PROCEDURE(t: Item; x, y: INTEGER; f: Display.Frame)(*override*) Must be recoded to: Draw*: PROCEDURE((*t: Item;*)o: Dialogs.Objects; x, y: INTEGER; f: Display.Frame)(*override*) VAR t: Item; (*added*) BEGIN t := o(Item); (*added*) ... END Draw; Correct, is there a better way? -- Tomas Kral <thomas.kral@email.cz>
Hi, Testing now on `Open.Dlg' dialog, having very few items. All items get now loaded, as it seems. But I needed to insert two dummy reads of 2 integers, they appear in file twice, right after x,y,w,h,bool What are these integers??? 1st INT 2nd INT 1a 06 00 40 0d 03 40 00 00 Why x,y,w,h are so high values??? This is loading log report: DialogButtons Open MyEdit.Print file 6064 26 4288 65528 128 <= x,y,w,h,bool Syntax10.Scn.Fnt DialogStaticTexts File 37856 4 24288 65528 128 <= x,y,w,h,bool DialogTexts file 64640 10 14288 65528 96 <= x,y,w,h,bool ABORT 0003F3E4 Dumping Open.dlg: $ hd Open.Dlg 00000000 03 00 44 69 61 6c 6f 67 42 75 74 74 6f 6e 73 00 |..DialogButtons.| 00000010 49 74 65 6d 44 65 73 63 00 4f 70 65 6e 00 4d 79 |ItemDesc.Open.My| 00000020 45 64 69 74 2e 50 72 69 6e 74 00 66 69 6c 65 20 |Edit.Print.file | 00000030 00 b0 17 1a 00 c0 10 f8 ff 80 1a 06 00 40 0d 03 |.............@..| 00000040 00 00 53 79 6e 74 61 78 31 30 2e 53 63 6e 2e 46 |..Syntax10.Scn.F| 00000050 6e 74 00 44 69 61 6c 6f 67 53 74 61 74 69 63 54 |nt.DialogStaticT| 00000060 65 78 74 73 00 49 74 65 6d 44 65 73 63 00 46 69 |exts.ItemDesc.Fi| 00000070 6c 65 00 00 00 e0 93 04 00 e0 5e f8 ff 80 1a 06 |le........^.....| 00000080 00 40 0d 03 00 00 01 01 00 53 79 6e 74 61 78 31 |.@.......Syntax1| 00000090 30 2e 53 63 6e 2e 46 6e 74 00 66 69 6c 65 00 44 |0.Scn.Fnt.file.D| 000000a0 69 61 6c 6f 67 54 65 78 74 73 00 49 74 65 6d 44 |ialogTexts.ItemD| 000000b0 65 73 63 00 66 69 6c 65 00 00 00 80 fc 0a 00 d0 |esc.file........| 000000c0 37 f8 ff 60 ae 0a 00 60 5b 03 00 00 00 |7..`...`[....| -- Tomas Kral <thomas.kral@email.cz>
Tomas The values are stored in a device-independent form; they are measured in 1/36000 mm. You have to divide them by a scale factor dependent on your device: 300 dpi printer 3048 83 ppi screen 10000 American points 12652 (TeX) Typesetting points 12700 (pdf/postscript) Continental Didot 13500 mm 36000 inch 914400 As typical monitors have ~83..93 ppi you normally divide the value by 10’000 to convert to pixels. Eg the monitors mostly offered in stores today are 24“ in diagonal with 1920x1080 pixels. This results in 92 ppi. For this screen you could divide the values by 9962 to have an absolutely accurate representation of the Dialog. But round 9962 up to 10‘000 and you‘re fine.
b0 17 1a 00 = 171 c0 10 f8 ff = -52 80 1a 06 00 = 40 40 0d 03 00 = 20
br Jörg
Am 01.12.2018 um 22:10 schrieb Tomas Kral <thomas.kral@email.cz>:
Hi,
Testing now on `Open.Dlg' dialog, having very few items.
All items get now loaded, as it seems. But I needed to insert two dummy reads of 2 integers, they appear in file twice, right after x,y,w,h,bool
What are these integers??? 1st INT 2nd INT 1a 06 00 40 0d 03 40 00 00
Why x,y,w,h are so high values???
This is loading log report:
DialogButtons Open MyEdit.Print file 6064 26 4288 65528 128 <= x,y,w,h,bool Syntax10.Scn.Fnt DialogStaticTexts File
37856 4 24288 65528 128 <= x,y,w,h,bool DialogTexts file
64640 10 14288 65528 96 <= x,y,w,h,bool ABORT 0003F3E4
Dumping Open.dlg:
$ hd Open.Dlg 00000000 03 00 44 69 61 6c 6f 67 42 75 74 74 6f 6e 73 00 |..DialogButtons.| 00000010 49 74 65 6d 44 65 73 63 00 4f 70 65 6e 00 4d 79 |ItemDesc.Open.My| 00000020 45 64 69 74 2e 50 72 69 6e 74 00 66 69 6c 65 20 |Edit.Print.file | 00000030 00 b0 17 1a 00 c0 10 f8 ff 80 1a 06 00 40 0d 03 |.............@..| 00000040 00 00 53 79 6e 74 61 78 31 30 2e 53 63 6e 2e 46 |..Syntax10.Scn.F| 00000050 6e 74 00 44 69 61 6c 6f 67 53 74 61 74 69 63 54 |nt.DialogStaticT| 00000060 65 78 74 73 00 49 74 65 6d 44 65 73 63 00 46 69 |exts.ItemDesc.Fi| 00000070 6c 65 00 00 00 e0 93 04 00 e0 5e f8 ff 80 1a 06 |le........^.....| 00000080 00 40 0d 03 00 00 01 01 00 53 79 6e 74 61 78 31 |.@.......Syntax1| 00000090 30 2e 53 63 6e 2e 46 6e 74 00 66 69 6c 65 00 44 |0.Scn.Fnt.file.D| 000000a0 69 61 6c 6f 67 54 65 78 74 73 00 49 74 65 6d 44 |ialogTexts.ItemD| 000000b0 65 73 63 00 66 69 6c 65 00 00 00 80 fc 0a 00 d0 |esc.file........| 000000c0 37 f8 ff 60 ae 0a 00 60 5b 03 00 00 00 |7..`...`[....|
-- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
A small correction: Dividing by 10’000 fits to a screen with 91 ppi instead of 83 ppi as I stated in previous mail 😩 screen divide by 87 ppi 10500 91 ppi 10000 96 ppi 9500 br Jörg
Am 02.12.2018 um 07:50 schrieb Jörg Straube <joerg.straube@iaeth.ch>:
Tomas
The values are stored in a device-independent form; they are measured in 1/36000 mm.
You have to divide them by a scale factor dependent on your device:
300 dpi printer 3048 83 ppi screen 10000 American points 12652 (TeX) Typesetting points 12700 (pdf/postscript) Continental Didot 13500 mm 36000 inch 914400
As typical monitors have ~83..93 ppi you normally divide the value by 10’000 to convert to pixels.
Eg the monitors mostly offered in stores today are 24“ in diagonal with 1920x1080 pixels. This results in 92 ppi. For this screen you could divide the values by 9962 to have an absolutely accurate representation of the Dialog. But round 9962 up to 10‘000 and you‘re fine.
b0 17 1a 00 = 171 c0 10 f8 ff = -52 80 1a 06 00 = 40 40 0d 03 00 = 20
br Jörg
Am 01.12.2018 um 22:10 schrieb Tomas Kral <thomas.kral@email.cz>:
Hi,
Testing now on `Open.Dlg' dialog, having very few items.
All items get now loaded, as it seems. But I needed to insert two dummy reads of 2 integers, they appear in file twice, right after x,y,w,h,bool
What are these integers??? 1st INT 2nd INT 1a 06 00 40 0d 03 40 00 00
Why x,y,w,h are so high values???
This is loading log report:
DialogButtons Open MyEdit.Print file 6064 26 4288 65528 128 <= x,y,w,h,bool Syntax10.Scn.Fnt DialogStaticTexts File
37856 4 24288 65528 128 <= x,y,w,h,bool DialogTexts file
64640 10 14288 65528 96 <= x,y,w,h,bool ABORT 0003F3E4
Dumping Open.dlg:
$ hd Open.Dlg 00000000 03 00 44 69 61 6c 6f 67 42 75 74 74 6f 6e 73 00 |..DialogButtons.| 00000010 49 74 65 6d 44 65 73 63 00 4f 70 65 6e 00 4d 79 |ItemDesc.Open.My| 00000020 45 64 69 74 2e 50 72 69 6e 74 00 66 69 6c 65 20 |Edit.Print.file | 00000030 00 b0 17 1a 00 c0 10 f8 ff 80 1a 06 00 40 0d 03 |.............@..| 00000040 00 00 53 79 6e 74 61 78 31 30 2e 53 63 6e 2e 46 |..Syntax10.Scn.F| 00000050 6e 74 00 44 69 61 6c 6f 67 53 74 61 74 69 63 54 |nt.DialogStaticT| 00000060 65 78 74 73 00 49 74 65 6d 44 65 73 63 00 46 69 |exts.ItemDesc.Fi| 00000070 6c 65 00 00 00 e0 93 04 00 e0 5e f8 ff 80 1a 06 |le........^.....| 00000080 00 40 0d 03 00 00 01 01 00 53 79 6e 74 61 78 31 |.@.......Syntax1| 00000090 30 2e 53 63 6e 2e 46 6e 74 00 66 69 6c 65 00 44 |0.Scn.Fnt.file.D| 000000a0 69 61 6c 6f 67 54 65 78 74 73 00 49 74 65 6d 44 |ialogTexts.ItemD| 000000b0 65 73 63 00 66 69 6c 65 00 00 00 80 fc 0a 00 d0 |esc.file........| 000000c0 37 f8 ff 60 ae 0a 00 60 5b 03 00 00 00 |7..`...`[....|
-- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Hi Joerg, Thank you.
But round 9962 up to 10‘000 and you‘re fine. Linz Oberon, also defines TextFrames.Unit = 10000, so I will keep for RISC System-V as suggested.
Linz has two byte SHORTS x(short),y(short),w(short),h(short),overlapping(bool)
b0 17 1a 00 = 171 c0 10 f8 ff = -52 80 1a 06 00 = 40 40 0d 03 00 = 20
b0 17 = x 1a 00 = y c0 10 = w f8 ff = h 80 = overlapping 1a 06 00 40 0d 03 00 00 = unused discarded ??????????? Other explanation could be that some of these values are lookup indices, as Dialogs.Load() keeps two tables tab1; tab2 on symbols loaded, but may get somehow confused by my coding to Oberon-7. BTW tab1,tab2 are never initialised! e.g. h := maxItems-1; REPEAT tab1[h][0] := 0X; tab2[h][0] := 0X; DEC(h) UNTIL h = 0; Since a dialog can have multiple items e.g. buttons, etc, symbols are never duplicated, rather with each subsequent reference only an index is stored, two byte tab{1,2} reference (short int). On the other hand, there are duplications of ItemDesc.{name}. Getting confused. -- Tomas Kral <thomas.kral@email.cz>
On Sun, 2 Dec 2018 10:42:32 +0100 Tomas Kral <thomas.kral@email.cz> wrote:
Linz has two byte SHORTS x(short),y(short),w(short),h(short),overlapping(bool)
Ah, now I see, Files.ReadLInt (r, o.x); Files.ReadLInt (r, o.y); Files.ReadLInt (r, o.w); Files.ReadLInt (r, o.h); I changed to Files.ReadInt() first and then seeing that, changed to Files.ReadShort(). It is really meant to read 4-byte Int. Now it makes sense to DIV by 10000. Loading log now reports: DialogButtons Open MyEdit.Print file 1710000 -520000 400000 200000 0 Syntax10.Scn.Fnt DialogStaticTexts File 300000 -500000 400000 200000 0 DialogTexts file 720000 -510000 700000 220000 0 ABORT 00041F04 Now I am worried about ABORT, that is exactly when the viewer is comes up. Message handler not installed? -- Tomas Kral <thomas.kral@email.cz>
ABORT tells you, you messed up with internal data structures possibly on the stack. If you return from a procedure and on the stack is no longer the return address but 0 (as you e.g. accidentially overwrote the stack with 0s) the CPU will jump to address 0, where the Abort handler sits. Or you call an unitialized procedure variable, you jump to 0 and get ABORT as well. There are a myriad of root causes for this ABORT messages. Jörg
Am 02.12.2018 um 13:43 schrieb Tomas Kral <thomas.kral@email.cz>:
On Sun, 2 Dec 2018 10:42:32 +0100 Tomas Kral <thomas.kral@email.cz> wrote:
Linz has two byte SHORTS x(short),y(short),w(short),h(short),overlapping(bool)
Ah, now I see,
Files.ReadLInt (r, o.x); Files.ReadLInt (r, o.y); Files.ReadLInt (r, o.w); Files.ReadLInt (r, o.h);
I changed to Files.ReadInt() first and then seeing that, changed to Files.ReadShort(). It is really meant to read 4-byte Int.
Now it makes sense to DIV by 10000.
Loading log now reports:
DialogButtons Open MyEdit.Print file 1710000 -520000 400000 200000 0 Syntax10.Scn.Fnt DialogStaticTexts File
300000 -500000 400000 200000 0 DialogTexts file
720000 -510000 700000 220000 0 ABORT 00041F04
Now I am worried about ABORT, that is exactly when the viewer is comes up. Message handler not installed?
-- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
On Sun, 2 Dec 2018 14:47:54 +0100 Jörg Straube <joerg.straube@iaeth.ch> wrote:
Or you call an unitialized procedure variable, you jump to 0 and get ABORT as well.
Hi Joerg, Thanks for your continued encouragement! The above was the case, I corrected some of the proc vars, I sometimes cannot simply decide if some Oberon-2 procedure is meant a dynamic call through do*, or a static one just taking `this' receiver object . So is a matter of style of coding plus my typos and a lot of faults in understanding. See picture, possibly better, I now get some messages flowing, but certainly still needs some more work to do. It may well be, that `Dialogs' can be ported to System-V and revised Oberon-7. I am overwhelmed by so much code just doing simple GUI, while also tempted to try something of my own. -- Tomas Kral <thomas.kral@email.cz>
Hi, This is a b&w version, I seem struggling with colours, whatever I do with buttons, is always black on black, so I use `zig-zag' dot pattern. The colour definition, does not seem honoured at first sight, by the objects. grey1* = 12; grey2* = 13; grey3* = 14; black* = 15; white* = 0; (** color codes *) -- Tomas Kral <thomas.kral@email.cz>
Hi, Now trying something of my own, not perfect, fun will start when I try to add some message loop (handler), as I do not understand this part much. Clicking on `DLog.Load' (several times), and `DLog.Update' does things. That mimics I can add objects at run time, possibly. MODULE DLog; (* TK 13.12.2018 Dialogs - simple coding for RISC *) IMPORT In, Out, Modules; TYPE Object* = POINTER TO ObjDesc; Methods* = POINTER TO MethodDesc; Rect* = POINTER TO RectDesc; ObjDesc* = RECORD do*: Methods; r*: Rect; (*bounding rectangle*) next: Object; id*: INTEGER END; RectDesc = RECORD x, y, w, h: INTEGER; END; MethodDesc* = RECORD draw*: PROCEDURE (o: Object); END; VAR first: Object; cnt: INTEGER; PROCEDURE Load*; VAR name: Modules.ModuleName; module: Modules.Module; New: PROCEDURE; BEGIN In.Open; In.Name(name); WHILE In.Done DO Out.String(name); Out.String(" loading "); Modules.Load(name, module); New := Modules.ThisCommand(module, "New"); IF Modules.res = 0 THEN New() END ; In.Name(name); Out.Ln END; END Load; PROCEDURE LinkObj*(o: Object); BEGIN o.next := first; first := o; INC(cnt); o.id := cnt END LinkObj; PROCEDURE Update*; VAR o: Object; BEGIN o := first; WHILE o # NIL DO o.do.draw(o); o := o.next END END Update; BEGIN first := NIL; cnt := 0 END DLog. DLog.Load DText DButton DButton DText DText ~ Objects from stream now, TODO from persistent file DLog.Update MODULE DText; IMPORT DLog, Out; TYPE Text = ARRAY 32 OF CHAR; Item = POINTER TO ItemDesc; ItemDesc = RECORD(DLog.ObjDesc) txt: Text; (*user runtime input*) END; VAR it: Item; m: DLog.Methods; PROCEDURE Draw(o: DLog.Object); BEGIN Out.String("Drawing text"); Out.Int(o.id, 2); Out.Ln END Draw; PROCEDURE New*; BEGIN NEW(it); DLog.LinkObj(it); it.do := m; m.draw := Draw END New; BEGIN NEW(m) END DText. MODULE DButton; IMPORT DLog, Out; CONST oval = 0; oblique = 1; TYPE Item = POINTER TO ItemDesc; ItemDesc = RECORD(DLog.ObjDesc) shape: INTEGER; END; VAR it: Item; m: DLog.Methods; PROCEDURE Draw(o: DLog.Object); BEGIN Out.String("Drawing button"); Out.Int(o.id, 2); Out.Ln END Draw; PROCEDURE New*; BEGIN NEW(it); DLog.LinkObj(it); it.do := m; m.draw := Draw END New; BEGIN NEW(m) END DButton. -- Tomas Kral <thomas.kral@email.cz>
„m.draw := Draw“ should be after NEW(m) in the two main bodies and deleted from both New()s Jörg
Am 13.12.2018 um 22:13 schrieb Tomas Kral <thomas.kral@email.cz>:
Hi,
Now trying something of my own, not perfect, fun will start when I try to add some message loop (handler), as I do not understand this part much.
Clicking on `DLog.Load' (several times), and `DLog.Update' does things.
That mimics I can add objects at run time, possibly.
MODULE DLog; (* TK 13.12.2018 Dialogs - simple coding for RISC *) IMPORT In, Out, Modules;
TYPE Object* = POINTER TO ObjDesc; Methods* = POINTER TO MethodDesc; Rect* = POINTER TO RectDesc;
ObjDesc* = RECORD do*: Methods; r*: Rect; (*bounding rectangle*) next: Object; id*: INTEGER END;
RectDesc = RECORD x, y, w, h: INTEGER; END;
MethodDesc* = RECORD draw*: PROCEDURE (o: Object); END;
VAR first: Object; cnt: INTEGER;
PROCEDURE Load*; VAR name: Modules.ModuleName; module: Modules.Module; New: PROCEDURE; BEGIN In.Open; In.Name(name); WHILE In.Done DO Out.String(name); Out.String(" loading "); Modules.Load(name, module); New := Modules.ThisCommand(module, "New"); IF Modules.res = 0 THEN New() END ; In.Name(name); Out.Ln END; END Load;
PROCEDURE LinkObj*(o: Object); BEGIN o.next := first; first := o; INC(cnt); o.id := cnt END LinkObj;
PROCEDURE Update*; VAR o: Object; BEGIN o := first; WHILE o # NIL DO o.do.draw(o); o := o.next END END Update;
BEGIN first := NIL; cnt := 0 END DLog.
DLog.Load DText DButton DButton DText DText ~ Objects from stream now, TODO from persistent file DLog.Update
MODULE DText; IMPORT DLog, Out;
TYPE Text = ARRAY 32 OF CHAR;
Item = POINTER TO ItemDesc; ItemDesc = RECORD(DLog.ObjDesc) txt: Text; (*user runtime input*) END;
VAR it: Item; m: DLog.Methods;
PROCEDURE Draw(o: DLog.Object); BEGIN Out.String("Drawing text"); Out.Int(o.id, 2); Out.Ln END Draw;
PROCEDURE New*; BEGIN NEW(it); DLog.LinkObj(it); it.do := m; m.draw := Draw END New;
BEGIN NEW(m) END DText.
MODULE DButton; IMPORT DLog, Out;
CONST oval = 0; oblique = 1;
TYPE Item = POINTER TO ItemDesc; ItemDesc = RECORD(DLog.ObjDesc) shape: INTEGER; END;
VAR it: Item; m: DLog.Methods;
PROCEDURE Draw(o: DLog.Object); BEGIN Out.String("Drawing button"); Out.Int(o.id, 2); Out.Ln END Draw;
PROCEDURE New*; BEGIN NEW(it); DLog.LinkObj(it); it.do := m; m.draw := Draw END New;
BEGIN NEW(m) END DButton.
-- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
On Thu, 13 Dec 2018 23:11:56 +0100 Jörg Straube <joerg.straube@iaeth.ch> wrote:
„m.draw := Draw“ should be after NEW(m) in the two main bodies and deleted from both New()s
Thank you, corrected. Added some fields so I may not use `Texts', no need to modify PO2013 `Texts' and `TextFrames'. Unlike the original Dialogs. MODULE DLog; (* TK 13.12.2018 Dialogs - simple coding for RISC *) IMPORT In, Out, Modules; TYPE Object* = POINTER TO ObjDesc; Methods* = POINTER TO MethodDesc; Rect* = POINTER TO RectDesc; ObjDesc* = RECORD do*: Methods; r*: Rect; (*bounding rectangle*) next: Object; id*: INTEGER END; RectDesc = RECORD x, y, w, h: INTEGER; END; MethodDesc* = RECORD draw*: PROCEDURE (o: Object); END; VAR first: Object; cnt: INTEGER; PROCEDURE Load*; VAR name: Modules.ModuleName; module: Modules.Module; New: PROCEDURE; BEGIN In.Open; In.Name(name); WHILE In.Done DO Out.String(name); Out.String(" loading "); Modules.Load(name, module); New := Modules.ThisCommand(module, "New"); IF Modules.res = 0 THEN New() END ; In.Name(name); Out.Ln END; END Load; PROCEDURE LinkObj*(o: Object); BEGIN o.next := first; first := o; INC(cnt); o.id := cnt END LinkObj; PROCEDURE Update*; VAR o: Object; BEGIN o := first; WHILE o # NIL DO o.do.draw(o); o := o.next END END Update; BEGIN first := NIL; cnt := 0 END DLog. DLog.Load DText DButton DButton DText DText ~ Objects from stream now, TODO from persistent file DLog.Update MODULE DText; IMPORT DLog, Out; TYPE Text = ARRAY 32 OF CHAR; Item = POINTER TO ItemDesc; ItemDesc = RECORD(DLog.ObjDesc) static: BOOLEAN; name: Text; END; VAR t: Item; m: DLog.Methods; PROCEDURE Draw(o: DLog.Object); BEGIN Out.String("Drawing text"); Out.Int(o.id, 2); Out.Ln END Draw; PROCEDURE New*; BEGIN NEW(t); DLog.LinkObj(t); t.do := m END New; BEGIN NEW(m); m.draw := Draw END DText. MODULE DButton; IMPORT DLog, Out; CONST oval = 0; oblique = 1; TYPE Item = POINTER TO ItemDesc; ItemDesc = RECORD(DLog.ObjDesc) shape: INTEGER; END; VAR t: Item; m: DLog.Methods; PROCEDURE Draw(o: DLog.Object); BEGIN Out.String("Drawing button"); Out.Int(o.id, 2); Out.Ln END Draw; PROCEDURE New*; BEGIN NEW(t); DLog.LinkObj(t); t.do := m END New; BEGIN NEW(m); m.draw := Draw END DButton. -- Tomas Kral <thomas.kral@email.cz>
Tomas: Andreas released the Oberon-2 compiler. Porting Dialogs to his compiler should be now significantly easier than porting to Oberon-07. Wojtek ________________________________________ From: Oberon [oberon-bounces@lists.inf.ethz.ch] on behalf of Tomas Kral [thomas.kral@email.cz] Sent: Thursday, December 13, 2018 5:30 PM To: oberon@lists.inf.ethz.ch Subject: Re: [Oberon] FPGA - OberonV4 Dialogs On Thu, 13 Dec 2018 23:11:56 +0100 Jörg Straube <joerg.straube@iaeth.ch> wrote:
„m.draw := Draw“ should be after NEW(m) in the two main bodies and deleted from both New()s
Thank you, corrected. Added some fields so I may not use `Texts', no need to modify PO2013 `Texts' and `TextFrames'. Unlike the original Dialogs. MODULE DLog; (* TK 13.12.2018 Dialogs - simple coding for RISC *) IMPORT In, Out, Modules; TYPE Object* = POINTER TO ObjDesc; Methods* = POINTER TO MethodDesc; Rect* = POINTER TO RectDesc; ObjDesc* = RECORD do*: Methods; r*: Rect; (*bounding rectangle*) next: Object; id*: INTEGER END; RectDesc = RECORD x, y, w, h: INTEGER; END; MethodDesc* = RECORD draw*: PROCEDURE (o: Object); END; VAR first: Object; cnt: INTEGER; PROCEDURE Load*; VAR name: Modules.ModuleName; module: Modules.Module; New: PROCEDURE; BEGIN In.Open; In.Name(name); WHILE In.Done DO Out.String(name); Out.String(" loading "); Modules.Load(name, module); New := Modules.ThisCommand(module, "New"); IF Modules.res = 0 THEN New() END ; In.Name(name); Out.Ln END; END Load; PROCEDURE LinkObj*(o: Object); BEGIN o.next := first; first := o; INC(cnt); o.id := cnt END LinkObj; PROCEDURE Update*; VAR o: Object; BEGIN o := first; WHILE o # NIL DO o.do.draw(o); o := o.next END END Update; BEGIN first := NIL; cnt := 0 END DLog. DLog.Load DText DButton DButton DText DText ~ Objects from stream now, TODO from persistent file DLog.Update MODULE DText; IMPORT DLog, Out; TYPE Text = ARRAY 32 OF CHAR; Item = POINTER TO ItemDesc; ItemDesc = RECORD(DLog.ObjDesc) static: BOOLEAN; name: Text; END; VAR t: Item; m: DLog.Methods; PROCEDURE Draw(o: DLog.Object); BEGIN Out.String("Drawing text"); Out.Int(o.id, 2); Out.Ln END Draw; PROCEDURE New*; BEGIN NEW(t); DLog.LinkObj(t); t.do := m END New; BEGIN NEW(m); m.draw := Draw END DText. MODULE DButton; IMPORT DLog, Out; CONST oval = 0; oblique = 1; TYPE Item = POINTER TO ItemDesc; ItemDesc = RECORD(DLog.ObjDesc) shape: INTEGER; END; VAR t: Item; m: DLog.Methods; PROCEDURE Draw(o: DLog.Object); BEGIN Out.String("Drawing button"); Out.Int(o.id, 2); Out.Ln END Draw; PROCEDURE New*; BEGIN NEW(t); DLog.LinkObj(t); t.do := m END New; BEGIN NEW(m); m.draw := Draw END DButton. -- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.inf.ethz.ch_mailman_listinfo_oberon&d=DwIGaQ&c=kbmfwr1Yojg42sGEpaQh5ofMHBeTl9EI2eaqQZhHbOU&r=uUiA_zLpwaGJIlq-_BM9w1wVOuyqPwHi3XzJRa-ybV0&m=AZINTDgIhqfeheIrEMML8BqJiaIjk-X1Mp24vvADKXI&s=uiG0fg7osSRnhTSCSqWrvs8u2WRc5wdPtzkLNhh4PhM&e=
On Fri, 14 Dec 2018 02:14:51 +0000 "Skulski, Wojciech" <skulski@pas.rochester.edu> wrote:
Andreas released the Oberon-2 compiler. Porting Dialogs to his compiler should be now significantly easier than porting to Oberon-07.
This is good news. I will leave V4 Dialogs for Oberon-7 as is, it needs some more tinkering, while it has more PO2013 look and feel. But it shows difference between Oberon-2/7 code style and basic idea how port may be accomplished. If onyone interested to toy with along Oberon-2 port, I can share the code. -- Tomas Kral <thomas.kral@email.cz>
On Thu, 13 Dec 2018 22:13:43 +0100 Tomas Kral <thomas.kral@email.cz> wrote:
Fun when I try to add some message loop (handler), as I do not understand this part much.
I have copied over `Handler' code from `GraphicFrames.Mod', and skinned it to a bare skeleton. It seems that to tap into Oberon event loop, one needs to extend `DisplayFrame' and install own `Handle'. It seems to avoid circular references, there is a need of three modules, Main, Control, and Frame. Possibly the concept of MVC, as noted in OOP by H.P.Mossenbock. I am now able to clear frame, on opening and resizing, plus calling Update to draw DLog elements. How do I clear frame only on initial opening not closing or resizing? Note actual M.Y, M.H, has to be picked from the frame message! I do not get(*understand*) all the other events, except `Oberon.InputMsg'. What if, I needed to add a new handler for each `DLog' element at runtime, how do I chain all handlers then? Frame* = POINTER TO FrameDesc; FrameDesc* = RECORD (Display.FrameDesc) END ; UpdateMsg = RECORD (Display.FrameMsg) id: INTEGER; END ; PROCEDURE Handle*(F: Display.Frame; VAR M: Display.FrameMsg); VAR x, y, h: INTEGER; BEGIN CASE F OF Frame: CASE M OF Oberon.InputMsg: IF M.id = Oberon.track THEN x := M.X; y := M.Y; IF M.keys # {} THEN ELSE Oberon.DrawMouse(MyMouse, x, y) END ELSIF M.id = Oberon.consume THEN END | UpdateMsg: (*my update, not sure what to do here*) | Oberon.ControlMsg: IF M.id = Oberon.neutralize THEN Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); Out.String("neutralize msg"); Out.Ln ELSIF M.id = Oberon.defocus THEN END | Oberon.SelectionMsg: Out.String("select msg"); Out.Ln | Oberon.CopyMsg: Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); | MenuViewers.ModifyMsg: Out.String("modify msg"); Out.Ln; Display.ReplConst(Display.black, F.X, M.Y, F.W, M.H, Display.replace); (*clear frame*) DLogs.Update (*redrawing dialog screen*) END END END Handle; -- Tomas Kral <thomas.kral@email.cz>
I recommend to read and study this description: https://www.inf.ethz.ch/personal/wirth/ProjectOberon/PO.System.pdf Especially chapter 3 and 4 Br Jörg
Am 15.12.2018 um 11:31 schrieb Tomas Kral <thomas.kral@email.cz>:
On Thu, 13 Dec 2018 22:13:43 +0100 Tomas Kral <thomas.kral@email.cz> wrote:
Fun when I try to add some message loop (handler), as I do not understand this part much.
I have copied over `Handler' code from `GraphicFrames.Mod', and skinned it to a bare skeleton. It seems that to tap into Oberon event loop, one needs to extend `DisplayFrame' and install own `Handle'.
It seems to avoid circular references, there is a need of three modules, Main, Control, and Frame. Possibly the concept of MVC, as noted in OOP by H.P.Mossenbock.
I am now able to clear frame, on opening and resizing, plus calling Update to draw DLog elements. How do I clear frame only on initial opening not closing or resizing? Note actual M.Y, M.H, has to be picked from the frame message! I do not get(*understand*) all the other events, except `Oberon.InputMsg'. What if, I needed to add a new handler for each `DLog' element at runtime, how do I chain all handlers then?
Frame* = POINTER TO FrameDesc; FrameDesc* = RECORD (Display.FrameDesc) END ;
UpdateMsg = RECORD (Display.FrameMsg) id: INTEGER; END ;
PROCEDURE Handle*(F: Display.Frame; VAR M: Display.FrameMsg); VAR x, y, h: INTEGER; BEGIN CASE F OF Frame: CASE M OF Oberon.InputMsg: IF M.id = Oberon.track THEN x := M.X; y := M.Y; IF M.keys # {} THEN ELSE Oberon.DrawMouse(MyMouse, x, y) END ELSIF M.id = Oberon.consume THEN END | UpdateMsg: (*my update, not sure what to do here*) | Oberon.ControlMsg: IF M.id = Oberon.neutralize THEN Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); Out.String("neutralize msg"); Out.Ln ELSIF M.id = Oberon.defocus THEN END | Oberon.SelectionMsg: Out.String("select msg"); Out.Ln | Oberon.CopyMsg: Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); | MenuViewers.ModifyMsg: Out.String("modify msg"); Out.Ln; Display.ReplConst(Display.black, F.X, M.Y, F.W, M.H, Display.replace); (*clear frame*) DLogs.Update (*redrawing dialog screen*) END END END Handle;
-- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
I recommend to read and study this description: PO.System.pdf Especially chapter 3 and 4
Doing my homework, message handlers unveil a lot more possibilities. Message handling in my case sometimes lead to unintended effects, such as mouse trailing its mark. -- Tomas Kral <thomas.kral@email.cz>
On Sat, 15 Dec 2018 11:45:10 +0100 Jörg <joerg.straube@iaeth.ch> wrote:
chapter 3 and 4
Recoded to this, I borrow from `GraphicFrames.Mod', that learn a lot from, I wish to use dY, currently have my `voff-Y' calculations. PROCEDURE Handle*(F: Display.Frame; VAR M: Display.FrameMsg); VAR x, y, h: INTEGER; o: DLogs.Object; BEGIN CASE F OF Frame: CASE M OF Oberon.InputMsg: IF M.id = Oberon.track THEN IF M.keys # {} THEN FlipHook(F, M); (*shuffle hook at x,y*) IF ~ F.focus THEN Oberon.PassFocus(Viewers.This(F.X, F.Y)); F.focus := TRUE END ; (*acquire focus*) o := DLogs.This(M.X, F.H-M.Y+F.Y); (*Y=0 top of frame, Y=H bottom frame*) IF o # NIL THEN Out.String("found"); Out.Ln END (*locate object at x,y coord*) ELSE Oberon.DrawMouse(Crosshair, M.X, M.Y) END ELSIF M.id = Oberon.consume THEN Out.String("consume msg: "); Out.Char(M.ch); Out.Ln END | UpdateMsg: Out.String("update msg"); Out.Ln (*not used yet*) | Oberon.ControlMsg: IF M.id = Oberon.neutralize THEN Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); Out.String("neutralize msg"); Out.Ln ELSIF M.id = Oberon.defocus THEN Out.String("defocus msg"); Out.Ln; F.focus := FALSE; HideHook(F) (*give up focus, hide hook*) END | Oberon.SelectionMsg: Out.String("select msg"); Out.Ln (*cannot give up select message to other frames?*) | Oberon.CopyMsg: Oberon.RemoveMarks(F.X, F.Y, F.W, F.H); | MenuViewers.ModifyMsg: HideHook(F); Display.ReplConst(Display.black, F.X, M.Y, F.W, M.H, Display.replace); (*clear frame*) Display.ReplPattern(7, Display1.grey0, F.X, M.Y, F.W, M.H, Display.invert); (*filler*) DLogs.Update(M.Y+M.H); (*redraw dialog, Y=M.Y+M.H, top of frame*) Out.String("modify msg"); Out.Int(M.id, 3); Out.Ln END END END Handle; I currently have only one dynamic call o.Draw(), I may need o.Handle() in addition. I do not use UpdateMsg, I plan to use when only one object needs updating (delete/move/change/...etc). Is it possible to have one frame for multiple dialogs, see picture? -- Tomas Kral <thomas.kral@email.cz>
On Thu, 15 Nov 2018 10:52:40 +0100 Jörg <joerg.straube@iaeth.ch> wrote:
Either you store the type info you got by the module Type.Mod or - cleaner - you call an instantiation routine of the module where you imported the POINTER from and let that module do its job.
My understanding is that Dialogs.Load() scans `*.Dlg' (meta?) file for module names, reading further some static and dynamic data. PROCEDURE LoadP (p: Panel; VAR r: Files.Rider); (** reads the panel from rider r *) BEGIN ... WHILE V{elements-count} > 0 DO P{Get Module Name} P{Load Name} P{Init Module with Dlg data} END ; DONE. For loading part, it does some magic with `Types' Types.NewObj (o, Types.This (Modules.ThisMod (module), name)); ASSERT (o # NIL); Could be it recoded to something like this? Modules.Load(name, dlgItem); Modules.ThisCommand(dlgItem, "Init()"); Many thanks and apologies for asking too much. -- Tomas Kral <thomas.kral@email.cz>
Yes. Jörg -----Original Message----- From: Oberon <oberon-bounces@lists.inf.ethz.ch> On Behalf Of Tomas Kral Sent: Tuesday, November 27, 2018 11:12 AM To: oberon@lists.inf.ethz.ch Subject: Re: [Oberon] FPGA - OberonV4 Dialogs On Thu, 15 Nov 2018 10:52:40 +0100 Jörg <joerg.straube@iaeth.ch> wrote:
Either you store the type info you got by the module Type.Mod or - cleaner - you call an instantiation routine of the module where you imported the POINTER from and let that module do its job.
My understanding is that Dialogs.Load() scans `*.Dlg' (meta?) file for module names, reading further some static and dynamic data. PROCEDURE LoadP (p: Panel; VAR r: Files.Rider); (** reads the panel from rider r *) BEGIN ... WHILE V{elements-count} > 0 DO P{Get Module Name} P{Load Name} P{Init Module with Dlg data} END ; DONE. For loading part, it does some magic with `Types' Types.NewObj (o, Types.This (Modules.ThisMod (module), name)); ASSERT (o # NIL); Could be it recoded to something like this? Modules.Load(name, dlgItem); Modules.ThisCommand(dlgItem, "Init()"); Many thanks and apologies for asking too much. -- Tomas Kral <thomas.kral@email.cz> -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
PROCEDURE LoadP (p: Panel; VAR r: Files.Rider); (** reads the panel from rider r *) BEGIN ... WHILE V{elements-count} > 0 DO P{Get Module Name} P{Load Name} P{Init Module with Dlg data} END ; DONE.
Doing away without `Types.Mod', the code skeleton shows what I am trying to achieve, but I still miss some parts of types, and how to get to their pointers at run time? MODULE TLoader; (* TK 29.11.2018 RISC type init loader *) IMPORT In, Out, Modules; TYPE T0 = INTEGER (*address*); T1 = INTEGER (*address*); PROCEDURE Run*; VAR name: Modules.ModuleName; module: Modules.Module; typeOf: PROCEDURE; BEGIN In.Open; In.Name(name); WHILE In.Done DO Out.String(name); Out.String(" loading "); Modules.Load(name, module); typeOf := Modules.ThisCommand(module, "Type"); IF Modules.res = 0 THEN typeOf END ; In.Name(name); Out.Ln END; END Run; BEGIN END TLoader. TLoader.Run M0 M1 ~ MODULE M0; IMPORT Out; TYPE T0* = RECORD END; PROCEDURE Type*; BEGIN Out.String("T0") END Type; BEGIN END M0. MODULE M1; IMPORT M0, Out; TYPE T1* = RECORD(M0.T0) END; PROCEDURE Type*; BEGIN Out.String("T1") END Type; BEGIN END M1. -- Tomas Kral <thomas.kral@email.cz>
On Thu, 29 Nov 2018 14:49:16 +0100 Tomas Kral <thomas.kral@email.cz> wrote:
how to get to their pointers at run time?
How about this? MODULE TLoader; (* TK 29.11.2018 RISC type init loader *) IMPORT In, Out, Modules; TYPE Object* = POINTER TO ObjDesc; ObjDesc* = RECORD i, j, k: INTEGER; END; VAR o: Object; (* scratch variable *) PROCEDURE Run*; VAR name: Modules.ModuleName; module: Modules.Module; Init: PROCEDURE; BEGIN In.Open; In.Name(name); WHILE In.Done DO Out.String(name); Out.String(" loading "); Modules.Load(name, module); Init := Modules.ThisCommand(module, "Init"); IF Modules.res = 0 THEN Init() END ; In.Name(name); Out.Ln END; END Run; PROCEDURE SetObjPtr*(obj: Object); BEGIN o := obj END SetObjPtr; BEGIN END TLoader. TLoader.Run M0 M1 ~ MODULE M0; IMPORT TLoader, Out; TYPE Item = POINTER TO ItemDesc; ItemDesc = RECORD(TLoader.ObjDesc) x, y, z: BYTE; END; VAR it0: Item; PROCEDURE Init*; BEGIN Out.String("Item0"); NEW(it0); TLoader.SetObjPtr(it0) END Init; BEGIN END M0. MODULE M1; IMPORT TLoader, M0, Out; TYPE Item = POINTER TO ItemDesc; ItemDesc = RECORD(TLoader.ObjDesc) a, b, c: CHAR; END; VAR it1: Item; PROCEDURE Init*; BEGIN Out.String("Item1"); NEW(it1); TLoader.SetObjPtr(it1) END Init; BEGIN END M1. -- Tomas Kral <thomas.kral@email.cz>
On Thu, 15 Nov 2018 09:26:44 +0100 Jörg Straube <joerg.straube@iaeth.ch> wrote:
"Types.Mod" could be ported to ProjectOberon 2013 but there are other ways to do it.
Yes, I see. But it may be an interesting exercise porting `Types.Mod', to RISC System-V, as it will show/document run time differences to Linz Oberon System. It is a very short module, so the effort may not be too big. May also aid some run-time debugging, while run time link-loading and `GC' is explained in PO2013. So perphaps a good start could be recoding the TypeTag structure. TYPE Type* = POINTER TO TypeDesc; TypeDesc* = RECORD tdsize: LONGINT; sentinel: LONGINT; (* -4 *) tag: Kernel.Tag; ext0: RECORD extlev: SHORTINT; filler: ARRAY 3 OF CHAR END ; name*: ARRAY 32 OF CHAR; module*: Modules.Module END ; -- Tomas Kral <thomas.kral@email.cz>
participants (4)
-
Jörg -
Jörg Straube -
Skulski, Wojciech -
Tomas Kral