• 🏆 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 v1.05

This bundle is marked as pending. It has not been reviewed by a staff member yet.
Blizzard gave us a powerful UI system and yet this system is giving it even more steroids and nice outfits!

:fp: User Manual

Key Features:
• Includes several primitive frame types (texture, text, slider, etc.)
• Compatible with custom frame definition
• Uses pixel as measurement unit
• Friendly UI natives wrappers
• Custom hierarchy system with in-depth inheritance control
• Automatically prevents non-simple frame from going out of the 4:3 bounds
• Enhanced frame pivot & anchor point feature for all-resolution support
• Automatic create context handling
• Extra security measures (prevents UI native related crashes out of the box)
• Customizable full-screen mode
• Important default/original frames container
• Includes all available built-in fdf files
Requirements:
• LinkedListModule : [Snippet] LinkedListModule
• Warcraft version 1.31+​

Code:
JASS:
library UIUtils requires LinkedListModule
    /*********************************************************************************
    *
    *            UI Utils v1.05
    *
    *    Create and manage user interface in highly convenient and intuitive way!
    *
    *    Check for update at: https://www.hiveworkshop.com/threads/320005/
    *
    *    Features:
    *        • Includes several primitive frame types (texture, text, slider, etc.)
    *        • Compatible with custom frame definition
    *        • Uses pixel as measurement unit
    *        • Friendly UI native wrappers
    *        • Custom hierarchy system with in-depth inheritance control
    *        • Automatically prevents non-simple frame from going out of the 4:3 bounds
    *        • Enhanced frame pivot & anchor point feature for all-resolution support
    *        • Automatic create context handling
    *        • Extra security measures (prevents UI native related crashes out of the box)
    *        • Customizable full-screen mode
    *        • Essential default/original frames container
    *        • Includes all available built-in fdf files
    *
    *    I.  System requirements:
    *        • LinkedListModule            : http://hiveworkshop.com/threads/snippet-linkedlistmodule.206552/
    *        • Warcraft III version 1.31+
    *
    *    II. Installation:
    *        • Import LinkedListModule
    *        • Copy UIUtils trigger to your map
    *        • Go to Import Manager and import following files to your map:
    *            - UIUtils.toc
    *            - UIUtils.fdf
    *        • Configure the system below
    *        • For true fullscreen you might need to manually remove the inventory cover texture
    *
    *    III. Credits:
    *        • Tasyen   | UI tutorials & researches
    *        • Dirac    | LinkedListModule
    *
    *    IV. API - (Complete manual: https://www.hiveworkshop.com/threads/320046/)
    *
    *           struct UIFrame                                                                                                                                                                                                                                                                            */static if FOLD then /*
               
                1. Ctor & dtor
                    - Let "isSimple" be "true" if it is a simple frame type
                        | static method create takes boolean isSimple, string frameType, UIFrame parent, real x, real y, integer level returns UIFrame
                       
                    - Dispose the frame
                        | method destroy takes nothing returns nothing
                   
                2. Wrappers
                    - Set & get frame's textures
                        • Might not be compatible with custom frame definition
                        • Some only work for specific type of primitive frames
                        • Some might not work properly just yet (blizzard limitation)
                        > Default main texture
                            | method operator texture= takes string filePath returns nothing
                            | method operator texture  takes nothing returns string
                        > Texture displayed when frame is disabled
                            | method operator disabledTexture= takes string filePath returns nothing
                            | method operator disabledTexture  takes nothing returns string
                        > Highlighter texture
                            | method operator highlightTexture= takes string filePath returns nothing
                            | method operator highlightTexture  takes nothing returns string
                        > Texture displayed when frame is pressed
                            | method operator pushedTexture= takes string filePath returns nothing
                            | method operator pushedTexture  takes nothing returns string
                        > Background texture for the frame
                            | method operator backgroundTexture= takes string filePath returns nothing
                            | method operator backgroundTexture  takes nothing returns string
                        > Border texture for the frame
                            | method operator borderTexture= takes string filePath returns nothing
                            | method operator borderTexture  takes nothing returns string
                   
                    - Set & get frame's parent
                        | method operator parent= takes UIFrame frame returns nothing
                        | method operator parent  takes nothing returns UIFrame
                       
                    - Get frame's screen space position
                        • Values might be affected by frame's parent anchor point
                            | method operator screenPosX takes nothing returns real
                            | method operator screenPosY takes nothing returns real
                   
                    - Get frame's bounds
                            | method operator left   takes nothing returns real
                            | method operator right  takes nothing returns real
                            | method operator top    takes nothing returns real
                            | method operator bottom takes nothing returns real
                           
                    - Get frame's true (scaled) size in pixel
                        | method operator width  takes nothing returns real
                        | method operator height takes nothing returns real
                       
                    - Set & get frame's scale factor
                        > Frame's independent scale factor
                            | method operator localScale= takes real r returns nothing
                            | method operator localScale  takes nothing returns real
                        > Frame's true scale
                            | method operator scale takes nothing returns real
                       
                    - Set & get frame's visibility state
                        | method operator visible= takes boolean state returns nothing
                        | method operator visible  takes nothing returns boolean
                       
                    - Set & get frame's transparency (0-255)
                        | method operator opacity= takes integer amount returns nothing
                        | method operator opacity  takes nothing returns integer
                       
                    - Set & get enable state of the frame
                        | method operator enabled= takes boolean state returns nothing
                        | method operator enabled  takes nothing returns boolean
                       
                    - Set & get frame's self sorting/layering order
                        | method operator level= takes integer level returns nothing
                        | method operator level  takes nothing returns integer
                        > Get frame's actual sorting/layering order
                            | method operator trueLevel takes nothing returns integer
                           
                    - Set & get frame's text content
                        | method operator text= takes string str returns nothing
                        | method operator text  takes nothing returns string
                       
                    - Set & get frame's text content length limit
                        | method operator maxLength= takes integer length returns nothing
                        | method operator maxLength  takes nothing returns integer
                       
                    - Set frame's text color
                        > Use "BlzConvertColor" function to convert ARGB color
                            | method operator textColor= takes integer color returns nothing
                       
                    - Set & get frame's model file
                        | method operator model= takes string filePath returns nothing
                        | method operator model  takes nothing returns string
                       
                    - Set vertex color of the model frame
                        > Use "BlzConvertColor" function to convert ARGB color
                            | method operator vertexColor= takes integer color returns nothing
                       
                    - Set & get value of slider frame
                        | method operator value= takes real r  returns nothing
                        | method operator value  takes nothing returns real
                       
                    - Step size is increment of slider bar relative to its min max value
                        | method operator stepSize= takes real r  returns nothing
                        | method operator stepSize  takes nothing returns real
                       
                    - Set & get tooltips frame
                        | method operator tooltips= takes UIFrame frame returns nothing
                        | method operator tooltips  takes nothing returns UIFrame
                       
                    - Get sub-frame handle based on passed name
                        • Usage: tempFrame.subFrame["tempFrameText"] => returns subframe handle of "tempFrame" by name of "tempFrameText"
                            | method operator subFrame[] takes string name returns framehandle
                       
                    - Register any event happen to the frame (click, mouse enter/leave, etc.)
                        • Use "UIFrame.TriggerComponent" to get the triggering frame
                        • Use "BlzGetTriggerFrameEvent()" function to get the event type
                            | method operator onAnyEvent= takes code func returns triggercondition
                   
                2. Methods
                    - Iterates through all child frames of the frame
                        • Use "UIFrame.EnumChild" to get the iterated child frame
                            | method forEachChild takes code func returns nothing
                       
                    - Set frame's text properties
                        | method setTextAlignment takes textaligntype vertical, textaligntype horizontal returns nothing
                        | method setFont takes string fontType, real fontSize, integer flags returns nothing
                   
                    - Set slider min max values
                        | method setMinMaxValue takes real min, real max returns nothing
                   
                    - Animate frame texture
                        | method setSpriteAnimate takes integer primaryProp, integer flags returns nothing
                       
                    - Give focus to the frame
                        | method setFocus takes boolean state returns nothing
                   
                    - Cage mouse inside the frame's boundaries
                        | method cageMouse takes boolean state returns nothing
                   
                    - Emulate click on the frame
                        | method click takes nothing returns nothing
                       
                    - Force update the frame
                        | method refresh takes nothing returns nothing
                       
                    - Modify frame's position
                        > Set frame's local position
                            | method move takes real x, real y returns nothing
                        > Set frame's screen position (ignores parent position)
                            | method moveEx takes real x, real y returns nothing
                        > Set frame position relative to other specified frame
                            | method relate takes UIFrame relative, real x, real y returns nothing
                           
                    - Set dimension of the frame
                        | method setSize takes real width, real height returns nothing
                       
                    - Set frame's anchor & pivot point
                        | method setPivotPoint  takes real x, real y returns nothing
                        | method setAnchorPoint takes real x, real y returns nothing
                   
                3. Members
                    - Main frame handle
                        | readonly framehandle frame

                    - Set & get frame's name
                        | string name

                    - Set & get property inheritance
                        • Frame refresh is recommended after modifying inheritance
                            | boolean inheritScale
                            | boolean inheritOpacity
                            | boolean inheritVisibility
                            | boolean inheritEnableState
                            | boolean inheritPosition
                            | boolean inheritLevel
                            | boolean scalePosition

                    - Frame's type name
                        | readonly string frameType
                       
                    - Frame's local space position
                        | readonly real localPosX
                        | readonly real localPosY
                       
                    - Frame's anchor & pivot points
                        | readonly real anchorX
                        | readonly real anchorY
                        | readonly real pivotX
                        | readonly real pivotY
                       
                    - Frame's unscaled size
                        | readonly real unscaledWidth
                        | readonly real unscaledHeight
                       
                    - Get frame text font properties
                        | readonly integer fontFlags
                        | readonly real    fontSize
                        | readonly string  fontType
                       
                    - Slider frame's min max value
                        | readonly real valueMin
                        | readonly real valueMax
                       
                    - Create context index of the frame
                        | readonly integer context
                       
                    - Local states of the frame
                        | readonly boolean visibleSelf
                        | readonly boolean enabledSelf
                       
                    - Is the frame a simple frame type or not
                        | readonly boolean isSimple
                       
                    - Local transparency of the frame
                        | readonly integer localOpacity
                       
                4. Static Members
                    - Representation for null frame
                        | readonly static UIFrame Null
                       
                    - Currently iterated frame of "forEachChild" method
                        | readonly static UIFrame EnumChild
                       
                    - Triggerer of the "onAnyEvent"
                        | readonly static UIFrame TriggerComponent

                    - Primitive frame names
                        | readonly static string TYPE_TEXT
                        | readonly static string TYPE_SIMPLE_TEXT
                        | readonly static string TYPE_TEXTURE
                        | readonly static string TYPE_SIMPLE_TEXTURE
                        | readonly static string TYPE_BUTTON
                        | readonly static string TYPE_SIMPLE_BUTTON
                        | readonly static string TYPE_BAR
                        | readonly static string TYPE_H_SLIDER
                        | readonly static string TYPE_V_SLIDER
                                                                                                                                                                                                                                                                                                        */
                                                                                                                                                                                                                                                                                                        endif
   /*           struct UIUtils                                                                                                                                                                                                                                                                            */static if FOLD then /*
   
                1. Static Methods
                    - Calculate aspect ratio height
                        | static method CalcAspectRatio takes real w, real h, real aspectWidth returns integer
                       
                    - Convert pixel unit to DPI and vice versa
                        • Usage: [value]*UIUtils.PXTODPI
                                 [value]*UIUtils.DPITOPX
                            | static method operator PXTODPI takes nothing returns real
                            | static method operator DPITOPX takes nothing returns real
                           
                    - Width of the 4:3 bound
                        | static method operator FrameBoundWidth takes nothing returns real
       
                    - Convert from pixel to screen x/y coordinate (in DPI unit)
                        | static method GetScreenPosX takes real x returns real
                        | static method GetScreenPosY takes real y returns real
                       
                    - Force update default frames
                        | static method RefreshDefaultFrames takes nothing returns nothing
                       
                    - Force update resolution
                        | static method RefreshResolution takes nothing returns nothing
                       
                    - Resolution change event
                        | static method RegisterOnResolutionChangeEvent takes code func returns triggercondition
                        | static method RemoveOnResolutionChangeEvent   takes triggercondition cond returns nothing
                       
                2. Static Members
                    - Updated after resolution change event
                        • Values might be async between clients
                            | readonly static integer ResolutionWidth
                            | readonly static integer ResolutionHeight
                            | readonly static integer AspectWidth
                            | readonly static integer AspectHeight
                                                                                                                                                                                                                                                                                                        */
                                                                                                                                                                                                                                                                                                        endif
   /*           struct DefaultFrame (singleton)                                                                                                                                                                                                                                                            */static if FOLD then /*
                    - Origin frames
                        | readonly static framehandle         Game
                        | readonly static framehandle         World
                        | readonly static framehandle         HeroBar
                        | readonly static framehandle array   HeroButton        [0 - 6]
                        | readonly static framehandle array   HeroHPBar         [0 - 6]
                        | readonly static framehandle array   HeroMPBar         [0 - 6]
                        | readonly static framehandle array   HeroIndicator     [0 - 6]
                        | readonly static framehandle array   ItemButton        [0 - 5]
                        | readonly static framehandle array   CommandButton     [0 - 11]
                        | readonly static framehandle array   SystemButton      [0 - 3]
                        | readonly static framehandle         Portrait
                        | readonly static framehandle         Minimap
                        | readonly static framehandle array   MinimapButton     [0 - 4]
                        | readonly static framehandle         Tooltip
                        | readonly static framehandle         UberTooltip
                        | readonly static framehandle         ChatMsg
                        | readonly static framehandle         UnitMsg
                        | readonly static framehandle         TopMsg
             
                    - Other frames
                        | readonly static framehandle         Console
                        | readonly static framehandle         GoldText
                        | readonly static framehandle         LumberText
                        | readonly static framehandle         FoodText
                        | readonly static framehandle         UnitNameText
                        | readonly static framehandle         ResourceBar
                        | readonly static framehandle         UpperButtonBar
                                                                                                                                                                                                                                                                                                        */
                                                                                                                                                                                                                                                                                                        endif
   /*
    *    V. Configurations
    *                                                                                                                                                                                                                                                                                                    */globals
        // 1. TOC file path
            private constant string TOC_FILE = "war3mapimported\\UIUtils.toc"
           
        // 2. Temporary cache name
            private constant string CACHE_NAME = "UIUtils.w3v"
           
        // 3. Resolution change detection interval
            private constant real RESOLUTION_CHECK_INTERVAL = 0.1
           
        // 4. true : hides console frames on map init (full screen)
            private constant boolean HIDE_CONSOLE_FRAME = true

        // 5. true : frame's properties will be retained when it changes parent
            private constant boolean PERSISTENT_CHILD_PROPERTIES = true
           
        // 6. true : helps to prevent non-simple frame from going beyond the 4:3 bounds
            private constant boolean REFRAIN_NON_SIMPLE_FRAME = true

        // 7. Reference resolution, as which is used to design the interface
            private constant integer RESOLUTION_WIDTH  = 1360
            private constant integer RESOLUTION_HEIGHT = 768
       
        // 8. Configure in-game message frame
            private constant boolean MESSAGE_FRAME_VISIBLE  = true
            private constant real    MESSAGE_FRAME_ANCHOR_X = 0.0
            private constant real    MESSAGE_FRAME_ANCHOR_Y = 1.0
            private constant real    MESSAGE_FRAME_PIVOT_X  = 0.0
            private constant real    MESSAGE_FRAME_PIVOT_Y  = 1.0
            private constant real    MESSAGE_FRAME_POS_X    = 100.0
            private constant real    MESSAGE_FRAME_POS_Y    = -150.0
           
        // 9. Configure in-game chat frame
            private constant boolean CHAT_FRAME_VISIBLE  = true
            private constant real    CHAT_FRAME_ANCHOR_X = 0.0
            private constant real    CHAT_FRAME_ANCHOR_Y = 0.0
            private constant real    CHAT_FRAME_PIVOT_X  = 0.0
            private constant real    CHAT_FRAME_PIVOT_Y  = 0.0
            private constant real    CHAT_FRAME_POS_X    = 10.0
            private constant real    CHAT_FRAME_POS_Y    = 100.0
           
        // 10. Configure tooltips frame
            private constant boolean TOOLTIPS_FRAME_VISIBLE  = true
            private constant real    TOOLTIPS_FRAME_ANCHOR_X = 1.0
            private constant real    TOOLTIPS_FRAME_ANCHOR_Y = 0.0
            private constant real    TOOLTIPS_FRAME_PIVOT_X  = 1.0
            private constant real    TOOLTIPS_FRAME_PIVOT_Y  = 0.0
            private constant real    TOOLTIPS_FRAME_POS_X    = -50.0
            private constant real    TOOLTIPS_FRAME_POS_Y    = 0.0
           
        // 11. Configure minimap frame
            private constant boolean MINIMAP_FRAME_VISIBLE  = true
            private constant real    MINIMAP_FRAME_ANCHOR_X = 1.0
            private constant real    MINIMAP_FRAME_ANCHOR_Y = 1.0
            private constant real    MINIMAP_FRAME_PIVOT_X  = 1.0
            private constant real    MINIMAP_FRAME_PIVOT_Y  = 1.0
            private constant real    MINIMAP_FRAME_POS_X    = 0.0
            private constant real    MINIMAP_FRAME_POS_Y    = 0.0
           
        // 12. Configure unit portrait frame
            private constant boolean PORTRAIT_FRAME_VISIBLE  = false
            private constant real    PORTRAIT_FRAME_ANCHOR_X = 0.0
            private constant real    PORTRAIT_FRAME_ANCHOR_Y = 0.0
            private constant real    PORTRAIT_FRAME_PIVOT_X  = 0.0
            private constant real    PORTRAIT_FRAME_PIVOT_Y  = 0.0
            private constant real    PORTRAIT_FRAME_POS_X    = 0.0
            private constant real    PORTRAIT_FRAME_POS_Y    = 0.0
           
        // 13. Configure other frame visibility
            private constant boolean RESOURCE_FRAME_VISIBLE   = false
            private constant boolean CMD_BUTTON_FRAME_VISIBLE = false
                                                                                                                                                                                                                                                                                                            endglobals
   /*
    *    END OF DOCUMENT ----- Modify following codes on your own risk
    *
    *********************************************************************************/
   
    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 ResourceBar = BlzGetFrameByName("ResourceBarFrame", 0)
            set UnitNameText = BlzGetFrameByName("SimpleNameValue", 0)
            set UpperButtonBar = BlzGetFrameByName("UpperButtonBarFrame", 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)
                call RefreshDefaultFrames()
                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)
                    call BlzFrameClearAllPoints(DefaultFrame.ResourceBar)
                    call BlzFrameSetAbsPoint(DefaultFrame.ResourceBar, 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
        readonly static framehandle         ResourceBar     = null
        readonly static framehandle         UpperButtonBar  = null
       
        implement DefaultFrameInit
    endstruct
   
    private keyword AllComponents

    struct UIUtils extends array
        readonly static integer ResolutionWidth  = RESOLUTION_WIDTH
        readonly static integer ResolutionHeight = RESOLUTION_HEIGHT
       
        readonly static real ScaleFactor = 1
       
        private static trigger resolutionChangeTrigg = CreateTrigger()

        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 operator FrameBoundWidth takes nothing returns real
            return (ResolutionWidth-ResolutionHeight/600.*800.)/2.
        endmethod
       
        static method GetScreenPosX takes real x returns real
            return (-FrameBoundWidth+x)*PXTODPI
        endmethod
       
        static method GetScreenPosY takes real y returns real
            return y*PXTODPI
        endmethod
       
        static method RefreshDefaultFrames takes nothing returns nothing
            static if MESSAGE_FRAME_VISIBLE then
                call BlzFrameClearAllPoints(DefaultFrame.UnitMsg)
                call BlzFrameSetAbsPoint(DefaultFrame.UnitMsg, FRAMEPOINT_BOTTOMLEFT,/*
                */ GetScreenPosX(MESSAGE_FRAME_POS_X+ResolutionWidth*MESSAGE_FRAME_ANCHOR_X-BlzFrameGetWidth(DefaultFrame.UnitMsg)*DPITOPX*MESSAGE_FRAME_PIVOT_X),/*
                */ GetScreenPosY(MESSAGE_FRAME_POS_Y+ResolutionHeight*MESSAGE_FRAME_ANCHOR_Y-BlzFrameGetHeight(DefaultFrame.UnitMsg)*DPITOPX*MESSAGE_FRAME_PIVOT_Y))
            endif
           
            static if CHAT_FRAME_VISIBLE then
                call BlzFrameSetAbsPoint(DefaultFrame.ChatMsg, FRAMEPOINT_BOTTOMLEFT,/*
                */ GetScreenPosX(CHAT_FRAME_POS_X+ResolutionWidth*CHAT_FRAME_ANCHOR_X-BlzFrameGetWidth(DefaultFrame.ChatMsg)*DPITOPX*CHAT_FRAME_PIVOT_X),/*
                */ GetScreenPosY(CHAT_FRAME_POS_Y+ResolutionHeight*CHAT_FRAME_ANCHOR_Y-BlzFrameGetHeight(DefaultFrame.ChatMsg)*DPITOPX*CHAT_FRAME_PIVOT_Y))
            endif

            static if TOOLTIPS_FRAME_VISIBLE then
                call BlzFrameClearAllPoints(DefaultFrame.UberTooltip)
                call BlzFrameSetAbsPoint(DefaultFrame.UberTooltip, FRAMEPOINT_BOTTOMLEFT,/*
                */ GetScreenPosX(TOOLTIPS_FRAME_POS_X+ResolutionWidth*TOOLTIPS_FRAME_ANCHOR_X-BlzFrameGetWidth(DefaultFrame.UberTooltip)*DPITOPX*TOOLTIPS_FRAME_PIVOT_X),/*
                */ GetScreenPosY(TOOLTIPS_FRAME_POS_Y+ResolutionHeight*TOOLTIPS_FRAME_ANCHOR_Y-BlzFrameGetHeight(DefaultFrame.UberTooltip)*DPITOPX*TOOLTIPS_FRAME_PIVOT_Y))
            endif
           
            call BlzFrameClearAllPoints(DefaultFrame.Minimap)
            static if MINIMAP_FRAME_VISIBLE then
                call BlzFrameSetAbsPoint(DefaultFrame.Minimap, FRAMEPOINT_BOTTOMLEFT,/*
                */ GetScreenPosX(MINIMAP_FRAME_POS_X+ResolutionWidth*MINIMAP_FRAME_ANCHOR_X-BlzFrameGetWidth(DefaultFrame.Minimap)*DPITOPX*MINIMAP_FRAME_PIVOT_X),/*
                */ GetScreenPosY(MINIMAP_FRAME_POS_Y+ResolutionHeight*MINIMAP_FRAME_ANCHOR_Y-BlzFrameGetHeight(DefaultFrame.Minimap)*DPITOPX*MINIMAP_FRAME_PIVOT_Y))
            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,/*
                */ GetScreenPosX(PORTRAIT_FRAME_POS_X+ResolutionWidth*PORTRAIT_FRAME_ANCHOR_X-BlzFrameGetWidth(DefaultFrame.Portrait)*DPITOPX*PORTRAIT_FRAME_PIVOT_X),/*
                */ GetScreenPosY(PORTRAIT_FRAME_POS_Y+ResolutionHeight*PORTRAIT_FRAME_ANCHOR_Y-BlzFrameGetHeight(DefaultFrame.Portrait)*DPITOPX*PORTRAIT_FRAME_PIVOT_Y))
            else
                call BlzFrameSetAbsPoint(DefaultFrame.Portrait, FRAMEPOINT_BOTTOMLEFT, -999.0, -999.0)
            endif
        endmethod
       
        static method RefreshResolution takes nothing returns nothing
            local AllComponents node
           
            set ResolutionWidth  = BlzGetLocalClientWidth()
            set ResolutionHeight = BlzGetLocalClientHeight()
            set ScaleFactor  = I2R(ResolutionHeight)/I2R(RESOLUTION_HEIGHT)
            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
        endmethod

        private static method CheckResolution takes nothing returns nothing
            if BlzGetLocalClientWidth() != ResolutionWidth or BlzGetLocalClientHeight() != ResolutionHeight then
                call RefreshResolution()
                call RefreshDefaultFrames()
                call TriggerEvaluate(resolutionChangeTrigg)
            endif
        endmethod
       
        static method RegisterOnResolutionChangeEvent takes code func returns triggercondition
            return TriggerAddCondition(resolutionChangeTrigg, Condition(func))
        endmethod
       
        static method RemoveOnResolutionChangeEvent takes triggercondition cond returns nothing
            call TriggerRemoveCondition(resolutionChangeTrigg, cond)
        endmethod

        implement UIUtilsInit
    endstruct
   
    private struct UISubFrame
        static UIFrame frame = 0
        method operator [] takes string s returns framehandle
            return BlzGetFrameByName(s, frame.context)
        endmethod
    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    unscaledWidth
        readonly real    unscaledHeight
        readonly real    valueMin
        readonly real    valueMax
        readonly real    fontSize
        readonly string  fontType
        readonly integer fontFlags
        readonly integer context
        readonly boolean isSimple
        readonly boolean visibleSelf
        readonly boolean enabledSelf
        readonly integer localOpacity
       
        private integer  m_level
        private integer  m_opacity
        private real     m_localScale
        private real     m_stepSize
        private real     m_width
        private real     m_height
        private real     m_scale
        private real     m_left
        private real     m_bottom
        private real     m_screenPosX
        private real     m_screenPosY
        private real     m_scaledLeft
        private real     m_scaledBottom
        private real     m_scaledScreenPosX
        private real     m_scaledScreenPosY
        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 subFrame takes nothing returns UISubFrame
            set UISubFrame.frame = this
            return 0
        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 frm returns nothing
            if frm != Null then
                if .m_parent != frm then
                    call .removeNode()
                endif
                call frm.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 - frm.screenPosX
                set .localPosY = .screenPosY - frm.screenPosY
            endif
            set .m_parent = frm
        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 width takes nothing returns real
            return .m_width
        endmethod
       
        method operator height takes nothing returns real
            return .m_height
        endmethod

        method operator localScale= takes real r returns nothing
            local thistype node = .m_childs.next
           
            set .m_localScale = RMaxBJ(r, 0.0001)
            if .parent == Null or not .inheritScale then
                set .m_scale = .localScale
            else
                set .m_scale = .localScale*.parent.scale
            endif
            set .m_width = .unscaledWidth*.scale
            set .m_height = .unscaledHeight*.scale
            call setSize(.unscaledWidth, .unscaledHeight)
            call setFont(.fontType, .fontSize, .fontFlags)
            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
            return .m_scale
        endmethod

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

            set .localOpacity = amount
            if .parent == Null or not .inheritOpacity then
                set .m_opacity = .localOpacity
            else
                set .m_opacity = R2I(I2R(.localOpacity)*I2R(.parent.opacity)/255.)
            endif
            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
            return m_opacity
        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 frame returns nothing
            set .m_tooltips = frame
            call BlzFrameSetTooltip(.frame, frame.frame)
        endmethod

        method operator tooltips takes nothing returns thistype
            return .m_tooltips
        endmethod
       
        method operator left takes nothing returns real
            return .m_left
        endmethod
       
        method operator right takes nothing returns real
            return .left+.width
        endmethod
       
        method operator bottom takes nothing returns real
            return .m_bottom
        endmethod
       
        method operator top takes nothing returns real
            return .bottom+.height
        endmethod
       
        method operator screenPosX takes nothing returns real
            return .m_screenPosX
        endmethod
       
        method operator screenPosY takes nothing returns real
            return .m_screenPosY
        endmethod
       
        private method normalizePosX takes real x returns real
            return RMinBJ(RMaxBJ(x, UIUtils.FrameBoundWidth+.width*.pivotX), UIUtils.ResolutionWidth-UIUtils.FrameBoundWidth-.width*(1.-.pivotX))
        endmethod
       
        private method normalizeScaledPosX takes real x returns real
            return RMinBJ(RMaxBJ(x, UIUtils.FrameBoundWidth+.width*.pivotX*UIUtils.ScaleFactor), UIUtils.ResolutionWidth-UIUtils.FrameBoundWidth-.width*(1.-.pivotX)*UIUtils.ScaleFactor)
        endmethod
       
        private method operator scaledLeft takes nothing returns real
            return .m_scaledLeft
        endmethod
       
        private method operator scaledBottom takes nothing returns real
            return .m_scaledBottom
        endmethod
       
        private method operator scaledScreenPosX takes nothing returns real
            return .m_scaledScreenPosX
        endmethod
       
        private method operator scaledScreenPosY takes nothing returns real
            return .m_scaledScreenPosY
        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 .unscaledWidth  = RMaxBJ(width,  0)
            set .unscaledHeight = RMaxBJ(height, 0)
            set .m_width = .unscaledWidth*.scale
            set .m_height = .unscaledHeight*.scale
            call BlzFrameSetSize(.frame, .width*UIUtils.ScaleFactor*UIUtils.PXTODPI, .height*UIUtils.ScaleFactor*UIUtils.PXTODPI)
            call move(.localPosX, .localPosY)
        endmethod
       
        private method calcRect takes nothing returns nothing
            local real pivotOffsetX = .width*.pivotX
            local real pivotOffsetY = .height*.pivotY
           
            set .m_left = .screenPosX-pivotOffsetX
            set .m_bottom = .screenPosY-pivotOffsetY
            set .m_scaledLeft = .scaledScreenPosX-pivotOffsetX*UIUtils.ScaleFactor
            set .m_scaledBottom = .scaledScreenPosY-pivotOffsetY*UIUtils.ScaleFactor
        endmethod

        method move takes real x, real y returns nothing
       
            local thistype node = .m_childs.next
            local real anchorOffsetX
            local real anchorOffsetY
            local real scale
           
            set .localPosX = x
            set .localPosY = y
            if .parent == Null or not .inheritPosition then
                set anchorOffsetX = UIUtils.ResolutionWidth*.anchorX
                set anchorOffsetY = UIUtils.ResolutionHeight*.anchorY
                if not .isSimple then
                    set .m_screenPosX = normalizePosX(.localPosX+anchorOffsetX)
                    set .m_scaledScreenPosX = normalizeScaledPosX(.localPosX*UIUtils.ScaleFactor+anchorOffsetX)
                else
                    set .m_screenPosX = .localPosX+anchorOffsetX
                    set .m_scaledScreenPosX = .localPosX*UIUtils.ScaleFactor+anchorOffsetX
                endif
                set .m_screenPosY = .localPosY+anchorOffsetY
                set .m_scaledScreenPosY = .localPosY*UIUtils.ScaleFactor+anchorOffsetY
            else
                if .scalePosition then
                    set scale = .parent.scale
                else
                    set scale = 1
                endif
                set anchorOffsetX = .parent.width*.anchorX
                set anchorOffsetY = .parent.height*.anchorY
                set .m_screenPosX = .parent.left+anchorOffsetX+.localPosX*scale
                set .m_screenPosY = .parent.bottom+anchorOffsetY+.localPosY*scale
                set .m_scaledScreenPosX = .parent.scaledLeft+(anchorOffsetX+.localPosX*scale)*UIUtils.ScaleFactor
                set .m_scaledScreenPosY = .parent.scaledBottom+(anchorOffsetY+.localPosY*scale)*UIUtils.ScaleFactor
            endif
            call calcRect()
            if .isSimple then
                set x = .scaledScreenPosX-.width*.pivotX*UIUtils.ScaleFactor
            else
                set x = normalizeScaledPosX(.scaledScreenPosX-.width*.pivotX*UIUtils.ScaleFactor)
            endif
            call BlzFrameSetAbsPoint(.frame, FRAMEPOINT_BOTTOMLEFT, UIUtils.GetScreenPosX(x), UIUtils.GetScreenPosY(.scaledScreenPosY-.height*.pivotY*UIUtils.ScaleFactor))
            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 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 fontType, real fontSize, integer flags returns nothing
            set .fontSize = fontSize
            set .fontType = fontType
            set .fontFlags = flags
            if .frameType == TYPE_SIMPLE_TEXT then
                call BlzFrameSetFont(.textFrameH, .fontType, .fontSize*.scale, .fontFlags)
            endif
        endmethod

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

            set .enabled = .enabledSelf
            set .opacity = .localOpacity
            set .level   = .m_level
            set .localScale = .localScale
            set node = .m_childs.next
            loop
                exitwhen node.head or node == 0
                call node.refresh()
                set node = node.next
            endloop
        endmethod

        private 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 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             = parent
            set .m_childs           = createNode()
            set .isSimple           = IsSimple(frameType, isSimple)
            if .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 .unscaledWidth      = BlzFrameGetWidth(.frame)*(RESOLUTION_HEIGHT/0.6)
            set .unscaledHeight     = BlzFrameGetHeight(.frame)*(RESOLUTION_HEIGHT/0.6)
            set .frameType          = frameType
            set .name               = frameType + I2S(.context)
            set .level              = level
            set .visibleSelf        = true
            set .enabledSelf        = true
            set .fontType           = "Fonts\\FRIZQT__.TTF"
            set .fontSize           = 0.013
            set .fontFlags          = 0
            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 refresh()
            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(CACHE_NAME)
            call BlzLoadTOCFile(TOC_FILE)
        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
