• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[vJASS] Dlist - tries to simplify working with Dialogs

Level 13
Joined
Nov 7, 2014
Messages
571
Dlist - tries to simplify the creation of static and dynamic dialogs (D[ialog]list)

JASS:
//! novjass

Dlist - tries to simplify the creation of static and dynamic dialogs (D[ialog]list)

Credits/References:
    cohadar (Dialog System): http://www.wc3c.net/showthread.php?t=97425
    PurgeandFire (Dialog Wrapper): http://www.hiveworkshop.com/threads/snippet-dialog-wrapper.240003/
    Toadcop (TCMDialogs): http://tcx.xgm.guru/downloads#tcx
    DysfunctionaI (Extended Hotkeys): http://www.hiveworkshop.com/threads/extended-hotkeys-spacebar-etc.245278/


API:

//
// Dlist methods
//

// creates an uninitialized Dlist instance
static method uninitialized takes nothing returns Dlist

// enables reinitialization of a Dlist (must be called when the Dlist is dynamic)
method reinit takes nothing returns Dlist

// begins the initialization of an uninitialized or reinit-ed Dlist
method begin_init takes nothing returns nothing

// ends the initialization of the Dlist
method end_init takes nothing returns nothing

// sets the tile for the Dlist
method title takes string title returns Dlist

// sets the on_click handler for the dlist
// NOTE: the type of the argument is string, i.e you have to pass the name of a function,
// the function cannot take nor return any arguments
method on_click takes string on_click returns Dlist

// sets the default color for Dlist-items when they are enabled
method enabled_color takes string enabled_color returns Dlist

// sets the default color for Dlist-items when they are disabled
method disabled_color takes string disabled_color returns Dlist

// sets the default hotkey color for Dlist-items
method hotkey_color takes string hotkey_color returns Dlist

// sets the enabled_color, disabled_color and hotkey_color to that of the other Dlist instance
method colors_from takes Dlist other returns Dlist

// shows the Dlist to a player
method show takes player p returns nothing

// shows the Dlist to all players
method show_all takes nothing returns nothing

// hides the Dlist for player p
method hide takes player p returns nothing

// hides the Dlist for all players
method hide_all takes nothing returns nothing

// adds an Dlist-item to the Dlist
method Item takes string text, integer hotkey returns Dlist//-item


//
// Dlist-item methods
//

// the colors passed to enabled_color, disabled_color and hotkey_color are not used for this Dlist-item
method no_default_colors takes boolean no_default_colors returns Dlist//-item

// disabled/enables the Dlist-item (Dlist-items are enabled by default)
method disabled takes boolean disabled returns Dlist//-item

// when the Dlist-item is clicked it shows the target Dlist to the player that clicked the Dlist-item
method on_click_show takes Dlist target returns Dlist//-item

// sets the m_idata field of the Dlist-item to idata
method idata takes integer idata returns Dlist//-item

// sets the m_rdata field of the Dlist-item to rdata
method rdata takes real rdata returns Dlist//-item

// sets the m_sdata field of the Dlist-item to sdata
method sdata takes string sdata returns Dlist//-item

//! endnovjass

library Dlist

// Gets rid of the ampersand (&) (if there is one), colorizes the character after the ampersand (if there is one)
// with color_amp, the rest of the string is colorized with color_other.
//
private function apply_colors takes string s, string color_amp, string color_other returns string
    local integer a
    local integer b
    local string c
    local string result = ""
    local string sub
    local string c_amp
    local string c_other

    set c_amp = ""
    if color_amp != "" then
        set c_amp = "|cff" + color_amp
    endif
    set c_other = ""
    if color_other != "" then
        set c_other = "|cff" + color_other
    endif

    set a = 0
    set b = 0
    loop
        set c = SubString(s, b, b + 1)

        if c == "" then
            // we reached the end of the string
            set result = result + c_other + SubString(s, a, b) + "|r"
            exitwhen true

        elseif c == "&" then
            set c = SubString(s, b + 1, b + 2)

            // trailing ampersand
            if c == "" then
                set result = result + c_other + SubString(s, a, b) + "|r"
                exitwhen true

            // double ampersand means a literal ampersand
            elseif c == "&" then
                set sub = SubString(s, a, b + 1)
                set result = result + c_other + sub + "|r"

                set b = b + 2
                set a = b

            // an ampersand followed by a character, colorizes that character with color_amp
            else
                // if the string begins with an ampersand don't add a color to the empty string
                if b != 0 then
                    set sub = SubString(s, a, b)
                    set result = result + c_other + sub + "|r"
                endif

                set sub = SubString(s, b + 1, b + 2)
                set result = result + c_amp + sub + "|r"

                set b = b + 2
                set a = b
            endif

        else
            set b = b + 1
        endif
    endloop

    return result
