AutoResizer => Responsive Gui Controls without code change

Post your working scripts, libraries and tools.
sashaatx
Posts: 344
Joined: 27 May 2021, 08:27
Contact:

AutoResizer => Responsive Gui Controls without code change

24 Jan 2024, 21:06

Credits go to the creator of GuiResizer, @FanaticGuru, it's required to use these classes:
viewtopic.php?f=83&t=113921&hilit=gui
This is just a mod for their class. I did not create GuiResizer, only the mods below.


Preamble -
Spoiler
Originally I wrote a converter, as GuiResizer requires custom formatted Sizing. I have changed the primary goal and outcome, this class now takes standard guiControl.Opt("x5 y+5 w500 y500") at runtime and adjusts to the thousandth decimal. There are 3 other libs at the bottom made for use with GuiResizer

Caveats:
- It is better to use the converter below than the runtime converter
- Converter is made for use with Easy AutoGui, found here github.com/samfisherirl/Easy-Auto-GUI-for-AHK-v2
- this was written in a couple hours time, Ill be making adjustments here over the following days
- there will likely be errors for use-cases I didn't think of, I used easy autogui output code for test cases. viewtopic.php?f=83&t=116159 Please share any issues you come across
- right now it does not account for negative pos
- functions found here: https://github.com/samfisherirl/GuiResizer-Addons.

future plans:
- bootstrap style fontSize breakpoints
- converter to script for future use - complete
- accept either sizes with HaveProp("XP")


AutoResizer

Image

Example

Code: Select all


#Requires Autohotkey v2
;AutoGUI 2.5.8 creator: Alguimist autohotkey.com/boards/viewtopic.php?f=64&t=89901
;AHKv2converter creator: github.com/mmikeww/AHK-v2-script-converter
;Easy_AutoGUI_for_AHKv2 github.com/samfisherirl/Easy-Auto-GUI-for-AHK-v2
#Include <AutoResizer>
myGui := Gui()
AutoResizer(myGui) ; only function call needed

