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

UI Utils (one-stop solution for UI business)

Status
Not open for further replies.

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
The system is already released at spell section. Find it here:
UI Utils Download


Introducing UI Utils, full potential of the new UI natives right at your fingertips!

Key features:
  1. Provides bunch of frame templates. It also includes a TOC file that references to all available internal fdf files.
  2. Nested parent-child system: property inheritance by child components.
  3. Pixel as basic measurement for frame size and position coordinate. Completely compatible with image editing programs such as Photoshop, etc.
  4. Provides full screen mode: hides original frames.
  5. Automatic create context handling: you don't even need to know what it is.
  6. Automatic resolution change adaptation: prevents UI from going out of screen.
  7. More to come...
Special credits given to @Tasyen for his UI tutorials!

Requires: [Snippet] LinkedListModule

Known issues (subject to improve):
  • Changing full screen mode during gameplay (not map init) might result in crash
  • Full screen mode removes a lot of important frames such as: error message, chat message, tooltips, etc.
  • Text size is currently not affected by local scale
  • Handling text isn't very intuitive right now as there's no way to get the text's actual width (at least not yet)
  • Template bar border isn't showing
  • Currently only supports standard aspect ratios (4:3, 16:9, & 16:10)
  • Little to non-existent documentation

Code WIP
JASS:
library UIUtils

    globals
        // Screen resolution used to design UI
        public constant real SCREEN_WIDTH  = 1360.0
        public constant real SCREEN_HEIGHT = 768.0
 
        // If true, all frames will be automatically adjusted on resolution change
        private constant boolean AUTOMATIC_ADJUSTMENT = true
        private constant real RESOLUTION_CHECK_INTERVAL = 0.1
 
        // If true, component's properties will be retained when it changes parent
        private constant boolean PERSISTENT_CHILD_PROPERTIES = true
    endglobals
 
    globals
        private real WidthFactor  = 1.0
        private real HeightFactor = 1.0
    endglobals

    private struct AllComponents extends array

        implement LinkedList

        static method add takes thistype this returns nothing
            call base.insertNode(this)
        endmethod

        static method remove takes thistype this returns nothing
            call removeNode()
        endmethod

    endstruct

    private module INIT
        private static method onInit takes nothing returns nothing

            local integer i

            call RefreshResolution()

            set FrameGameUI     = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
            set FrameWorld         = BlzGetOriginFrame(ORIGIN_FRAME_WORLD_FRAME, 0)
            set FrameHeroBar    = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BAR, 0)
            set FramePortrait    = BlzGetOriginFrame(ORIGIN_FRAME_PORTRAIT, 0)
            set FrameMinimap    = BlzGetOriginFrame(ORIGIN_FRAME_MINIMAP, 0)
            set FrameTooltip    = BlzGetOriginFrame(ORIGIN_FRAME_TOOLTIP, 0)
            set FrameUberTooltip = BlzGetOriginFrame(ORIGIN_FRAME_UBERTOOLTIP, 0)
            set FrameChatMsg    = BlzGetOriginFrame(ORIGIN_FRAME_CHAT_MSG, 0)
            set FrameUnitMsg    = BlzGetOriginFrame(ORIGIN_FRAME_UNIT_MSG, 0)
            set FrameTopMsg        = BlzGetOriginFrame(ORIGIN_FRAME_TOP_MSG, 0)

            set i = 0
            loop
                exitwhen i > 11
                set FrameHeroButton[i]       = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, i)
                set FrameHeroHPBar[i]       = BlzGetOriginFrame(ORIGIN_FRAME_HERO_HP_BAR, i)
                set FrameHeroMPBar[i]       = BlzGetOriginFrame(ORIGIN_FRAME_HERO_MANA_BAR, i)
                set FrameHeroIndicator[i] = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, i)
                set FrameItemButton[i]       = BlzGetOriginFrame(ORIGIN_FRAME_ITEM_BUTTON, i)
                set FrameCommandButton[i] = BlzGetOriginFrame(ORIGIN_FRAME_COMMAND_BUTTON, i)
                set FrameSystemButton[i]  = BlzGetOriginFrame(ORIGIN_FRAME_SYSTEM_BUTTON, i)
                set FrameMinimapButton[i] = BlzGetOriginFrame(ORIGIN_FRAME_MINIMAP_BUTTON, i)
                set i = i + 1
            endloop
 
            set FrameConsoleUI = BlzGetFrameByName("ConsoleUI", 0)
 
            static if AUTOMATIC_ADJUSTMENT then
                call TimerStart(CreateTimer(), RESOLUTION_CHECK_INTERVAL, true, function thistype.CheckResolution)
            endif

        endmethod
    endmodule

    struct UIUtils extends array

        readonly static integer ResolutionWidth  = 0
        readonly static integer ResolutionHeight = 0
        readonly static integer AspectWidth  = 0
        readonly static integer AspectHeight = 0
 
        readonly static boolean IsFullScreen = false
        readonly static boolean CommandButtonsVisible = true

        private static real RefAspectWorld  = 5.0
        private static real RefAspectWidth  = 4.0
        private static real RefAspectHeight = 3.0
        private static real RefExtraWidth   = 0.0

        readonly static real MinFrameX = 0.0
        readonly static real MaxFrameX = 0.0
        readonly static real DPIMinX = 0.0
        readonly static real DPIMaxX = 0.0
        readonly static real DPIMinY = 0.0
        readonly static real DPIMaxY = RefAspectHeight/RefAspectWorld
        private  static real PxToDPI = 0.0

        readonly static framehandle         FrameGameUI
        readonly static framehandle         FrameWorld
        readonly static framehandle         FrameHeroBar
        readonly static framehandle array     FrameHeroButton
        readonly static framehandle array     FrameHeroHPBar
        readonly static framehandle array     FrameHeroMPBar
        readonly static framehandle array     FrameHeroIndicator
        readonly static framehandle array     FrameItemButton
        readonly static framehandle array     FrameCommandButton
        readonly static framehandle array     FrameSystemButton
        readonly static framehandle         FramePortrait
        readonly static framehandle         FrameMinimap
        readonly static framehandle array     FrameMinimapButton
        readonly static framehandle         FrameTooltip
        readonly static framehandle         FrameUberTooltip
        readonly static framehandle         FrameChatMsg
        readonly static framehandle         FrameUnitMsg
        readonly static framehandle         FrameTopMsg
 
        readonly static framehandle         FrameConsoleUI

        private static method CalcAspectRatio takes real w, real h, real aw returns integer
            return R2I(aw*h/w+0.5)
        endmethod

        static method XCoordToDPI takes real x returns real
            return x*PxToDPI/RefAspectWidth+DPIMinX
        endmethod

        static method YCoordToDPI takes real y returns real
            return y*PxToDPI/RefAspectWidth
        endmethod

        static method SizeToDPI takes real r returns real
            return r*PxToDPI/RefAspectWidth
        endmethod

        static method DPIToXCoord takes real dpi returns real
            return (dpi-DPIMinX)*RefAspectWidth/PxToDPI
        endmethod

        static method DPIToYCoord takes real dpi returns real
            return dpi*RefAspectWidth/PxToDPI
        endmethod

        static method DPIToSize takes real dpi returns real
            return dpi*RefAspectWidth/PxToDPI
        endmethod

        static method RefreshResolution takes nothing returns nothing
 
            local AllComponents node

            set ResolutionWidth  = BlzGetLocalClientWidth()
            set ResolutionHeight = BlzGetLocalClientHeight()
            set WidthFactor  = ResolutionWidth/SCREEN_WIDTH
            set HeightFactor = ResolutionHeight/SCREEN_HEIGHT
            if CalcAspectRatio(ResolutionWidth, ResolutionHeight, 4) == 3 then
                set PxToDPI = RefAspectWidth/(ResolutionWidth/1024.0*1280.0)
                set AspectWidth   = 4
                set AspectHeight  = 3
                set RefExtraWidth = 0.0
            elseif CalcAspectRatio(ResolutionWidth, ResolutionHeight, 16) == 9 then
                set PxToDPI = RefAspectWidth/(ResolutionWidth/1360.0*1280.0)
                set AspectWidth   = 16
                set AspectHeight  = 9
                set RefExtraWidth = 0.525
            elseif CalcAspectRatio(ResolutionWidth, ResolutionHeight, 16) == 10 then
                set PxToDPI = RefAspectWidth/(ResolutionWidth/1280.0*1280.0)
                set AspectWidth   = 16
                set AspectHeight  = 10
                set RefExtraWidth = 0.4
            endif
            set MinFrameX = RefExtraWidth*320.0
            set MaxFrameX = ResolutionWidth-MinFrameX
            set DPIMinX   = -(RefExtraWidth/RefAspectWidth)
            set DPIMaxX   = RefAspectWidth/RefAspectWorld-DPIMinX
 
            set node = AllComponents.base.next
            loop
                exitwhen node.head or node == 0
                if UIComponent(node).parent == UIComponent.Null then
                    set UIComponent(node).localScale = UIComponent(node).localScale
                endif
                set node = node.next
            endloop

        endmethod
 
        static method FullScreenMode takes boolean state, boolean commandBtn returns nothing

            local integer i
            local real x
            local real y

            local real yo
            local real xo1
            local real xo2

            set IsFullScreen = state
            set CommandButtonsVisible = commandBtn
            call BlzHideOriginFrames(state)
            call BlzFrameClearAllPoints(FrameWorld)
            call BlzFrameClearAllPoints(FrameConsoleUI)
            if state then
                // Fit viewport to screen
                call BlzFrameSetAllPoints(FrameWorld, FrameGameUI)
                call BlzFrameSetAbsPoint(FrameConsoleUI, FRAMEPOINT_RIGHT, XCoordToDPI(-999.0), YCoordToDPI(-999.0))
                // Retain in-game message frame position
                set yo  = SizeToDPI(300.0)
                set xo1 = SizeToDPI(65.0)
                set xo2 = SizeToDPI(710.0)
                call BlzFrameClearAllPoints(FrameUnitMsg)
                call BlzFrameSetAbsPoint(FrameUnitMsg, FRAMEPOINT_TOPLEFT, xo1, 0.5)
                call BlzFrameSetAbsPoint(FrameUnitMsg, FRAMEPOINT_TOPRIGHT, xo2, 0.5)
                call BlzFrameSetAbsPoint(FrameUnitMsg, FRAMEPOINT_BOTTOMLEFT, xo1, yo)
                call BlzFrameSetAbsPoint(FrameUnitMsg, FRAMEPOINT_BOTTOMRIGHT, xo2, yo)
            else
                // Restore viewport
                call BlzFrameSetAbsPoint(FrameWorld, FRAMEPOINT_TOPLEFT, 0.0, 0.58)
                call BlzFrameSetAbsPoint(FrameWorld, FRAMEPOINT_TOPRIGHT, 0.8, 0.58)
                call BlzFrameSetAbsPoint(FrameWorld, FRAMEPOINT_BOTTOMLEFT, 0.0, 0.13)
                  call BlzFrameSetAbsPoint(FrameWorld, FRAMEPOINT_BOTTOMRIGHT, 0.8, 0.13)
                call BlzFrameSetAllPoints(FrameConsoleUI, FrameGameUI)
            endif

            if commandBtn or not state then
                set x = 959.0
                set y = 168.0
            endif
            set i = 0
            loop
                exitwhen FrameCommandButton[i] == null
                call BlzFrameClearAllPoints(FrameCommandButton[i])
                if commandBtn or not state then
                    // Restore command buttons position
                    call BlzFrameSetAbsPoint(FrameCommandButton[i], FRAMEPOINT_TOPLEFT, XCoordToDPI(x), YCoordToDPI(y))
                    if i == 3 or i == 7 then
                        set x = 959.0
                        set y = y - DPIToSize(BlzFrameGetHeight(FrameCommandButton[i])) - 6.0
                    else
                        set x = x + DPIToSize(BlzFrameGetWidth (FrameCommandButton[i])) + 7.0
                    endif
                else
                    // Get command buttons out of screen
                    call BlzFrameSetAbsPoint(FrameCommandButton[i], FRAMEPOINT_RIGHT, XCoordToDPI(-999.0), YCoordToDPI(-999.0))
                endif
                set i = i + 1
            endloop

        endmethod

        static method CalcFrameSpacing takes UIComponent from, UIComponent to, boolean topdown returns real

            local real size1
            local real size2
            local framepointtype anchor1 = from.anchorPoint
            local framepointtype anchor2 = to.anchorPoint

            if topdown then
                set size1 = from.height
                set size2 = to.height
                if anchor1 == FRAMEPOINT_TOPLEFT or anchor1 == FRAMEPOINT_TOP or anchor1 == FRAMEPOINT_TOPRIGHT then
                    set size1 = 0.0
                elseif anchor1 == FRAMEPOINT_LEFT or anchor1 == FRAMEPOINT_CENTER or anchor1 == FRAMEPOINT_RIGHT then
                    set size1 = size1*0.5
                endif
                if anchor2 == FRAMEPOINT_BOTTOMLEFT or anchor2 == FRAMEPOINT_BOTTOM or anchor2 == FRAMEPOINT_BOTTOMRIGHT then
                    set size2 = 0.0
                elseif anchor2 == FRAMEPOINT_LEFT or anchor2 == FRAMEPOINT_CENTER or anchor2 == FRAMEPOINT_RIGHT then
                    set size2 = size2*0.5
                endif
            else
                set size1 = from.width
                set size2 = to.width
                if anchor1 == FRAMEPOINT_TOPRIGHT or anchor1 == FRAMEPOINT_RIGHT or anchor1 == FRAMEPOINT_BOTTOMRIGHT then
                    set size1 = 0.0
                elseif anchor1 == FRAMEPOINT_TOP or anchor1 == FRAMEPOINT_CENTER or anchor1 == FRAMEPOINT_BOTTOM then
                    set size1 = size1*0.5
                endif
                if anchor2 == FRAMEPOINT_TOPLEFT or anchor2 == FRAMEPOINT_LEFT or anchor2 == FRAMEPOINT_BOTTOMLEFT then
                    set size2 = 0.0
                elseif anchor2 == FRAMEPOINT_TOP or anchor2 == FRAMEPOINT_CENTER or anchor2 == FRAMEPOINT_BOTTOM then
                    set size2 = size2*0.5
                endif
            endif

            return size1+size2
        endmethod
 
        private static method CheckResolution takes nothing returns nothing
            if BlzGetLocalClientWidth() != ResolutionWidth or BlzGetLocalClientHeight() != ResolutionHeight then
                call RefreshResolution()
            endif
        endmethod

        implement INIT

    endstruct

    struct UIComponent extends array

        implement LinkedList
 
        string name

        readonly framehandle frame
        private  framehandle textFrameH
        private  framehandle modelFrameH
        private  framehandle mainTextureH
        private  framehandle disabledTextureH
        private  framehandle pushedTextureH
        private  framehandle highlightTextureH
        private  framehandle backgroundTextureH
        private  framehandle borderTextureH
        private  framepointtype anchor

        readonly string frameType
        readonly real localX
        readonly real localY
        readonly real screenX
        readonly real screenY
        readonly real minValue
        readonly real maxValue
        readonly integer context

        private thistype par
        private thistype child
        private thistype tips
        private integer lvl
        private real localSize
        private real localWidth
        private real localHeight
        private real step
        private string mainTextureFile
        private string disabledTextureFile
        private string pushedTextureFile
        private string highlightTextureFile
        private string backgroundTextureFile
        private string borderTextureFile
        private string modelFile
        private trigger anyEventTrigg

        readonly static thistype Null = 0
        readonly static thistype EnumChild = 0
        readonly static thistype TriggerComponent = 0

        readonly static string TYPE_TEXT            = "UIUtilsText"
        readonly static string TYPE_SIMPLE_TEXT        = "UIUtilsSimpleText"
        readonly static string TYPE_TEXTURE            = "UIUtilsTexture"
        readonly static string TYPE_SIMPLE_TEXTURE     = "UIUtilsSimpleTexture"
        readonly static string TYPE_BUTTON             = "UIUtilsButton"
        readonly static string TYPE_BAR             = "UIUtilsBar"
        readonly static string TYPE_H_SLIDER        = "UIUtilsSliderH"
        readonly static string TYPE_V_SLIDER        = "UIUtilsSliderV"

        private static trigger ExecTrigg = CreateTrigger()
        private static gamecache GC
        private static hashtable HT
 
        private static method IsSimple takes string frameType, boolean isSimple returns boolean
            return frameType == TYPE_SIMPLE_TEXT or frameType == TYPE_SIMPLE_TEXTURE or frameType == TYPE_BAR or isSimple and not (frameType == TYPE_TEXT or frameType == TYPE_TEXTURE or frameType == TYPE_BUTTON or frameType == TYPE_H_SLIDER or frameType == TYPE_V_SLIDER)
        endmethod
 
        private static method GetTriggerComponent takes nothing returns boolean
            set TriggerComponent = LoadInteger(HT, GetHandleId(BlzGetTriggerFrame()), 0)
            return false
        endmethod

        method operator onAnyEvent= takes code func returns triggercondition
 
            local integer i
 
            if .anyEventTrigg == null then
                set .anyEventTrigg = CreateTrigger()
                set i = 1
                loop
                    exitwhen i > 16
                    call BlzTriggerRegisterFrameEvent(.anyEventTrigg, .frame, ConvertFrameEventType(i))
                    set i = i + 1
                endloop
                call TriggerAddCondition(.anyEventTrigg, Condition(function thistype.GetTriggerComponent))
            endif
 
            return TriggerAddCondition(.anyEventTrigg, Condition(func))
        endmethod
 
        method operator anchorPoint= takes framepointtype point returns nothing
            set .anchor = point
              call BlzFrameClearAllPoints(.frame)
            call move(.localX, .localY)
        endmethod

        method operator anchorPoint takes nothing returns framepointtype
            return .anchor
        endmethod

        method operator parent= takes thistype comp returns nothing
            if comp != Null then
                if .par != comp then
                    call .removeNode()
                endif
                call comp.child.insertNode(this)
            endif
 
            static if not PERSISTENT_CHILD_PROPERTIES then
                if .par != Null then
                    set .localScale = .localScale*.par.localScale
                endif
                set .localX = .screenX - comp.screenX
                set .localY = .screenY - comp.screenY
            endif
 
            set .par = comp
            set .par.localScale = .par.localScale
 
        endmethod

        method operator parent takes nothing returns thistype
            return .par
        endmethod

        method operator text= takes string str returns nothing
            call BlzFrameSetText(.textFrameH, str)
        endmethod

        method operator text takes nothing returns string
            return BlzFrameGetText(.textFrameH)
        endmethod

        method operator maxLength= takes integer len returns nothing
            call BlzFrameSetTextSizeLimit(.textFrameH, len)
        endmethod

        method operator maxLength takes nothing returns integer
            return BlzFrameGetTextSizeLimit(.textFrameH)
        endmethod

        method operator textColor= takes integer color returns nothing
            call BlzFrameSetTextColor(.textFrameH, color)
        endmethod

        method operator texture= takes string filePath returns nothing
            set .mainTextureFile = filePath
            call BlzFrameSetTexture(.mainTextureH, filePath, 0, true)
            if StringLength(.disabledTextureFile) == 0 then
                set .disabledTexture = filePath
            endif
            if StringLength(.pushedTextureFile) == 0 then
                set .pushedTexture = filePath
            endif
        endmethod

        method operator texture takes nothing returns string
            return .mainTextureFile
        endmethod

        method operator disabledTexture= takes string filePath returns nothing
            set .disabledTextureFile = filePath
            call BlzFrameSetTexture(.disabledTextureH, filePath, 0, true)
        endmethod

        method operator disabledTexture takes nothing returns string
            return .disabledTextureFile
        endmethod

        method operator highlightTexture= takes string filePath returns nothing
            set .highlightTextureFile = filePath
            call BlzFrameSetTexture(.highlightTextureH, filePath, 0, true)
        endmethod

        method operator highlightTexture takes nothing returns string
            return .highlightTextureFile
        endmethod

        method operator pushedTexture= takes string filePath returns nothing
            set .pushedTextureFile = filePath
            call BlzFrameSetTexture(.pushedTextureH, filePath, 0, true)
        endmethod

        method operator pushedTexture takes nothing returns string
            return .pushedTextureFile
        endmethod

        method operator backgroundTexture= takes string filePath returns nothing
            set .backgroundTextureFile = filePath
            call BlzFrameSetTexture(.backgroundTextureH, filePath, 0, true)
        endmethod

        method operator backgroundTexture takes nothing returns string
            return .backgroundTextureFile
        endmethod

        method operator borderTexture= takes string filePath returns nothing
            set .borderTextureFile = filePath
            call BlzFrameSetTexture(.borderTextureH, filePath, 0, true)
        endmethod

        method operator borderTexture takes nothing returns string
            return .borderTextureFile
        endmethod

        method operator model= takes string filePath returns nothing
            set .modelFile = filePath
            call BlzFrameSetModel(.modelFrameH, filePath, 0)
        endmethod

        method operator model takes nothing returns string
            return .modelFile
        endmethod

        method operator vertexColor= takes integer color returns nothing
            call BlzFrameSetVertexColor(.modelFrameH, color)
        endmethod

        method operator value= takes real r returns nothing
            call BlzFrameSetValue(.frame, r)
        endmethod

        method operator value takes nothing returns real
            return BlzFrameGetValue(.frame)
        endmethod

        method operator stepSize= takes real r returns nothing
            set .step = RMaxBJ(r, 0.0001)
            call BlzFrameSetStepSize(.frame, .step)
        endmethod

        method operator stepSize takes nothing returns real
            return .step
        endmethod

        method operator localScale= takes real r returns nothing

            local thistype node = .child.next

            set .localSize = RMaxBJ(r, 0.0001)
            call setSize(.width, .height)
            call move(.localX, .localY)

            loop
                exitwhen node.head or node == 0
                set node.localScale = node.localScale
                set node = node.next
            endloop

        endmethod

        method operator localScale takes nothing returns real
            return .localSize
        endmethod

        method operator scale takes nothing returns real
            if .parent == Null then
                return .localScale
            else
                return .localScale * .parent.scale
            endif
        endmethod

        method operator opacity= takes integer amount returns nothing
            call BlzFrameSetAlpha(.frame, amount)
        endmethod

        method operator opacity takes nothing returns integer
            return BlzFrameGetAlpha(.frame)
        endmethod

        method operator level= takes integer level returns nothing
            set .lvl = level
            call BlzFrameSetLevel(.frame, level)
        endmethod

        method operator level takes nothing returns integer
            return .lvl
        endmethod

        method operator tooltips= takes thistype comp returns nothing
            set .tips = comp
            call BlzFrameSetTooltip(.frame, comp.frame)
        endmethod

        method operator tooltips takes nothing returns thistype
            return .tips
        endmethod

        method operator visible= takes boolean state returns nothing
            call BlzFrameSetVisible(.frame, state)
        endmethod

        method operator visible takes nothing returns boolean
            return BlzFrameIsVisible(.frame)
        endmethod

        method operator enabled= takes boolean state returns nothing
            call BlzFrameSetEnable(.frame, state)
        endmethod

        method operator enabled takes nothing returns boolean
            return BlzFrameGetEnable(.frame)
        endmethod

        method operator width takes nothing returns real
            return .localWidth
        endmethod

        method operator height takes nothing returns real
            return .localHeight
        endmethod

        method setSize takes real width, real height returns nothing
            set .localWidth  = RMaxBJ(width,  0)
            set .localHeight = RMaxBJ(height, 0)
            call BlzFrameSetSize(frame, UIUtils.SizeToDPI(.localWidth*.scale*WidthFactor), UIUtils.SizeToDPI(.localHeight*.scale*WidthFactor))
        endmethod

        method move takes real x, real y returns nothing

            local thistype node = .child.next

            set .localX = x
            set .localY = y
            if .parent == Null then
                set .screenX = x
                set .screenY = y
            else
                set .screenX = .parent.screenX+.localX*.parent.scale
                set .screenY = .parent.screenY+.localY*.parent.scale
            endif
            call BlzFrameSetAbsPoint(.frame, .anchor, UIUtils.XCoordToDPI(.screenX*WidthFactor), UIUtils.YCoordToDPI(.screenY*HeightFactor))

            loop
                exitwhen node.head or node == 0
                call node.move(node.localX, node.localY)
                set node = node.next
            endloop

        endmethod

        method moveEx takes real x, real y returns nothing
            if .parent == Null then
                call move(x, y)
            else
                call move((x-.parent.screenX)/.parent.localScale, (y-.parent.screenY)/.parent.localScale)
            endif
        endmethod

        method relate takes thistype relative, real x, real y returns nothing
            if .parent == Null then
                call move(relative.screenX+x, relative.screenY+y)
            else
                call moveEx(relative.screenX+x, relative.screenY+y)
            endif
        endmethod

        method click takes nothing returns nothing
            call BlzFrameClick(.frame)
        endmethod

        method cageMouse takes boolean state returns nothing
            call BlzFrameCageMouse(.frame, state)
        endmethod

        method setFocus takes boolean state returns nothing
            call BlzFrameSetFocus(.frame, state)
        endmethod

        method setSpriteAnimate takes integer primaryProp, integer flags returns nothing
            call BlzFrameSetSpriteAnimate(.frame, primaryProp, flags)
        endmethod

        method setMinMaxValue takes real min, real max returns nothing
            set .minValue = min
            set .maxValue = max
            call BlzFrameSetMinMaxValue(.frame, min, max)
        endmethod

        method setFont takes string fontPath, real height, integer flags returns nothing
            call BlzFrameSetFont(.textFrameH, fontPath, height, flags)
        endmethod

        method setTextAlignment takes textaligntype vertical, textaligntype horizontal returns nothing
            call BlzFrameSetTextAlignment(.textFrameH, vertical, horizontal)
        endmethod
 
        method getSubFrame takes string name returns framehandle
            return BlzGetFrameByName(name, .context)
        endmethod

        method forChilds takes code func returns nothing
 
            local thistype node = .child.next

            call TriggerAddAction(ExecTrigg, func)
            loop
                exitwhen node.head or node == 0
                set EnumChild = node
                call TriggerExecute(ExecTrigg)
                set node = node.next
            endloop
            call TriggerClearActions(ExecTrigg)

        endmethod

        method destroy takes nothing returns nothing

            local thistype node = .child.next
 
            loop
                exitwhen node.head or node == 0
                call node.destroy()
                set node = node.next
            endloop

            call BlzDestroyFrame(.frame)
            call DestroyTrigger(.anyEventTrigg)
            call StoreInteger(GC, name, I2S(.context), GetStoredInteger(GC, name, "0"))
            call StoreInteger(GC, name, "0", .context)
            call AllComponents.remove(this)
            call .child.flushNode()
            call removeNode()
            call deallocate()
            set .anyEventTrigg         = null
            set .mainTextureH        = null
            set .disabledTextureH     = null
            set .highlightTextureH     = null
            set .pushedTextureH     = null
            set .backgroundTextureH = null
            set .borderTextureH     = null
            set .textFrameH         = null
            set .modelFrameH         = null
            set .frame                 = null
            set .name                  = null
            set .frameType             = null
            set .child                 = 0
 
        endmethod

        static method create takes boolean isSimple, string frameType, thistype par, real x, real y, integer level returns thistype
 
            local thistype this = allocate()
            local integer tempInt
 
            set .context = GetStoredInteger(GC, frameType, "0")
            set tempInt  = GetStoredInteger(GC, frameType, I2S(context))
            if tempInt == 0 then
                call StoreInteger(GC, frameType, "0", context+1)
            else
                call StoreInteger(GC, frameType, "0", tempInt)
            endif
 
            if IsSimple(frameType, isSimple) then
                set .frame             = BlzCreateSimpleFrame(frameType, UIUtils.FrameGameUI, .context)
            else
                set .frame             = BlzCreateFrame(frameType, UIUtils.FrameGameUI, 0, .context)
            endif
            set .mainTextureH        = getSubFrame(frameType + "Texture")
            set .disabledTextureH     = getSubFrame(frameType + "Disabled")
            set .highlightTextureH     = getSubFrame(frameType + "Highlight")
            set .pushedTextureH     = getSubFrame(frameType + "Pushed")
            set .backgroundTextureH = getSubFrame(frameType + "Background")
            set .borderTextureH     = getSubFrame(frameType + "Border")
            set .textFrameH         = getSubFrame(frameType + "Text")
            set .modelFrameH         = getSubFrame(frameType + "Model")
            if .mainTextureH == null then
                set .mainTextureH     = frame
            endif
 
            set .localWidth         = UIUtils.DPIToSize(BlzFrameGetWidth(.frame))
            set .localHeight        = UIUtils.DPIToSize(BlzFrameGetHeight(.frame))
            set .anchor             = FRAMEPOINT_BOTTOMLEFT
            set .child                 = createNode()
            set .frameType            = frameType
            set .name                 = frameType + I2S(.context)
            set .parent             = par
            set .level                 = level
            set .value                 = 0.0
            set .localScale         = 1.0
 
            set .mainTextureFile        = ""
            set .disabledTextureFile    = ""
            set .pushedTextureFile        = ""
            set .highlightTextureFile    = ""
            set .backgroundTextureFile    = ""
            set .borderTextureFile        = ""
            set .modelFile                = ""
 
            call move(x, y)
            call setMinMaxValue(0.0, 1.0)
            call AllComponents.add(this)
            call SaveInteger(HT, GetHandleId(.frame), 0, this)

            return this
        endmethod

        private static method onInit takes nothing returns nothing
            set HT = InitHashtable()
            set GC = InitGameCache("UIUtils.w3v")
              call BlzLoadTOCFile("war3mapimported\\UIUtils.toc")
        endmethod

    endstruct

