Home   Archive   Permalink

Modifying a VID gui at run time

I’m trying to add tiles selected by the user to a gui defined with VID.
I have an “mgui” block defined as follows:
mgui: [
    size: 300x500
    backcolor 100.100.100
    style tile box 40x40
    origin 20x440
    tile red [color: 'red add-tile]
    tile green [color: 'green add-tile]
    origin 20x20
    tile orange tile blue tile purple return
This creates a standing rectangle with two tiles at the bottom, one red and one green. You can see that the tiles have some code that defines the value of a variable “Color” and then call a function add-tile, that has been defined like this:
add-tile: does [append mgui compose [tile (color)] show mgui]
Then I try:
view layout mgui
The expectation is that when the user clicks on one of the tiles at the bottom -for example, the red one- an equivalent tile will appear under the first row of tiles located on the top. Yet, when I run this code, no tile appears and instead the interpreter provides the following error message:
Misplaced item: 300x500
** Script Error: Invalid graphics face object
** Where: add-tile
** Near: show mgui
However, if I ask to probe mgui I get that the words were added to the mgui block, as you can see after the last return in the code (last two words):
>> probe mgui
     size: 300x500
     backcolor 100.100.100
     style tile box 40x40
     origin 20x440
     tile red [color: 'red add-tile]
     tile green [color: 'green add-tile]
     origin 20x20
     tile orange tile blue tile purple return tile red
So I feel that the code was successful in updating the mgui block, however, I don’t get the expected result. Any ideas as of why?
Thanks in advance for your input

posted by:   brotherdamian     22-Sep-2019/0:12:27-7:00

Oops! Please note that the “size” instruction in the block provided has an assignment operator, which was a typo that I noted after posting the question. The correct mgui block should read:
mgui: [
    size 300x500
    backcolor 100.100.100
    style tile box 40x40
    origin 20x440
    tile red [color: 'red add-tile]
    tile green [color: 'green add-tile]
    origin 20x20
    tile orange tile blue tile purple return
with this change, the error message after clicking the red tile in the bottom says:
** Script Error: Invalid graphics face object
** Where: add-tile
** Near: show mgui
And still does not produce the expected result, despite having successfully appended “tile red” at the end of the mgui block.
Any insights are deeply appreciated!

posted by:   brotherdamian     22-Sep-2019/11:06:40-7:00

Welcome to the world of dynamic faces!
Here's your code minimally fixed to add a new tile at a random location each time you click one of the two lower buttons.
Note some changes:
-- lo-mgui is the "compiled" version of mgui - ie what comes out of doing a LAYOUT
-- lo-mgui/pane is a BLOCK of FACES - it is here that we add our new tile face
-- New-tile could better be created with MAKE-FACE, the code here in ADD-TILE uses LAYOUT just for relative simplification of the example code
-- We need SHOW LO-GUI at the end of ADD-TILE - Rebol does not automatically update the displayed GUI.
mgui: [
     size 300x500
     backcolor 100.100.100
     style tile box 40x40
     origin 20x440
     tile red [color: 'red add-tile]
     tile green [color: 'green add-tile]
     origin 20x20
     tile orange tile blue tile purple return
add-tile: does [
    layout [
     style tile box 40x40
     new-tile: tile pink
    new-tile/offset: random 200x200
    new-tile/color: random 255.255.255
    append lo-mgui/pane new-tile
    show lo-mgui
    print ["added - number of faces is now" length? lo-mgui/pane]
unview/all view lo-mgui: layout mgui

posted by:   Sunanda     22-Sep-2019/15:48:54-7:00

Oh! Thank you so much for this. It seems that this subject is a bit more involved.
Now I can see that it is not the original block of VID code that I need to modify but the “compiled” version after “Layout” had processed it (what you labeled “lo-mgui”).
I can use append regularly, but to the “panel” properties of what I am guessing is an object now. Is that right?
If I had not specified the /offset of new-tile, would have Rebol used the default values as defined by “space”, “origin” and the like, uniformly adding to the rows and columns of tiles? Or is that something that "Layout" does and now I need to do it programmatically?
Would the code using “make-face” instead of “layout” look like this?
New-tile: make-face/styles [ box 40x40 ]
I can see why you need to “show” after each addition. But why do you need to unview/all to begin with?
Again, thanks for your help!

posted by:   brotherdamian     22-Sep-2019/18:46:42-7:00

All VID FACES are OBJECTs. LAYOUT is simply a convenient way of making a load of FACES in one go, and it handles lots of useful things like working out each FACE's offset.
Every FACE OBJECT has a /PANE block. In the case of your tiles, they are the bottom of the FACE hierarchy, so they each have an empty /PANE block.
You can look at the basic information for a FACE and any FACES contained in its /PANE block like this:
     dump-face lo-mgui
LAYOUTs can be more complicated than that - your TILEs could contain other FACEs in their /PANEs - and so on. Here's a very simple example of a FACE hierarchy that is two levels deep:
dump-face view/new layout [
             panel 100x100 white [box 50x50 red box 20x20 blue]
             panel 100x100 pink [box 40x40 green box 30x30 yellow]
LAYOUT generates OFFSETs (in accordance with your DOWN or ACROSS) relative to the /PANE in which the FACE appears. If we had not put an OFFSET in the LAYOUT in ADD-TILE, all the new tiles would have default offsets of 10x10 - so they'd overlay your first Red Tile - delete the NEW-TILE/OFFSET line and you should see that behavior.
If you want the new tile to go somewhere relative to existing tiles in the same PANEL, then you need to replace the NEW-TILE/OFFSET line with a more sophisticated version of:
     last-old-tile: last lo-mgui/pane
     new-tile/offset: 0x40 + last-old-tile/offset
UNVIEW/ALL is helpful, especially if you have been doing VIEW/NEW .... DO-EVENTS - it clears all the old GUI windows.
VIEW/NEW ... DO-EVENTS is helpful as it gives you access to both the console, and the GUI. Try this:
     unview/all view/NEW lo-mgui: layout mgui
The GUI appears, but does not respond to clicks. You can still use the console, eg:
    print length? lo-mgui/pane
    print lo-mgui/size
    lo-mgui/pane/1/color: black
    show lo-mgui
To get the GUI to start working, type in the console:
A good introduction to making FACES dynamically is here:

posted by:   Sunanda     22-Sep-2019/20:47:10-7:00

Interesting Sunanda!
Do you happen to know how layout gets the layout block into the object and how the step from the object to the display on the screen is implemented?

posted by:   Arnold     14-Apr-2020/11:12:53-7:00

Sorry - not in any detail.
If, in Rebol, you do....
     source layout
....you can see the dialect code that creates the object - or at least some of it.
Similarly, you can see the equivalent in Red.
How that converts to the operating system's graphic APIs is not something I've ever looked at in any detail.
Red is open source. If you download the source and have a look around in modules / view / backend you can find code that interfaces to Android, MacOs and Windows.

posted by:   Sunanda     14-Apr-2020/17:26:05-7:00

If you look at the source of the 'layout, function, you can follow how the 'new-face object is created and returned:
>> source layout
layout: func [
     {Return a face with a pane built from style description dialect.}
     specs [block!] "Dialect block of styles, attributes, and layouts"
     /size pane-size [pair!] "Size (wide and high) of pane face"
     /offset where [pair!] "Offset of pane face"
     /parent new [object! word! block!] "Face style for pane"
     /origin pos [pair!] "Set layout origin"
     /styles list [block!] "Block of styles to use"
     /keep "Keep style related data"
     /tight "Zero offset and origin"
     /local pane way space tabs var value args new-face pos-rule val facets start vid-rules max-
off guide
     def-style rtn word
     if tight [
         if not offset [offset: true where: 0x0]
         if not origin [origin: true pos: 0x0]
     new-face: make any [
         all [parent object? new new]
         all [parent word? new get-style new]
     ] any [all [parent block? new new] [parent: 'panel]]
     if not parent [
         new-face/offset: any [
             all [offset where]
     new-face/size: pane-size: any [
         all [size pane-size]
         system/view/screen-face/size - (2 * new-face/offset)
     new-face/pane: pane: copy []
     max-off: origin: where: either origin [pos] [20x20]
     space: 8x8 way: 0x1 pos: guide: none tabs: 100x100
     def-style: none
     new-face/styles: styles: either styles [list] [copy vid-styles]
     parse specs [some [thru 'style val:
             [set word word! (if not find styles word [insert styles reduce [word none]])
                 | none (error "Expected a style name" val)
     parse specs [some [thru 'styles val: [
                 set word word! (
                     if all [value? word value: get word block? value] [
                         insert styles value
                 ) | none (error "Expected a style name" val)
     rtn: [where: (max-off * reverse way) + (way * any [guide origin])]
     vid-rules: [
         'return (do rtn)
         | 'at [set pos pair! (where: pos) | none]
         | 'space pos-rule (space: 1x1 * pos)
         | 'pad pos-rule (
             value: either integer? pos [way * pos] [pos]
             where: where + value
             max-off: max-off + value
         | 'across (if way <> 1x0 [way: 1x0 do rtn])
         | 'below (if way <> 0x1 [do rtn way: 0x1])
         | 'origin [set pos [pair! | integer!] (origin: pos * 1x1) | none] (where: max-off: orig
         | 'guide [set pos pair! (guide: pos do rtn) | none (guide: where)] (max-off: 0x0)
         | 'tab (where: next-tab tabs way where)
         | 'tabs [
             set value [block! | pair!] (tabs: value) |
             set value integer! (tabs: value * 1x1)
         | 'indent pos-rule (where/x: either integer? pos [where/x + pos] [pos/x])
         | 'style set def-style word!
         | 'styles set value block!
         | 'size set pos pair! (pane-size: new-face/size: pos size: true)
         | 'backcolor set value tuple! (new-face/color: value)
         | 'backeffect set value block! (new-face/effect: value)
         | 'do set value block! (do :value)
     pos-rule: [set pos [integer! | pair! | skip (error "Expected position or size:" :pos)]]
     if empty? vid-words [
         foreach value vid-rules [if lit-word? :value [append vid-words to-word value]]
     while [not tail? specs] [
         forever [
             value: first specs specs: next specs
             if set-word? :value [var: :value break]
             if not word? :value [error "Misplaced item:" :value break]
             if find vid-words value [
                 either value = 'style [
                     facets: reduce [first specs]
                     specs: next specs
                 ] [
                     set [specs facets] do-facets start: specs [] styles
                 if :var [set :var where var: none]
                 insert facets :value
                 if not parse facets vid-rules [error "Invalid args:" start]
             new: select styles value
             if not new [error "Unknown word or style:" value break]
             set [specs facets] do-facets specs new/words styles
             new: make new either val: select facets 'with [expand-specs new val] [[]]
             new/style: value
             new/pane-size: pane-size
             new/styles: styles
             new/flags: exclude new/flags state-flags
             if not flag-face? new fixed [new/offset: where]
             grow-facets new facets
             track ["Style:" new/style "Offset:" new/offset "Size:" new/size]
             either def-style [
                 change next find styles def-style new
                 def-style: none
             ] [
                 new/parent-face: none
                 if :var [new/var: bind to-word :var :var]
                 do bind new/init in new 'init
                 if new/parent-face [new: new/parent-face]
                 if :var [set :var new var: none]
                 append pane new
                 if not flag-face? new fixed [
                     max-off: maximum max-off new/size + space + where
                     where: way * (new/size + space) + where
                 if all [warn any [new/offset/x > pane-size/x new/offset/y > pane-size/y]] [
                     error "Face offset outside the pane:" new/style
                 track ["Style:" new/style "Offset:" new/offset "Size:" new/size]
                 if not keep [
                     new/init: copy []
                     new/words: new/styles: new/facets: none
     if not size [
         foreach face pane [if flag-face? face drop [face/size: 0x0]]
         new-face/size: size: origin + second span? pane
         foreach face pane [
             if flag-face? face drop [face/size: size]
             face/pane-size: size
Then if you look at the source of 'view, you can see how the local scr-face object is generated from the 'view-face object (which is the 'new-face object returned by the 'layout function above).
>> source view
view: func [
     "Displays a window face."
     view-face [object!]
     /new "Creates a new window and returns immediately"
     /offset xy [pair!] "Offset of window on screen"
     /options opts [block! word!] "Window options [no-title no-border resize]"
     /title text [string!] "Window bar title"
     /local scr-face
     scr-face: system/view/screen-face
     if find scr-face/pane view-face [return view-face]
     either any [new empty? scr-face/pane] [
         view-face/text: any [
             all [system/script/header system/script/title]
             copy ""
         new: all [not new empty? scr-face/pane]
         append scr-face/pane view-face
     ] [change scr-face/pane view-face]
     if all [
         view-face/feel = system/view/vid/vid-face/feel
     ] [
         view-face/feel: window-feel
     if offset [view-face/offset: xy]
     if options [view-face/options: opts]
     if title [view-face/text: text]
     show scr-face
     if new [do-events]
That object is displayed on screen by the 'show function, which is native (you can peer under the hood more to see how the C-level renderer works in R3):
>> source show
show: native [
     "Display a face or block of faces."
     face [object! block!]

posted by:   Nick     14-Apr-2020/20:24:21-7:00

Thanks Nick (and Sunanda) for your answer.
I am not interested in the Red code. It distracts me from what I want, and they also have no Linux solution.
I want to recreate a simple version and it will be Linux only for now. I am currently on Ubuntu and there is no R2/View for Linux, so thanks for posting the code here, very helpoful indeed.
And it shall be a little more GOB like.
This is a welcome push in the back.

posted by:   Arnold     16-Apr-2020/6:20:24-7:00

Arnold, what do you mean by Red not having a Linux View? AFAIK it is being constantly worked on, though it is more of a community effort, rather than an official development, or so is my understanding. Is it that you find the Red View engine not being suitable, due to native OS widgets, or just you don't like the Red project attitude, or both? :-)

posted by:   -pekr-     16-Apr-2020/7:35:47-7:00

Unfortunately I am in the same position, I prefer to continue using the old trusted Rebol because Red's progress has been too slow. There is hardly anything there and they don't even have a clear roadmap of when ver 1.0 is coming out. Their only answer is when it is ready, it will come out. An answer like this scares the hell out of me, and does not give me the confidence that this is something that i can depend on. I am not saying this to criticize, but to explain why not everybody is moving to RED. In my case, I am sticking with a trusted Rebol, while preparing to move to Julia or Ruby in the future.

posted by:   Red's progress is too slow     16-Apr-2020/8:34:26-7:00

I think that I might agree with some of your points (as the public (non)existence of the roadmap), but then there are points I simply can't agree to ....
For example - ppl are too much sticking with R2, not to say the original R3 (not necessarily enhanced Ren-C), which was nonfinished product too. R2 is not 64 bit either. Red/View is already more capable than R2's. You've got https, etc.
I also know Arnold. Do you think, that for one man, to start tinker with low level Ren-C code, not fully understanding C/C++, it is easier to create a Linux View for Ren-C? That would be great achievement, but something tells me, looking at GTS progress, that I already know, who's basically wasting his time (unless some education along the way is not the nice factor to consider).

posted by:   -pekr-     16-Apr-2020/10:11:03-7:00

Pekr - I am one of those who have tried very hard to use Red, rather Rebol....But on two separate projects now I've reluctantly had to fall back to Rebol.
As an example, let me quote verbatim from an email I wrote this week to a fellow Red/Reboller who'd asked what I was doing during the Corona lockdown:
> I've been writing a little content management system for a non-profit for
> their audio book library. I tried to write it in Red. Broke Red quite badly.
> (Imagine the console just pinging out of existence, and you can (after some
> days of debugging red-herrings down rabbit holes) prove that the last statement
> executed was an innocuous RETURN).
> I suspect the problem is garbage collection. And to be fair, the program was
> doing some strenuous things - such as reading many 500Mbyte zip files.
> Anyway, it turned out to be very simple to convert it to Rebol.
> And that broke Rebol too. But at least Rebol was polite enough to admit
> in an error message that it could not read files that large.
> And now it's a Frankenhodgepodge of Rebol code that will shell out to
> other utilities (such as DOS COPY command, WINSCP for FTPing large files,
> 7zip for zip file handling. etc).
> I've half a mind to refactor the GUI front end so it is in Red (for the
> nice stuff like rich-test) and have that shell out to Rebol for the dangerous bulk processing.
(The current code - with all the shelling out for handling large files - will kinda run in Red, but with mysterious crashes. The Rebol code runs rock solid, except for its inability to read files if their name contains certain UNICODE characters).
It's all a trade off; and - for my recent projects, Red has started as favorite, but been lapped by Rebol.

posted by:   Sunanda     16-Apr-2020/14:48:27-7:00

Have you reported your findings? Have you helped to isolate the code? Because I can see some crucial things being fixed on the go, as the project is still active. There was e.g. a GC bug, when Red went awry on reading more than 512KB of data. And yes, it was fixed pretty quickly.
So far, your R2 might serve you well, just the notion of the zero possibility of it being fixed by Carl, would scare me enough, as your next Win10 or other OS update might break things forever.

posted by:   -pekr-     16-Apr-2020/16:21:07-7:00

Yes, I've reported the apparent root cause:
But Red simply does not have enough diagnostics to make debugging easy - eg finding that one-liner that makes the console vanish was a considerable amount of work.
If I run the app now, I can watch it (in Red) stop processing events at random and/or ping out of existence at random. Is that the same bug or a different one? I'll fine out when the first one is fixed,
And yes, relying on Rebol is scary. But Red's bugs are directly tripping me up - and they are not easy to isolate.

posted by:   Sunanda     16-Apr-2020/17:13:26-7:00

Well Pekr, the main problem with Red is that it has no 64 bit support. Completely left unclear when or even IF it will ever come. I fear that will be a long wait. The GTK Linux backend is a community effort where the progress is not clear for me if any. Considering the Red team I can't see it getting integrated into the main repo. That also can become a long wait.
At least I have now proven I can do little bit of static GTK stuff for REN-C now.
I decided to fill in the long wait on Red progress with learning some things and create a very basic and understandable first stage of GUI. One where people will be able to contribute.

posted by:   Arnold     17-Apr-2020/17:42:54-7:00

@Pekr, yeah I agree, I know that Rebol2 will stop working at some point, and it is not 64 bit. I was only trying to explain why in my particular case, I did not move to Red and suspect some(not all) other people maybe in the same boat. I am looking at Julia or Ruby or Dart right now for the future. At least they seem more mature. It's more because of the uncertainty that keeps hanging over Red's progress that makes it a no go for me. Unfortunately I am not into the REN stuff, which I think will just be investing time into something that will not go far.

posted by:   Red's progress is too slow     17-Apr-2020/21:03:47-7:00

Arnold - as I said - nothing against your endeavor, you will surely learn many things along your way.
Would just like to correct your GTK situaiton knowledghe though. It USED to be a community project. Later on, it was taken over by the extended Red Team. Nowadays, bitbegin works on that mainly.
Also to your "progress is not clear for me, if any" - are you sure? There's almost daily activity and cca 30 commits in April so far - https://github.com/red/red/commits/GTK
So - keep an eye on that, though I am not sure, if Red's View engine mapping to GTK underlyings might be inspirative to your project.

posted by:   -pekr-     18-Apr-2020/2:44:49-7:00

@pekr Is it strange that I kind of get the idea that you are with the f00 'police'? I can't imagine Linux GTK GUI pulled into the mainline within the year. In fact I don't expect any new release 'soon'(TM)
Is there also a source for the 'do-facets 'grow-facets 'track functions and 'vid-styles ?

posted by:   Arnold     18-Apr-2020/5:47:32-7:00

Arnold - it's strange that I kind of get the idea that you are just starting with pointless accussations once again. I am noone's police, especially not Red's one, as I am not part of the project nor do I have any internal info.
All I tried to do is to correct your incorrect statement re the GTK project status. Your statement was public and wrong and other ppl could think the GTK development is not ongoing.
Proving you wrong you even did not bother to acknowledge that, instead you show off another moaning GTK branch not being merged in the mainline. Switching branches and compiling Red stuff is so easy, that even a non-programmer like me can do it ...
But - whatever ...

posted by:   -pekr-     18-Apr-2020/6:31:20-7:00

Stating the obvoious has become starting pointless accusations.
Let me just say to all the world that is still in believer modus: it will never come.
Just prove me wrong instead of 'just saying' ;-)

posted by:   Arnold     18-Apr-2020/8:17:38-7:00

Tried to use R2 Linux: libXt.so.6 missing
Tried to use VirtualBox and install ReactOS but R2 is not useable, guess something with not installed typeface is playing up there.
Do we really want to be dependent on the wife's Windows laptop here??
Well Carl, then it is definitely time to return!

posted by:   Arnold     18-Apr-2020/14:10:15-7:00

Okay, so how is this layout supposed to work when all these "functions" do not exist?

posted by:   Arnold     18-Apr-2020/15:14:31-7:00

And there is more.
When I do this in console
view layout [button "ok"]
it shows me the window with button "ok".
But when I adapt the source of layout and copy paste that back into the view console, now all of a sudden it immediately complains:
>> view layout [button "ok"]
** Script Error: vid-face has no value
** Where: layout
** Near: new-face: make any [
     all [parent object? new new]
     all [parent word? new get-style new]
] any
Why now the complaining when before, this was no problem whatsoever?

posted by:   iArnold     20-Apr-2020/9:12:41-7:00

Without any more information it is a guessing game.
set [specs facets] do-facets start: specs [] styles
Without knowing what do-facets does, this line suggests that do-facets takes two arguments, the first being specs, the second an ampty block that is not even copy'ed
But this entire layout function seems to spin around the keywords in vid-rules and the set-words. So the rest of the specs body with all button/label/field stuff and the values for size and other attributes is handled inside the do-facets and put on the face by grow-facets.
Any explanation is welcome.

posted by:   Arnold     23-Apr-2020/10:35:41-7:00

One could somehow expect, that you are lurking around Rebol, Ren-c and Red long time enough to understand concept of bindings and that you cannot just replace some code randomly and expect, that it will work (without properly binding the block of code to the right contexts).
Not that I could bring more light into your issue... as Rebol2 is still closed source and it is long time I used View/VID last time.

posted by:   Oldes     25-Apr-2020/4:28:55-7:00

Thank you Oldes. Yes binding, I have considered this. Yet BIND? and BOUND? do not expose the existing bindings of these functions. (If you can improve on this experience I had, that is very welcome too)

posted by:   Arnold     25-Apr-2020/9:27:33-7:00

I think one of the problems with Red was instead of making a GUI library like Rebol Doc made use of the graphics GUI libraries of all the different OS platforms. I'm not being mean for saying this. I'm not saying I' smarter than him. I fully understand why Doc did this. I think that this could be done in the long run but I believe it was too much work at one time. I mean just writing Red was complicated enough. If he would have taken rebols GUI library (AGG) or Anti-Grain Geometry and used it as is. Maybe rewrite it in Red system or had written it to use low level OpenGL then he could have had a cross platform system AND THEN work on the graphics for each system. I think he bit off more than he could chew. I'm not trying to be overly critical. He's done fabulous stuff but people can only do so much.
I also expect even if he gets Red working if he does not have a simple library that can be cross platform that Red will soon suffer from bit rot and no one will be able to figure out all the mass of work that went into making all these separate OS gui's work the same on each platform.

posted by:   Sam the Truck     29-Jun-2020/15:49:55-7:00



Type the reverse of this captcha text: "r e s r a p - l r u - p a m i"