Contents

UI Utils Demo (Map)

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Update:
- Code & document clean up
- Auto-size frame on resolution change
- Added UIUtils.FrameBoundWidth to help dealing with the 4:3 bounds
- Improved anchor & pivot handling
- Added frame bounds getter (left, right, top, & bottom)
- Font properties are stored inside variables (readonly)
- Font size is now adjusted according to the frame's scale

I wish I can make a better demo and manual for the system, but this is all the time I have left for modding..
 
Last edited:
Level 19
Joined
Aug 16, 2007
Messages
881
I'm not sure the resolution is applied/calculated properly for all the frames. I've tested 3 different scenarios and each and every one of them did not end up looking as the preview that's provided.

My screen resolution is 2560x1440 and in-game it's set to 1920x1080.

The only thing I modified in the script was the "Reference resolution".

1360x768
1360x768_1.png 1360x768_2.png

1920x1080
1920x1080_1.png 1920x1080_2.png

2560x1440
2560x1440_1.png 2560x1440_2.png

Edit:
Here's how it looks like when I set the in-game resolution to 2560x1440:
WC3ScrnShot_111019_143408_01.png WC3ScrnShot_111019_143415_02.png



Great work so far, I could really use something like this for a future project.
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Little update:
- Added feature to automatically prevent non-simple frame going out of the 4:3 bounds
- A little demo code improvement and fixed typo
- Removed junk font file
- FIT_TO_HEIGHT is set to true by default

