• 🏆 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!

Slidy

Status
Not open for further replies.
Level 13
Joined
Nov 7, 2014
Messages
571
Slidy - WarCraft-ish sliders

JASS:
library Slidy

//! novjass

Slidy - tries to mimic the GUI widgets called sliders

General notes:
    A slider is a GUI widget (reference: https://en.wikipedia.org/wiki/Slider_(computing)) that
    produces a value within some range.

    A Slidy slider is made of 3 parts: label (texttag, optional), track bar (lightning) and an indicator (unit).
    These parts are customizable, i.e you can set their color, size, etc., but they also have "reasonable" defaults.

Use cases:
    a) debugging some range of values where using chat commands would be impractical/cumbersome
    b) have a lot of fun while doing so =)


API:

// NOTE: color arguments of type integer use the format: AARRGGBB

//
// Create/Destroy
//

// Creates a slider where:
//     min_value is the minimum value of the range
//     max_value is the maximu value of the range
//     (x, y) is the position of the left corner of the slider
//
static method create takes real min_value, real max_value, real x, real y returns thistype

// Destroys the slider.
method destroy takes nothing returns nothing


//
// Customize
//

// Slider
//

// Sets the initial value for the slider. (default: min_value)
method initial_value takes real value returns nothing

// Sets the width of the slider. (default: 512.0)
method width takes real width returns nothing


// Label
//

// Sets the text for the label. (default: "")
method label_text takes string text returns nothing

// Sets the label size of the label. (default: 10.0)
method label_size takes real size returns nothing

// Sets the color for the label. (default: 0xFFFFFFFF, i.e non-transparant, white)
method label_color takes integer color returns nothing

// Rounds the value of the slider to dp number of decimal places which is displayed after the label. (default: 2)
method label_value_decimal_places takes integer dp returns nothing

// The y-offset of the label. (default: 64.0)
method label_y_offset takes real offset returns nothing


// Track bar
//

// Sets the id for the tack bar. (default: "DRAM" (drain mana))
method track_bar_id takes string id returns nothing

// Sets the color of the track bar (default: 0xFFFFFFFF)
method track_bar_color takes integer color returns nothing


// Indicator
//

// Sets the player which can control the indicator. (default: Player(0), Player Red)
method indicator_player takes player p returns nothing

// Sets the unit-id of the indicator. (default: 'hfoo', footman =))
method indicator_id takes integer id returns nothing

// Sets the player color of the indicator. (default: PLAYER_COLOR_RED)
method indicator_player_color takes playercolor p_color returns nothing

// Sets the vertex color of the indicator. (default: 0xFFFFFFFF)
method indicator_vertext_color takes integer color returns nothing

// Sets the movement speed of the indicator. (default: 350.0)
method indicator_speed takes real speed returns nothing

// Sets the scale of the indicator. (default: 1.0)
method indicator_scale takes real scale returns nothing


// Show
//
// Sliders are initially invisible, this method must be called in order for them to appear.
// NOTE: this method must be called after all the customizing methods!
//
method show takes nothing returns nothing

//! endnovjass


globals
    // every 1.0 / X-th of a second gather the values from each Slidy instance
    private constant real GATHER_VALUES_DELAY = 1.0 / 32.0
endglobals


// Maps the value x from the range [a, b] to the range [c, d].
//
public function map takes real x, real a, real b, real c, real d returns real
    local real t = (x - a) / (b - a)
    local real y = c +  t * (d - c)
    return y
endfunction

globals
    public integer alpha = 0
    public integer red = 0
    public integer green = 0
    public integer blue = 0
endglobals
public function get_argb takes integer color returns nothing
    local boolean is_neg = color < 0
    local integer t

    if is_neg then
        set color = color + 0x80000000
    endif

    set t = color / 0x100
    set blue = color - t * 0x100
    set color = t

    set t = color / 0x100
    set green = color - t * 0x100
    set color = t

    set t = color / 0x100
    set red = color - t * 0x100
    set color = t

    set t = color / 0x100
    set alpha = color - t * 0x100
    // set color = t
    if is_neg then
        set alpha = alpha + 0x80
    endif