endlibrary
 

Attachments

  • UI Utils v1.0.w3x
    530.7 KB · Views: 579
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Yeah that's the plan.


Here's the results of this code atm:
JASS:
        set comp = UIComponent.create(UIComponent.TYPE_BAR, UIComponent.Null, 0.0, 768.0, 1)
        set comp.anchorPoint = FRAMEPOINT_TOPLEFT
        set comp.texture = "Replaceabletextures\\Teamcolor\\Teamcolor00.blp"
        call comp.setSize(64.0, 64.0)

        set comp2 = UIComponent.create(UIComponent.TYPE_BAR, comp, 1360.0, 768.0, 0)
        set comp2.anchorPoint = FRAMEPOINT_TOPRIGHT
        set comp2.texture = "Replaceabletextures\\Teamcolor\\Teamcolor01.blp"
        call comp2.setSize(64.0, 64.0)

        set comp3 = UIComponent.create(UIComponent.TYPE_BAR, comp, 1360.0, 0.0, 0)
        set comp3.anchorPoint = FRAMEPOINT_BOTTOMRIGHT
        set comp3.texture = "Replaceabletextures\\Teamcolor\\Teamcolor02.blp"
        call comp3.setSize(64.0, 64.0)

        set comp4 = UIComponent.create(UIComponent.TYPE_BAR, comp, 0.0, 0.0, 0)
        set comp4.anchorPoint = FRAMEPOINT_BOTTOMLEFT
        set comp4.texture = "Replaceabletextures\\Teamcolor\\Teamcolor03.blp"
        call comp4.setSize(64.0, 64.0)