@lolreported : the scrollbar and footman icon's size goes nuts because I didn't set their sizes in the demo code. So they have their default size in the frame definition, which is in DPI unit, which might causes the mess up in different resolutions. And the radar size follows the scroll bar size too thus the gigantism. Same case for the action buttons. Check out the update and see if it works better for you : ) P.S. the size issue isn't fixed yet
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Update v1.03:
- Added link to the manual
- getSubFrame is now privatized and replaced with slightly different interface. Before: .getSubFrame(name) Now: .subFrame[name]
- Cache name and toc file path are added to configuration
- Now default size from fdf definition will be calculated based on the reference resolution, not current resolution. To fix inconsistent frame size when the map is loaded on different resolutions.

I like to see more new up to date systems coming on hive this looks great, will have a look and probably using it for future map.
Looking forward for some feedback!
 
Level 19
Joined
Aug 16, 2007
Messages
881
Little update:
- Added feature to automatically prevent non-simple frame going out of the 4:3 bounds
- A little demo code improvement and fixed typo
- Removed junk font file
- FIT_TO_HEIGHT is set to true by default

@lolreported : the scrollbar and footman icon's size goes nuts because I didn't set their sizes in the demo code. So they have their default size in the frame definition, which is in DPI unit, which might causes the mess up in different resolutions. And the radar size follows the scroll bar size too thus the gigantism. Same case for the action buttons. Check out the update and see if it works better for you : ) P.S. the size issue isn't fixed yet
It worked much better now (tested with version 1.03); all frames are true to size and aligned properly regardless of resolution.

