Why do I get error with show window in Rebol/Red? - rebol

When I click on button refresh, I get an error
v: [field1 "to refresh" field2 "to refresh"
button "refresh" [show v]]
view v
How can refresh v ?
Update: I don't have error but it doesn't refresh:
test: [
["a1" "b1"]
["a2" "b2"]
]
i: 1
v: layout compose [
field data test/:i/1 field data test/:i/2 button "refresh" [i: i + 1 show v]
]
view v

Show expects a face, not a block.
You want probably something along
v: layout [
f1: field "to refresh"
f2: field "to refresh"
button "refresh" [f1/text: f2/text show v ]
]
To see a change you should type something in the second input field before clicking on the button.
To make something (usefully) working with your update you can use
i: 1
sw: true
v: layout compose [
f1: field data test/:i/1
f2: field data test/:i/2
button "refresh" [
i: pick [1 2] sw: not sw
f1/text: test/:i/1
f2/text: test/:i/2
show v
]
]
show does not load the face definition block again, but the red-gui-system docs say
"Red/View will update both face and graphic objects in realtime as their properties are changed. This is the default behavior, but it can be switched off, when full control over screen updates is desirable. This is achieved by:
system/view/auto-sync?: off
When automatic syncing is turned off, you need to use show function on faces to get the graphic objects updated on screen."
I guess you can get something similar to your intention by destroying the old face object and building a new with the specification block.
test: [
["a1" "b1"]
["a2" "b2"]
]
i: 1
sw: true
vvw: layout v: [
field data test/:i/1
field data test/:i/2
button "refresh" [
i: pick [1 2] sw: not sw
unview vvw
view v
]
]
view vvw

Not sure what you mean by "refresh", but Red's GUI is reactive, you don't need to explicitly tell it to update.
If you just want to update the text data (increment its value) - here's a short working example:
view [f: field "42" button "increment" [f/data: f/data + 1]]
That is, f is assigned to the just created field. On button press - it receives new value, by acessing its data member.

Related

Changing observed property value in EventHandler changes Event properties