upload_2019-6-15_12-17-29.png
upload_2019-6-15_12-22-51.png

Accurate enough...

Not sure what should be the base (0, 0) of the coordinate system. By default it's bottom left, but I personally prefer it to be at top left, just like in visual studio. But let's listen to some opinions...
 
Level 9
Joined
Mar 6, 2012
Messages
64
Awesome. Would be cool to add an option that makes the frame adapt to whatever resolution the player is, like scaling the frames designed to that resolution equivalent to the ratio to another resolution. Anyways, this makes creating frames easier since it makes you edit the actual size of the frame in a image editing program.
 
Level 3
Joined
Mar 11, 2019
Messages
31
Wait is this basically going to let me edit the UI without having to be some kind of coder genius? Because I really need that.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Update:
- Improved UIUtils init
- Nested parent-child system is now fully working
- Aspect ratio-based coordinate conversion
- Support for 4:3, 16:9, & 16:10 resolutions
- Basic resolution change adaptation (still requires map restart)
- Added some extra operators for changing value, min/max value, and local properties
- Both local and screen position are now stored and readable by user

Wait is this basically going to let me edit the UI without having to be some kind of coder genius? Because I really need that.
The purpose of this library is to facilitate highly user-friendly and intuitive UI design creation and modification, but it still requires some vJass coding knowledge.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Update:
- Automatic create context handling
- Now properly destroy component
- Local scale now has floor limit of 0.0001 to avoid thread crash
- Added component name for user to modify
- Fixed infinite loop issue when modifying destroyed component properties
- Now removes command button panel on full screen mode
- Some improvements
 