I'll experience a bit more when I have time and see if it's something I could use, thanks!
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
It worked much better now (tested with version 1.03); all frames are true to size and aligned properly regardless of resolution.

I'll experience a bit more when I have time and see if it's something I could use, thanks!
Good to hear! Let me know if you find something wrong : )
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Update v1.04:
- Now uses principally correct coordinating system. Position wrappers return correct and consistent values while maintaining 100% UI accuracy and consistency, eliminating inconsistencies when UI is loaded under different resolutions.
- Now automatically maintains UI scales and fits it to the resolution height (removed from configuration), because why not? No one wants their UI looks inconsistent.
- Now all resolutions are supposed to be supported out of the box.

Disclaimer: doesn't fully support origin frame resizing yet
 
Level 18
Joined
Jan 1, 2018
Messages
728
I took the liberty of improving the method to calculate the aspect ratio using this algorithm:
JASS:
function CalcGCD takes integer a, integer b returns integer
    if a == b then
        return a
    elseif a > b then
        return CalcGCD(a - b, b)
    else
        return CalcGCD(a, b - a)
    endif
endfunction

// Usage:
local integer gcd
set ResolutionWidth  = BlzGetLocalClientWidth()
set ResolutionHeight = BlzGetLocalClientHeight()
set gcd = CalcGCD(ResolutionWidth, ResolutionHeight)
set AspectWidth  = ResolutionWidth / gcd
set AspectHeight = ResolutionHeight / gcd
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
I took the liberty of improving the method to calculate the aspect ratio using this algorithm:
JASS:
function CalcGCD takes integer a, integer b returns integer
    if a == b then
        return a
    elseif a > b then
        return CalcGCD(a - b, b)
    else
        return CalcGCD(a, b - a)
    endif