endfunction

struct Dlist extends array
    private static integer instance_count = 0
    private static thistype fl_head = 0
    private thistype fl_next

    private thistype dl_tail
    private thistype dl_next

    private static thistype array map
    readonly static thistype clicked_dlist
    readonly static thistype clicked_item
    readonly static player clicking_player

     // fields that are used when the instance acts as a list/dialog
     //
    private dialog d
    private integer next_btn_pos
    readonly string m_title
    readonly string m_on_click
    readonly string m_enabled_color
    readonly string m_disabled_color
    readonly string m_hotkey_color


     // fields that are used when the instance acts as a list-item/button
     //
    private button it
    private string text
    readonly integer hotkey
    readonly integer pos
    readonly boolean m_no_default_colors
    readonly boolean m_disabled
    readonly thistype m_on_click_show
    readonly integer m_idata
    readonly real m_rdata
    readonly string m_sdata


    private static method allocate takes nothing returns thistype
        local thistype this

        if fl_head != 0 then
            set this = fl_head
            set fl_head = fl_head.fl_next

        else
            set instance_count = instance_count + 1
            set this = instance_count
        endif

        set this.fl_next = 0
        return this
    endmethod

    private method deallocate takes nothing returns nothing
        set this.fl_next = fl_head
        set fl_head = this
    endmethod

    private static method dispatch takes nothing returns nothing
        local button it = GetClickedButton()
        local thistype dl_it
        local thistype dl

        set clicked_dlist = map[GetHandleId(GetClickedDialog()) - 0x00100000]
        set clicking_player = GetTriggerPlayer()

        set dl_it = clicked_dlist.dl_next
        loop
            exitwhen dl_it == 0

            if dl_it.it == it then
                set clicked_dlist.clicked_item = dl_it

                if dl_it.m_on_click_show != 0 then
                    set dl = dl_it.m_on_click_show
                    call DialogSetMessage(dl.d, dl.m_title)
                    call DialogDisplay(clicking_player, dl.d, true)
                    exitwhen true

                elseif dl_it.m_disabled then
                    set dl = clicked_dlist
                    call DialogSetMessage(dl.d, dl.m_title)
                    call DialogDisplay(clicking_player, dl.d, true)
                    exitwhen true

                else
                    if clicked_dlist.m_on_click != "" then
                        call ExecuteFunc(clicked_dlist.m_on_click)
                    endif
                    exitwhen true
                endif
            endif

            set dl_it = dl_it.dl_next
        endloop

        set it = null
    endmethod

     // methods that are used when the instance acts as a list/dialog
     //
    static method uninitialized takes nothing returns thistype
        local thistype this = allocate()
        local trigger t

        set this.dl_tail = this

        set this.d = DialogCreate()
        set t = CreateTrigger()
        call TriggerRegisterDialogEvent(t, this.d)
        call TriggerAddAction(t, function thistype.dispatch)

        set map[GetHandleId(this.d) - 0x00100000] = this

        return this
    endmethod

    method reinit takes nothing returns thistype
        local Dlist dl_it
        local Dlist next

        call DialogClear(this.d)

        set this.dl_tail = this

        set dl_it = this.dl_next
        loop
            exitwhen dl_it == 0

            set dl_it.it = null
            set next = dl_it.dl_next
            set dl_it.dl_next = 0
            call dl_it.deallocate()

            set dl_it = next
        endloop

        return this
    endmethod

    method begin_init takes nothing returns nothing
        set this.m_title = ""
        set this.m_on_click = ""
    endmethod

    method end_init takes nothing returns nothing
        local thistype dl_it
        local string text

        set dl_it = this.dl_next
        loop
            exitwhen dl_it == 0

            if dl_it.m_no_default_colors then
                set text = dl_it.text

            elseif dl_it.m_disabled then
                set text = apply_colors(dl_it.text, this.m_disabled_color, this.m_disabled_color)

            else // if not dl_it.m_disabled
                set text = apply_colors(dl_it.text, this.m_hotkey_color, this.m_enabled_color)
            endif

            set dl_it.it = DialogAddButton(this.d, text, dl_it.hotkey)

            set dl_it = dl_it.dl_next
        endloop
    endmethod

    method title takes string title returns thistype
        set this.m_title = title
        return this
    endmethod

    method on_click takes string on_click returns thistype
        set this.m_on_click = on_click
        return this
    endmethod

    method enabled_color takes string enabled_color returns thistype
        set this.m_enabled_color = enabled_color
        return this
    endmethod
    method disabled_color takes string disabled_color returns thistype
        set this.m_disabled_color = disabled_color
        return this
    endmethod
    method hotkey_color takes string hotkey_color returns thistype
        set this.m_hotkey_color = hotkey_color
        return this
    endmethod
    method colors_from takes thistype other returns thistype
        set this.m_enabled_color = other.m_enabled_color
        set this.m_disabled_color = other.m_disabled_color
        set this.m_hotkey_color = other.m_hotkey_color
        return this
    endmethod

    method show takes player p returns nothing
        // when a button of a dialog A is clicked and it displays another dialog B
        // the title of dialog A is set to "", that's why we need to reset it every time
        // before we show a dialog to a player
        //
        call DialogSetMessage(this.d, this.m_title)
        call DialogDisplay(p, this.d, true)
    endmethod
    method show_all takes nothing returns nothing
        call DialogSetMessage(this.d, this.m_title)
        call DialogDisplay(GetLocalPlayer(), this.d, true)
    endmethod

    method hide takes player p returns nothing
        call DialogDisplay(p, this.d, false)
    endmethod
    method hide_all takes nothing returns nothing
        call DialogDisplay(GetLocalPlayer(), this.d, false)
    endmethod


    // methods that are used when the instance acts as a list-item/button
    //
    method Item takes string text, integer hotkey returns thistype
        local thistype dl_it = allocate()

        set this.dl_tail.dl_next = dl_it
        set this.dl_tail = dl_it
        set dl_it.dl_next = 0

        set dl_it.text = text
        set dl_it.hotkey = hotkey

        set this.next_btn_pos = this.next_btn_pos + 1
        set dl_it.pos = this.next_btn_pos

        set dl_it.m_no_default_colors = false
        set dl_it.m_disabled = false
        set dl_it.m_on_click_show = 0

        return dl_it
    endmethod

    method no_default_colors takes boolean no_default_colors returns thistype
        set this.m_no_default_colors = no_default_colors
        return this
    endmethod

    method disabled takes boolean disabled returns thistype
        set this.m_disabled = disabled
        return this
    endmethod

    method on_click_show takes thistype target returns thistype
        set this.m_on_click_show = target
        return this
    endmethod

    method idata takes integer idata returns thistype
        set this.m_idata = idata
        return this
    endmethod
    method rdata takes real rdata returns thistype
        set this.m_rdata = rdata
        return this
    endmethod
    method sdata takes string sdata returns thistype
        set this.m_sdata = sdata
        return this
    endmethod