Level 3
Joined
Mar 11, 2019
Messages
31
The purpose of this library is to facilitate highly user-friendly and intuitive UI design creation and modification, but it still requires some vJass coding knowledge.

Do you think there will ever be a GUI modifiable version that changes the variables in jass?

Also, if not, how should a noob go about learning how to implement this into his map?
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Update:
- Auto adjustments to all frames on resolution change
- Entering full screen mode no longer removes in-game message
- Exit full screen mode is now compatible with all aspect ratios
- Now scales width, height, and position properly according to parent's scale
- Some improvements and extra features
 
Last edited:
Level 3
Joined
Mar 11, 2019
Messages
31
How the hell do I get rid of the 3d portrait? I'm using call UIUtils.FullScreenMode(true, false) and can't seem to get rid of it.

grrrr.png
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Update:
  1. Now supports 6 basic template frames:
    • Simple Text: can't change color, doesn't block mouse click
    • Text: can change color, blocks mouse click, has events
    • Texture: display texture file, has events, has two textures (main & disabled)
    • Simple Texture: display texture file, doesn't have events, only have one main texture
    • Bar: for things like healthbar, has two textures: main (filler) & background
    • Button: interactible, has multiple textures: main, disabled, pushed, & highlight
  2. More advanced templates will come later:
    • Scroll Bar
    • Check Box
    • Radio Button
    • Model
    • Sprite
    • Input Box
    • Text Area
  3. Added wrapper for all frame properties
  4. Added universal frame event system

Looks like it's very close to completion, only need to add the remaining templates and make a decent system demo.

Will you eventually handle highlighting? Or will such feature be up to the user to manage himself?

I am thinking of using this library to create a simple extended inventory like something similar to the below image.

View attachment 325838
This library will provide everything you need to create such system (only UI-related parts of course).

How the hell do I get rid of the 3d portrait? I'm using call UIUtils.FullScreenMode(true, false) and can't seem to get rid of it.

View attachment 325859
The portrait isn't showing for me. Try updating the lib code.
 
Last edited:
Level 3
Joined
Mar 11, 2019
Messages
31
Update:


The portrait isn't showing for me. Try updating the lib code.

Damn, wtf. It's still showing up for me. I'm really new to Jass/coding in general so I might be doing something wrong.

So I have the LinkedListModule pasted in the top "map.w3x" in the trigger section, along with your library under it.

Then I have

JASS:
function InitUI takes nothing returns nothing
 
    call UIUtils.FullScreenMode(true, false)


endfunction

under those, then I have a trigger that runs on map initialization: Custom script: call InitUI()

Should that be working? Sorry if this is annoying lol.

Nvm, I figured it out. The way my map loads in bugs it out for some reason, but if i delay the UI it works.
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Update:
  • Added slider template (vertical & horizontal)
  • Text template (non-simple one) is temporarily removed
  • Step size now has floor limit of 0.0001 to avoid slider getting stuck
  • Min/Max value is now stored in readable variable
  • Added MinRenderX & MaxRenderX variables to help coordinating non-simple frames
  • Added some demo codes. Demo map is now available for testing. Includes:
    • Basic templates demo
    • Parent-child system demo (inventory scaling)
    • Slider demo (minimap targeting)
    • Healthbar demo
Feedback is highly appreciated : )
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Would be cool if you explain how to use it.
Well this one is an unfinished product. I'm currently using it in EmberCraft. Once it can satisfy all the map's needs, I will release it with complete documentation and tutorials. Sorry but for now you must wait or learn from the poor demo codes.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
I want to announce that I'm back developing this system.

Updates:
- Added feature to remove console UI without removing (optional) some important frames (like uber tooltips, message frame, minimap, etc.)
- Improved code structure
- Added pivot and anchor point feature
- Can detect more aspect ratio variations
- UIComponent is renamed to UIFrame
- etc

