Seaside - clear form on re-render? - smalltalk

Is there a way to reset all of the text inputs for a page when it's re-rendered? The page keeps loading with the text from the previous rendering still in the inputs.

That depends very much on the way you render those inputs. If you use Seaside components, then you might implement you own logic within the callback:
html textInput
callback: [ :value | self setOrResetMyInputWith: value ]
with: 'my input'.
#setOrResetMyInputWith: might then look like this:
setOrResetMyInputWith: aString
myInputValue := self allCriteriaMet
ifTrue: [ aString ]
ifFalse: [ nil ]
Keep in mind that you cannot predict the order in which the callbacks will be evaluated. Therefore, it might be easier to do the check before rendering:
renderContentOn: html
self checkMyInputs.
"continue rendering process"
...
You could then simply reset your instance variables if the criteria are not satisfied.
That's for components. If you use Magritte, than Magritte's verification mechanism should take care of this. All you need to do is to enable verification in the respective descriptions.

Related

How can I store a code block in a variable and call it and get its return value whenever needed?

I'm making a little text adventure in Smalltalk. It's made up of "screens" that have their texts and choices for other screens included. Since I want the game to be dynamic, I also want to include branching. For instance, if the player is at a blacksmith and wants to buy an axe, the screen the player goes to immediately checks if the player has enough money and jumps to one of two other screens based on that.
I already have this working: The screens (classes named Place) have a list where the first item is the function and the following items are the arguments. However, I have it done in a very ugly way: the first item is a string that is then compared against in a big "action" method, so it looks something like this:
game data method:
blacksmith := Place new.
blacksmith choiceText: 'I would like an axe.';
blacksmith action add: 'money'; add: 20; add: blacksmith_good; add: blacksmith_bad.
action method: (currentScreen is also a Place; the class also contains a BranchMoney method that does the actual decision making)
(currentScreen action at: 1) = 'money'
ifTrue: [
currentScreen := (currentScreen BranchMoney)
]
That's obviously not ideal, and I would like to compact it by doing something like this:
game data method:
blacksmith action add: [blacksmith BranchMoney]; add: 20; add: blacksmith_good; add: blacksmith_bad.
action method:
currentScreen := (currentScreen action at: 1)
So that instead of string checking the game would just directly proceed with the method I want it to do.
However, it doesn't seem to work - I've tried different changes to the code, and the problem seems to be that the currentScreen := (currentScreen action at: 1) line just replaces the contents of currentScreen with the code block contents – it doesn't calculate the block's contents and use its resulting value that is of type Place.
I've tried using round brackets in the game data method – that throws a list out of bounds exception, because it tries to calculate the expression immediately, before other arguments have even been added. Changing the first item name in game data method to currentScreen BranchMoney doesn't seem to make a difference.
I've also tried adding a return in the game data method, like this: blacksmith action add: [^blacksmith BranchMoney], so that it would have a value to return, no luck. Doing something like currentScreen := [^currentScreen action at: 1] in the action method doesn't work either.
For some shots in the dark, I tried the ExternalProcedure call and call: methods, but that failed too.
In Smalltalk every block is a regular object that you can store and retrieve the same you would do with any other object:
b := [self doSomething]
stores in b the block (much as b := 'Hello' stores a string in b). What I think you are missing is the #value message. To execute the block do the following
b value "execute self doSomething and answer with the result"
In case your block has one argument use #value: instead
b := [:arg | self doSomethingWith: arg]
later on
b value: 17 "execute the block passing 17 as the argument"
(for two arguments use #value:value:, for three #value:value:value: and for many #valueWithArguments:.)
Note however that this approach of using blocks and Arrays of arguments doesn't look very elegant (or even convenient). However, to help you with some better alternative we would need to learn more about your game. So, go check whether #value (and friends) let you progress a little bit and feel free to come back here with your next question. After some few iterations we could guide you towards a clearer route.
Example
b := [:m | m < 20 ifTrue: ['bad'] ifFalse: ['good']].
will produce
b value: 15 "==> 'bad'"
b value: 25 "==> 'good'"

How to preserve attachment content between render passes

I have multiple "renderers" which should draw to the same attachment (swap chain image to be precise). I don't know the number of such renderers beforehand so I can't use subpasses. This is how I wanted to implement it:
VkCommandBuffer cb{...}; // get current "main" command buffer
for(auto r : renderers)
{
VkRenderPassBeginInfo renderPassBeginInfo{get_render_pass_begin_info(...)};
vkCmdBeginRenderPass(cb, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
array<VkCommandBuffer, 2> buffs{r->getCommandBuffers()}; // renderer build two secondary command buffers...
vkCmdExecuteCommands(cb, 1, buffs[0]); // first should be used in a render pass
vkCmdEndRenderPass(cb);
vkCmdExecuteCommands(cb, 1, buffs[1]); // second should be used ooutside of a render pass
}
The problem here is that each new call to vkCmdBeginRenderPass clears the target. This happens because the attachment was created with loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR because I need to clear it (but only once).
The solution in my case would be to move vkCmdBeginRenderPass and vkCmdEndRenderPass outside of the loop, but in this case, I need to "collect" all secondary command buffers that can't be used inside a render pass and execute them later.
But since the concept of render passes doesn't go into my head I wonder if there may be a way to keep the attachment's data between render passes?
You could stop clearing the attachments on load. Just manually clear them, either before the render pass begins or at the start of the first subpass.
That being said, render passes are not cheap, and this is really not the way to use them. The correct solution is to restructure your rendering code so that you only need a single render pass.

Rebol: Dynamic binding of block words

In Rebol, there are words like foreach that allow "block parametrization" over a given word and a series, e.g., foreach w [1 2 3] [print w]. Since I find that syntax very convenient (as opposed to passing func blocks), I'd like to use it for my own words that operate on lazy lists, e.g map/stream x s [... x ... ].
How is that syntax idiom called? How is it properly implemented?
I was searching the docs, but I could not find a straight answer, so I tried to implement foreach on my own. Basically, my implementation comes in two parts. The first part is a function that binds a specific word in a block to a given value and yields a new block with the bound words.
bind-var: funct [block word value] [
qw: load rejoin ["'" word]
do compose [
set (:qw) value
bind [(block)] (:qw)
[(block)] ; This shouldn't work? see Question 2
]
]
Using that, I implemented foreach as follows:
my-foreach: func ['word s block] [
if empty? block [return none]
until [
do bind-var block word first s
s: next s
tail? s
]
]
I find that approach quite clumsy (and it probably is), so I was wondering how the problem can be solved more elegantly. Regardless, after coming up with my contraption, I am left with two questions:
In bind-var, I had to do some wrapping in bind [(block)] (:qw) because (block) would "dissolve". Why?
Because (?) of 2, the bind operation is performed on a new block (created by the [(block)] expression), not the original one passed to my-foreach, with seperate bindings, so I have to operate on that. By mistake, I added [(block)] and it still works. But why?
Great question. :-) Writing your own custom loop constructs in Rebol2 and R3-Alpha (and now, history repeating with Red) has many unanswered problems. These kinds of problems were known to the Rebol3 developers and considered blocking bugs.
(The reason that Ren-C was started was to address such concerns. Progress has been made in several areas, though at time of writing many outstanding design problems remain. I'll try to just answer your questions under the historical assumptions, however.)
In bind-var, I had to do some wrapping in bind [(block)] (:qw) because (block) would "dissolve". Why?
That's how COMPOSE works by default...and it's often the preferred behavior. If you don't want that, use COMPOSE/ONLY and blocks will not be spliced, but inserted as-is.
qw: load rejoin ["'" word]
You can convert WORD! to LIT-WORD! via to lit-word! word. You can also shift the quoting responsibility into your boilerplate, e.g. set quote (word) value, and avoid qw altogether.
Avoiding LOAD is also usually preferable, because it always brings things into the user context by default--so it loses the binding of the original word. Doing a TO conversion will preserve the binding of the original WORD! in the generated LIT-WORD!.
do compose [
set (:qw) value
bind [(block)] (:qw)
[(block)] ; This shouldn't work? see Question 2
]
Presumably you meant COMPOSE/DEEP here, otherwise this won't work at all... with regular COMPOSE the embedded PAREN!s cough, GROUP!s for [(block)] will not be substituted.
By mistake, I added [(block)] and it still works. But why?
If you do a test like my-foreach x [1] [print x probe bind? 'x] the output of the bind? will show you that it is bound into the "global" user context.
Fundamentally, you don't have any MAKE OBJECT! or USE to create a new context to bind the body into. Hence all you could potentially be doing here would be stripping off any existing bindings in the code for x and making sure they are into the user context.
But originally you did have a USE, that you edited to remove. That was more on the right track:
bind-var: func [block word value /local qw] [
qw: load rejoin ["'" word]
do compose/deep [
use [(qw)] [
set (:qw) value
bind [(block)] (:qw)
[(block)] ; This shouldn't work? see Question 2
]
]
]
You're right to suspect something is askew with how you're binding. But the reason this works is because your BIND is only redoing the work that USE itself does. USE already deep walks to make sure any of the word bindings are adjusted. So you could omit the bind entirely:
do compose/deep [
use [(qw)] [
set (:qw) value
[(block)]
]
]
the bind operation is performed on a new block (created by the [(block)] expression), not the original one passed to my-foreach, with separate bindings
Let's adjust your code by taking out the deep-walking USE to demonstrate the problem you thought you had. We'll use a simple MAKE OBJECT! instead:
bind-var: func [block word value /local obj qw] [
do compose/deep [
obj: make object! [(to-set-word word) none]
qw: bind (to-lit-word word) obj
set :qw value
bind [(block)] :qw
[(block)] ; This shouldn't work? see Question 2
]
]
Now if you try my-foreach x [1 2 3] [print x]you'll get what you suspected... "x has no value" (assuming you don't have some latent global definition of x it picks up, which would just print that same latent value 3 times).
But to make you sufficiently sorry you asked :-), I'll mention that my-foreach x [1 2 3] [loop 1 [print x]] actually works. That's because while you were right to say a bind in the past shouldn't affect a new block, this COMPOSE only creates one new BLOCK!. The topmost level is new, any "deeper" embedded blocks referenced in the source material will be aliases of the original material:
>> original: [outer [inner]]
== [outer [inner]]
>> composed: compose [<a> (original) <b>]
== [<a> outer [inner] <b>]
>> append original/2 "mutation"
== [inner "mutation"]
>> composed
== [<a> outer [inner "mutation"] <b>]
Hence if you do a mutating BIND on the composed result, it can deeply affect some of your source.
until [
do bind-var block word first s
s: next s
tail? s
]
On a general note of efficiency, you're running COMPOSE and BIND operations on each iteration of your loop. No matter how creative new solutions to these kinds of problems get (there's a LOT of new tech in Ren-C affecting your kind of problem), you're still probably going to want to do it only once and reuse it on the iterations.