endstruct

endlibrary
 

Attachments

  • dlist-demo.w3x
    22.6 KB · Views: 94
Can there be a destroy/flush method?

Could you add a note to do all config only between init functions?

Using table would be a more white solution over map[GetHandleId(GetClickedDialog()) - 0x00100000].

set dl_it.it = DialogAddButton(this.d, text, dl_it.hotkey)
^dl_it could be attached to the button here, in method end_init.

I would personaly probably prefer to use code parameter instead of string for function execution (trigger solution), but maybe your preference.

Dlist seems a bit generic. Could you write Dialog out?

If you care for these:
JASS:
method show_all takes nothing returns nothing
    call DialogSetMessage(this.d, this.m_title)
    call DialogDisplay(GetLocalPlayer(), this.d, true)
endmethod
->
JASS:
method show_all takes nothing returns nothing
    call show(GetLocalPlayer())
endmethod
and
JASS:
method hide_all takes nothing returns nothing
    call DialogDisplay(GetLocalPlayer(), this.d, false)
endmethod
->
JASS:
method hide_all takes nothing returns nothing
    call hide(GetLocalPlayer())
endmethod

I was honestly a bit confused how to make hotkeys in other color in the button, until I saw the "&" in your example, and then looked the the code.
It could be pointed a bit better, maybe from the new Item function already. This functionality:
JASS:
// Gets rid of the ampersand (&) (if there is one), colorizes the character after the ampersand (if there is one)
// with color_amp, the rest of the string is colorized with color_other.
//
private function apply_colors takes string s, string color_amp, string color_other returns string

Some general name suggestions:

method on_click takes string on_click returns Dlist
^sounds like an event. For functions that do something, mostly an active verb is more intuitive.
method register_onClick takes string on_click returns Dlist
/
method onClick_register takes string on_click returns Dlist

Same for the "colors_from" and some other methods.

method Item
^This only method starts with an upper case. ^^

edit:

Quite good resource, but for now sending to GY due to lacking response Could be approved after update.
 
Last edited:
Top