The new pivot and anchor system is inspired by Unity. This is a more elegant solution for all-resolution support. And now you are not fixed to use frame's corner only (top left, etc.), instead you can set the pivot point to anywhere inside the frame's area, and beyond its area in fact. You can anchor each frame to any point of the screen and the frame will be anchored to that point on any resolution (takes frame offset into account of course).

Here's a simple demo:

Anchor x: 1.0, y: 1.0 (screen's or parent frame's top right)
Pivot x: 1.0, y: 1.0 (frame's top right)
Position x: 0.0, y: 0.0

ui.gif

(image is downscaled by 40%)

The anchor system itself is still being improved...

Updated code:
JASS:
library UIUtils requires LinkedListModule

    globals
        // 1. Screen resolution used to design the interface
        public  constant real RESOLUTION_WIDTH  = 1360.0
        public  constant real RESOLUTION_HEIGHT = 768.0
  
        // 2. If true, it will hide console frames on map init
        private constant boolean HIDE_CONSOLE_FRAME = true

        // 3. If true, all frames will be automatically adjusted on resolution change
        private constant real RESOLUTION_CHECK_INTERVAL = 0.1

        // 4. If true, component's properties will be retained when it changes parent
        private constant boolean PERSISTENT_CHILD_PROPERTIES = true
  
        // 3. In-game message visibility
        public constant boolean MESSAGE_FRAME_VISIBLE = true
        public constant real MESSAGE_FRAME_POS_X = 200.0
        public constant real MESSAGE_FRAME_POS_Y = 300.0
  
        // 4. Chat message visibility
        public constant boolean CHAT_FRAME_VISIBLE = true
        public constant real CHAT_FRAME_POS_X = 10.0
        public constant real CHAT_FRAME_POS_Y = 100.0
  
        // 5. Tooltips visibility
        public constant boolean TOOLTIPS_FRAME_VISIBLE = true
        public constant real TOOLTIPS_FRAME_POS_X = 1075.0
        public constant real TOOLTIPS_FRAME_POS_Y = 384.0
  
        // 6. Other frame visibility
        public constant boolean MINIMAP_FRAME_VISIBLE = false
        public constant real MINIMAP_FRAME_POS_X = 0.0
        public constant real MINIMAP_FRAME_POS_Y = 0.0
  
        public constant boolean PORTRAIT_FRAME_VISIBLE = false
        public constant real PORTRAIT_FRAME_POS_X = 0.0
        public constant real PORTRAIT_FRAME_POS_Y = 0.0
  
        public constant boolean RESOURCE_FRAME_VISIBLE = false
        public constant boolean CMD_BUTTON_FRAME_VISIBLE = false
    endglobals

    private module DefaultFrameInit
        private static method onInit takes nothing returns nothing
            local integer i

            set Game        = BlzGetOriginFrame(ORIGIN_FRAME_GAME_UI, 0)
            set World       = BlzGetOriginFrame(ORIGIN_FRAME_WORLD_FRAME, 0)
            set HeroBar     = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BAR, 0)
            set Portrait    = BlzGetOriginFrame(ORIGIN_FRAME_PORTRAIT, 0)
            set Minimap     = BlzGetOriginFrame(ORIGIN_FRAME_MINIMAP, 0)
            set Tooltip     = BlzGetOriginFrame(ORIGIN_FRAME_TOOLTIP, 0)
            set UberTooltip = BlzGetOriginFrame(ORIGIN_FRAME_UBERTOOLTIP, 0)
            set ChatMsg     = BlzGetOriginFrame(ORIGIN_FRAME_CHAT_MSG, 0)
            set UnitMsg     = BlzGetOriginFrame(ORIGIN_FRAME_UNIT_MSG, 0)
            set TopMsg      = BlzGetOriginFrame(ORIGIN_FRAME_TOP_MSG, 0)

            set i = 0
            loop
                exitwhen i > 11
                set HeroButton[i]    = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON, i)
                set HeroHPBar[i]     = BlzGetOriginFrame(ORIGIN_FRAME_HERO_HP_BAR, i)
                set HeroMPBar[i]     = BlzGetOriginFrame(ORIGIN_FRAME_HERO_MANA_BAR, i)
                set HeroIndicator[i] = BlzGetOriginFrame(ORIGIN_FRAME_HERO_BUTTON_INDICATOR, i)
                set ItemButton[i]    = BlzGetOriginFrame(ORIGIN_FRAME_ITEM_BUTTON, i)
                set CommandButton[i] = BlzGetOriginFrame(ORIGIN_FRAME_COMMAND_BUTTON, i)
                set SystemButton[i]  = BlzGetOriginFrame(ORIGIN_FRAME_SYSTEM_BUTTON, i)
                set MinimapButton[i] = BlzGetOriginFrame(ORIGIN_FRAME_MINIMAP_BUTTON, i)
                set i = i + 1
            endloop
 
            set Console    = BlzGetFrameByName("ConsoleUI", 0)
            set GoldText   = BlzGetFrameByName("ResourceBarGoldText", 0)
            set LumberText = BlzGetFrameByName("ResourceBarLumberText", 0)
            set FoodText   = BlzGetFrameByName("ResourceBarSupplyText", 0)
            set UnitNameText = BlzGetFrameByName("SimpleNameValue", 0)
        endmethod
    endmodule

    private module UIUtilsInit
        private static method onInit takes nothing returns nothing
            local integer i
      
            call RefreshResolution()
      
            static if HIDE_CONSOLE_FRAME then
                call BlzEnableUIAutoPosition(false)
                call BlzFrameClearAllPoints(DefaultFrame.World)
                call BlzFrameClearAllPoints(DefaultFrame.Console)
          
                call BlzFrameSetAllPoints(DefaultFrame.World, DefaultFrame.Game)
                call BlzFrameSetAbsPoint(DefaultFrame.Console, FRAMEPOINT_TOPRIGHT, -999.0, -999.0)
          
                static if MESSAGE_FRAME_VISIBLE then
                    call BlzFrameClearAllPoints(DefaultFrame.UnitMsg)
                    call BlzFrameSetAbsPoint(DefaultFrame.UnitMsg, FRAMEPOINT_BOTTOMLEFT, MESSAGE_FRAME_POS_X*PXTODPI, MESSAGE_FRAME_POS_Y*PXTODPI)
                endif
          
                static if CHAT_FRAME_VISIBLE then
                    call BlzFrameSetAbsPoint(DefaultFrame.ChatMsg, FRAMEPOINT_BOTTOMLEFT, CHAT_FRAME_POS_X*PXTODPI, CHAT_FRAME_POS_Y*PXTODPI)
                endif

                static if TOOLTIPS_FRAME_VISIBLE then
                    call BlzFrameClearAllPoints(DefaultFrame.UberTooltip)
                    call BlzFrameSetAbsPoint(DefaultFrame.UberTooltip, FRAMEPOINT_BOTTOMLEFT, TOOLTIPS_FRAME_POS_X*PXTODPI, TOOLTIPS_FRAME_POS_Y*PXTODPI)
                endif
          
                call BlzFrameClearAllPoints(DefaultFrame.Minimap)
                static if MINIMAP_FRAME_VISIBLE then
                    call BlzFrameSetAbsPoint(DefaultFrame.Minimap, FRAMEPOINT_BOTTOMLEFT, MINIMAP_FRAME_POS_X*PXTODPI, MINIMAP_FRAME_POS_Y*PXTODPI)
                else
                    call BlzFrameSetAbsPoint(DefaultFrame.Minimap, FRAMEPOINT_BOTTOMLEFT, -999.0, -999.0)
                endif

                call BlzFrameClearAllPoints(DefaultFrame.Portrait)
                static if PORTRAIT_FRAME_VISIBLE then
                    call BlzFrameSetAbsPoint(DefaultFrame.Portrait, FRAMEPOINT_BOTTOMLEFT, PORTRAIT_FRAME_POS_X*PXTODPI, PORTRAIT_FRAME_POS_XY*PXTODPI)
                else
                    call BlzFrameSetAbsPoint(DefaultFrame.Portrait, FRAMEPOINT_BOTTOMLEFT, -999.0, -999.0)
                endif

                static if not RESOURCE_FRAME_VISIBLE then
                    call BlzFrameClearAllPoints(DefaultFrame.GoldText)
                    call BlzFrameSetAbsPoint(DefaultFrame.GoldText, FRAMEPOINT_BOTTOMLEFT, -999.0, -999.0)

                    call BlzFrameClearAllPoints(DefaultFrame.LumberText)
                    call BlzFrameSetAbsPoint(DefaultFrame.LumberText, FRAMEPOINT_BOTTOMLEFT, -999.0, -999.0)

                    call BlzFrameClearAllPoints(DefaultFrame.FoodText)
                    call BlzFrameSetAbsPoint(DefaultFrame.FoodText, FRAMEPOINT_BOTTOMLEFT, -999.0, -999.0)
                endif

                static if not CMD_BUTTON_FRAME_VISIBLE then
                    set i = 0
                    loop
                        exitwhen DefaultFrame.CommandButton[i] == null
                        call BlzFrameClearAllPoints(DefaultFrame.CommandButton[i])
                        call BlzFrameSetAbsPoint(DefaultFrame.CommandButton[i], FRAMEPOINT_BOTTOMLEFT, -999.0, -999.0)
                        set i = i + 1
                    endloop
                endif
            endif
 
            call TimerStart(CreateTimer(), RESOLUTION_CHECK_INTERVAL, true, function thistype.CheckResolution)
        endmethod
    endmodule
 
    struct DefaultFrame extends array
 
        readonly static framehandle         Game            = null
        readonly static framehandle         World            = null
        readonly static framehandle         HeroBar            = null
        readonly static framehandle array   HeroButton
        readonly static framehandle array   HeroHPBar
        readonly static framehandle array   HeroMPBar
        readonly static framehandle array   HeroIndicator
        readonly static framehandle array   ItemButton
        readonly static framehandle array   CommandButton
        readonly static framehandle array   SystemButton
        readonly static framehandle         Portrait        = null
        readonly static framehandle         Minimap            = null
        readonly static framehandle array   MinimapButton
        readonly static framehandle         Tooltip            = null
        readonly static framehandle         UberTooltip        = null
        readonly static framehandle         ChatMsg            = null
        readonly static framehandle         UnitMsg            = null
        readonly static framehandle         TopMsg            = null

        readonly static framehandle         Console            = null
        readonly static framehandle         GoldText        = null
        readonly static framehandle         LumberText        = null
        readonly static framehandle         FoodText        = null
        readonly static framehandle         UnitNameText    = null
  
        implement DefaultFrameInit
  
    endstruct
 
    private keyword AllComponents

    struct UIUtils extends array

        readonly static integer ResolutionWidth  = 0
        readonly static integer ResolutionHeight = 0
        readonly static integer AspectWidth  = 0
        readonly static integer AspectHeight = 0

        static method CalcAspectRatio takes real w, real h, real aspectWidth returns integer
            return R2I(aspectWidth*h/w+0.5)
        endmethod
  
        static method operator PXTODPI takes nothing returns real
            return 0.6/ResolutionHeight
        endmethod
  
        static method operator DPITOPX takes nothing returns real
            return ResolutionHeight/0.6
        endmethod
  
        static method GetScreenPosX takes real x returns real
            return (-(ResolutionWidth-ResolutionHeight/600.*800.)/2.+x)*PXTODPI
        endmethod
  
        static method GetScreenPosY takes real y returns real
            return 0.6*(y/ResolutionHeight)
        endmethod
  
        static method RefreshResolution takes nothing returns boolean
            local AllComponents node
      
            set ResolutionWidth  = BlzGetLocalClientWidth()
            set ResolutionHeight = BlzGetLocalClientHeight()
      
            if CalcAspectRatio(ResolutionWidth, ResolutionHeight, 4) == 3 then
                set AspectWidth   = 4
                set AspectHeight  = 3
            elseif CalcAspectRatio(ResolutionWidth, ResolutionHeight, 16) == 9 then
                set AspectWidth   = 16
                set AspectHeight  = 9
            elseif CalcAspectRatio(ResolutionWidth, ResolutionHeight, 16) == 10 then
                set AspectWidth   = 16
                set AspectHeight  = 10
            elseif CalcAspectRatio(ResolutionWidth, ResolutionHeight, 21) == 9 then
                set AspectWidth   = 21
                set AspectHeight  = 9
            elseif CalcAspectRatio(ResolutionWidth, ResolutionHeight, 32) == 9 then
                set AspectWidth   = 32
                set AspectHeight  = 9
            else
                set AspectWidth   = 0
                set AspectHeight  = 0
            endif
      
            set node = AllComponents.base.next
            loop
                exitwhen node.head or node == 0
                if UIFrame(node).parent == UIFrame.Null then
                    call UIFrame(node).refresh()
                endif
                set node = node.next
            endloop

            return AspectWidth != 0
        endmethod

        private static method CheckResolution takes nothing returns nothing
            if BlzGetLocalClientWidth() != ResolutionWidth or BlzGetLocalClientHeight() != ResolutionHeight then
                call RefreshResolution()
            endif
        endmethod

        implement UIUtilsInit

    endstruct
 
    struct UIFrame extends array

        implement LinkedList

        string name

        boolean inheritScale
        boolean inheritOpacity
        boolean inheritVisibility
        boolean inheritEnableState
        boolean inheritPosition
        boolean inheritLevel
        boolean scalePosition

        readonly string  frameType
        readonly real     localPosX
        readonly real     localPosY
        readonly real     anchorX
        readonly real     anchorY
        readonly real     pivotX
        readonly real     pivotY
        readonly real     width
        readonly real     height
        readonly real     valueMin
        readonly real     valueMax
        readonly integer context
        readonly boolean visibleSelf
        readonly boolean enabledSelf
        readonly integer localOpacity
  
        private integer m_level
        private real     m_localScale
        private real     m_stepSize

        private thistype m_parent
        private thistype m_childs
        private thistype m_tooltips
  
        private string mainTextureFile
        private string disabledTextureFile
        private string pushedTextureFile
        private string highlightTextureFile
        private string backgroundTextureFile
        private string borderTextureFile
        private string modelFile
        private trigger anyEventTrigg

        readonly framehandle frame
        private  framehandle textFrameH
        private  framehandle modelFrameH
        private  framehandle mainTextureH
        private  framehandle disabledTextureH
        private  framehandle pushedTextureH
        private  framehandle highlightTextureH
        private  framehandle backgroundTextureH
        private  framehandle borderTextureH

        readonly static thistype Null = 0
        readonly static thistype EnumChild = 0
        readonly static thistype TriggerComponent = 0

        readonly static string TYPE_TEXT            = "UIUtilsText"
        readonly static string TYPE_SIMPLE_TEXT     = "UIUtilsSimpleText"
        readonly static string TYPE_TEXTURE         = "UIUtilsTexture"
        readonly static string TYPE_SIMPLE_TEXTURE  = "UIUtilsSimpleTexture"
        readonly static string TYPE_BUTTON          = "UIUtilsButton"
        readonly static string TYPE_SIMPLE_BUTTON   = "UIUtilsSimpleButton"
        readonly static string TYPE_BAR             = "UIUtilsBar"
        readonly static string TYPE_H_SLIDER        = "UIUtilsSliderH"
        readonly static string TYPE_V_SLIDER        = "UIUtilsSliderV"

        private static trigger ExecTrigg = CreateTrigger()
        private static gamecache GC
        private static hashtable HT

        private static method IsSimple takes string frameType, boolean isSimple returns boolean
            return frameType == TYPE_SIMPLE_TEXT or frameType == TYPE_SIMPLE_TEXTURE or frameType == TYPE_BAR or isSimple and not (frameType == TYPE_TEXT or frameType == TYPE_TEXTURE or frameType == TYPE_BUTTON or frameType == TYPE_H_SLIDER or frameType == TYPE_V_SLIDER)
        endmethod

        private static method GetTriggerComponent takes nothing returns boolean
            set TriggerComponent = LoadInteger(HT, GetHandleId(BlzGetTriggerFrame()), 0)
            return false
        endmethod

        method operator onAnyEvent= takes code func returns triggercondition
            local integer i
 
            if .anyEventTrigg == null then
                set .anyEventTrigg = CreateTrigger()
                set i = 1
                loop
                    exitwhen i > 16
                    call BlzTriggerRegisterFrameEvent(.anyEventTrigg, .frame, ConvertFrameEventType(i))
                    set i = i + 1
                endloop
                call TriggerAddCondition(.anyEventTrigg, Condition(function thistype.GetTriggerComponent))
            endif
 
            return TriggerAddCondition(.anyEventTrigg, Condition(func))
        endmethod

        method operator parent= takes thistype comp returns nothing
            if comp != Null then
                if .m_parent != comp then
                    call .removeNode()
                endif
                call comp.m_childs.insertNode(this)
            endif
 
            static if not PERSISTENT_CHILD_PROPERTIES then
                if .m_parent != Null then
                    set .localScale = .localScale*.m_parent.localScale
                endif
                set .localPosX = .screenPosX - comp.screenPosX
                set .localPosY = .screenPosY - comp.screenPosY
            endif

            set .m_parent = comp
            call refresh()
        endmethod

        method operator parent takes nothing returns thistype
            return .m_parent
        endmethod

        method operator text= takes string str returns nothing
            call BlzFrameSetText(.textFrameH, str)
        endmethod

        method operator text takes nothing returns string
            return BlzFrameGetText(.textFrameH)
        endmethod

        method operator maxLength= takes integer length returns nothing
            call BlzFrameSetTextSizeLimit(.textFrameH, length)
        endmethod

        method operator maxLength takes nothing returns integer
            return BlzFrameGetTextSizeLimit(.textFrameH)
        endmethod

        method operator textColor= takes integer color returns nothing
            call BlzFrameSetTextColor(.textFrameH, color)
        endmethod

        method operator texture= takes string filePath returns nothing
            set .mainTextureFile = filePath
            call BlzFrameSetTexture(.mainTextureH, filePath, 0, true)
            if StringLength(.disabledTextureFile) == 0 then
                set .disabledTexture = filePath
            endif
            if StringLength(.pushedTextureFile) == 0 then
                set .pushedTexture = filePath
            endif
        endmethod

        method operator texture takes nothing returns string
            return .mainTextureFile
        endmethod

        method operator disabledTexture= takes string filePath returns nothing
            set .disabledTextureFile = filePath
            call BlzFrameSetTexture(.disabledTextureH, filePath, 0, true)
        endmethod

        method operator disabledTexture takes nothing returns string
            return .disabledTextureFile
        endmethod

        method operator highlightTexture= takes string filePath returns nothing
            set .highlightTextureFile = filePath
            call BlzFrameSetTexture(.highlightTextureH, filePath, 0, true)
        endmethod

        method operator highlightTexture takes nothing returns string
            return .highlightTextureFile
        endmethod

        method operator pushedTexture= takes string filePath returns nothing
            set .pushedTextureFile = filePath
            call BlzFrameSetTexture(.pushedTextureH, filePath, 0, true)
        endmethod

        method operator pushedTexture takes nothing returns string
            return .pushedTextureFile
        endmethod

        method operator backgroundTexture= takes string filePath returns nothing
            set .backgroundTextureFile = filePath
            call BlzFrameSetTexture(.backgroundTextureH, filePath, 0, true)
        endmethod

        method operator backgroundTexture takes nothing returns string
            return .backgroundTextureFile
        endmethod

        method operator borderTexture= takes string filePath returns nothing
            set .borderTextureFile = filePath
            call BlzFrameSetTexture(.borderTextureH, filePath, 0, true)
        endmethod

        method operator borderTexture takes nothing returns string
            return .borderTextureFile
        endmethod

        method operator model= takes string filePath returns nothing
            set .modelFile = filePath
            call BlzFrameSetModel(.modelFrameH, filePath, 0)
        endmethod

        method operator model takes nothing returns string
            return .modelFile
        endmethod
  
        method operator trueWidth takes nothing returns real
            return .width*.scale
        endmethod
  
        method operator trueHeight takes nothing returns real
            return .height*.scale
        endmethod

        method operator localScale= takes real r returns nothing
            local thistype node = .m_childs.next

            set .m_localScale = RMaxBJ(r, 0.0001)
            call setSize(.width, .height)
            call move(.localPosX, .localPosY)

            loop
                exitwhen node.head or node == 0
                set node.localScale = node.localScale
                set node = node.next
            endloop
        endmethod

        method operator localScale takes nothing returns real
            return .m_localScale
        endmethod

        method operator scale takes nothing returns real
            if .parent == Null or not .inheritScale then
                return .localScale
            else
                return .localScale * .parent.scale
            endif
        endmethod

        method operator opacity= takes integer amount returns nothing
            local thistype node = .m_childs.next

            set .localOpacity = amount
            call BlzFrameSetAlpha(.frame, .opacity)

            loop
                exitwhen node.head or node == 0
                set node.opacity = node.localOpacity
                set node = node.next
            endloop
        endmethod

        method operator opacity takes nothing returns integer
            if .parent == Null or not .inheritOpacity then
                return .localOpacity
            else
                return R2I(I2R(.localOpacity) * I2R(.parent.opacity)/255.)
            endif
        endmethod

        method operator level= takes integer level returns nothing
            local thistype node = .m_childs.next

            set .m_level = level
            call BlzFrameSetLevel(.frame, .trueLevel)

            loop
                exitwhen node.head or node == 0
                set node.level = node.m_level
                set node = node.next
            endloop
        endmethod

        method operator level takes nothing returns integer
            return .m_level
        endmethod

        method operator trueLevel takes nothing returns integer
            if .parent == Null or not .inheritLevel then
                return .m_level
            else
                return .m_level + .parent.level
            endif
        endmethod

        method operator visible= takes boolean state returns nothing
            local thistype node = .m_childs.next

            set .visibleSelf = state
            call BlzFrameSetVisible(.frame, .visible)

            loop
                exitwhen node.head or node == 0
                set node.visible = node.visibleSelf
                set node = node.next
            endloop
        endmethod

        method operator visible takes nothing returns boolean
            if .parent == Null or not .inheritVisibility then
                return .visibleSelf
            else
                return .visibleSelf and .parent.visible
            endif
        endmethod

        method operator enabled= takes boolean state returns nothing
            local thistype node = .m_childs.next

            set .enabledSelf = state
            call BlzFrameSetEnable(.frame, .enabled)

            loop
                exitwhen node.head or node == 0
            set node.enabled = node.enabledSelf
                set node = node.next
            endloop
        endmethod

        method operator enabled takes nothing returns boolean
            if .parent == Null or not .inheritEnableState then
                return .enabledSelf
            else
                return .enabledSelf and .parent.enabled
            endif
        endmethod

        method operator vertexColor= takes integer color returns nothing
            call BlzFrameSetVertexColor(.modelFrameH, color)
        endmethod

        method operator value= takes real r returns nothing
            call BlzFrameSetValue(.frame, r)
        endmethod

        method operator value takes nothing returns real
            return BlzFrameGetValue(.frame)
        endmethod

        method operator stepSize= takes real r returns nothing
            set .m_stepSize = RMaxBJ(r, 0.0001)
            call BlzFrameSetStepSize(.frame, .m_stepSize)
        endmethod

        method operator stepSize takes nothing returns real
            return .m_stepSize
        endmethod

        method operator tooltips= takes thistype comp returns nothing
            set .m_tooltips = comp
            call BlzFrameSetTooltip(.frame, comp.frame)
        endmethod

        method operator tooltips takes nothing returns thistype
            return .m_tooltips
        endmethod

        method setAnchorPoint takes real x, real y returns nothing
            set .anchorX = x
            set .anchorY = y
            call move(.localPosX, .localPosY)
        endmethod

        method setPivotPoint takes real x, real y returns nothing
            set .pivotX = x
            set .pivotY = y
            call move(.localPosX, .localPosY)
        endmethod

        method setSize takes real width, real height returns nothing
            set .width  = RMaxBJ(width,  0)
            set .height = RMaxBJ(height, 0)
            call BlzFrameSetSize(frame, .trueWidth*UIUtils.PXTODPI, .trueHeight*UIUtils.PXTODPI)
            if .pivotX + .pivotY + .anchorX + .anchorY != 0 then
                call move(.localPosX, .localPosY)
            endif
        endmethod
  
        method operator screenPosX takes nothing returns real
            if .parent == Null or not .inheritPosition then
                return .localPosX
            elseif .scalePosition then
                return .parent.screenPosX+.localPosX*.parent.scale
            else
                return .parent.screenPosX+.localPosX
            endif
        endmethod
  
        method operator screenPosY takes nothing returns real
            if .parent == Null or not .inheritPosition then
                return .localPosY
            elseif .scalePosition then
                return .parent.screenPosY+.localPosY*.parent.scale
            else
                return .parent.screenPosY+.localPosY
            endif
        endmethod

        method move takes real x, real y returns nothing
            local thistype node = .m_childs.next

            set .localPosX = x
            set .localPosY = y
            call BlzFrameSetAbsPoint(.frame, FRAMEPOINT_BOTTOMLEFT, UIUtils.GetScreenPosX(.screenPosX+UIUtils.ResolutionWidth*.anchorX-.trueWidth*.pivotX), UIUtils.GetScreenPosY(.screenPosY+UIUtils.ResolutionHeight*.anchorY-.trueHeight*.pivotY))

            loop
                exitwhen node.head or node == 0
                call node.move(node.localPosX, node.localPosY)
                set node = node.next
            endloop
        endmethod

        method moveEx takes real x, real y returns nothing
            if .parent == Null or not .inheritPosition then
                call move(x, y)
            else
                call move((x-.parent.screenPosX)/.parent.localScale, (y-.parent.screenPosY)/.parent.localScale)
            endif
        endmethod

        method relate takes thistype relative, real x, real y returns nothing
            if .parent == Null then
                call move(relative.screenPosX+x, relative.screenPosY+y)
            else
                call moveEx(relative.screenPosX+x, relative.screenPosY+y)
            endif
        endmethod
  
        method refresh takes nothing returns nothing
            set .localScale = .localScale
            set .visible = .visibleSelf
            set .enabled = .enabledSelf
            set .opacity = .localOpacity
            set .level   = .m_level
        endmethod

        method click takes nothing returns nothing
            call BlzFrameClick(.frame)
        endmethod

        method cageMouse takes boolean state returns nothing
            call BlzFrameCageMouse(.frame, state)
        endmethod

        method setFocus takes boolean state returns nothing
            call BlzFrameSetFocus(.frame, state)
        endmethod

        method setSpriteAnimate takes integer primaryProp, integer flags returns nothing
            call BlzFrameSetSpriteAnimate(.frame, primaryProp, flags)
        endmethod

        method setMinMaxValue takes real min, real max returns nothing
            set .valueMin = min
            set .valueMax = max
            call BlzFrameSetMinMaxValue(.frame, min, max)
        endmethod

        method setFont takes string fontPath, real height, integer flags returns nothing
            call BlzFrameSetFont(.textFrameH, fontPath, height, flags)
        endmethod

        method setTextAlignment takes textaligntype vertical, textaligntype horizontal returns nothing
            call BlzFrameSetTextAlignment(.textFrameH, vertical, horizontal)
        endmethod

        method getSubFrame takes string name returns framehandle
            local framehandle h = BlzGetFrameByName(name, .context)
      
            if h == null then
                return .frame
            else
                return h
            endif
        endmethod

        method forEachChild takes code func returns nothing
            local thistype node = .m_childs.next

            call TriggerAddAction(ExecTrigg, func)
            loop
                exitwhen node.head or node == 0
                set EnumChild = node
                call TriggerExecute(ExecTrigg)
                set node = node.next
            endloop
            call TriggerClearActions(ExecTrigg)
        endmethod

        method destroy takes nothing returns nothing
            local thistype node = .m_childs.next
 
            loop
                exitwhen node.head or node == 0
                call node.destroy()
                set node = node.next
            endloop

            call BlzDestroyFrame(.frame)
            call DestroyTrigger(.anyEventTrigg)
            call StoreInteger(GC, name, I2S(.context), GetStoredInteger(GC, name, "0"))
            call StoreInteger(GC, name, "0", .context)
            call AllComponents.remove(this)
            call .m_childs.flushNode()
            call removeNode()
            call deallocate()

            set .anyEventTrigg      = null
            set .mainTextureH       = null
            set .disabledTextureH   = null
            set .highlightTextureH  = null
            set .pushedTextureH     = null
            set .backgroundTextureH = null
            set .borderTextureH     = null
            set .textFrameH         = null
            set .modelFrameH        = null
            set .frame              = null
            set .name               = null
            set .frameType          = null
            set .m_parent           = Null
            set .m_childs           = 0
        endmethod

        static method create takes boolean isSimple, string frameType, thistype m_parent, real x, real y, integer level returns thistype
            local thistype this = allocate()
            local integer tempInt
 
            set .context = GetStoredInteger(GC, frameType, "0")
            set tempInt  = GetStoredInteger(GC, frameType, I2S(context))
            if tempInt == 0 then
                call StoreInteger(GC, frameType, "0", context+1)
            else
                call StoreInteger(GC, frameType, "0", tempInt)
            endif
 
            set .parent             = m_parent
            set .m_childs           = createNode()
            if IsSimple(frameType, isSimple) then
                set .frame          = BlzCreateSimpleFrame(frameType, DefaultFrame.Game, .context)
            else
                set .frame          = BlzCreateFrame(frameType, DefaultFrame.Game, 0, .context)
            endif
            set .mainTextureH       = getSubFrame(frameType + "Texture")
            set .disabledTextureH   = getSubFrame(frameType + "Disabled")
            set .highlightTextureH  = getSubFrame(frameType + "Highlight")
            set .pushedTextureH     = getSubFrame(frameType + "Pushed")
            set .backgroundTextureH = getSubFrame(frameType + "Background")
            set .borderTextureH     = getSubFrame(frameType + "Border")
            set .textFrameH         = getSubFrame(frameType + "Text")
            set .modelFrameH        = getSubFrame(frameType + "Model")

            set .inheritScale        = true
            set .inheritOpacity        = true
            set .inheritVisibility    = true
            set .inheritEnableState    = true
            set .inheritPosition    = true
            set .inheritLevel        = true
            set .scalePosition         = true
 
            set .width              = BlzFrameGetWidth(.frame)*UIUtils.DPITOPX
            set .height                = BlzFrameGetHeight(.frame)*UIUtils.DPITOPX
            set .frameType          = frameType
            set .name               = frameType + I2S(.context)
            set .level              = level
            set .visibleSelf        = true
            set .enabledSelf        = true
            set .value              = 0.0
            set .localScale         = 1.0
            set .anchorX             = 0.0
            set .anchorY             = 0.0
            set .pivotX              = 0.0
            set .pivotY              = 0.0
            set .opacity            = 255
 
            set .mainTextureFile       = ""
            set .disabledTextureFile   = ""
            set .pushedTextureFile     = ""
            set .highlightTextureFile  = ""
            set .backgroundTextureFile = ""
            set .borderTextureFile     = ""
            set .modelFile             = ""
 
            call move(x, y)
            call setMinMaxValue(0.0, 1.0)
            call AllComponents.add(this)
            call SaveInteger(HT, GetHandleId(.frame), 0, this)

            return this
        endmethod

        private static method onInit takes nothing returns nothing
            set HT = InitHashtable()
            set GC = InitGameCache("UIUtils.w3v")
            call BlzLoadTOCFile("war3mapimported\\UIUtils.toc")
        endmethod

    endstruct

    private struct AllComponents extends array

        implement LinkedList

        static method add takes thistype this returns nothing
            call base.insertNode(this)
        endmethod

        static method remove takes thistype this returns nothing
            call removeNode()
        endmethod

    endstruct
 
