1. The 30th edition of the Modeling Contest is finally up! The Portable Buildings need your attention, so come along and have a blast!
    Dismiss Notice
  2. The Aftermath has been revealed for the 19th Terraining Contest! Be sure to check out the Results and see what came out of it.
    Dismiss Notice
  3. Melee Mapping Contest #3 - Results are out! Congratulate the winners and check plenty of new 4v4 melee maps designed for this competition!
    Dismiss Notice
  4. The winners of our cinematic soundtrack competition have been decided! Step by the Music Contest #11 - Results to check the entries and congratulate the winners!
    Dismiss Notice

[Snippet] Dialog Wrapper

Discussion in 'JASS Resources' started by PurgeandFire, Aug 24, 2013.

  1. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,418
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    This is a wrapper to ease the creation of dialogs. It does not offer bonus functionality, but it will ease the process of creating dialogs by giving you a clear API with nice documentation. That is the only goal of this snippet.

    I realized shortly after I made this that The_Witcher already submitted a similar system that even has a similar API. His also does more than mine. But mine is cool--it does just the right amount of things. It is kind of like the little bear's soup in goldilocks.

    Anyway, there are multiple ways to approach handling a dialog. Personally, I like consolidating the functions since they usually have similar behavior. Other people may prefer to have a separate callback per dialog button (in which case, use The_Witcher's system).

    Check out the sample code for an example of its usage. Enjoy.

    Code (vJASS):
    library Dialog /* v.1.1.0.0
    **************************************************
    *
    *   A struct wrapper for easy dialog creation.
    *
    **************************************************
    *
    */
     requires Table  /* [url]http://www.hiveworkshop.com/forums/jass-resources-412/snippet-new-table-188084/[/url]
    *
    **************************************************
    *
    *   struct Dialog
    *
    *       static method create() returns thistype
    *          
    *           Creates a new dialog and returns its instance.
    *
    *       method operator title= takes string s
    *
    *           Sets the title message for the dialog.
    *
    *       method addButton( string text, integer hotkey ) returns button
    *
    *           Adds a button to the dialog that reads <text>.
    *           The hotkey serves as a shortcut to press a dialog
    *           button. Example input: 'a', 'b', 512 (esc).
    *
    *       method display( player p, boolean flag )
    *          
    *           Shows/hides a dialog for a particular player.
    *
    *       method displayAll( boolean flag )
    *
    *           Shows/hides a dialog for all players.
    *
    *       method clear()
    *  
    *           Clears a dialog of its message and buttons.
    *
    *       method destroy()
    *
    *           Destroys a dialog and its instance.
    *
    *   -- Event API --
    *
    *       method registerClickEvent( boolexpr b )
    *
    *           Registers when a dialog button is clicked.
    *
    *       static method getClickedDialog() returns Dialog
    *       static method getClickedButton() returns button
    *       static method getPlayer() returns player
    *
    *            Event responses.
    *
    **************************************************
    *
    *   Constants - Credits to DysfunctionaI for the list!
    */

        globals
            constant integer KEY_SPACEBAR          = 32
           
            /* Number Pad */
            constant integer KEY_NUMPAD_0          = 257
            constant integer KEY_NUMPAD_1          = 258
            constant integer KEY_NUMPAD_2          = 259
            constant integer KEY_NUMPAD_3          = 260
            constant integer KEY_NUMPAD_4          = 261
            constant integer KEY_NUMPAD_5          = 262
            constant integer KEY_NUMPAD_6          = 263
            constant integer KEY_NUMPAD_7          = 264
            constant integer KEY_NUMPAD_8          = 265
            constant integer KEY_NUMPAD_9          = 266
            constant integer KEY_NUMPAD_PLUS       = 267
            constant integer KEY_NUMPAD_MINUS      = 268
            constant integer KEY_NUMPAD_ASTERISK   = 269
            constant integer KEY_NUMPAD_SLASH      = 270
            constant integer KEY_NUMPAD_PERIOD     = 271
           
            constant integer KEY_EQUALS            = 272
            constant integer KEY_MINUS             = 273
            constant integer KEY_LEFT_BRACKET      = 274
            constant integer KEY_RIGHT_BRACKET     = 275
            constant integer KEY_BACKSLASH         = 276
            constant integer KEY_SEMICOLON         = 277
            constant integer KEY_APOSTROPHE        = 278
            constant integer KEY_COMMA             = 279
            constant integer KEY_PERIOD            = 280  
            constant integer KEY_SLASH             = 281
            constant integer KEY_ESCAPE            = 512
            constant integer KEY_BACKSPACE         = 514
           
            /* Arrows */
            constant integer KEY_LEFT_ARROW        = 516
            constant integer KEY_UP_ARROW          = 517
            constant integer KEY_RIGHT_ARROW       = 518
            constant integer KEY_DOWN_ARROW        = 519
           
            constant integer KEY_INSERT            = 520
            constant integer KEY_DELETE            = 521
            constant integer KEY_HOME              = 522
            constant integer KEY_END               = 523
            constant integer KEY_PAGE_UP           = 524
            constant integer KEY_PAGE_DOWN         = 525
            constant integer KEY_CAPS_LOCK         = 526
            constant integer KEY_NUM_LOCK          = 527
            constant integer KEY_SCROLL_LOCK       = 528
            constant integer KEY_PAUSE             = 529
           
            /* Function Buttons */
            constant integer KEY_F1                = 768
            constant integer KEY_F2                = 769
            constant integer KEY_F3                = 770
            constant integer KEY_F4                = 771
            constant integer KEY_F5                = 772
            constant integer KEY_F6                = 773
            constant integer KEY_F7                = 774
            constant integer KEY_F8                = 775
            constant integer KEY_F9                = 776
            constant integer KEY_F10               = 777
            constant integer KEY_F11               = 778
            constant integer KEY_F12               = 779
        endglobals
    /*
    **************************************************/


        globals
            private Table instance = 0
        endglobals
       
        private module DialogInit
            private static method onInit takes nothing returns nothing
                set instance = Table.create()
            endmethod
        endmodule

        struct Dialog
            private dialog dg
            private trigger click
            private string msg
           
            static method getClickedDialog takes nothing returns thistype
                return instance[GetHandleId(GetClickedDialog())]
            endmethod
            static method getClickedButton takes nothing returns button
                return GetClickedButton()
            endmethod
            static method getPlayer takes nothing returns player
                return GetTriggerPlayer()
            endmethod
           
            method operator title= takes string text returns nothing
                call DialogSetMessage(this.dg, text)
                set this.msg = text
            endmethod
           
            method addButton takes string text, integer hotkey returns button
                return DialogAddButton(this.dg, text, hotkey)
            endmethod
           
            method display takes player p, boolean flag returns nothing
                call DialogDisplay(p, this.dg, flag)
                call DialogSetMessage(this.dg, this.msg)
            endmethod
            method displayAll takes boolean flag returns nothing
                call DialogDisplay(GetLocalPlayer(), this.dg, flag)
                call DialogSetMessage(this.dg, this.msg)
            endmethod
           
            method clear takes nothing returns nothing
                call DialogClear(this.dg)
                set this.msg = ""
            endmethod
           
            method registerClickEvent takes boolexpr b returns nothing
                if this.click == null then
                    set instance[GetHandleId(this.dg)] = this
                    set this.click = CreateTrigger()
                    call TriggerRegisterDialogEvent(this.click, this.dg)
                endif
                call TriggerAddCondition(this.click, b)
            endmethod
           
            method destroy takes nothing returns nothing
                debug if this.dg == null then
                debug     call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, "[Dialog] Attempted to destroy null dialog.")
                debug endif
               
                if this.click != null then
                    call DestroyTrigger(this.click)
                    call instance.remove(GetHandleId(this.dg))
                    set this.click = null
                endif
               
                call DialogClear(this.dg)
                call DialogDestroy(this.dg)
                set this.dg = null
                call this.deallocate()
            endmethod
       
            static method create takes nothing returns thistype
                local thistype this = thistype.allocate()
                set this.dg = DialogCreate()
                return this
            endmethod
           
            implement DialogInit
        endstruct
       
    endlibrary


    Sample:
    Sample Code
    Code (vJASS):
    scope Testing initializer Init
        // Creates a dialog with buttons for different fruit

        // When you click one, it will make an item that has absolutely
        // nothing to do with the fruit you chose

        globals
            private button array buttons
        endglobals
       
        private function DialogEvent takes nothing returns boolean
            local Dialog  log = Dialog.getClickedDialog()
            local button  b   = Dialog.getClickedButton()
           
            call BJDebugMsg("Clicked: " + I2S(log))
            call BJDebugMsg("Player Name: " + GetPlayerName(GetTriggerPlayer()))
           
            if b == buttons[0] then
                call CreateItem('afac', 0, 0)
            elseif b == buttons[1] then
                call CreateItem('spsh', 0, 0)
            elseif b == buttons[2] then
                call CreateItem('ajen', 0, 0)
            elseif b == buttons[3] then
                call CreateItem('bgst', 0, 0)
            endif
                   
            call log.destroy()
            set b = null
            return false
        endfunction
       
        private function AppendHotkey takes string source, string hotkey returns string
            return "|cffffcc00[" + hotkey + "]|r " + source
        endfunction

        private function DialogTest takes nothing returns nothing
            local Dialog log = Dialog.create()
           
            set log.title  = "Fruit"
            set buttons[0] = log.addButton(AppendHotkey("Apple",     "A"), 'A')
            set buttons[1] = log.addButton(AppendHotkey("Banana",    "B"), 'B')
            set buttons[2] = log.addButton(AppendHotkey("Orange",    "C"), 'C')
            set buttons[3] = log.addButton(AppendHotkey("Hyoi Pear", "D"), 'D')
           
            call log.displayAll(true)
            call log.registerClickEvent(Condition(function DialogEvent))
        endfunction

        private function Init takes nothing returns nothing
            call TimerStart(CreateTimer(), 0, false, function DialogTest)
        endfunction
    endscope
     
    Last edited: Mar 15, 2014
  2. mckill2009

    mckill2009

    Joined:
    Mar 10, 2009
    Messages:
    4,696
    Resources:
    34
    Maps:
    5
    Spells:
    27
    JASS:
    2
    Resources:
    34
    This is like the wrapper I made in my maps, but no plans to post it XD...anyway why dont you create the trigger in the 'create' method instead of putting it separate?...
     
  3. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,418
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Thanks for the feedback mckill.

    Maybe I'll move it. I like the explicitness at the moment. But I agree, it makes sense to put it in the create method. I suppose no one would use a dialog without registering the events. xD
     
  4. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,543
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    I like it but I really think Alloc and ErrorMessage should be optional and the members db and click should be accessible (with better names).
     
  5. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,149
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    If Alloc was optional, he'd be writing identical code to Alloc :\. I don't personally see the point to writing identical code when that code already exists in a resource :p. Alloc also supports things like leak checking.

    The same goes for ErrorMessage. It kind of sets a style that was influenced by mag's tutorial on error messages.

    Writing special internal resources for a resource isn't a very good practice ^)^


    but w/e, I'm a noob, so don't mind me : )


    My only comment is: why you no use event? : (. You are missing some functionality as a result, like registering triggers :\. Please add a register trigger function if you are very averse to using Event ;). Ofc, if you used Event, it'd all be written and the API would be provided ^_^.

    edit
    I'm not sure if this would work or not, by try using private keyword allocate/deallocate to hide the methods from Alloc. You should probably keep the leak checking API open tho. If that wouldn't work, you should try putting it in a private struct and using that struct purely for instancing ;). This is just for proper encapsulation ofc.
     
  6. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,543
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    lol Alloc can be replaced by with the standard allocation, and error message can be replaced with displaying a message, so your points are invalid.

    All I said was make them optional?
     
  7. Nestharus

    Nestharus

    Joined:
    Jul 10, 2007
    Messages:
    6,149
    Resources:
    8
    Spells:
    3
    Tutorials:
    4
    JASS:
    1
    Resources:
    8
    he'd be losing the leak checking then for Alloc ;\

    As for error messages, please see this =)

    http://www.hiveworkshop.com/forums/miscellaneous-tutorials-456/error-messages-235148/


    otherwise, let it burn, muahahaha
     
  8. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,543
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
  9. chobibo

    chobibo

    Joined:
    Sep 24, 2005
    Messages:
    2,692
    Resources:
    0
    Resources:
    0
    Would be nice if you could add a list of integer hotkeys too, maybe on the main post or as a comment.
     
  10. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,418
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    That should be doable. I think the one I use in my map doesn't use either of them.

    And I guess you mean the dialog (dg), right (instead of db)?

    For most of them, you can just use
    'A', 'B', 'C', 'D'
    , etc. But with this thread here, maybe there are others. We'll see. :thumbs_up:
     
    Last edited: Dec 20, 2013
  11. Anachron

    Anachron

    Joined:
    Sep 9, 2007
    Messages:
    6,167
    Resources:
    66
    Icons:
    49
    Packs:
    2
    Tools:
    1
    Maps:
    3
    Spells:
    9
    Tutorials:
    1
    JASS:
    1
    Resources:
    66
    I agree with TriggerHappy, please make Alloc and ErrorMessage optional.
     
  12. edo494

    edo494

    Joined:
    Apr 16, 2012
    Messages:
    3,855
    Resources:
    5
    Spells:
    1
    JASS:
    4
    Resources:
    5
    the link doesnt link to anything, the link is the first quote from TriggerHappy :D
     
  13. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,418
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Oops lol. I guess I thought I copy and pasted the link, but it didn't. Fixed. :p
     
  14. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,543
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    Gonna update this?

    One feature I would like is to have constants representing unusual hotkeys (that can't be defined through raw codes) like escape, home, end ect...
     
  15. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,418
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    Done. Updated to 1.1.0.0. Special thanks to DysfunctionaI and his awesome list of hotkeys:
    http://www.hiveworkshop.com/forums/miscellaneous-tutorials-456/extended-hotkeys-spacebar-etc-245278/

    I added those hotkeys and I removed some unnecessary error checking, and removed the dependency on Alloc and ErrorMessage.

    Shift doesn't seem to work, but I tested all the other ones and they all work. I can't guarantee what will happen in multiplayer if you use a key that is already bound to something (because dialogs have different behavior in multiplayer-they don't pause the game), so idk whether it will press the dialog button or do what it is bound to (or if it does both). But they work fine in single player without any issues.
     
  16. TriggerHappy

    TriggerHappy

    Code Moderator

    Joined:
    Jun 23, 2007
    Messages:
    3,543
    Resources:
    22
    Spells:
    11
    Tutorials:
    2
    JASS:
    9
    Resources:
    22
    Great. Approved :grin:
     
  17. sethmachine

    sethmachine

    Joined:
    Aug 7, 2013
    Messages:
    1,318
    Resources:
    0
    Resources:
    0
    One of the great parts of this library is the globals you provide for the key values, which of course you get some credit for for compiling them into a resource, but many thanks to DysfuncionaI's hard work at finding these values.

    This definitely does well at doing one well-defined task well, namely simplifying the interface / API to create dialogs in WC3 via JASS.

    The other alternative, Bannar's, complements this one I think, it's a lot heavier and does a lot more stuff, going so far as to create a wrapper for the
    button
    native.

    Thanks again for this resource!
     
  18. Bannar

    Bannar

    Joined:
    Mar 19, 2008
    Messages:
    3,086
    Resources:
    20
    Spells:
    5
    Tutorials:
    1
    JASS:
    14
    Resources:
    20
    My resource is not meant to deprecate PnF' wrapper. My intention was to extend functionality of dialog and button natives because they clearly lack some. In op I've posted why/when you should use it. It it still usefull as simple wrapper, but in situation when at least you are playing with connect methods to link multiple dialog pages e.g to create some kind of book/questions and answers template.

    In short: you want simple, more convenient way of dealing with dialogs: you use this one. However, when you want some additional features and easy event handling, my snippet should be perfect for you.

    I've not added hotkeys for reason similar to order ids. In my opinion hotkeys/orders are usefull in many cases, thus its better to just have standalone library for such ^)^
     
  19. PurgeandFire

    PurgeandFire

    Code Moderator

    Joined:
    Nov 11, 2006
    Messages:
    7,418
    Resources:
    18
    Icons:
    1
    Spells:
    4
    Tutorials:
    9
    JASS:
    4
    Resources:
    18
    @sethmachine: Thanks for the kind words. :)

    @Bannar: Yep. This is purely a wrapper, so it doesn't offer any special functionality. Yours is geared for pages and button control.

    As for hotkeys, I considered having it separate, but I don't think any other natives use those integers. You can use them in the object editor though. I included them in this script partially as documentation/a reference. If anyone needs the codes in the future, they can refer back to this. :)
     
  20. pOke

    pOke

    Joined:
    Mar 24, 2013
    Messages:
    1,067
    Resources:
    1
    Maps:
    1
    Resources:
    1
    So I'm still rather new to vJass so go easy :p.

    I'm trying to use this to let players select their game mode preferences.

    However, after a timeout I want to destroy/hide all the dialogs that have yet to be clicked. My issue is that I'm not entirely sure how to reference them.

    Here's my dialog code just in case it's somehow pertinent.


    Code (vJASS):

    library DialogSetUp requires MessageAll

        globals
            private button array buttons
            integer array voteRound
            integer array voteTime
            integer array votePower
            integer array voteType
            boolean tooLate = false
        endglobals
       
       
    private function AppendHotkey takes string source, string hotkey returns string
            return "|cffffcc00[" + hotkey + "]|r " + source
    endfunction
       
    private function TypeButton takes nothing returns boolean
            local Dialog  log = Dialog.getClickedDialog()
            local button  b   = Dialog.getClickedButton()
            local player p = Dialog.getPlayer()
            local string s
           
            if b == buttons[0] then
                set s = "Solo"
                set voteType[0] = voteType[0] + 1
            elseif b == buttons[1] then
                set s = "Teams"
                set voteType[1] = voteType[1] + 1
            endif
           
            call Message(GetRealName(p) + " voted for " + s)
            call log.destroy()
            set b = null
            set p = null
            return false
    endfunction        
       
    private function TypeDialog takes player p returns nothing
            local Dialog log = Dialog.create()
           
            set log.title  = "Game Type?"
            set buttons[0] = log.addButton(AppendHotkey("Standard (Solo)",     "A"), 'A')
            set buttons[1] = log.addButton(AppendHotkey("Reds versus Blues (Teams)",    "B"), 'B')
           
            call log.display(p, true)
            call log.registerClickEvent(Condition(function TypeButton))
    endfunction    

    private function PowerUpButton takes nothing returns boolean
            local Dialog  log = Dialog.getClickedDialog()
            local button  b   = Dialog.getClickedButton()
            local player p = Dialog.getPlayer()
            local string s
           
            if b == buttons[0] then
                set s = "Enable"
                set votePower[0] = votePower[0] + 1
            elseif b == buttons[1] then
                set s = "Disable"
                set votePower[1] = votePower[1] + 1
            endif
           
            call Message(GetRealName(p) + " voted to " + s + " Power-Ups")
            call log.destroy()
            set b = null
            call TypeDialog(p)
            set p = null
            return false
    endfunction  
       
    private function PowerUpDialog takes player p returns nothing
            local Dialog log = Dialog.create()
           
            set log.title  = "Power-Ups?"
            set buttons[0] = log.addButton(AppendHotkey("Enable",     "A"), 'A')
            set buttons[1] = log.addButton(AppendHotkey("Disable",    "B"), 'B')
           
            call log.display(p, true)
            call log.registerClickEvent(Condition(function PowerUpButton))
    endfunction      
       
    private function TimeButton takes nothing returns boolean
            local Dialog  log = Dialog.getClickedDialog()
            local button  b   = Dialog.getClickedButton()
            local player p = Dialog.getPlayer()
            local string s
           
            if b == buttons[0] then
                set s = "3"
                set voteTime[0] = voteTime[0] + 1
            elseif b == buttons[1] then
                set s = "5"
                set voteTime[1] = voteTime[1] + 1
            elseif b == buttons[2] then
                set s = "7"
                set voteTime[2] = voteTime[2] + 1
            elseif b == buttons[3] then
                set s = "10"
                set voteTime[3] = voteTime[3] + 1
            endif
           
            call Message(GetRealName(p) + " voted for " + s + " minutes per round")
            call log.destroy()
            set b = null
            call PowerUpDialog(p)
            set p = null
            return false
    endfunction      
       
     private function TimePerRoundDialog takes player p returns nothing
            local Dialog log = Dialog.create()
           
            set log.title  = "Time per Round?"
            set buttons[0] = log.addButton(AppendHotkey("3 minutes",     "A"), 'A')
            set buttons[1] = log.addButton(AppendHotkey("5 minutes",    "B"), 'B')
            set buttons[2] = log.addButton(AppendHotkey("7 minutes",    "C"), 'C')
            set buttons[3] = log.addButton(AppendHotkey("10 minutes", "D"), 'D')
           
            call log.display(p, true)
            call log.registerClickEvent(Condition(function TimeButton))
    endfunction  
       
    private function RoundsButton takes nothing returns boolean
            local Dialog  log = Dialog.getClickedDialog()
            local button  b   = Dialog.getClickedButton()
            local player p = Dialog.getPlayer()
            local string s
            local string s2
           
            if b == buttons[0] then
                set s = "1"
                set s2 = " round"
                set voteRound[0] = voteRound[0] + 1
            elseif b == buttons[1] then
                set s = "3"
                set s2 = " rounds"
                set voteRound[1] = voteRound[1] + 1
            elseif b == buttons[2] then
                set s = "5"
                set s2 = " rounds"
                set voteRound[2] = voteRound[2] + 1
            elseif b == buttons[3] then
                set s = "10"
                set s2 = " rounds"
                set voteRound[3] = voteRound[3] + 1
            elseif b == buttons[4] then
                set s = "100"
                set s2 = " rounds"
                set voteRound[4] = voteRound[4] + 1
            endif
           
            call Message(GetRealName(p) + " voted for " + s + s2)
            call log.destroy()
            set b = null
            call TimePerRoundDialog(p)
            set p = null
            return false
    endfunction    
       
    private function RoundsDialog takes nothing returns nothing
            local Dialog log = Dialog.create()
           
            set log.title  = "Number of Rounds?"
            set buttons[0] = log.addButton(AppendHotkey("1",     "A"), 'A')
            set buttons[1] = log.addButton(AppendHotkey("3",    "B"), 'B')
            set buttons[2] = log.addButton(AppendHotkey("5",    "C"), 'C')
            set buttons[3] = log.addButton(AppendHotkey("10", "D"), 'D')
            set buttons[4] = log.addButton(AppendHotkey("100", "E"), 'E')
           
            call log.displayAll(true)
            call log.registerClickEvent(Condition(function RoundsButton))
    endfunction

     function CreateDialog takes nothing returns nothing
             call TimerStart(CreateTimer(), 0, false, function RoundsDialog)
    endfunction  
       
    endlibrary