ID:152169
 
Everyone knows those happy little input() and alert() boxes that you use all the time:

do this do that ask for input() wait until input received do this do that

That part where it asks for input and then waits until its received - I want to mimic that with interface windows. Since interface windows are great for allowing you to use labels, inputs and buttons to basically create your own style of alert boxes, I want to use them for just that. The trouble is, I can't figure out how to make them wait until you respond to the box before continuing the proc.

Now looking at similar examples, Shadowdarke's sd_Alert() library uses browser popups to achieve the same effect as alerts. But the browser has the advantage that the "okay" button can be linked back to a datum which is behind the scenes managing the browser alert. I can't think of any way to link an interface popup with a datum.

So I guess I'm just wondering if anyone has any novel ideas on how to use interface popups to imitate the effects of alert boxes?

do this do that popup an interface window wait until input from interface window is received do this do that
I'm pretty sure this is how that one special alert system is made, but it might be with using vars.

do this
do that
check for var
if false, set to true
ask for input()
wait until input received
set car to false
do this
do that


I forgot what the library was called. It might be sd_Alert, but if you search "alert()", some things will come up.
In response to Kaiochao2536
The thing is, he doesn't want an input() or an alert(), even if it is HTML based. He wants it to be a part of the interface (DMF).


Anyways, you can do hacky way for now: have an infinite loop using a variable while it is false, and if something is chosen on the interface, send a message to Topic() to change that variable to a true variable, which will break that loop, than set it back as false.

And winclone()

var/continue = 0
mob/verb/ROCK()
usr << "Hi"
while(!continue)sleep(1) // waits for continuation
usr<<"GASP!"

//Have some sort of Topic() here, which checks if it is okay to continue onwards, obtained from the interface, than set continue=1 and a short time after set it back to 0.


Too bad there's no wincreate() which you can program in the elements and define it via winset() :(
In response to GhostAnime
I thought it was possible to create controls. Not with wincreate(), though. I think I have to check the skin reference again.

EDIT: Near the bottom of the reference, "Creating or deleting controls at runtime."
In response to GhostAnime
GhostAnime wrote:
The thing is, he doesn't want an input() or an alert(), even if it is HTML based. He wants it to be a part of the interface (DMF).


Anyways, you can do hacky way for now: have an infinite loop using a variable while it is false, and if something is chosen on the interface, send a message to Topic() to change that variable to a true variable, which will break that loop, than set it back as false.

And winclone()

var/continue = 0
> mob/verb/ROCK()
> usr << "Hi"
> while(!continue)sleep(1) // waits for continuation
> usr<<"GASP!"
>
> //Have some sort of Topic() here, which checks if it is okay to continue onwards, obtained from the interface, than set continue=1 and a short time after set it back to 0.

Too bad there's no wincreate() which you can program in the elements and define it via winset() :(

"continue" is reserved, isn't it?
In response to GhostAnime
That's the thing - if you use alerts or browser popups, you can have a datum that stores the variables for things like the check to see when to end the infinite loop. That's how sd_Alert does it:

sd_Alert
var/response = 0

New()
var/response = 0
player << browse() // create popup
while(!response)
sleep(2)
player << browse(null) // delete popup
del(src)


In the mean time, hitting a button in the popup window will send an argument to the sd_Alert datum's Topic() proc telling it to set response to 1, thus closing the popup.

However, I have no idea how to send anything to a Topic() proc from an interface button.
In response to Foomer
However, I have no idea how to send anything to a Topic() proc from an interface button.
Perhaps you could put the reference text in a hidden label and then retrieve it when the button's verb is called. The help file says that you can dereference text by using the locate() command, but I have not tried it. In theory, you should then be able to call the object's Topic().
In response to Foomer
You don't need to send anything to Topic(). Shadowdarke used Topic, becuase that was the only means of communication between the browser pop-up and the datum. With 4.0, you have much more freedom to choose where to send your input. You could set the default command of the button to a hidden verb that sets the value of the variable and ends the loop. That's the way I'd go.

~X
In response to Foomer
Foomer wrote:
However, I have no idea how to send anything to a Topic() proc from an interface button.

All topic links which you want to affect datums are formatted and processed in the same way:

byond :// ?src=\ref[usr] ; arg1=blah ; arg2 ; arg3=57

(sans spaces, of course) ...will be received by /client/Topic:

client/Topic(href, href_list[], hsrc)

href = "src=\[0x10000059];arg1=blah;arg2;arg3=57"
href_list["src"] = "\[0x1000059]"; href_list["arg1"] = "blah"; href_list["arg2"] = null; href_list["arg3"] = "57"
hsrc = usr (in this case only, since usr was the one with internal ID 0x10000059)

...and if the hsrc argument is non-null, the default /client/Topic will then automatically call /datum/Topic for the appropriate object:

mob/Topic(href, href_list[])

...where you can then process the object accordingly.


It's important to think of buttons as "verb activators". That is, any time you click a button in a DMF, the button simply performs command-line input behind the scenes. Anything that the client can type into the command line is thus something that the button can do.