endlibrary
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Holy shit. Ive been gone for just one year and all this is possible now? Im so excited to come back to mapping soon.

Amazing effort and system. Cant wait to try it out in practice.

If only blizzard would be as dependable as the hive Community.
Yes it is.

Good to see you back man..
 
Level 5
Joined
Apr 26, 2006
Messages
160
I tried using this on my map and it was great, until I clicked a chicken at some point and the chicken portrait filled my entire screen!

Pressing spacebar got me out of it to the regular camera view, but after that things like unit selection/highlights/health bars didn't show anymore.

Edit: Pressing F1 gets me out of it properly but it is consistently happening when I get near a trash doodad.
 

Attachments

  • WC3ScrnShot_020520_043609_001.png
    WC3ScrnShot_020520_043609_001.png
    1.6 MB · Views: 63
Last edited:
Level 5
Joined
Apr 26, 2006
Messages
160
@Kanaru is your UI Utils up to date (v1.05)? Find the latest version here: UI Utils v1.05

EDIT:
Main post has been updated to avoid further confusions.
Yes it is!

I can consistently click this chicken and the portrait will fill the entire screen, press F1 to exit, and keep doing it. In this case F1 is selecting my hero unit.
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Yes it is!

I can consistently click this chicken and the portrait will fill the entire screen, press F1 to exit, and keep doing it. In this case F1 is selecting my hero unit.
Does the same issue also happen when you test the system's demo map? If not then it could be caused by faulty system configuration or one of your trigger/code. If that's the case then I will need to look at all of your UI related triggers including the UI Utils (that is inside your map) itself...
 