endfunction

globals
    private constant real FONT_SIZE_TO_HEIGHT = 0.023 / 10.0
endglobals
private function create_label takes string text, real x, real y, real size, integer color returns texttag
    local texttag tt = CreateTextTag()

    call SetTextTagText(tt, text, size * FONT_SIZE_TO_HEIGHT)

    call SetTextTagPos(tt, x, y, /*height-offset:*/ 0.0)

    call get_argb(color)
    call SetTextTagColor(tt, red, green, blue, alpha)

    call SetTextTagVisibility(tt, true)
    call SetTextTagPermanent(tt, false) // must be set to false otherwise the alpha value of the color is ignored

    call SetTextTagLifespan(tt, 123456.0)

    return tt
endfunction

private function create_track_bar takes string id, real x1, real y1, real x2, real y2, integer color returns lightning
    local lightning li = AddLightning(id, false, x1, y1, x2, y2)

    call get_argb(color)
    call SetLightningColor(li, red / 255.0, green / 255.0, blue / 255.0, alpha / 255.0)

    return li
endfunction

private function create_indicator takes player p, integer oid, real x, real y, real speed, real scale, playercolor player_color, integer vertex_color returns unit
    local unit u = CreateUnit(p, oid, x, y, /*facing(left: 180.0, right: 0.0)*/ 0.0)

    call UnitAddAbility(u, 'Avul') // make it invulnerable
    call SetUnitMoveSpeed(u, speed)
    call SetUnitScale(u, scale, scale, scale)
    call SetUnitColor(u, player_color)
    call get_argb(vertex_color)
    call SetUnitVertexColor(u, red, green, blue, alpha)

    return u
endfunction