endfunction

// Usage:
local integer gcd
set ResolutionWidth  = BlzGetLocalClientWidth()
set ResolutionHeight = BlzGetLocalClientHeight()
set gcd = CalcGCD(ResolutionWidth, ResolutionHeight)
set AspectWidth  = ResolutionWidth / gcd
set AspectHeight = ResolutionHeight / gcd
Nice. But I'm planning to drop the aspect ratio thing in the next update. Unless someone can convince me that it can be actually useful for something. You can still submit it as separate snippet in the jass section though...

EDIT:
Tested the system on EmberCraft and it performs..... terrible! (In sense that EmberCraft is constantly updating 900+ frames per 0.1 for the minimap system, but it can be better) A lot of inefficiencies were exposed so I will be making a big update when it can be fully utilized in EmberCraft, including a couple of new features such as frame masking, that can be actually very useful in advanced maps. Good side is resolution change is no longer an issue.
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
very good, I tried it with the version of warcraft forged and I got some incompatibility
Mind to give us more details?

I have no idea how to show/hide a simple UI Frame ? There is also no template of this simple thing in your triggers. Help a noob!
I made this tutorial: LINK, it's incomplete but already covers the very basics and should help you a bit...
 
Level 6
Joined
Aug 28, 2015
Messages
213
How do I hide the inventoryCover frame I can't see it on your test map but when I transfer your system in a different map it shows up.
Also what is the handle of the day time UI I would like to hide it too
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
How do I hide the inventoryCover frame I can't see it on your test map but when I transfer your system in a different map it shows up.
Also what is the handle of the day time UI I would like to hide it too
In the demo map I removed the inventory cover through the advanced - gameplay interface settings. While for TOD frame I haven't tried to find it, maybe @Tasyen knows? But you can also remove it through the same interface setting, under the 'model' section, by replacing it with empty dummy model.
 