Last edited:
Level 5
Joined
Apr 26, 2006
Messages
160
I can't seem to replicate it in the demo map. I removed the chicken from my map and it hasn't happened since, I don't know what it is about it, there weren't any triggers related to the chicken and the portrait frame was always hidden.
 
Level 3
Joined
Dec 23, 2005
Messages
29
I've also have the 'chicken portrait' glitch, although it happened to me whenever i would click on a building or a naval unit.

I simply copy pasted the command button triggers from the demo map.
 
Level 5
Joined
Apr 26, 2006
Messages
160
I've also have the 'chicken portrait' glitch, although it happened to me whenever i would click on a building or a naval unit.

I simply copy pasted the command button triggers from the demo map.

I just made a new map and tried it out, I had a worker unit that can build things, if I create a building and click it, it will fill the screen with the portrait.

Same thing where I just copy pasted the triggers for UIUtils, LinkedListModule, and the Command Buttons. Though this happens even if the Command Buttons script isn't there, so it's all in UIUtils.

In UIUtils, PORTRAIT_FRAME_VISIBLE = false

If I set it to true, it just fills the screen from the beginning. I don't see any options for even setting its scale/width/height or anything either, just anchor points/position/pivot. I don't see any documentation about existing frames like this in the manual: [JASS/AI] - UI Utils Manual