Since clients can type URLs into the command line, all you need to do is make the button's command equal to a URL, and that'll be that.


[edit]Note, of course, that you must set the command at runtime, using the winset() proc, since when creating the interface file you won't have access to the usr's runtime ID.
In response to Foomer
Here, something along these lines:

fo_Alert // your alert datum
var
result // to hold the result

New(mob/M, message, title, option1, option2, option3)
..()
// build your alert interface here...

Del()
// destroy your alert interface here...
..()

proc
GetResult(t as text) // your button uses this as the default command
set hidden = 1 // followed by the value of the button
result = t // ie: default command: GetResult "OK"

proc
fo_alert(mob/M = usr, message, title, option1 = "OK", option2, option3)
if(!M || !M.client) return
var/fo_Alert/A = new(M, message, title, option1, option2, option3)
M.verbs += /fo_Alert/proc/GetResult
while(!A.result) sleep(-1)
. = A.result
M.verbs -= /fo_Alert/proc/GetResult
del(A)
return . // this line may not be neccessary

mob
verb
test()
fo_alert(,"This is a test of the fo_Alert system.", "Testing")


~X
In response to Jtgibson
I just tried setting the Okay button's command:

datum/proc/blah()
winset(src.target, "[src.window].confirm", "command=byond://?src=\ref[src];confirm=true")


However, I'm not having any success even getting a response from the client/Topic() proc doing this.
In response to EGUY
Yes it is, hence why it is blue, thus this means that continue was used for a reason instead of another variable name... maybe because it is an example?
In response to Foomer
It occurs to me that setting the button's command to:

"command=byond://?src=\ref[src];confirm=true"

At run time is actually setting it to "command=byond".

Because you can't store a params list (which is what the link is) in a params list!

Any other suggestions?

(At this point I'm beginning to doubt the wisdom of requiring params instead of lists for everything.)
In response to Foomer
set it to "command='byond://?src=\ref[src]&confirm=true;'"

parameters are separated with an ampresand &, not the semi-colon. That's what separates a parameter in winset(). Also, try putting the command's value within single-quotes.

If that fails, you may have to go with the method I drew up earlier in this topic, using a verb instead of Topic().

~X
In response to Xooxer
Xooxer wrote:
try putting the command's value within single-quotes.

That works. I never new that. Good to know!
In response to Foomer
Okay, here's my interface window popup datum:

/***********************************************************
Interface Alerts - iAlert!

Example:
var/iAlert/i = new(usr, "window")
var/result = i.Response(arg1, arg2)

NOTE: You need to set the id of your "Okay" button to
"confirm" if you want to get a return value from GetReturn().
If you want a "cancel" button, you need to set its id
to "cancel" or it won't respond.

iAlerts use two-steps to get the results from the alert:

The first step is used to create the alert datum, tell it
which interface window to use and assign it to a player.

The second step is used to get the player's response to
the provided window. Any arguments provided for the Response
proc will be passed on to the Display() and GetReturn() procs.

The Display() proc is used to setup the window, assigning
new values to interface elements and so forth. Arguments used
for the Response() proc can be used here to determine how
the interface elements should be set up.

The GetReturn() proc lets you decide how you want the
alert to understand the values intered in the alert window
to be returned. The value returned by the Response() proc
is the same as the value returned by this proc.
***********************************************************/


iAlert
var
target
window
response
confirmed

New(mob/target=usr, window)
// Make sure that the target is an acceptable player
// with a client before allowing the window to be created.
if(!ismob(target))
del(src)
if(!target.client || !window)
del(src)

src.target = target
src.window = window
return

Del()
winshow(src.target, src.window, 0)
sleep(100)
..()

Topic(href, params[])
if(params["confirm"])
src.confirmed = 1
src.response = 1
spawn(2)
del(src)

// This function is called after the iAlert is created
// in order to retreive a player's response from the window.
proc/Response()
src.Display(args)
winset(src.target, "[src.window].cancel", "command='byond://?src=\ref[src]'")
winset(src.target, "[src.window].confirm", "command='byond://?src=\ref[src];confirm=true'")
winshow(src.target, src.window, 1)
while(src.target && !src.response)
sleep(2)
if(src.confirmed)
return src.GetReturn(args)
return null

// Use this to setup the window before it is displayed,
// such as filling in inputs or adjusting labels.
proc/Display(arguments)
return

// This is how you tell the alert what kind of value you want it
// to return. The value returned by the Response() is the same
// as the value returned by this proc.
proc/GetReturn(arguments)
return
In response to Foomer
You're still using a semi-colon to separate the paramters in your URL, when you should be using the apresand &. The winset() command uses the semi-colon to separate parameters, so this could potentially confuse the compiler.
In response to Xooxer
Apparently the '' around it lets it read it as one big chunk.

As far as parameters go, ; and & do exactly the same thing.
In response to GhostAnime
Well I was going to say that it was probably because it was an example, but I was just saying that for the sake of people who try and copy it right from the post. :D