At as-pair problem
Hi there! I really need all the help I can get right now. I am trying to set pieces on a GUI using at and as-pair based on a count that could vary, to provide a score with images instead of numbers. My first approach was to produce the final result that I want: view layout [ size 640x480 style star image load %star.png at 61x307 star at 122x307 star at 183x307 star at 244x307 star at 305x307 star ] So far so good. Then I notice that the x part of the coordinates have a difference of 61 on each successive iteration. If I could insert a value that changes in that amount I could solve my problem, so I try: factor: 2 view layout [ size 640x480 style star image load %star.png at (as-pair 61 307) star at (as-pair 61 * factor 307) star ] and it works! In the last line, REBOL knows to multiply 61 by the factor to produce the first component of the pair. So now all I have to do is increment the factor up to the count, which is the value that changes, I try: view layout [ size 640x480 style star image load %star.png for factor 1 count 1 [ at (as-pair 61 * factor 307) star ] ] The last line has not changed at all but now the instruction doesn't work and REBOL complains with: ** Script Error: at expected series argument of type: series port Why?! How do I fix this? For a while I though that maybe factor needed to be reduced or composed, not because I know what I am doing (I am not and really just trying to learn) but because I don't know what else, so I try: at (as-pair reduce [ 61 * (i) ] 307) star but ** Script Error: as-pair expected x argument of type: number so I go: at (as-pair to-integer reduce [ 61 * (i) ] 307) star and then it gets really discouraging: ** Script Error: Invalid argument: 61 So I try: at (as-pair to-integer compose [ 61 * (i) ] 307) star but: ** Script Error: Invalid argument: 61 * 1 which I though was working before. This is a bit maddening to me because I feel that instead of consistency I am always dealing with exceptions. If this works: pos-x: [ 61 122 183 244 305 ] count: 4 repeat x count [ print form as-pair (pick pos-x x) 307 ] giving me the set of coordinates I need, how come this doesn't? pos-x: [ 61 122 183 244 305 ] count: 4 view layout [ size 640x480 style star image load %star.png repeat x count [ at (as-pair (pick pos-x x) 307) star ] ] ** Script Error: at expected series argument of type: series port What am I doing wrong? Thanks in advance for all insights and ideas.
posted by: Brother Damian 13-Dec-2013/2:09:33-8:00
The view block consists of a special dialect, which is parsed using rules specific to building GUIs, so the 'for loop can't be included there. Typically, the solution is to build the GUI block first, then display it: R E B O L [] factor: 2 count: 6 gui: copy [ size 640x480 style star image %star.png ] repeat factor count [ append gui compose [at (as-pair 61 * factor 307) star] ] view layout gui About 'repeat instead of 'for - here it doesn't really matter, but it's good to use 'repeat for larger loops, since it's a faster native function (also a little shorter syntactically). Also about 'compose - I typically use it instead of 'reduce because it doesn't require ticks for unevaluated words (just put evaluated portions of code in parentheses).
posted by: Nick 13-Dec-2013/7:47:56-8:00
Thanks Nick, that is very informative and it helps me a lot.
posted by: Brother Damian 13-Dec-2013/8:46:49-8:00
Just in case it's useful, here's another way to do it: R E B O L [] factor: 2 count: 6 stars: func [f c] [ g: copy [style star image %star.png] repeat f c [ append g compose [at (as-pair 61 * f 307) star] ] g ] view layout compose [ size 640x480 (stars factor count) ]
posted by: Nick 13-Dec-2013/13:46:15-8:00
That example uses a function which builds and returns the stars portion of the GUI block, so that the GUI layout code is a little more readable. Notice that the GUI block is composed.
posted by: Nick 13-Dec-2013/14:32:20-8:00
Great Nick, thanks! I am analyzing this and can say with pride that I can read the function, mostly. So let me ask you this: The stars function has a g standing by itself at the end of the repeat block (line 7). Is this a return value for the function? If so, are we using a feature where the last value is commonly returned by functions so we don't really need to type return or this something else entirely? Then, in line 4, what is the difference between: g: copy [style star image %star.png] and g: [style star image %star.png] (without the copy) and why do you prefer the first version? I see that you now use the function compose twice. Why do we need to compose the GUI block as well? And in a more general note: many times I use names and REBOL knows to use their values, for example: block: [ "alpha" "beta" "gamma" ] n: 2 if I type: pick block n I get the expected result of beta (which requires to use the value of two stored in the name n) but if I try path notation: print block/n I get an error, usually: ** Script Error: Invalid path value: n I know (by reading you tutorials Nick, and many, many thanks for them) that reduce, compose and even the : allow me to extract the value from the name used, as if I had typed the value directly. So one can solve the issue by coding: print compose [ block/(n) ] But: why is block understood as name but not n? (that is, why does only n need to be reduced but not block?) More generally: When is it necessary to reduce or compose? Under what circumstances will REBOL use the value of the name and when is it necessary to explicitly extract the value with these functions? I am not sure if I should star another thread or I can ask these questions here. I will do as directed. And thanks again Nick for all your help
posted by: Brother Damian 13-Dec-2013/15:29:43-8:00
The "g" at the end of the function is just a shorthand way of writing "return g". The last value in a function definition is always returned, unless a 'return is evaluated elsewhere in the function. I always use "copy" to initialize a new (empty) block, any time I know that the block label will be repeatedly initialized. Here it's not necessary, because within the context of the function, that word is locally defined, but it's a force of habit for me. I do the same thing whenever referring to widget/text, and other properties, just to be sure I'm dealing with an isolated instance of the value. It was force of habit in this situation, but not a bad habit in general with Rebol - it'll save you from lots of potential bugs. The first compose, inside the function is used to build each item in the local 'g block. That entire constructed block is then returned from the function, and needs to be evaluated before being passed to the layout function, which is what the second compose accomplishes. If you need to evaluate a value within a path, it either needs to be composed or reduced, or the get-word notation needs to be used (i.e., block/:n or compose [block/(n)]). I think the get-word notation is most popular, because it's most concise. I tend to use the "pick block n" syntax a lot, because it's been the most versatile and readable syntax in many varied situations. Otherwise (outside of path notation), compose and reduce work as expected.
posted by: Nick 13-Dec-2013/17:09:03-8:00
Hello all! I'm a complete noob in Rebol and came here to ask some questions, but reading this post I understood the use of copy and compose, which solved my small problems. Thanks a lot! My (first!) prog is a system-tools launcher for Win XP (in French, sorry): R E B O L [Title: "Lanceur"] data: [ ["Dx Diags" "C:\WINDOWS\system32\dxdiag.exe" "Diagnostics DirectX"] [ "Services" "C:\WINDOWS\system32\services.msc" "Services Windows"] [ "Restore" "C:\WINDOWS\system32\Restore\rstrui.exe" "Restoration systθme"] ] sty: stylize [ btn: button 100x30 160.140.120 lbl: label 220.200.180 font-size 20 ] win: copy [ backdrop 140.160.180 styles sty vh1 "Outils systθme" font-size 44 font-color 200.150.100 ] foreach elm data [ append win compose [return across] append win compose [btn (elm/1)] append win compose/deep [[call/shell (elm/2)]] append win compose [lbl (elm/3)] ] view center-face layout win Now I just have to put the data as lines in a text file (so it can easily be extended/translated), and construct the block from there. Happy coding! P. - S. By the way, right now I'm using Crimson editor, which is nice, but is there a free editor with syntax coloration _and_ code folding?
posted by: Old Nick 13-Feb-2014/16:31:55-8:00
ETA: Scite folds & colors, so ditch my PS.
posted by: Old Nick 13-Feb-2014/17:34:22-8:00
Hi Old Nick :) Glad to see you got it going. Just to be sure it's clear, the second half of your code could be shortened a bit: win: copy [ backdrop 140.160.180 styles sty vh1 "Outils systθme" font-size 44 font-color 200.150.100 across ] foreach elm data [ append win compose/deep [ return btn (elm/1) [call/shell (elm/2)] lbl (elm/3) ] ]
posted by: Nick 14-Feb-2014/22:09:59-8:00
Also, there's no requirement to place the button items within separate nested blocks within the 'data block: R E B O L [Title: "Lanceur"] data: [ "Dx Diags" "C:\WINDOWS\system32\dxdiag.exe" "Diagnostics DirectX" "Services" "C:\WINDOWS\system32\services.msc" "Services Windows" "Restore" "C:\WINDOWS\system32\Restore\rstrui.exe" "Restoration systθme" ] sty: stylize [ btn: button 100x30 160.140.120 lbl: label 220.200.180 font-size 20 ] win: copy [ backdrop 140.160.180 styles sty vh1 "Outils systθme" font-size 44 font-color 200.150.100 across ] foreach [bt prg txt] data [ append win compose/deep [ return btn (bt) [call/shell (prg)] lbl (txt) ] ] view center-face layout win
posted by: Nick 14-Feb-2014/22:22:47-8:00
Hello (young) Nick! ;) Many thanks for having taken interest in my small problem. Of course your modification is 250% better: putting the "across" out of the loop (I had understood it as a kind of switch, like a gsave/grestore or pushmatrix/popmatrix pair); flat data structure (shows nicely how "compose" works). I had tried the "foreach [x1 x2 x3]" trick, but somehow messed up. Needed the master's hand
For my part I put the data in a text file, so it can be easily read/modified/translated: # Restoration systθme Restore C:\WINDOWS\system32\Restore\rstrui.exe Restoration systθme # Lettres assignιes aux disques Disks C:\WINDOWS\system32\diskmgmt.msc Lettres disques &c. And it is read by my small launcher (skipping void lines and #-preceded comments) with: read-data: function [infile][res][ res: exclude (read/lines infile) [""] forall res [if res/1/1 = (to-char "#") [remove res]] res ] data: read-data %data.txt I'm not so happy with the "forall" part, but don't know if it's possible (or even elegant) to get that job done by "exclude"? One last question: how do I get rid of the permission-asking when I start my mini-prog? (I'm using Rebol 2.7.8.3.1.) Many thanks for your kind help, Old Nick
posted by: Old Nick 21-Feb-2014/12:42:49-8:00
O.N., If the purpose is simply to load your data from a file, the most basic solution is to just copy your data block to a file. For example, put these lines in %data.txt: "Dx Diags" "C:\WINDOWS\system32\dxdiag.exe" "Diagnostics DirectX" "Services" "C:\WINDOWS\system32\services.msc" "Services Windows" "Restore" "C:\WINDOWS\system32\Restore\rstrui.exe" "Restoration systθme" You can use a semicolon to start any comment line, and include blank lines as desired, just as in normal Rebol code: ; Restoration systθme "Restore" "C:\WINDOWS\system32\Restore\rstrui.exe" "Restoration systθme" ; Lettres assignιes aux disques "Disks" "C:\WINDOWS\system32\diskmgmt.msc" "Lettres disques" ; "Dx Diags" "C:\WINDOWS\system32\dxdiag.exe" "Diagnostics DirectX" ; "Services" "C:\WINDOWS\system32\services.msc" "Services Windows" The code below will load either of the 2 data files above in the exact same way: R E B O L [Title: "Lanceur"] data: load %data.txt sty: stylize [ btn: button 100x30 160.140.120 lbl: label 220.200.180 font-size 20 ] win: copy [ backdrop 140.160.180 styles sty vh1 "Outils systθme" font-size 44 font-color 200.150.100 across ] foreach [bt prg txt] data [ append win compose/deep [ return btn (bt) [call/shell (prg)] lbl (txt) ] ] view center-face layout win You could also use read/lines, if you want to avoid the extra quotes. Then your data file just needs to look like this: Dx Diags C:\WINDOWS\system32\dxdiag.exe Diagnostics DirectX Services C:\WINDOWS\system32\services.msc Services Windows Restore C:\WINDOWS\system32\Restore\rstrui.exe Restoration systθme If you prefer to keep your data file in the format above, my first inclination for 'read-data would have been to do something like this: read-data: func [infile][ remove-each r read/lines infile [(#"#" = r/1) or ("" = trim r)] ]
posted by: Nick 22-Feb-2014/21:07:24-8:00
And, unless you need to reuse that code somewhere else, you might well just use the following line to assign the label 'data to the values you want: data: remove-each r read/lines %data.txt [(#"#" = r/1) or ("" = trim r)]
posted by: Nick 22-Feb-2014/21:13:33-8:00
To eliminate the security requestor, you can use the -s option on the command line. I typically use -si when creating .exe sfx files (I typically use iexpress, which comes on all modern Windows PCs to create .exe files): "C:\myfolder\rebol.exe -si merchants_village.r"
posted by: Nick 22-Feb-2014/22:10:47-8:00
Nick, thanks for your kind help! I love your one-line read-and-format: "data: remove-each r read/lines %data.txt [(#"#" = r/1) or ("" = trim r)]" starts to look like a cross between Mathematica and Forth code ;) I understood also why you wrote "" = trim r, and not, as I would have done spontaneously, trim r = "" (of course one can use parentheses). Well, you're an old Rebol hand
I set the security with the -s switch for launching a script from the editor, but is there a way to do it from _inside_ the script? (Without making an ad hoc shortcut I'm on Windows or batch file.) I tried secure [file allow], but no good. (Just thought of it: through the startfile, perhaps?)
posted by: Old Nick 26-Feb-2014/22:50:34-8:00
The point of the security requestor is to prevent malicious scripts from performing unwanted activities, so giving a script the ability to change its own security level would defeat the purpose. You can use the 'secure function to change default security levels (yes, even in your startup file), but unless you run the interpreter with -s, you will still see a requestor asking whether it's ok to change security levels: http://www.rebol.com/docs/words/wsecure.html It's my understanding that if you really want to remove all security requestors, the only way to do that is on the command line (in a link, batch file, as part of any other system command which can call the Rebol interpreter, etc.) with the -s option. I don't think there's another way around that, and it's the only way I've ever done things. For example, any .exe files I create with iexpress or some other SFX packager, or any other links, icons, or installations of any script created for users who I don't want to have to see or bother with a requestor, are always run with "rebol.exe -si myscript.r". Otherwise, for ad hoc scripts that I've written for myself or user familiar with Rebol, I always just press "A" on the keyboard to allow all.
posted by: Nick 27-Feb-2014/14:54:47-8:00
Ah! Doing my little bit of programming only for myself, I'm not much into those security problems still my question was of a nice stupidity level! *blush* I started a new project, and so have a new problem. This line gives me (nearly) what I want: call/output "dir F:" %test.txt (Actually I only need the end of the second line, to get hardware information.) I could then read the test.txt file into Rebol, but there certainly is a more direct way to capture the result of the command. Trying to redirect to a variable set to an empty string or an empty block diden't work. Another, analogous question. If I use a batch file and want to see the output (or the console closes immediately), I have to write two commands: dir f: pause Now, how to send _two_ commands from Rebol with call/show? Tried a lot of things, but
Once more, thank you for your kind help!
posted by: Old Nick 3-Mar-2014/1:01:54-8:00
This does work: y: copy "" call/show/output "dir C:" y editor y For multiple 'call commands, you can loop through a block: foreach i ["dir c:" "pause"] [call/console i]
posted by: Nick 3-Mar-2014/11:57:05-8:00
Well, I looked at the documentation, and hope I understand what the call refinements are for. Yet it's strange: If I type directly into an open (Rebol) console: y: copy "" call/output "dir C:" y (dropping the show, as I only need the y string) print y all's OK. If I run the same script, be it by double-clicking its icon or from the editor: y: copy "" call/output "dir C:" y print y (here possibly a "wait 5", changes nothing) nothing happens, but Rebol stays in memory and hogs the CPU (having to kill the process). Now if I insert a dummy line into the script to open the (Rebol) console before the call: y: copy "" print "Starting" call/output "dir C:" y print y wait 5 the script executes and Rebol quits after 5 secs, but the printed string is void. I checked that antivirus & firewall aren't at the root of that. Sorry to be so verbose, but I tried to be as clear as possible. And thanks for your suggestions!
posted by: Old Nick 5-Mar-2014/3:23:59-8:00
Something we're unaware of in your local environment is interfering. This works fine for me, both in the interpreter, and in a script: y: copy "" call/output "dir C:" y print y What are in your rebol.r and user.r startup files?
posted by: Nick 5-Mar-2014/10:12:36-8:00
You are using R2, correct?
posted by: Nick 5-Mar-2014/11:51:06-8:00
|