SUGGESTION: GUI.ProcessClick and Button.ProcessClick

Started by monkey0506, Fri 14/06/2013 14:26:49

Previous topic - Next topic

monkey0506

In response to this recent thread, 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):

Code: cpp
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?

Crimson Wizard

#1
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.

monkey0506

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?

Crimson Wizard

#3
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)

Calin Leafshade

I think the events system requires an overhaul anyway. The winforms paradigm seems good to me:

Code: javascript

    button.Click += function() end
    button.OnClick() // runs the Click event manually.

Crimson Wizard


monkey0506

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:00
Quote 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.

Crimson Wizard

#7
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:00
Quote 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.

SMF spam blocked by CleanTalk