I have a TableView with a column of ComboBox cells, created with ComboBoxTableCell.forTableColumn(). I'm very new to JavaFX. You may want to skip to "TLDR" at the bottom before going through all of it.
In onEditCommit() for the column, I launch an Alert to get confirmation ("Really ____?"). If it isn't confirmed, I want the cell's value to revert to what it was originally. The observed property is a SimpleStringProperty, and the table/row/bean type is a FooBar object. The table is backed by an ObservableList<FooBar>, retrieved using the Event object. This is the EventHandler, in kotlin:
EventHandler { ev ->
ev.newValue?.let { str ->
println("A old ${ev.oldValue} ===> new ${ev.newValue}")
list[ev.tablePosition.row]?.let { foobar ->
if (str != foobar.prop.value) {
val confirm = runDialog()
if (!confirm) foobar.prop.value = ev.oldValue
println("B old ${ev.oldValue} ---> new ${ev.newValue} "
+"| prop ${foobar.prop.value}")
}
}
}
}
The ComboBox has three options, "Alpha", "Beta", "Charlie". Here's what happens when I select the ComboBox and change the value, but then cancel in the confirm dialoge (the actual output is indented):
[ Box reads "Alpha"; select "Beta" ]
A old Alpha ===> new Beta
[ Cancel dialog... Box reads "Beta"
B old Alpha ---> new Beta | prop Alpha
[ Repeat by selecting "Charlie" ]
A old Alpha ===> new Charlie
[ Cancel dialog ]
B old Alpha ---> new Charlie | prop Alpha
[ Box reads "Charlie" ]
Notice that the property is being reset, but the cell contents aren't reflecting that. I thought this might be an issue with what happens when the handler returns -- ie., the commit happens afterward -- but using Platform.runLater() to set the property did not make a difference.
What did is intuiting that the edit is never committed, ie., foobar.prop.value is always the same, so setting it to oldValue doesn't change anything. However, the ComboBox is still out-of-sync with the property it is supposed to be an observer of.
This theory is supported by the fix, which is to stash oldValue and set foobar.prop to something new before running the dialog.
val orig = ev.oldValue
list[ev.tablePosition.row]?.let { foobar ->
if (str != foobar.format.value) {
// Set before dialog.
foobar.format.value = ev.newValue
val confirm = runDialog()
if (!confirm()) foobar.format.value = orig
But what's a bit mysterious here is why orig is necessary at all -- why not just foobar.format.value = ev.oldValue? Because ev.oldValue changes in between the third
last and last lines above; I'm guessing the Event object is actually being recycled and set with foobar.format.value. Or it could have to do with the dialog, which probably makes it a bone fide bug. Here's what happens using the fix:
[ Box reads "Alpha"; select "Beta" ]
A old Alpha ===> new Beta
[ Cancel dialog... Box reads "Alpha"
B old Alpha ---> new Beta | prop Alpha ]
So I am at least able to get what I want, but I am troubled by all this unexpected behaviour.
Here's what happens if, instead of using orig, I change that assignment to ev.oldValue (with no other changes):
[ Box reads "Alpha"; select "Beta" ]
A old Alpha ===> new Beta
[ Cancel dialog... Box reads "Beta" ]
B old Beta ---> new Beta | prop Beta
Back to the same problem.
(TLDR) This means changing foobar.prop.value in the handler has the side affect of changing ev.oldValue.
Confirmed with:
println("old ${ev.oldValue}")
foobar.prop.value = ev.newValue
println("old now ${ev.oldValue}")
Which I guess is the short version of this question. I'm sure I'm not the first to notice this. Is that behaviour expected, documented or easily explicable? I suppose there is a certain desirability in it, but it makes the Event object seem a bit shifty.
There's also the matter of the ComboBox falling out of sync with the value, which does not seem desirable at all.
This is openjfx 11 on x64 linux.

Turn on/off mouseOver attribute in elm-ui

I am trying to make a simple game on Elm with elm-ui for my interest, but I stacked how to turn on/off mouseOver attribute.
I made a sample code for my explanation: https://ellie-app.com/9rvqJxz4ypga1
In this code, model has only two status (Myself|Opposite) which represent the turn of the game.
I would like to turn on changing background color of each tiles with mouseOver when model has the same status as the label of the tile.
viewTile is the main code which contains what I want to do.
viewTile : Player -> Model -> Element Msg
viewTile player model =
let
desc =
if player == Myself then
"Myself"
else
"Opposite"
changeMouseOver =
if player == model then
mouseOver [ Bg.color (rgba 1 0.2 0.3 0.5) ]
else
mouseOver []
in
column [ width (px 100), height (px 100), Border.width 1, changeMouseOver ] [ el [ centerX, centerY] ( text <| desc ) ]
For example, if model has "Myself" status, mouseOver will turn on only the tile labeled "Myself" .
In addition, "Change turn" button can change model like Myself <-> Opposite.
This trial showed good result if you clicked this button one time. However if you clicked again (means to recover model to Myself), mouseOver of "Myself" tile do not work.
I tried move the if code from let-in section to external, but it did not also work well.
How should I change the code to work turn on/off mouseOver?
This issue seems to be browser-specific one, I tried this code with Ellie in Safari 13.0.5. Firefox 78.0.2 works fine.

How do I retrieve text from an html element?

How do I get the caption from a button?
decorateOn : String -> Html Msg -> Html Msg
decorateOn selectedCaption button =
if button.text == selectedCaption then
button [ class "selectedNavigationButton" ] []
else
button [ class "navigationButton" ] []
button does not have a field named text. - The type of button
is:
Html Home.Msg
Which does not contain a field named text.
Note, I realize that the "button" is really of type Html Msg.
You need to turn your thinking on its head. Rather than seeing what is in the button text, you need to set the text at the same stage as setting the class. So that gives you something like
decorateOn : String -> Html Msg -> Html Msg
decorateOn selectedCaption button =
if selectedCaption == "the selected value" then
button [ class "selectedNavigationButton" ] [text selectedCaption ]
else
button [ class "navigationButton" ] [text selectedCaption]
You can't get the text from a button without resorting to hacks involving ports and JavaScript. Moreover, you can't really inspect anything about the Elm Virtual DOM from within Elm.
Instead, try to refactor your app so that you can get the information from your model.

Why does a button hide itself and another differently?

In the following Rebol 2 code, why does button a become visible 5 seconds after it's clicked, while remaining hidden 5 seconds after button b is clicked?
f: does [hide a wait 5]
view layout [
a: button "a" [f]
b: button "b" [f]
]
It looks like a bug that
view layout [
a: button "hide me" [ hide face ]
b: button "hide a" [ hide a ]
]
doesn't work to hide the "a" button unless the hide is called from another button. Your wait 5 must be triggering an update of the layout so that the button disappears.
Instead of wait 5, using do-events (wait []) keeps the button hidden.
view layout [
a: button "hide me" [ hide face do-events ]
b: button "hide a" [ hide a ]
]
When each button is clicked, it is redrawn to look “pressed”, and stays “pressed” until its action has completed. Then, after it's action has completed, the button is redrawn as “unpressed”.
During button a's action, it is hidden, but when its action is completed, it is shown again when it's “unpressed” state is drawn. According to this function summary of hide, hide only “temporarily removes the face from view”, and “The face will become visible again the next time the face is shown either directly or indirectly through one of its parent faces.”
During button b's action, button a is hidden, but when button b's action is completed, it is button b that is redrawn as “unpressed”. At this point, button a is untouched and remained hidden.
Considering Graham Chiu's code:
view layout [
a: button "hide me" [ hide face do-events ]
b: button "hide a" [ hide a ]
]
In this case, the reason why button a remains hidden after being clicked, is that its action doesn't reach completion until the window is closed. If wait 5 represents code which needs to be executed when the button is clicked, it needs to be put before do-events. Otherwise it is not executed until the window is closed.
view layout [
a: button "hide me and print" [
hide face
print "I need to say this when clicked."
do-events
print "I can wait until the window is closed."
]
b: button "hide a" [ hide a ]
]
Some other ways to make a button hide itself can be found on this page under the subheading: “Hiding self”. For example:
view l: layout [b: button [b/show?: false unview/all view l]]

How do you set initial focus in a layout?

rebol []
view [
f: field ""
button "focus" on-action [
focus f
]
when [load] on-action [focus f]
]
Using the focus button sets the focus correctly but I'd like the focus to set when the panel appears. I'd have thought the load trigger should do this but it doesn't.
The correct trigger to use is the 'enter trigger
when [enter] on-action [focus f]