Squeak Smalltalk: Game loop

In many languages you can do something like the following:
while true:
handle events like keyboard input
update game world
draw screen
(optional: delay execution)
while this is far from optimal it should suffice for simple games.
How do you do this in Squeak Smalltalk?
I can read keyboard input and react to it as described on wiki.squeak.org. But if I try to execute something like
1 to: 10 do: [ :i | game updateAndDraw ]
all the events are only ever handled after the loop has executed.
Morphic already provides that main loop. It's in MorphicProject class>>spawnNewProcess:
uiProcess := [
[ world doOneCycle. Processor yield ] repeat.
] newProcess ...
And if you dig into doOneCycle you will find it
(optionally) does a delay (interCyclePause:)
checks for screen resize
processes events
processes step methods
re-displays the world
Your code should hook into these phases by adding mouse/keyboard event handlers, step methods for animation, and draw methods for redisplaying. All of these should be methods in your own game morph. You can find examples throughout the system.
To perform an action a fixed number of times:
10 timesRepeat: [game updateAndDraw]
To use while semantics:
i := 5
[i > 0] whileTrue: [
i printNl.
i := i - 1.
]
To create a perpetual loop using while semantics,
[true] whileTrue: [something do]
You should be able to take advantage of the Morphic event loop by using the Object >> #when:send:to: message.

