Advertisement

Author Topic: funcCreateDialog.sqf makes it easy to work with dialogs. Running in.  (Read 2264 times)

0 Members and 1 Guest are viewing this topic.

Offline Denisko-Redisko

  • Members
  • *
This function makes it easy to work with dialogs.
Suppose we have about such a description (simplified):
Code: [Select]
class DlgExample {
    idd = 10923;
    class controls
    {
        class Display: RscTextMulti { idc = 200; };
        class Button: RscButton { idc = 101; };
        class Link: RscLink { idc = 102; };
        class Input: RscEdit { idc = 103; };
        class Slider: RscSliderH { idc = 104; };
        class Listbox: RscListBox { idc = 105; };
    };
};
Now we can work with him in this spirit:
Code: [Select]
{
    _rsc = "DlgExample";

    _private = [
        "_buttonState", "_linkState", "_textState",
        "_sliderState", "_listboxState", "_showProperty"
    ];

    _handlers = [

        "Button", "ButtonDown", {
            _buttonState = "botton down time: " + str time;
            call _showProperty
        },

        "Link", "ButtonDown", {
            _linkState = "link click time: " + str time;
            call _showProperty
        },

        "Input", "KeyDown", {
            _textState = "current text: " + ctrlText _ctrlInput;
            call _showProperty
        },

        "Slider", "SliderPosChanged", {
            _sliderState = "slider position: " + str (sliderPosition _ctrlSlider);
            call _showProperty
        },

        "Listbox", "LBSelChanged", {
            _listboxState = "listbox selected item: " + (_ctrlListbox lbText lbCurSel _ctrlListbox);
            call _showProperty
        }
    ];

    _constructor = {

        _showProperty = {

            _ctrlDisplay ctrlSetText (
                _buttonState  + "\n" +
                _linkState    + "\n" +
                _textState    + "\n" +
                _sliderState  + "\n" +
                _listboxState + "\n"
            )
        };

        _buttonState  = "";
        _linkState    = "";
        _textState    = "";
        _sliderState  = "";
        _listboxState = "";

        for "_i" from 0 to 100 do {
            _ctrlListbox lbAdd ("item number " + str _i)
        };

    };

    _destructor = { hint "_destructor"; };

} call funcCreateDialog;
No global variables in your code.
No numeric identifiers.
No any code in description.ext.


sorry for my english

Offline Mandoble

  • Former Staff
  • ****
    • Grunt ONE and MandoMissile suite
Very fine piece of code  :clap:

What is missing for the public is a clear description of the purpose as well as clear instructions for the usage, unless you want it limited only for advanced users.

Also you might want to put your tag in the name of the file funcCreateDialog.intro and the function

Offline Spooner

  • Members
  • *
  • Mostly useless
    • Community Base Addons
Well, that is the most convoluted code I've seen in ArmA so far ;) Not saying that is a bad thing, but it gave me a real headache trying to follow it. I've not run the code or tried to use it, but I think I get a grip of what it is trying to achieve. A very noble aim if it can work as it intends to...