Level 6
Joined
Aug 28, 2015
Messages
213
In the demo map I removed the inventory cover through the advanced - gameplay interface settings. While for TOD frame I haven't tried to find it, maybe Tasyen knows? But you can also remove it through the same interface setting, under the 'model' section, by replacing it with empty dummy model.
Yes this worked perfect I was able to clean up everything but the menu button, so that you can actually leave the map again.
that would be nice to mention in your tutorial maybe so others know too.
 
Level 3
Joined
Jan 20, 2020
Messages
48
Updated to 1.05. I don't remember exactly what changes I made but this version performs much better on EmberCraft (handles 900+frames): some getters are now pre-calculated on property changes. The "masking" feature hasn't been implemented yet.
If I have currently turned everything for UI off (basically full screen mode), what would I use to turn multiboards back on for display?
 
Level 9
Joined
Jul 15, 2005
Messages
154
All my simple text frames will not justify any direction but center for some reason. No matter the length of the player name, its always centered. This is the creation:



set textPlayerName = UIFrame.create(true, UIFrame.TYPE_SIMPLE_TEXT, UIFrame.Null, -200.0, -50.0, 0)
set textPlayerName.name = "PlayerName"
set textPlayerName.text = ""
set textPlayerName.onAnyEvent = function FrameEvent
call textPlayerName.setAnchorPoint(0.22, 1.01 - Yoffset)
call textPlayerName.setPivotPoint(0.15, 0.9 - Yoffset)
call textPlayerName.setTextAlignment(TEXT_JUSTIFY_TOP, TEXT_JUSTIFY_LEFT)
call textPlayerName.refresh()
 