Edit: I think I found a workaround, I set it to true and set everything from 0.0 to 1.0. Maybe it's just rendering off the screen to the right due to the anchor point so it's effectively invisible?


Separately I have an issue with the Command Buttons where it won't show all the buildings that can be built. I don't think it's checking the number of buttons with submenus, and I have no idea how to script that. I can't figure out a way to get a generic "player clicked an ability", only specific abilities, which could work with Build but then it wouldn't reregister if you leave that menu.

It can sometimes show them if I click another unit then click back without exiting the build menu, but the frames won't be spaced properly (so they are overlapping). The odd thing is that it seems okay in the demo map.

Edit: I just made it a periodic event and it works fine now.
 
Last edited:
Level 5
Joined
Apr 26, 2006
Messages
160
It might be a "bug" inside UIUtils since it never actually change the portrait frame's size and only clear it's points, maybe that breaks the frame's size. But haven't really investigated it.
Sorry I keep having new stuff here, the minimap is also very strangely squished even on the example map.
 
Level 1
Joined
Jun 14, 2009
Messages
4
Hello, and first off thank you for this immensely useful mod! I can already see its capabilities and how it will (greatly) help out my map.

I would like to report however, that I've also had both the 'Zoomed Portrait' bug (happened randomly when I left clicked a neutral hostile critter, a Gnoll), and my minimap appears squished (both my own and the provided sample map).

Thank you for your work!
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
I also have the squished minimap in the example map. Also all ability buttons overlap each other in the demo map. Playing on 1920x1080 resolution full screen mode.
The minimap isn't a simple frame, that explains the squishing. For now the fix would be to manually move the minimap frame using the Blz function. And for command buttons too, the demo map never actually set their sizes and the ClearAbsPoints function seems to break their size or something.

In the next update, each original frame will be treated as UIFrame instances so modifying them would be as easy as modifying custom ones, and boundaries restriction for non-simple frame would be applied too, fixing the squished issues in the process.


I hope stuffs will be discussed over the real resource thread in the future. I don't know how the lab is now actually more noticeable than the spell section itself.. so tragic :/
 
Status
Not open for further replies.
Top