Well, since you are clearly striving for perfection, I'll give you some relatively nit-picking suggestions/corrections:
* mcrNameOfGlobalDisplayStorage is an unnecessary workaround. Either #mcrGlobalDisplayStorage or 'mcrGlobalDisplayStorage' will work just as well.
* Please replace preprocessFile with preprocessFileLineNumbers to give us some decent error messages when things go wrong (I'm talking about errors in "our" closure, not in your function, that is).
* Please use OFPEC tags consistantly if you are going to use them (you use one for RLS_VDMJ_DISPLAY_DATA_3MQ8K0WWVLQABRMPBGIE, but then not for funcCreateDialog).
* I suspect you could remove all dynamic code using compile (which is a nightmare to debug when it fails) just by passing more values from function to function. The GUI runs very quickly, and you generally don't have dialogs shown in a heavy firefight with low FPS, so the extra load from this extra processing would be irrelevant.
* Better error reporting if the structure of the closure is wrong might be useful (telling the user exactly what data is wrong rather than just that there was an error would be helpful). This isn't critical to it working but I can see issues as things get more complex. Still, you have better error handling than 99% of other code ;)
* There doesn't seem to be a way that I can push data into the closure, which is a major issue (I may have just not seen how to do this). I could poll a global inside a script spawned from the constructor, I suppose, but I might want a control that is updated based on external changes.
* The onLoad handler has to be hard-coded, since the display will not exist until after that handler has triggered. How would I interact between that handler and your dynamic handlers?
* Any thoughts on how this might work or, in fact, if it would be useful, for overlays (that is, cutRsc/textRsc rather than createDialog)?
* Manage multiple controls feeding into a single handler:
Code: [Select]
["Button1", "Button2", "Button3"], "ButtonDown", {
   
},
[Arma 2] CBA: Community Base Addons
[Arma 1] SPON Core (including links to my other scripts)

Offline Denisko-Redisko

  • Members
  • *
Spooner, Mandoble, big thanx, guys!

Quote from: Mandoble
What is missing for the public is a clear description of the purpose as well as clear instructions for the usage, unless you want it limited only for advanced users.

I'm try to do it. It in using a very simple, but I haven't yet considerations as it is available to describe.

Quote from: Spooner
* mcrNameOfGlobalDisplayStorage is an unnecessary workaround. Either #mcrGlobalDisplayStorage or 'mcrGlobalDisplayStorage' will work just as well.

Well, prerocessor doesn't know the sqf-syntax, but it knows that such a string. All that is enclosed in quotation marks preprocessor leaves as is. I'm happy to be removed unnecessary macro, but I don't know how to do it. :(

Quote
Please use OFPEC tags

This is only one function, name it as you are comfortable.
I'm afraid that I not be allowed into heaven if I mixed in one name snake_case and camelCase :)
I would like to use the prefix rls, if he is not busy.

Quote
I suspect you could remove all dynamic code using compile (which is a nightmare to debug when it fails) just by passing more values from function to function.

I'm not sure that I understood the idea.
Variables are stored in an array, rather than in a some nameSpace. They need to create and then save their values in the array. A solution could be to use the reception:
Code: [Select]
{
    // pseudo-closure

    _var1 = something;
    _var2 = something;

    waitUtil {

        if( some event ) then {
            call eventHandler
        };
        some event != close
    }
}
But it seriously worsen the response time. Perhaps you have an idea how to solve it?

-------------
I think that the attempt to imitate classical closures (similar a closures of perl, ruby or democratic javascript) is doomed to failure.
Rather, it some "syntactic sugar". Some semblance of dialogNamespace.

Quote
The onLoad handler has to be hard-coded, since the display will not exist until after that handler has triggered. How would I interact between that handler and your dynamic handlers?
Hmm. I don't use onLoad handler, but _constructor have access to the current namespace and dialog-namesapce:
Code: [Select]
_someObject = player;
_someString = "some string";
_someNumber = 123123;

{
    _rsc = "DlgExample";
    _private = ["_obj", "_str", "_num"];

    _constructor = {
        _obj = _someObject;
        _str = _someString;
        _num = _someNumber;
    };

    private "_funcDisplay";

    _funcDisplay = {
        _ctrlDisplay ctrlSetText format[
            "_obj: %1\n_str: %2\n_num: %3\n", _obj, _str, _num
        ];
    };

    _handlers = [
        "Button", "ButtonDown", _funcDisplay,
        "Link", "ButtonDown", _funcDisplay,
    ];

} call rlsFuncCreateDialog;

I changed the function name, and added two very simple examples.
sorry for my english

Offline Spooner

  • Members
  • *
  • Mostly useless
    • Community Base Addons
Quote
Well, prerocessor doesn't know the sqf-syntax, but it knows that such a string. All that is enclosed in quotation marks preprocessor leaves as is. I'm happy to be removed unnecessary macro, but I don't know how to do it. :(
The preprocessor does not process anything inside " which is what delimits strings in C. However, in SQF, strings can be in single quotes which the preprocessor doesn't care about, so you can use 'mcrGlobalDisplayStorage'. On the other hand, since it is usual to want to have a macro inside double-quotes, you can use #mcrGlobalDisplayStorage which will expand the macro then wrap that is double-quotes which also works as you want it to. Your solution is fine, but I was explaining two simpler workarounds since it might make other things you are doing simpler (and it is always good to have more weapons in the armoury ;) ).

Quote
This is only one function, name it as you are comfortable.
I'm afraid that I not be allowed into heaven if I mixed in one name snake_case and camelCase :)
I would like to use the prefix rls, if he is not busy.
Well, since the function is inside your script, then you are the one that is in control of its name. It is always better to take responsibility for anything in scripts you release, since you should expect users to not be running around inside your code altering stuff just to make it work (it should work in all circumstances without them needing to edit it).

As far as tags (or anything else goes) there are sylistic things (such as spon_cheese versus SPON_cheese, since SQF ignores case) and there are functional things (such as cheese vs SPON_cheese). Frankly, the former are just going to cause arguments between people who should know better and the latter are things which will cause your script to crash and burn when used with other people's. RLS_ tag is, in fact, available; just register it so no-one else uses it and we can all be sure your tagged namespace doesn't step on any other developer. Incidentally, the underscore is a requirement, since it removes your namespace globals from those developers who don't bother to even use a tag (your RLSLap == non-tag using developer's rlSlap, but RLS_lap is an actual separated namespace; well, OK, that isn't a perfect argument since you wouldn't be "separate" from people using snake case...but can't be perfect).

Quote
I'm not sure that I understood the idea.
Variables are stored in an array, rather than in a some nameSpace. They need to create and then save their values in the array. A solution could be to use the reception:
Code: [Select]
{
    // pseudo-closure

    _var1 = something;
    _var2 = something;

    waitUtil {

        if( some event ) then {
            call eventHandler
        };
        some event != close
    }
}
But it seriously worsen the response time. Perhaps you have an idea how to solve it?
Well, if you can store the function somewhere, you can store some extra values in the same place, rather than storing them inside the function itself. Can't concentrate hard enough to work out how you'd get around this need for compiled code, but I think any removal of dynamic code is a boon. Not utterly sure it is possible though...

Quote
Hmm. I don't use onLoad handler, but _constructor have access to the current namespace and dialog-namesapce:
onLoad is critical for overlays that are modified (since it is the only way to get the display handle) and can help you ensure that dialogs work better together (since you don't have to wait until the dialog is created and ensure that it wasn't closed before it got opened and you know it is definitely the open you opened and not another one, etc.).

To be picky again, the attached script in your first post should always be updated with the latest version of your script. This is the first one anyone coming to your thread should see and want to download and keeping this as the only version available simplifies things (believe me, people will often not go past your first post, especially if your thread is long and give them two files to download and they'll pick a random one rather than bother reading the name of the file ;)). Personally, I would recommend only putting files in your first post and linking back to that post in later posts if they get updated. Having a date or version number on your files makes a big difference, but people shouldn't have to trawl through the entire thread to find the latest version.
« Last Edit: 04 May 2009, 04:12:50 by Spooner »
[Arma 2] CBA: Community Base Addons
[Arma 1] SPON Core (including links to my other scripts)

Offline Denisko-Redisko

  • Members
  • *
Quote from: Spooner
However, in SQF, strings can be in single quotes which the preprocessor doesn't care about, so you can use 'mcrGlobalDisplayStorage'.
This is indeed a very useful thing, I didn't know this, thanks!

Quote
Well, since the function is inside your script, then you are the one that is in control of its name. It is always better to take responsibility for anything in scripts you release, since you should expect users to not be running around inside your code altering stuff just to make it work (it should work in all circumstances without them needing to edit it).
You are right, quite right. I just take it too lightly. 
Quote
onLoad is critical for overlays that are modified (since it is the only way to get the display handle) and can help you ensure that dialogs work better together (since you don't have to wait until the dialog is created and ensure that it wasn't closed before it got opened and you know it is definitely the open you opened and not another one, etc.).
I doubt that I will be able to make overlays support. I just don't hang on that would be dynamic OnLoad. The main purpose of the script - a single namespace for multiple event handlers.
If I were to avoid global variables (in the script manager overlays), I would do it this way:
Code: [Select]
onLoad = "_this execVM 'overlayController.sqf'";
Perhaps I have not worked with the overlay, but they need handling events?
----
Regarding the rest of your instructions - I will try to take them into account :)
sorry for my english

Offline Spooner

  • Members
  • *
  • Mostly useless
    • Community Base Addons
My "instructions" are a mix of demands (reasonable or otherwise), instructions, suggestions and musings. Take or leave them based on your own needs, but I usually have something useful to say in most of it :whistle: You'll also find I tell you to follow rules that I haven't followed myself in my releases, but this is usually since I implemented it years ago and have learnt a better way since then...

An overlay does not have any reason to generate events, except the onLoad (which is critical!). They will then just show static information (not terribly useful, but can be used, for example, to make the screen covered with blood or something like that) but more usefully, the controls will be updated by a script spawned from the onLoad handler (at least until the display handle becomes null). Since an overlay isn't a dialog, it can't be found using findDisplay, so the only way to query or modify it is to use the handle sent to the onLoad handler. I was indeed thinking that you could get something like this working with a simple line of code in the config (personally, I'm quite happy to have a single call/spawn in the config-side handlers, but having even a line of script in there is indeed a bad design).

I use overlays in this way for SPON Rangefinder and SPON RearView and SPON Status (though I should have used a dialog for this). Overlays should be avoided as much as possible though, since there can only ever be two shown at a time and there isn't a system for managing who has access to them (It was something I often thought of adding to SPON Core, but if I implemented all my ideas for Core, I'd be modding from now until doomsday :D ).
[Arma 2] CBA: Community Base Addons
[Arma 1] SPON Core (including links to my other scripts)

Offline Denisko-Redisko

  • Members
  • *
In Arma2 now have an excellent command: "CONTROL setVariable ARRAY".
I hope this thing much simpler task.
String b:NAMESPACE setVariable ARRAY
String b:CONTROL setVariable ARRAY
String b:OBJECT setVariable ARRAY
String b:GROUP setVariable ARRAY


sorry for my english

Offline Spooner

  • Members
  • *
  • Mostly useless
    • Community Base Addons
That just allows you to store variables on controls, as far as I can tell (you could just set/get vars on objects in A1; in A2 seems to be on controls, displays, groups, locations, namespaces, tasks and teamMembers).

Think there are a lot of dialog extensions though, but not yet got much info.
[Arma 2] CBA: Community Base Addons
[Arma 1] SPON Core (including links to my other scripts)