In response to this recent thread (http://www.adventuregamestudio.co.uk/forums/index.php?topic=48443.0), I decided to take a quick glance in the engine source to see what is actually going on when you click on a GUI/GUIControl, and I found this function (../Engine/ac/gui.cpp, Line 247):
void process_interface_click(int ifce, int btn, int mbut) {
if (btn < 0) {
// click on GUI background
gameinst->RunTextScript2IParam(guis[ifce].clickEventHandler,
RuntimeScriptValue().SetDynamicObject(&scrGui[ifce], &ccDynamicGUI),
RuntimeScriptValue().SetInt32(mbut));
return;
}
int btype=(guis[ifce].objrefptr[btn] >> 16) & 0x000ffff;
int rtype=0,rdata;
if (btype==GOBJ_BUTTON) {
GUIButton*gbuto=(GUIButton*)guis[ifce].objs[btn];
rtype=gbuto->leftclick;
rdata=gbuto->lclickdata;
}
else if ((btype==GOBJ_SLIDER) || (btype == GOBJ_TEXTBOX) || (btype == GOBJ_LISTBOX))
rtype = IBACT_SCRIPT;
else quit("unknown GUI object triggered process_interface");
if (rtype==0) ;
else if (rtype==IBACT_SETMODE)
set_cursor_mode(rdata);
else if (rtype==IBACT_SCRIPT) {
GUIObject *theObj = guis[ifce].objs[btn];
// if the object has a special handler script then run it;
// otherwise, run interface_click
if ((theObj->GetNumEvents() > 0) &&
(theObj->eventHandlers[0][0] != 0) &&
(!gameinst->GetSymbolAddress(theObj->eventHandlers[0]).IsNull())) {
// control-specific event handler
if (strchr(theObj->GetEventArgs(0), ',') != NULL)
gameinst->RunTextScript2IParam(theObj->eventHandlers[0],
RuntimeScriptValue().SetDynamicObject(theObj, &ccDynamicGUIObject),
RuntimeScriptValue().SetInt32(mbut));
else
gameinst->RunTextScriptIParam(theObj->eventHandlers[0],
RuntimeScriptValue().SetDynamicObject(theObj, &ccDynamicGUIObject));
}
else
gameinst->RunTextScript2IParam("interface_click",
RuntimeScriptValue().SetInt32(ifce),
RuntimeScriptValue().SetInt32(btn));
}
}
This seems relatively straightforward enough. I actually got called into work early today (just waiting on clothes to dry), but I'm curious how difficult it would be to provide methods such as GUI.ProcessClick and Button.ProcessClick which would in turn place calls into this method. I honestly haven't made any serious attempt at modifying the engine source directly, but am I wrong in thinking that this would be an extremely simple thing to implement?
I would question the choice of function. AGS has ProcessClick, which does not refer to particular object, but tests any entity at given point (practically - simulates mouse click). Also, RunInteraction, that is an object-related function and allows to trigger particular event.
I think that if we consider keeping consistency, there should be either ProcessClickOnGUI(x,y) or GUI/GUIControl.RunInteraction, or both.
I think the reason I was somewhat wary of "RunInteraction" is that it's rather vague in terms of a GUI/GUIControl what it actually means. For other things (characters, hotspots, inventory items, and objects), when you call RunInteraction you're passing in a CursorMode for the interaction. Obviously that doesn't apply to GUIs. Also, what does Label.RunInteraction do? Or Slider.RunInteraction? Or ListBox.RunInteraction? While these may have conceivable usages, the name is ambiguous to the actual meaning.
We should also avoid adding any new methods in the global scope to AGScript...we already have enough confusion because of the pseudo-quasi-OO-style.
But regardless of what we call it, it should be easy to implement, yes?
I am wrong about RunInteraction of course. The GUI does not distinct interactions (Walk, Look, etc). The may be RunEvent instead. Or SimulateClick, or any better name one may come with. My point was that ProcessClick name is already related to simulating mouse click at given coords.
Regarding simplicity, I think there's a chance it is very easy. Although I would keep fingers crossed, for AGS has a lot of traps inside...
E: Oh, and -
Quote from: monkey_05_06 on Fri 14/06/2013 14:49:31
We should also avoid adding any new methods in the global scope to AGScript...we already have enough confusion because of the pseudo-quasi-OO-style.
I do not think this is a valid approach. Since there are global functions already, we will eventually need to OO-ize them all. Which won't become more difficult task if we add few more.
And if function does not refer to certain object, why should it be made one's member? (I guess ProcessClick may become a member of Screen class in the future)
I think the events system requires an overhaul anyway. The winforms paradigm seems good to me:
button.Click += function() end
button.OnClick() // runs the Click event manually.
.OnClick! this is how it should be called. :)
Quote from: Crimson Wizard on Fri 14/06/2013 14:52:00The may be RunEvent instead. Or SimulateClick, or any better name one may come with. My point was that ProcessClick name is already related to simulating mouse click at given coords.
"already related to simulating mouse click at given coords." How is the fact that the simulated click is on a GUI/Button any different than this description? I'm not demanding that the name "ProcessClick" be used, but it follows the same logical nomenclature of the global method.
Quote from: Crimson Wizard on Fri 14/06/2013 14:52:00Quote from: monkey_05_06 on Fri 14/06/2013 14:49:31We should also avoid adding any new methods in the global scope to AGScript...we already have enough confusion because of the pseudo-quasi-OO-style.
I do not think this is a valid approach. Since there are global functions already, we will eventually need to OO-ize them all. Which won't become more difficult task if we add few more.
What you're saying here essentially amounts to, "why do it the right way now, when we can just fix it later?" If a new function directly relates to an object (script object, not just an AGS Object), it
absolutely should be made a member method,
not a global function.
Quote from: Crimson Wizard on Fri 14/06/2013 14:52:00And if function does not refer to certain object, why should it be made one's member? (I guess ProcessClick may become a member of Screen class in the future)
If for no other reasons than consistency and organization, I still say that these methods should be grouped together (if not as member methods, as static methods). This is further supported by existing methods
Game.*, for example.
Quote from: monkey_05_06 on Sun 16/06/2013 03:14:12
"already related to simulating mouse click at given coords." How is the fact that the simulated click is on a GUI/Button any different than this description? I'm not demanding that the name "ProcessClick" be used, but it follows the same logical nomenclature of the global method.
Is it? You did not mention parameters it should take. If they are x/y coords, it will follow the same "nomenclature", though I understood your idea so that it will simulate click on exactly the object it is called from, in which case it has different meaning.
Quote from: monkey_05_06 on Sun 16/06/2013 03:14:12
Quote from: Crimson Wizard on Fri 14/06/2013 14:52:00Quote from: monkey_05_06 on Fri 14/06/2013 14:49:31We should also avoid adding any new methods in the global scope to AGScript...we already have enough confusion because of the pseudo-quasi-OO-style.
I do not think this is a valid approach. Since there are global functions already, we will eventually need to OO-ize them all. Which won't become more difficult task if we add few more.
What you're saying here essentially amounts to, "why do it the right way now, when we can just fix it later?" If a new function directly relates to an object (script object, not just an AGS Object), it absolutely should be made a member method, not a global function.
What I am saying is to stay consistent. Since we already have a lot of global functions, we should either make them object-oriented all at once (or at least all functions in a related group), or not being afraid of adding another one (especially if it is a variant of already existing global function).
If you are going to add a function that IS really a member function, then of course add it as a member function.
But my sentence about adding global function was related to hypothetical variant of ProcessClick, which I called ProcessClickOnGUI, which could work same way as ProcessClick work. If it is not something you want to add, then all this is irrelevant.