struct Slidy // is a horizontal slider
    readonly real value
    readonly real min_value
    readonly real max_value
    readonly real m_initial_value

    readonly real min_x
    readonly real mid_x
    readonly real max_x
    readonly real y

    readonly real m_width = 512.0

    readonly texttag label = null
    readonly string m_label_text = ""
    readonly real m_label_size = 10.0
    readonly integer m_label_color = 0xFFFFFFFF
    readonly integer m_label_value_decimal_places = 2 // x.yy
    readonly real m_label_y_offset = 64.0

    readonly lightning track_bar = null
    readonly string m_track_bar_id = "DRAM"
    readonly integer m_track_bar_color = 0xFFFFFFFF

    readonly unit indicator = null
    readonly player m_indicator_player = Player(0)
    readonly integer m_indicator_id = 'hfoo'
    readonly playercolor m_indicator_player_color = PLAYER_COLOR_RED
    readonly integer m_indicator_vertext_color = 0xFFFFFFFF
    readonly real m_indicator_speed = 350.0
    readonly real m_indicator_scale = 1.0


    method initial_value takes real value returns nothing
        if value < this.min_value then
            set value = this.min_value
        elseif value > this.max_value then
            set value = this.max_value
        endif
        set this.m_initial_value = value
    endmethod
    method width takes real width returns nothing
        set this.m_width = width
    endmethod


    method label_text takes string text returns nothing
        set this.m_label_text = text
    endmethod
    method label_size takes real size returns nothing
        set this.m_label_size = size
    endmethod
    method label_color takes integer color returns nothing
        set this.m_label_color = color
    endmethod
    method label_value_decimal_places takes integer dp returns nothing
        set this.m_label_value_decimal_places = dp
    endmethod
    method label_y_offset takes real offset returns nothing
        set this.m_label_y_offset = offset
    endmethod


    method track_bar_id takes string id returns nothing
        set this.m_track_bar_id = id
    endmethod
    method track_bar_color takes integer color returns nothing
        set this.m_track_bar_color = color
    endmethod


    method indicator_player takes player p returns nothing
        set this.m_indicator_player = p
    endmethod
    method indicator_id takes integer id returns nothing
        set this.m_indicator_id = id
    endmethod
    method indicator_player_color takes playercolor p_color returns nothing
        set this.m_indicator_player_color = p_color
    endmethod
    method indicator_vertext_color takes integer color returns nothing
        set this.m_indicator_vertext_color = color
    endmethod
    method indicator_speed takes real speed returns nothing
        set this.m_indicator_speed = speed
    endmethod
    method indicator_scale takes real scale returns nothing
        set this.m_indicator_scale = scale
    endmethod


    private static trigger trg = CreateTrigger()
    private timer tmr = CreateTimer()
    private static thistype array list
    private integer list_pos
    private static integer list_size = 0

    static method gather_values takes nothing returns nothing
        local thistype this
        local integer i
        local string s

        set i = 1
        loop
            exitwhen i > list_size
            set this = list[i]

            set this.value = map(GetUnitX(this.indicator), this.min_x, this.max_x, this.min_value, this.max_value)
            if this.m_label_text != "" then
                set s = this.m_label_text + " (" + R2SW(this.value, 1, this.m_label_value_decimal_places) + ")"
                call SetTextTagText(this.label, s, this.m_label_size * FONT_SIZE_TO_HEIGHT)
            endif

            set i = i + 1
        endloop
    endmethod

    static method restrict_indicator_movement takes nothing returns nothing
        local unit u = GetTriggerUnit()
        local thistype this = GetUnitUserData(u)
        local real ox = GetOrderPointX()
        local integer oid = GetIssuedOrderId()

        if oid != /*patrol*/ 851990 then
            set oid = /*move*/ 851986
        endif

        if ox < this.min_x then
            set ox = this.min_x
        elseif ox > this.max_x then
            set ox = this.max_x
        endif

        call DisableTrigger(trg) // prevent recursion
        call IssuePointOrderById(u, oid, ox, this.y)
        call EnableTrigger(trg)
    endmethod

    static method create takes real min_value, real max_value, real x, real y returns thistype
        local thistype this = allocate()

        set this.min_value = min_value
        set this.max_value = max_value
        set this.m_initial_value = min_value

        set this.min_x = x
        set this.y = y

        return this
    endmethod

    method show takes nothing returns nothing
        local string s
        local real x
        local real y

        set this.mid_x = this.min_x + 0.5 * this.m_width
        set this.max_x = this.min_x + this.m_width

        if this.m_label_text != "" then
            set s = this.m_label_text
            set x = this.mid_x - 0.5 * StringLength(s) * this.label_size
            set y = this.y + this.m_label_y_offset
            set this.label = create_label(s, x, y, this.m_label_size, this.m_label_color)
        endif

        set this.track_bar = create_track_bar(this.m_track_bar_id, this.min_x, this.y, this.max_x, this.y, this.m_track_bar_color)

        set x = map(this.m_initial_value, this.min_value, this.max_value, this.min_x, this.max_x)
        set this.indicator = create_indicator(this.m_indicator_player, this.m_indicator_id, x, this.y, this.m_indicator_speed, this.m_indicator_scale, this.m_indicator_player_color, this.m_indicator_vertext_color)
        call SetUnitUserData(this.indicator, this)
        call TriggerRegisterUnitEvent(trg, this.indicator, EVENT_UNIT_ISSUED_POINT_ORDER)
        call TriggerAddAction(trg, function thistype.restrict_indicator_movement)

        set list_size = list_size + 1
        set list[list_size] = this
        set this.list_pos = list_size
        if list_size == 1 then
            call TimerStart(tmr, GATHER_VALUES_DELAY, true, function thistype.gather_values)
        endif
    endmethod

    method destroy takes nothing returns nothing
        call DestroyTextTag(this.label)
        call DestroyLightning(this.track_bar)
        call RemoveUnit(this.indicator)

        set list[this.list_pos] = list[list_size]
        set list[list_size].list_pos = this.list_pos

        set list_size = list_size - 1
        if list_size <= 0 then
            call PauseTimer(tmr)
        endif

        call this.deallocate()
    endmethod

endstruct

endlibrary
 

Attachments

  • slidy-demo.w3x
    21.2 KB · Views: 59
Last edited:
Status
Not open for further replies.
Top