Level 9
Joined
Jul 15, 2005
Messages
154
All my simple text frames will not justify any direction but center for some reason. No matter the length of the player name, its always centered. This is the creation:



set textPlayerName = UIFrame.create(true, UIFrame.TYPE_SIMPLE_TEXT, UIFrame.Null, -200.0, -50.0, 0)
set textPlayerName.name = "PlayerName"
set textPlayerName.text = ""
set textPlayerName.onAnyEvent = function FrameEvent
call textPlayerName.setAnchorPoint(0.22, 1.01 - Yoffset)
call textPlayerName.setPivotPoint(0.15, 0.9 - Yoffset)
call textPlayerName.setTextAlignment(TEXT_JUSTIFY_TOP, TEXT_JUSTIFY_LEFT)
call textPlayerName.refresh()

That would be awesome, attach it or send to

Thanks dude
 
Last edited:
Level 9
Joined
Jul 15, 2005
Messages
154
Hmmm, with that new fdf, it seems I can't get it to display more than 3 characters before it's cut off. The text is left aligned though

EDIT: Nvm, I'm dumb. You have to use .setSize to increase the text box sizing
 
Last edited:

Zwiebelchen

Hosted Project GR
Level 35
Joined
Sep 17, 2009
Messages
7,236
I'm having issues with Simple_Text.

Somehow it always renders behind other elements, even with a higher level than all background elements.

JASS:
            set main_slot[i] = UIFrame.create(false, UIFrame.TYPE_BUTTON, actionbar_main, -92 - (j-1)*58 + i*58, 0, 3)
            set main_slot[i].texture = "Gaias\\UI\\Slot_Background.tga"
            set main_slot[i].pushedTexture = "Gaias\\UI\\Slot_Background.tga"
            call main_slot[i].setAnchorPoint(0.5, 0.06)
            call main_slot[i].setPivotPoint(0.5, 0.5)
            call main_slot[i].setSize(86, 86)
           set main_slot_key[i] = UIFrame.create(false, UIFrame.TYPE_SIMPLE_TEXT, main_slot[i], 0, 0, 4)
           call main_slot_key[i].setAnchorPoint(0.7, 0.3)
            call main_slot_key[i].setPivotPoint(0.5, 0.5)
           set main_slot_key[i].text = "Q"
           call main_slot_key[i].setFont("fonts\\thowr___.ttf", 0.009, 0)
           set main_slot_key[i].textColor = BlzConvertColor(255, 255, 255, 255)

The code above renders my text behind the button for some reason.
 

Zwiebelchen

Hosted Project GR
Level 35
Joined
Sep 17, 2009
Messages
7,236
Simple frames will always render behind non-simple frames. Also the currently supported FDF does not support non-simple text frames. A way around this that I use is transparent non-simple buttons & everything else is a simple frame. The ordering seems to work okay with non-simple frames, even text frames from my experience.
This is quite a cumbersome workaround. Isn't it possible to fix the fdf to allow non-simple text?
 

Zwiebelchen

Hosted Project GR
Level 35
Joined
Sep 17, 2009
Messages
7,236
For anyone interested, I wrote an optional struct for UIUtils that allows creating a MouseArea - a simple invisible rectangular frame that fires mouse enter, mouse leave and click events.
This particular MouseArea is designed so that it works even outside the 4:3 bounds and automatically refreshes its position with resolution changes (thanks to UIUtils).

Just drop it directly at the bottom of the UIUtils library (before "endlibrary").
JASS:
//Notes: - UIMouseArea can not be created at map init.
//          - This struct works by abusing a leaderboard frame. Leaderboards will no longer work when using this