ButtonOK := myGui.Add("Button", "x16 y304 w269 h98", "&OK")
CheckBox1 := myGui.Add("CheckBox", "x16 y27 w120 h23", "CheckBox")
ComboBox1 := myGui.Add("ComboBox", "x16 yp+50 w120", ["ComboBox"])
Edit1 := myGui.Add("Edit", "x16 yp+50 w120 h21")
myGui.Add("GroupBox", "x488 y24 w120 h80", "GroupBox")
myGui.Add("Link", "x232 y24 w120 h23", "<a href=`"https://autohotkey.com`">autohotkey.com</a>")
myGui.Add("ListBox", "x230 y77 w120 h154", ["ListBox"])
ButtonOK.OnEvent("Click", OnEventHandler)
myGui.OnEvent('Close', (*) => ExitApp())
myGui.Title := "Window"
myGui.Show("w620 h420")

OnEventHandler(*)
{
	ToolTip("Click! This is a sample action.`n"
	. "Active GUI element values include:`n"  
	. "ButtonOK => " ButtonOK.Text "`n", 77, 277)
	SetTimer () => ToolTip(), -3000 ; tooltip timer
}


AutoResizer.ahk:

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force
#Warn all, off
#Include <GuiResizer>

class AutoResizer extends GuiResizer
{
    static GuiW := 0
    static GuiH := 0
    static GuiX := 0
    static GuiY := 0
    static hwnd := false
    static path := ""
    static is__file__ := false
    static func := {}
    static timer := {}
     
    static Call(guiObj, path?)
    {
        if AutoResizer.hwnd != false || AutoResizer.hwnd != 0
            return
        guiObj.Opt("-DPIScale +Resize +MinSize250x150")
        
        guiObj.OnEvent("Size", GuiResizer)
        AutoResizer.hwnd := guiObj.hwnd, AutoResizer.path := IsSet(path) ? path : ""
        AutoResizer.timer := {Call: AutoResizer.wait4GuiShow}
        if !WinExist("ahk_id " guiObj.hwnd)
            SetTimer(AutoResizer.timer, 100)
        else
            IsSet(path) ? AutoResizer.setPos(guiObj, path) : AutoResizer.setPos(guiObj)
    }
    static wait4GuiShow(*)
    {
        while !WinExist("ahk_id " AutoResizer.hwnd)
            return
        g := GuiFromHwnd(AutoResizer.hwnd)
        g.GetPos(&x, &y, &w, &h)
        if (w = 0 || h = 0)
            return
        SetTimer(AutoResizer.timer, 0)
            
        AutoResizer.setPos(GuiFromHwnd(AutoResizer.hwnd), AutoResizer.path = ""
            ? AutoResizer.path : false)
    }
    static setPos(guiObj, path := "")
    {
        Sleep(50)
        guiObj.GetPos(&x, &y, &w, &h)
        AutoResizer.GuiW := w
        AutoResizer.GuiH := h
        AutoResizer.GuiX := x
        AutoResizer.GuiY := y
        ctrls := []
        replacementCtrls := []
        for hwnd, ctrl in guiObj
        {
            ControlGetPos(&x, &y, &w, &h, ctrl)
            if (w = 0 || h = 0)
                continue
            ;replacementCtrls.Push(AutoResizer.Mapify(ctrl, x, y, w, h, &ctrls))
            ctrl.XP := Round(Number(x / AutoResizer.GuiW), 3)
            ctrl.YP := Round(Number(y / AutoResizer.GuiH), 3)
            ctrl.WidthP := Round(Number(w / AutoResizer.GuiW), 3)
            ctrl.HeightP := Round(Number(h / AutoResizer.GuiH), 3)
            ;Toolbox_.FormatOpt(ctrl,ctrl.xp,ctrl.yp,ctrl.widthp,ctrl.heightp)
            try{
                ctrl.Redraw()
            }
        }
        guiObj.OnEvent("Size", GuiResizer)
        GuiResizer.Now(guiObj)
        if !AutoResizer.is__file__
            return
    }
    ; #########################################
    ; placeholder for converting to real GuiResize format perminately 
    ; #########################################

    ; static Mapify(ctrl, x, y, w, h, &ctrls)
    ; {
    ;     m := Map()
    ;     m["WP"] := Round(w / AutoResizer.GuiW, 2)
    ;     m["HP"] := Round(h / AutoResizer.GuiH, 2)
    ;     m["XP"] := Round(x / AutoResizer.GuiW, 2)
    ;     m["YP"] := Round(y / AutoResizer.GuiH, 2)
    ;     m['Text'] := ctrl.HasProp("Text") ? ctrl.text : false
    ;     m['Value'] := ctrl.HasProp("Value") ? ctrl.Value : false
    ;     m['Type'] := ctrl.HasProp("Type") ? ctrl.Type : false
    ;     for k, v in m
    ;     {
    ;         if (InStr(v, "0."))
    ;         {
    ;             temp := StrSplit(v, ".")
    ;             m[k] := (temp.Has(2)) ? "." temp[2] : v
    ;         }
    ;     }
    ;     return m
    ; }
    ; static writeToFile(path?)
    ; {
    ;     if path != ""
    ;         path := A_ScriptFullPath
    ;     contents := FileOpen(path, "r").Read()
    ;     newScript := AutoResizer.GUify(replacementCtrls, contents)
    ;     SplitPath(path, , &dir, , &name)
    ;     FileOpen(dir "\" name "_converted.ahk", "w").Write(newScript)
    ;     Run("notepad.exe `"" dir "\" name "_converted.ahk`"")
    ;     ExitApp()
    ; }
}

class Toolbox_ extends GuiResizer
{
    static FormatOpt(ctrl, xp?, yp?, wp?, hp?, anchor?) 
    {
        if IsSet(anchor)
            ctrl.A := anchor
        options := ""
        if IsSet(xp)
            options .= DoTheMath(xp, "xp")
        if IsSet(yp)
            options .= DoTheMath(yp, "yp")
        if IsSet(wp)
            options .= DoTheMath(wp, "wp")
        if IsSet(hp)
            options .= DoTheMath(hp, "hp")
        options := StrReplace(options, "0.", ".")
        GuiResizer.Opt(ctrl, options)
        doTheMath(val, str)
        {
            if val < 0
                val += 1
            return str Round(val, 2) " "
        }
    }
    static FO(ctrl, xp?, yp?, wp?, hp?, anchor?) => GuiReSizer.FormatOpt(ctrl, xp?, yp?, wp?, hp?, anchor?)
}
_____________________________

Converter Gui

Convert standard guis to guiresizer

Code: Select all

#Requires AutoHotkey v2.0
#SingleInstance Force  
#Warn all, off

class Convert2Resizer
{
    static GuiW := 0
    static GuiH := 0
    static GuiX := 0
    static GuiY := 0
    
    static Call(guiObj, path?) 
    {
        guiObj.Show()
        guiObj.GetPos(&x, &y, &w, &h)
        Convert2Resizer.GuiW := w
        Convert2Resizer.GuiH := h
        Convert2Resizer.GuiX := x
        Convert2Resizer.GuiY := y
        ctrls := []
        replacementCtrls := []
        for hwnd, ctrl in guiObj
        {
            replacementCtrls.Push(Convert2Resizer.Mapify(ctrl, &ctrls))
        }
        if !IsSet(path)
            path := A_ScriptFullPath
        contents := FileOpen(path, "r").Read()
        newScript := Convert2Resizer.GUify(replacementCtrls, contents)
        SplitPath(path, , &dir, , &name)
        FileOpen(dir "\" name "_converted.ahk", "w").Write(newScript)
        Run("notepad.exe `"" dir "\" name "_converted.ahk`"")
        exitapp()
    }
    static Mapify(ctrl, &ctrls)
    {
        m := Map()
        ctrl.GetPos(&ctrlX, &ctrlY, &ctrlW, &ctrlH)
        m["WP"] := Round(ctrlW / Convert2Resizer.GuiW, 2)
        m["HP"] := Round(ctrlH / Convert2Resizer.GuiH, 2)
        m["XP"] := Round(ctrlX / Convert2Resizer.GuiW, 2)
        m["YP"] := Round(ctrlY / Convert2Resizer.GuiH, 2)
        m['Text'] := ctrl.HasProp("Text") ? ctrl.text : false
        m['Value'] := ctrl.HasProp("Value") ? ctrl.Value : false
        m['Type'] := ctrl.HasProp("Type") ? ctrl.Type : false
        for k, v in m
        {
            if (InStr(v, "0."))
            {
                temp := StrSplit(v, ".")
                m[k] := (temp.Has(2)) ? "." temp[2] : v
            }
        }
        return m
    }
    static GUify(replacementCtrls, contents)
    {
        contents := StrReplace(contents, "``t", ""), contents := StrReplace(contents, "``r", "")
        splitLines := StrSplit(contents, "`n")

        storage := "myCtrls"
        guiname := "myGui"
        newScript := "#Requires Autohotkey v2`n#SingleInstance force`n"
            . "#Include <GuiReSizer>`n`n" storage " := {}`n"
            . guiname " := Gui(), " guiname ".Opt(`"+Resize +MinSize250x150`")`n" guiname ".OnEvent(`"Size`", GuiReSizer)`n"
        defaults := Map()
        defaults := ctrlDefault()
        for _map in replacementCtrls
        {
            line := (_map['Value'] != false && _map['Value'] != "") ? array_contains(splitLines,(_map['Value']))
                : (_map['Text'] != false && _map['Text'] != "") ? array_contains(splitLines, (_map['Text'])) : false
            if line
            {
                if InStr(splitLines[line], "Add(") && InStr(splitLines[line], ":=")
                    _map['Name'] := Trim(StrSplit(splitLines[line], " := ")[1]) 
            }
            else {
                _map['Name'] := Trim(_map["Type"]) A_Index
            }
            if !_map.Has('Name')
                _map['Name'] := 'ctrl' A_Index
            ; Start building the AHK script by creating GUI controls based on the information in _map
            newScript .= storage "." _map['Name'] " := " guiname ".Add(`"" _map['Type'] "`", `"`","
            ; Depending on the control 'Type', the generated script will configure it differently
            newScript .= (!InStr(_map['Type'], "List"))
                ? (!InStr(_map['Type'], "ComboBox"))
                    ? " `"`")`n" : "[`"`"])`n"
                : "[`"`"])`n"
                
            ; If there are default settings for the type of GUI control in _map,
            ; check if there's a function associated and it's not false, then add that configuration to the script
            t := _map['Type']
            d := defaults.Has(t) ? defaults[t] : 
            defaults[_map['Type']]
            newScript .= defaults.Has(_map['Type'])
                ? (_map[defaults[_map['Type']]['function']] != false)
                    ? storage "." _map['Name'] "." defaults[_map['Type']]['function'] " := `""
                        . _map[defaults[_map['Type']]['function']] "`"`n"
                        : ""
                : ""

            newScript .= "pushToResizer(" storage "."
                . _map['Name'] ", " _map['XP'] ", " _map['YP'] ", " _map['WP'] ", " _map['HP'] ")`n"
        }
        return newScript . Convert2Resizer.compressionFunc() . "`n" guiname ".Show()`n"
    }
    static  compressionFunc() {
        funcG := ""
        
        return funcG .= "`n`npushToResizer(ctrl, xp, yp, wp, hp)`n{`n"
            . "`tctrl.xp := xp `n"
            . "`tctrl.yp := yp `n"
            . "`tctrl.wp := wp `n"
            . "`tctrl.hp := hp `n}`n"
    }
}

array_contains(arr, search, case_sensitive := 0)
{
    for index, value in arr {
        if !IsSet(value)
            continue
        else if InStr(value, search, CaseSense := case_sensitive)
            return index
    }
    return 0
}

ctrlDefault()
{
    return m := Map("Button", map("ctrl", "Button", "event", "Click", "function", "Text"),
        "DropDownList", map("ctrl", "DropDownList", "event", "Change", "function", "Text"),
        "Edit", map("ctrl", "Edit", "event", "Change", "function", "Value"),
        "DateTime", map("ctrl", "DateTime", "event", "Change", "function", "Value"),
        "MonthCal", map("ctrl", "MonthCal", "event", "Change", "function", "Value"),
        "Radio", map("ctrl", "Radio", "event", "Click", "function", "Value"),
        "CheckBox", map("ctrl", "CheckBox", "event", "Click", "function", "Value"),
        "GroupBox", map("ctrl", "CheckBox", "event", "Click", "function", "Text"),
        "ComboBox", map("ctrl", "ComboBox", "event", "Change", "function", "Text"),
        "ListView", map("ctrl", "ListView", "event", "Click", "function", "GetNext"),
        "ListBox", Map("ctrl", "ListBox", "event", "Click", "function", "Value"))
}

SplitPath(A_ScriptFullPath, &fn)
if InStr(fn, "ert2Re")
    myGui := Constructor_()

Constructor_() {
    myGui := Gui()
    ButtonSelectGUIScript := myGui.Add("Button", "x24 y64 w174 h39", "Select GUI Script")
    Edit1 := myGui.Add("Edit", "x24 y8 w432 h38")
    ButtonConvert := myGui.Add("Button", "x208 y64 w154 h37", "Convert")
    ButtonSelectGUIScript.OnEvent("Click", FS)
    ButtonConvert.OnEvent("Click", Convert)
    myGui.OnEvent('Close', (*) => ExitApp())
    myGui.Title := "Window"
    myGui.Show("w501 h122")
    
    FS(*)
    {
        global F
        F := FileSelect(, "C:\", "Select script for conversion")
        if F != ""
            if !FileExist(F)
                F := false
            else 
                Edit1.Value := F
            
    }
    Convert(*)
    {
        global F
        if !F
        {
            Msgbox "File not Found"
            return
        }
        contents := FileOpen(F, "r").Read()
        Lib := FileOpen(A_ScriptFullPath, "r").Read()
        script := ""
        start := false
        Loop parse, contents, "`n" "`r" 
        {
            if !start
                if InStr(A_LoopField, "Gui(")
                {
                    start := true
                    if InStr(A_LoopField, ":=")
                        guiName := Trim(StrSplit(A_LoopField, ":=")[1]) 
                } else 
                    continue
            if InStr(A_LoopField, ".Add") && InStr(A_LoopField, guiName)
            {
                script .= Trim(A_LoopField) "`n"
                ; e_ := ctrlDefault().__Enum(2)
                ; while e_(&k)
                ;     if InStr(A_LoopField, k)  
            }
            else if InStr(A_LoopField, "Show(")
            {
                tmp := StrSplit(Trim(A_LoopField), "Show(")[2]
                tmp := StrSplit(tmp, ")")[1]
                regexWidth := "w(\d+)"
                regexHeight := "h(\d+)"

                width := ""
                height := ""
                ; Perform the regex search for width
                if RegExMatch(tmp, regexWidth, &widthMatch) && width = "" {
                    width := widthMatch[0] ; The number after 'w'
                }
                ; Perform the regex search for height
                if RegExMatch(tmp, regexHeight, &heightMatch) && height = "" {
                    height := heightMatch[0] ; The number after 'h'
                }
                break
            }
        }
        if !IsSet(guiName)
            return
        
        SplitPath(F, , &D)
        tempFileContents := Lib "`n" guiName " := Gui()`n" script "`n" guiName . ".Show(`"" 
        tempFileContents .= (width != "") ? width : (height != "") ? height : "'w' A_ScreenWidth*.8 ' h' A_ScreenHeight"
        tempFileContents .= "`")" "`nConvert2Resizer(" guiName ", `"" F "`")`n"
        FileOpen(D "\tempFile.ahk", "w").Write(tempFileContents)
        RunWait(A_AhkPath " `"" D "\tempFile.ahk" "`"", , ,&PID)
        Sleep(100)
        x := 0
        While ProcessExist(PID)
        {
            x+=1
            Sleep 100
            if x > 500
                break
        }
        try{
            FileDelete(A_MyDocuments "\tempFile.ahk")
        }
        ExitApp()
    }

    return myGui
}
BetweenStr(text, startDelim, endDelim?) {
    if !IsSet(endDelim)
        endDelim := startDelim
    results := []  ; Initialize an empty array to store the results
    startIndex := 1 ; Start search from the beginning of the string
    while (startIndex := InStr(text, startDelim, true, startIndex + StrLen(startDelim)))
    {
        ; Find the matching end delimiter from the found start delimiter
        endIndex := InStr(text, endDelim, true, startIndex + StrLen(startDelim))
        if (!endIndex)  ; If no ending delimiter is found, break the loop
            break
        extracted := SubStr(text, startIndex + StrLen(startDelim), endIndex - (startIndex + StrLen(startDelim)))
        results.Push(extracted)
        startIndex := endIndex
    }
    return results
}
____________________________
Lib#2

Library for using CreateImageButton with GuiResizer
ezgif-2-2e6994005c (1).gif
ezgif-2-2e6994005c (1).gif (1.06 MiB) Viewed 1513 times

Code: Select all

DetectHiddenWindows("off")

/*
    Class: StyleButton

    Description:
    This class defines a set of functionalities for configuring and styling buttons. Combining GuiResizer's
    Responsive design and accounting for size changes while applying styles to buttons.

    Requires:
    1. CreateImageButton.ahk
    2. UseGDIP.ahk
    3. GuiResizer.ahk

    Example:
    ButtonOK := myGui.Add("Button", "", "&OK")
    SetButton(ButtonOK, 0, "success") ; success being a map key in IBStyles, any style map should do. 

    Class Functions:
    1. Call(ctrl, offset, style)
        ; see CreateImageButton.ahk for more information
        This function handles the button call and applies styling based on parameters. It gets the position of the button
        and pushes the set function with certain parameters to funcArray based on the button's width and height.

    2. Set(ctrl, style, offset, isEvent?)
       This function sets the button's configuration. It gets the button's position, sets the control size in a map,
       and styles the button by calling the myStyleMap function.

    3. enumButtons(*)
       This function enumerates through the buttons, resets the error flag, and runs each function in the funcArray.

    Nested Functions:
    1. myStyleMap(ctrl, offset, style)
       This defined function styles the button by calling the CreateImageButton function with certain parameters.
*/
class StyleButton
{
    static err := 0
    static buttons := []
    
    static Call(ctrl, offset, style)
    {
        ctrl.GetPos(, , &w, &h)
        StyleButton.buttons.Push({ctrl: ctrl, offset: offset, style: style, w: w, h: h})
        ctrl.Gui.OnEvent("Size", StyleButton.enumButtons)
        if w != 0 && h != 0 && WinActive(ctrl.Gui.hwnd)
        {
            StyleButton.Set(StyleButton.buttons[StyleButton.buttons.Length], offset, style)
        }
    }

    static Set(btn, offset, style)
    {
        btn.ctrl.Gui.GetPos(, , &w, &h)

        if h = 0 or w = 0 or !WinActive(btn.ctrl.Gui.hwnd)
        {
            return
        }
        btn.ctrl.GetPos(, , &w, &h)
        if btn.w < w or btn.h < h
        {
            btn.w := w
            btn.h := h
            btn.ctrl.Opt("w" w " h" h)
        }
        
        UseGDIP()
        if btn.ctrl.gui
            myStyleMap(btn.ctrl, offset, style)
    }

    static enumButtons(*)
    {
        for btn in StyleButton.buttons
        {
            StyleButton.set(btn, btn.offset, btn.style)
        }
    }
}

myStyleMap(ctrl, offset, style) => CreateImageButton(ctrl, offset, IBStyles[style]*)


IBStyles := Map()
; credit to jNizM
; https://www.autohotkey.com/boards/memberlist.php?mode=viewprofile&u=75  

IBStyles["info"] := [[0x80C6E9F4, , , 0, 0x8046B8DA, 1], [0x8086D0E7, , , 0, 0x8046B8DA, 1], [0x8046B8DA, , , 0, 0x8046B8DA, 1], [0xFFF0F0F0, , , 0, 0x8046B8DA, 1]]
IBStyles["success"] := [[0x80C6E6C6, , , 0, 0x805CB85C, 1], [0x8091CF91, , , 0, 0x805CB85C, 1], [0x805CB85C, , , 0, 0x805CB85C, 1], [0xFFF0F0F0, , , 0, 0x805CB85C, 1]]
IBStyles["warning"] := [[0x80FCEFDC, , , 0, 0x80F0AD4E, 1], [0x80F6CE95, , , 0, 0x80F0AD4E, 1], [0x80F0AD4E, , , 0, 0x80F0AD4E, 1], [0xFFF0F0F0, , , 0, 0x80F0AD4E, 1]]
IBStyles["critical"] := [[0x80F0B9B8, , , 0, 0x80D43F3A, 1], [0x80E27C79, , , 0, 0x80D43F3A, 1], [0x80D43F3A, , , 0, 0x80D43F3A, 1], [0xFFF0F0F0, , , 0, 0x80D43F3A, 1]]

IBStyles["info-outline"] := [[0xFFF0F0F0, , , 0, 0x8046B8DA, 1], [0x80C6E9F4, , , 0, 0x8046B8DA, 1], [0x8086D0E7, , , 0, 0x8046B8DA, 1], [0xFFF0F0F0, , , 0, 0x8046B8DA, 1]]
IBStyles["success-outline"] := [[0xFFF0F0F0, , , 0, 0x805CB85C, 1], [0x80C6E6C6, , , 0, 0x805CB85C, 1], [0x8091CF91, , , 0, 0x805CB85C, 1], [0xFFF0F0F0, , , 0, 0x805CB85C, 1]]
IBStyles["warning-outline"] := [[0xFFF0F0F0, , , 0, 0x80F0AD4E, 1], [0x80FCEFDC, , , 0, 0x80F0AD4E, 1], [0x80F6CE95, , , 0, 0x80F0AD4E, 1], [0xFFF0F0F0, , , 0, 0x80F0AD4E, 1]]
IBStyles["critical-outline"] := [[0xFFF0F0F0, , , 0, 0x80D43F3A, 1], [0x80F0B9B8, , , 0, 0x80D43F3A, 1], [0x80E27C79, , , 0, 0x80D43F3A, 1], [0xFFF0F0F0, , , 0, 0x80D43F3A, 1]]

IBStyles["info-round"] := [[0x80C6E9F4, , , 8, 0x8046B8DA, 1], [0x8086D0E7, , , 8, 0x8046B8DA, 1], [0x8046B8DA, , , 8, 0x8046B8DA, 1], [0xFFF0F0F0, , , 8, 0x8046B8DA, 1]]
IBStyles["success-round"] := [[0x80C6E6C6, , , 8, 0x805CB85C, 1], [0x8091CF91, , , 8, 0x805CB85C, 1], [0x805CB85C, , , 8, 0x805CB85C, 1], [0xFFF0F0F0, , , 8, 0x805CB85C, 1]]
IBStyles["warning-round"] := [[0x80FCEFDC, , , 8, 0x80F0AD4E, 1], [0x80F6CE95, , , 8, 0x80F0AD4E, 1], [0x80F0AD4E, , , 8, 0x80F0AD4E, 1], [0xFFF0F0F0, , , 8, 0x80F0AD4E, 1]]
IBStyles["critical-round"] := [[0x80F0B9B8, , , 8, 0x80D43F3A, 1], [0x80E27C79, , , 8, 0x80D43F3A, 1], [0x80D43F3A, , , 8, 0x80D43F3A, 1], [0xFFF0F0F0, , , 8, 0x80D43F3A, 1]]

IBStyles["info-outline-round"] := [[0xFFF0F0F0, , , 8, 0x8046B8DA, 1], [0x80C6E9F4, , , 8, 0x8046B8DA, 1], [0x8086D0E7, , , 8, 0x8046B8DA, 1], [0xFFF0F0F0, , , 8, 0x8046B8DA, 1]]
IBStyles["success-outline-round"] := [[0xFFF0F0F0, , , 8, 0x805CB85C, 1], [0x80C6E6C6, , , 8, 0x805CB85C, 1], [0x8091CF91, , , 8, 0x805CB85C, 1], [0xFFF0F0F0, , , 8, 0x805CB85C, 1]]
IBStyles["warning-outline-round"] := [[0xFFF0F0F0, , , 8, 0x80F0AD4E, 1], [0x80FCEFDC, , , 8, 0x80F0AD4E, 1], [0x80F6CE95, , , 8, 0x80F0AD4E, 1], [0xFFF0F0F0, , , 8, 0x80F0AD4E, 1]]
IBStyles["critical-outline-round"] := [[0xFFF0F0F0, , , 8, 0x80D43F3A, 1], [0x80F0B9B8, , , 8, 0x80D43F3A, 1], [0x80E27C79, , , 8, 0x80D43F3A, 1], [0xFFF0F0F0, , , 8, 0x80D43F3A, 1]]

#Include CreateImageButton.ahk
#Include UseGDIP.ahk
Example for Lib#2

Code: Select all

#Include SetButton.ahk
#Include GuiResizer.ahk
#Requires Autohotkey v2
#SingleInstance Force
SetWinDelay(10)
;AutoGUI 2.5.8 creator: Alguimist autohotkey.com/boards/viewtopic.php?f=64&t=89901
;AHKv2converter creator: github.com/mmikeww/AHK-v2-script-converter
;Easy_AutoGUI_for_AHKv2 github.com/samfisherirl/Easy-Auto-GUI-for-AHK-v2

myGui := Gui()
myGui.opt("+Resize +MinSize250x150")
myGui.OnEvent("Size", GuiResizer)
ButtonOK := myGui.Add("Button", "", "&OK")

OkayAgain := myGui.Add("Button", "x+10", "&OK")
ButtonOK.wp := 0.5
OkayAgain.xp := -0.45
OkayAgain.wp := 0.4
StyleButton(ButtonOK, 0, "success")
StyleButton(OkayAgain, 0, "critical-round")

; Finished := myGui.Add("Button", "", "Finished")
; my custom method for GuiResizer formatting
; GuiReSizer.FormatOpt(Finished, .1, .2, 0.8, 0.2)
; Cancel := myGui.Add("Button", "", "Cancel")
; my custom method for GuiResizer formatting
; GuiReSizer.FormatOpt(Cancel, .1, .5, 0.8, 0.2)

StyleButton(Finished, 0, "info-round")
StyleButton(Cancel, 0, "critical-round")

myGui.OnEvent('Close', (*) => ExitApp())
myGui.Title := "Window"
myGui.Show("w620 h320")

Lib #3 - Toolbox

GuiResizer (by @FanaticGuru) doesn't mesh well with parent child guis. This provides a simple toggle visibility for script.
Second feature, autoformat standard numeric params for GuiResizer.Opt() which doesnt like 0. before values

Code: Select all

        ; This function defines a property called "ToggleVisible" on the prototype of the Object class.
        ; When called, it hides or shows all GUI controls from the given object.
        ; The function returns 1 if any controls were hidden or shown, otherwise it returns 0.
        Object.Prototype.DefineProp("ToggleVisible", { Call: HideAll_guiCtrls_fromObj })

        ; This function hides or shows all GUI controls from the given object.
        ; It iterates over the properties of the object and checks if they are set and if they are objects with a "Visible" property.
        ; If a control is found, its "Visible" property is toggled and the status is set to 1.
        ; The function returns the status indicating if any controls were hidden or shown.

        ; Example:
        ; myGui.ParentGui := {}
        ; myGui.ParentGui.Buttons := {}
        ; myGui.ParentGui.Buttons.Next := myGui.Add("Button", , "Hello World")
        ; ...additional buttons may be added to group
        ; myGui.ParentGui.ToggleVisible()
        ;
        HideAll_guiCtrls_fromObj(selfObj)
        {
            status := 0
            for index, value in selfObj.OwnProps() {
                if !IsSet(value)
                    continue
                else if IsObject(value)
                {
                    if not InStr(value.__Class, "Gui.")
                        status := HideAll_guiCtrls_fromObj(value)
                    else if value.HasProp("Visible")
                    {
                        value.Visible := !value.Visible
                        status := 1
                    }
                }
            }
            return status
        }
        
        
        ;@@@@@@@@@@@ add the below function inside of guiresizer.ahk before the class ends @@@@@@@@@@@@@@@@@@@
        
            ; ....the rest of GuiResizer above
    
    /**
     * Formats and sets the positioning and sizing options for a control in the GuiReSizer class.
     * 
     * @memberof GuiReSizer
     * @static
     * @function FormatOpt
     * 
     * @param {Object} ctrl - The control object to apply the formatting to.
     * @param {number} [xp] - X positional offset as a percentage of Gui width.
     * @param {number} [yp] - Y positional offset as a percentage of Gui height.
     * @param {number} [wp] - Width of control as a percentage of Gui width.
     * @param {number} [hp] - Height of control as a percentage of Gui height.
     * 
     * @example
     *  Usage:
     * GuiReSizer.FormatOpt(myControlObj, xp := .10, yp := .20, wp := .30, hp := .40, anchor?);
     * 
     *  This will set the X position to 10% of the Gui width,
     *  Y position to 20% of the Gui height,
     *  Width to 30% of the Gui width,
     *  Height to 40% of the Gui height.
     */
    static FormatOpt(ctrl, xp?, yp?, wp?, hp?, anchor?) 
    {
        if IsSet(anchor)
            ctrl.A := anchor
        options := ""
        if IsSet(xp)
            options .= GuiResizer.doTheMath(xp, "xp")
        if IsSet(yp)
            options .= GuiResizer.doTheMath(yp, "yp")
        if IsSet(wp)
            options .= GuiResizer.doTheMath(wp, "wp")
        if IsSet(hp)
            options .= GuiResizer.doTheMath(hp, "hp")
        options := StrReplace(options, "0.", ".")
        GuiResizer.Opt(ctrl, options)
    }
    
    static doTheMath(val, str) {
        if val < 0
            val += 1
        return str Round(val, 2) " "
    }
    ; easily copy an existing controls format to another control, for parent/child gui usage 
    static Duplicate(ctrl, ctrlToCopy) => GuiResizer.FormatOpt(ctrl, ctrlToCopy.XP, ctrlToCopy.YP, ctrlToCopy.WidthP, ctrlToCopy.HeightP)
    
    ; ....the end of GuiResizer
}
Lib #4 tooltip docs for vscode

Code: Select all

/**
 * @class GuiReSizer
 * @author Fanatic Guru
 * @version 2023-03-13
 * @description Class to Handle the Resizing of Gui and Move and Resize Controls.
 *   Update 2023-02-15: Add more Min Max properties and renamed some Properties.
 *   Update 2023-03-13: Major rewrite. Converted to Class to allow for Methods.
 * @requires AutoHotkey v2.0.2+
 *
 * @param {Object} GuiObj - Gui Object.
 * @param {Number} WindowMinMax - Window status. 0 = neither minimized nor maximized, 1 = maximized, -1 = minimized.
 * @param {Number} Width - Width of GuiObj.
 * @param {Number} Height - Height of GuiObj.
 * @returns {Class} GuiReSizer instance.
 *
 * @example
 * 
 * ; GuiObj.OnEvent("Size", GuiReSizer)
 * ; guiList.Button.TopLeft := guiList.Add("Button", "Default", "TopLeft")
 * ; guiList.Button.TopLeft.XP := 0.20 ; 20% from Left Margin
 * ; guiList.Button.TopLeft.YP := 0.70 ; 70% from Top Margin
 * ; guiList.Button.TopLeft.WidthP := 0.20 ; 20% Width of Gui Width
 * ; guiList.Button.TopLeft.Height := 20 ; 20 Height of Gui Height 
 * 
 * @property {Number} X - X positional offset from margins.
 * @property {Number} Y - Y positional offset from margins.
 * @property {Number} XP - X positional offset from margins as a percentage of Gui width.
 * @property {Number} YP - Y positional offset from margins as a percentage of Gui height.
 * @property {Number} OriginX (OX) - Control origin X, defaults to 0 (left side of control), this relocates the origin.
 * @property {Number} OriginXP (OXP) - Control origin X as a percentage of Gui width, defaults to 0 (left side of control), this relocates the origin.
 * @property {Number} OriginY (OY) - Control origin Y, defaults to 0 (top side of control), this relocates the origin.
 * @property {Number} OriginYP (OYP) - Control origin Y as a percentage of Gui height, defaults to 0 (top side of control), this relocates the origin.
 * @property {Number} Width (W) - Width of control.
 * @property {Number} WidthP (WP) - Width of control as a percentage of Gui width.
 * @property {Number} Height (H) - Height of control.
 * @property {Number} HeightP (HP) - Height of control as a percentage of Gui height.
 * @property {Number} MinX - Minimum X offset.
 * @property {Number} MaxX - Maximum X offset.
 * @property {Number} MinY - Minimum Y offset.
 * @property {Number} MaxY - Maximum Y offset.
 * @property {Number} MinWidth (MinW) - Minimum control width.
 * @property {Number} MaxWidth (MaxW) - Maximum control width.
 * @property {Number} MinHeight (MinH) - Minimum control height.
 * @property {Number} MaxHeight (MaxH) - Maximum control height.
 * @property {Boolean} Cleanup (C) - When set to true, will redraw this control each time to clean up artifacts (normally not required and causes flickering).
 * @property {Function} Function (F) - Custom function that will be called for this control.
 * @property {Object} Anchor (A) - Control object anchor so that size and position commands are in relation to another control.
 * @property {Boolean} AnchorIn (AI) - Controls where the control is restricted to the inside of another control.
 *
 * @method Now
 * @description Forces a manual Call now for {GuiObj}.
 * @param {Object} GuiObj - Gui Object.
 *
 * @method Opt
 * @description Same as Options method.
 * @param {Object} switches - Switches for Options method.
 *
 * @method Options
 * @description All options are set as a string with each switch separated by a space "x10 yp50 oCM".
 * @param {Object} switches - Switches for setting options.
 * @param {Number} x - X.
 * @param {Number} y - Y.
 * @param {Number} xp - XP.
 * @param {Number} yp - YP.
 * @param {Number} wp - WidthP.
 * @param {Number} hp - HeightP.
 * @param {Number} w - Width.
 * @param {Number} h - Height.
 * @param {Number} minx - MinX.
 * @param {Number} maxx - MaxX.
 * @param {Number} miny - MinY.
 * @param {Number} maxy - MaxY.
 * @param {Number} minw - MinWidth.
 * @param {Number} maxw - MaxWidth.
 * @param {Number} minh - MinHeight.
 * @param {Number} maxh - MaxHeight.
 * @param {Number} oxp - OriginXP.
 * @param {Number} oyp - OriginYP.
 * @param {Number} ox - OriginX.
 * @param {Number} oy - OriginY.
 * @param {String} o - Origin: "L" left, "C" center, "R" right, "T" top, "M" middle, "B" bottom; may use 1 or 2 letters.
 *
 * @property {Object} Gui Properties:
 * @property {Number} Init - {Gui}.Init := 1, will cause all controls of the Gui to be redrawn on the next function call.
 *                           {Gui}.Init := 2, will also reinitialize abbreviations.
 */
Last edited by sashaatx on 10 Feb 2024, 10:50, edited 16 times in total.
https://github.com/samfisherirl
? /Easy-Auto-GUI-for-AHK-v2 ? /Useful-AHK-v2-Libraries-and-Classes : /Pulovers-Macro-Creator-for-AHKv2 :
sashaatx
Posts: 344
Joined: 27 May 2021, 08:27
Contact:

Re: AutoResizer => Fully Responsive Gui Controls without code change

04 Feb 2024, 12:45

completely changed from converter to runtime handler

Code: Select all

 #Requires AutoHotkey v2.0
#SingleInstance Force
#Warn all, off
#Include <GuiResizer>

class Convert2Resizer extends GuiResizer
{
    static GuiW := 0
    static GuiH := 0
    static GuiX := 0
    static GuiY := 0
    static hwnd := false
    static path := ""
    static is__file__ := false
    static func := {}
    static timer := {}
     
    static Call(guiObj, path?)
    {
        guiObj.Opt("-DPIScale")
        guiObj.OnEvent("Size", GuiResizer)
        Convert2Resizer.hwnd := guiObj.hwnd, Convert2Resizer.path := IsSet(path) ? path : ""
        Convert2Resizer.timer := {Call: Convert2Resizer.wait4GuiShow}
        ;Convert2Resizer.f := ObjBindMethod(Convert2Resizer.wait4GuiShow, "Call")
        ;Convert2Resizer.F.timer.Call := ObjBindMethod(Convert2Resizer.wait4GuiShow, "Call")
        if !WinExist("ahk_id " guiObj.hwnd)
            SetTimer(Convert2Resizer.timer, 100)
        else
            IsSet(path) ? Convert2Resizer.getPos(guiObj, path) : Convert2Resizer.getPos(guiObj)
    }
    static wait4GuiShow(*)
    {
        while !WinExist("ahk_id " Convert2Resizer.hwnd)
            return
        g := GuiFromHwnd(Convert2Resizer.hwnd)
        g.GetPos(&x, &y, &w, &h)
        if (w = 0 || h = 0)
            return
        SetTimer(Convert2Resizer.timer, 0)
            
        Convert2Resizer.setPos(GuiFromHwnd(Convert2Resizer.hwnd), Convert2Resizer.path = ""
            ? Convert2Resizer.path : false)
    }
    static setPos(guiObj, path := "")
    {
        Sleep(50)
        guiObj.GetPos(&x, &y, &w, &h)
        Convert2Resizer.GuiW := w
        Convert2Resizer.GuiH := h
        Convert2Resizer.GuiX := x
        Convert2Resizer.GuiY := y
        ctrls := []
        replacementCtrls := []
        for hwnd, ctrl in guiObj
        {
            ControlGetPos(&x, &y, &w, &h, ctrl)
            if (w = 0 || h = 0)
                continue
            ;replacementCtrls.Push(Convert2Resizer.Mapify(ctrl, x, y, w, h, &ctrls))
            ctrl.XP := Round(Number(x / Convert2Resizer.GuiW), 3)
            ctrl.YP := Round(Number(y / Convert2Resizer.GuiH), 3)
            ctrl.WidthP := Round(Number(w / Convert2Resizer.GuiW), 3)
            ctrl.HeightP := Round(Number(h / Convert2Resizer.GuiH), 3)
            ;Toolbox_.FormatOpt(ctrl,ctrl.xp,ctrl.yp,ctrl.widthp,ctrl.heightp)
            try{
                ctrl.Redraw()
            }
        }
        guiObj.Opt("+Resize +MinSize250x150")
        guiObj.OnEvent("Size", GuiResizer)
        GuiResizer.Now(guiObj)
        if !Convert2Resizer.is__file__
            return
    }
    ; #########################################
    ; placeholder for converting to real GuiResize format perminately 
    ; #########################################

    ; static Mapify(ctrl, x, y, w, h, &ctrls)
    ; {
    ;     m := Map()
    ;     m["WP"] := Round(w / Convert2Resizer.GuiW, 2)
    ;     m["HP"] := Round(h / Convert2Resizer.GuiH, 2)
    ;     m["XP"] := Round(x / Convert2Resizer.GuiW, 2)
    ;     m["YP"] := Round(y / Convert2Resizer.GuiH, 2)
    ;     m['Text'] := ctrl.HasProp("Text") ? ctrl.text : false
    ;     m['Value'] := ctrl.HasProp("Value") ? ctrl.Value : false
    ;     m['Type'] := ctrl.HasProp("Type") ? ctrl.Type : false
    ;     for k, v in m
    ;     {
    ;         if (InStr(v, "0."))
    ;         {
    ;             temp := StrSplit(v, ".")
    ;             m[k] := (temp.Has(2)) ? "." temp[2] : v
    ;         }
    ;     }
    ;     return m
    ; }
    ; static writeToFile(path?)
    ; {
    ;     if path != ""
    ;         path := A_ScriptFullPath
    ;     contents := FileOpen(path, "r").Read()
    ;     newScript := Convert2Resizer.GUify(replacementCtrls, contents)
    ;     SplitPath(path, , &dir, , &name)
    ;     FileOpen(dir "\" name "_converted.ahk", "w").Write(newScript)
    ;     Run("notepad.exe `"" dir "\" name "_converted.ahk`"")
    ;     ExitApp()
    ; }
}

class Toolbox_ extends GuiResizer
{
    static FormatOpt(ctrl, xp?, yp?, wp?, hp?, anchor?) 
    {
        if IsSet(anchor)
            ctrl.A := anchor
        options := ""
        if IsSet(xp)
            options .= DoTheMath(xp, "xp")
        if IsSet(yp)
            options .= DoTheMath(yp, "yp")
        if IsSet(wp)
            options .= DoTheMath(wp, "wp")
        if IsSet(hp)
            options .= DoTheMath(hp, "hp")
        options := StrReplace(options, "0.", ".")
        GuiResizer.Opt(ctrl, options)
        doTheMath(val, str)
        {
            if val < 0
                val += 1
            return str Round(val, 2) " "
        }
    }
    static FO(ctrl, xp?, yp?, wp?, hp?, anchor?) => GuiReSizer.FormatOpt(ctrl, xp?, yp?, wp?, hp?, anchor?)
}
https://github.com/samfisherirl
? /Easy-Auto-GUI-for-AHK-v2 ? /Useful-AHK-v2-Libraries-and-Classes : /Pulovers-Macro-Creator-for-AHKv2 :
cgx5871
Posts: 319
Joined: 26 Jul 2018, 14:02

Re: AutoResizer => Responsive Gui Controls without code change

20 Feb 2024, 02:31

How to specify a control not to follow changes?@sashaatx
cgx5871
Posts: 319
Joined: 26 Jul 2018, 14:02

Re: AutoResizer => Responsive Gui Controls without code change

20 Feb 2024, 15:06

AHKpy.ahk 390 Line ctrl.Opt("Background101011") not supported---hotkey gui
sashaatx
Posts: 344
Joined: 27 May 2021, 08:27
Contact:

Re: AutoResizer => Responsive Gui Controls without code change

20 Feb 2024, 20:16

cgx5871 wrote:
20 Feb 2024, 02:31
How to specify a control not to follow changes?@sashaatx
i have a method built in but it depends on the changes, theres colors, sizes, show or not show. If you specify, happy to help
https://github.com/samfisherirl
? /Easy-Auto-GUI-for-AHK-v2 ? /Useful-AHK-v2-Libraries-and-Classes : /Pulovers-Macro-Creator-for-AHKv2 :
cgx5871
Posts: 319
Joined: 26 Jul 2018, 14:02

Re: AutoResizer => Responsive Gui Controls without code change

21 Feb 2024, 01:45

A very strange phenomenon, #Include <SetButtonStyle>
It intercepts my hotkey Ctrl+u, which I use to display another gui.
I checked for a long time and found out that it was a problem with #Include <SetButtonStyle>.
i dont know with it?@sashaatx

Return to “Scripts and Functions (v2)”

Who is online

Users browsing this forum: aseiot, niCode and 21 guests