Condition inside a loop in smalltalk

I'm trying to draw a chain of symbols by using a loop. I'm doing this way, but it always draw x circles...
1 to: x do: [
(self lastWasSquare)
ifTrue: [ self drawCircle]
ifFalse: [ self drawSquare]
]
I also tried:
x timesRepeat: [
(self lastWasSquare)
ifTrue: [ self drawCircle]
ifFalse: [ self drawSquare]
].
But still drawing circles. I also tryed to do it by adding a :n | variable to the loop and asking if even, but again, it's always executing the circle code.
What am I doing wrong?
Thank you
It looks like your call to self lastWasSquare keeps returning true so that your #ifTrue:ifFalse: keeps going into the block that calls self drawCircle. You can either:
Make sure that your drawCircle and drawSquare methods properly set your lastWasSquare instance variable (at least I'm assuming that's just a getter method).
Move the decision of whether the last item drawn was a circle or a square into a temporary variable.
The first way is better if you need the lastWasSquare value anywhere outside the method you're working on. The second way is better if it's the only place where you're drawing circles or squares (keep the scope as small as it needs to be) and could look something like this:
| lastWasSquare |
lastWasSquare := false.
x timesRepeat: [
lastWasSquare
ifTrue: [ self drawCircle ]
ifFalse: [ self drawSquare ].
lastWasSquare := lastWasSquare not
].
So you're continually toggling the lastWasSquare between true and false, and it will draw alternating shapes. (I'm assuming that's what you're trying to achieve when you say "draw a chain of symbols"...)
If neither of these apply, then, as Uko said in the comments, you'd need to post more of your code in order for us to be able to help you.