struct UIMouseArea
   private static framehandle lb
   private static thistype array area
   private static integer count = 0

   private framehandle f
   private trigger t
   private integer id
   private real blx
   private real bly
   private real trx
   private real try

   private static method redrawMouseArea takes nothing returns nothing
       local integer i = 0
       local real x1
       local real y1
       local real x2
       local real y2
       loop
       exitwhen i >= thistype.count
           set x1 = UIUtils.GetScreenPosX(area[i].blx*UIUtils.ResolutionWidth)
           set y1 = UIUtils.GetScreenPosY(area[i].bly*UIUtils.ResolutionHeight)
           set x2 = UIUtils.GetScreenPosX(area[i].trx*UIUtils.ResolutionWidth)
           set y2 = UIUtils.GetScreenPosY(area[i].try*UIUtils.ResolutionHeight)
       call BlzFrameClearAllPoints(area[i].f)
               call BlzFrameSetAbsPoint(area[i].f, FRAMEPOINT_BOTTOMLEFT, x1, y1)
                call BlzFrameSetSize(area[i].f, x2-x1, y2-y1)
       set i = i + 1
       endloop
   endmethod

   method operator visible= takes boolean show returns nothing
       call BlzFrameSetVisible(this.f, show)
   endmethod
   method operator visible takes nothing returns boolean
       return BlzFrameIsVisible(this.f)
   endmethod
   method operator enabled= takes boolean on returns nothing
       call BlzFrameSetEnable(this.f, on)
   endmethod
   method operator enabled takes nothing returns boolean
       return BlzFrameGetEnable(this.f)
   endmethod

   method onDestroy takes nothing returns nothing
       set thistype.area[thistype.count-1].id = this.id
       set thistype.area[this.id] = thistype.area[thistype.count-1]
       set thistype.area[thistype.count-1] = 0
       set thistype.count = thistype.count - 1
       call BlzDestroyFrame(this.f)
       set this.f = null
       call DestroyTrigger(this.t)
       set this.t = null
   endmethod

   static method create takes real blx, real bly, real trx, real try, code c returns thistype
       local thistype this = thistype.allocate()
       local real x1 = UIUtils.GetScreenPosX(blx*UIUtils.ResolutionWidth)
       local real y1 = UIUtils.GetScreenPosY(bly*UIUtils.ResolutionHeight)
       local real x2 = UIUtils.GetScreenPosX(trx*UIUtils.ResolutionWidth)
       local real y2 = UIUtils.GetScreenPosY(try*UIUtils.ResolutionHeight)
       set thistype.area[this.count] = this
       set this.id = this.count
       set this.count = this.count + 1

       set this.blx = blx
       set this.bly = bly
       set this.trx = trx
       set this.try = try

       set this.f = BlzCreateFrameByType("BUTTON", "MouseArea", thistype.lb, "", 0)
            call BlzFrameSetAbsPoint(this.f, FRAMEPOINT_BOTTOMLEFT, x1, y1)
            call BlzFrameSetSize(this.f, x2-x1, y2-y1)

       set this.t = CreateTrigger()
            call BlzTriggerRegisterFrameEvent(t, this.f, FRAMEEVENT_CONTROL_CLICK)
            call BlzTriggerRegisterFrameEvent(t, this.f, FRAMEEVENT_MOUSE_ENTER)
            call BlzTriggerRegisterFrameEvent(t, this.f, FRAMEEVENT_MOUSE_LEAVE)
            call TriggerAddAction(t, c)
       return this
   endmethod

       private static method afterInit takes nothing returns nothing
           local leaderboard lb = CreateLeaderboardBJ(bj_FORCE_ALL_PLAYERS, "title")
           set thistype.lb = BlzGetFrameByName("Leaderboard", 0)
           call BlzFrameSetSize(thistype.lb, 0, 0)
           call BlzFrameSetVisible(BlzGetFrameByName("LeaderboardBackdrop", 0), false)
           call BlzFrameSetVisible(BlzGetFrameByName("LeaderboardTitle", 0), false)
           call UIUtils.RegisterOnResolutionChangeEvent(function thistype.redrawMouseArea)
       endmethod

       private static method onInit takes nothing returns nothing
           call TimerStart(CreateTimer(), 0, false, function thistype.afterInit)
       endmethod
endstruct

Heres a demo code:

JASS:
function test takes nothing returns nothing
   local frameeventtype eventType = BlzGetTriggerFrameEvent()
   local framehandle which = BlzGetTriggerFrame()
        if eventType == FRAMEEVENT_MOUSE_ENTER then
       call BJDebugMsg("enter")
   elseif eventType == FRAMEEVENT_MOUSE_LEAVE then
       call BJDebugMsg("leave")
   elseif eventType == FRAMEEVENT_MOUSE_UP then
       call BJDebugMsg("click")
       //Return focus to main game
       call BlzFrameSetEnable(which, false)
       call BlzFrameSetEnable(which, true)
   endif
   set eventType = null
   set which = null
endfunction

function somefunc takes nothing returns nothing
    //coordinates are bottomleft x, bottomleft y, topright x and topright y at screen scale (0.0-1.0)
    call UIMouseArea.create(0.0, 0.0, 0.2, 0.2, function thistype.test)
endfunction
 
Last edited:

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Chat doesn't seem visible with this on. How can I turn it on?
I will assume you enabled the full screen feature. If that's the case then you might want to play around these variables to configure the chatbox position:

JASS:
        // 9. Configure in-game chat frame
            private constant boolean CHAT_FRAME_VISIBLE  = true
            private constant real   CHAT_FRAME_ANCHOR_X = 0.0
            private constant real   CHAT_FRAME_ANCHOR_Y = 0.0
            private constant real   CHAT_FRAME_PIVOT_X  = 0.0
            private constant real   CHAT_FRAME_PIVOT_Y  = 0.0
            private constant real   CHAT_FRAME_POS_X    = 10.0
            private constant real   CHAT_FRAME_POS_Y    = 100.0
 
Level 5
Joined
Jul 16, 2017
Messages
65
I will assume you enabled the full screen feature. If that's the case then you might want to play around these variables to configure the chatbox position:

JASS:
        // 9. Configure in-game chat frame
            private constant boolean CHAT_FRAME_VISIBLE  = true
            private constant real   CHAT_FRAME_ANCHOR_X = 0.0
            private constant real   CHAT_FRAME_ANCHOR_Y = 0.0
            private constant real   CHAT_FRAME_PIVOT_X  = 0.0
            private constant real   CHAT_FRAME_PIVOT_Y  = 0.0
            private constant real   CHAT_FRAME_POS_X    = 10.0
            private constant real   CHAT_FRAME_POS_Y    = 100.0
How would I make it so that it's exactly the same as it was normally? What are the default values? Sorry, I'm not well versed in jass.
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
JASS:
            set ResolutionWidth  = BlzGetLocalClientWidth()
            set ResolutionHeight = BlzGetLocalClientHeight()
            set ScaleFactor  = I2R(ResolutionHeight)/I2R(RESOLUTION_HEIGHT)
This causes a local desync if the game is minimized because the resolution natives return 0. This causes division by zero which causes a local thread crash.
Notice that the divisor is the constant variable RESOLUTION_HEIGHT, which shouldn't be set to zero.

EDIT:
Been like ~1.5 years since upload, and not a single moderation attempted. :bored:
 
Last edited:
Level 23
Joined
Jan 1, 2011
Messages
1,504
Notice that the divisor is the constant variable RESOLUTION_HEIGHT, which shouldn't be set to zero.

EDIT:
Been like ~1.5 years since upload, and not a single moderation attempted. :bored:
Hmm, indeed, I was having desync issues with this until I checked for zero resolution and set ResWidth/Height to the constant. This for example:
JASS:
        static method operator PXTODPI takes nothing returns real
            return 0.6/ResolutionHeight
        endmethod
 

Kazeon

Hosted Project: EC
Level 33
Joined
Oct 12, 2011
Messages
3,449
Hmm, indeed, I was having desync issues with this until I checked for zero resolution and set ResWidth/Height to the constant. This for example:
JASS:
        static method operator PXTODPI takes nothing returns real
            return 0.6/ResolutionHeight
        endmethod
I see. I tested the system in multiplayer numerous times, how didn't I think to hit the minimize button not even once lol. :/
Have you been able to fix the issue? The quick fix would be to check if BlzGetLocalClientWidth/Height doesn't return zero before updating the global variables and before firing the resolution change event.
 
Level 23
Joined
Jan 1, 2011
Messages
1,504
I see. I tested the system in multiplayer numerous times, how didn't I think to hit the minimize button not even once lol. :/
Have you been able to fix the issue? The quick fix would be to check if BlzGetLocalClientWidth/Height doesn't return zero before updating the global variables and before firing the resolution change event.
My fix was exactly this, and it seems to have resolved all issues completely.
 
Top