Here is a version of the script which adds 20 plugins before showing the GUI - let's see if this reproduces the issue.
Code: Select all
#SingleInstance force
Gui +Hwndhwnd
mc := new MainClass(hwnd)
Loop 20 {
mc.AddPlugin()
}
mc.Show()
return
^Esc::
GuiClose:
ExitApp
class MainClass {
PluginHeight := 35
PluginWidth := 450
FrameWidth := this.PluginWidth + 50
Plugins := {} ; Holds plugin instances
PluginOrder := [] ; Holds order of plugins
__New(hMainGui){
this.MainGui := new WrappedGui(hMainGui)
this.MainGui.GuiCmd("+Resize")
this.AddButton := this.MainGui.AddControl("Button", this.AddPlugin.Bind(this), "Center w" this.FrameWidth " aw", "Add Plugin")
this.PluginFrame := new WrappedGui()
this.PluginFrame.GuiCmd("-Caption")
this.PluginFrame.GuiCmd("+VScroll")
this.PluginFrame.GuiCmd("Color", "Black")
this.MainGui.GuiCmd("Add", "Gui", "xm y+5 w" this.FrameWidth " h200 aw ah", this.PluginFrame.hwnd)
; You cannot remove a Gui if you add it with Gui, Add, Gui...
; So we have to use +Parent to attach plugins to the parent Gui
; We therefore use a Spacer GuiControl in the plugin area to force the scrollbar to the desired size
this.Spacer := this.PluginFrame.AddControl("Edit", 0, "x5 y0 w5 h0")
this.SetSpacerHeight(0)
}
Show(){
this.MainGui.GuiCmd("Show", "x0 y0")
}
AddPlugin(){
scroll_pos := this.PluginFrame.GetScrollPos()
plugin := new Plugin(this)
this.Plugins[plugin.Guid] := plugin
this.PluginOrder.Push(plugin.Guid)
plugin_height := plugin.GetHeight()
ypos := this.Spacer.Height + 5
plugin.ypos := ypos
adjusted_pos := ypos - scroll_pos
plugin.GuiCmd("Show", "x15 y" adjusted_pos " w" this.PluginWidth " h" this.PluginHeight)
this.SetSpacerHeight(this.Spacer.Height + plugin_height + 5)
}
RemovePlugin(id){
scroll_pos := this.PluginFrame.GetScrollPos()
plugin := this.Plugins[id]
plugin_height := plugin.GetHeight()
plugin.GuiCmd("Destroy")
old_guid := plugin.Guid
old_order := this.GetPluginOrder(old_guid)
this.Plugins.Delete(old_guid)
max := this.PluginOrder.Length()
Loop % max - old_order {
id := old_order + A_Index
guid := this.PluginOrder[id]
plugin := this.Plugins[guid]
plugin.ypos -= plugin_height + 4
adjusted_pos := plugin.ypos - scroll_pos
plugin.GuiCmd("Show", "x15 y" adjusted_pos)
}
this.PluginOrder.RemoveAt(old_order)
this.SetSpacerHeight(this.Spacer.Height - plugin_height - 4)
}
ReorderPlugin(guid, dir){
scroll_pos := this.PluginFrame.GetScrollPos()
; Find the order of the plugin that the user clicked on
passed_order := this.GetPluginOrder(guid)
if (passed_order == 0 || (dir == -1 && passed_order == 1) || (dir == 1 && passed_order == this.PluginOrder.Length()))
return ; top tried to move up bottom tried to move down
; Gui swapping is handled as if the user had always clicked Move Down
; If user clicks Move Up, swap the inputs
if (dir == - 1){
top_guid := this.PluginOrder[passed_order - 1]
bot_guid := guid
} else {
top_guid := guid
bot_guid := this.PluginOrder[passed_order + 1]
}
top_plugin := this.Plugins[top_guid]
bot_plugin := this.Plugins[bot_guid]
; Move the "top" gui down and the "bot" gui up
top_y := top_plugin.ypos
bot_plugin.Move(top_y, scroll_pos)
top_plugin.Move(bot_plugin.ypos + bot_plugin.GetHeight() + 4, scroll_pos) ; ToDo - Fix Bodge for GetHeight()
; Swap the PluginOrder
top_id := this.PluginOrder.RemoveAt(passed_order)
this.PluginOrder.InsertAt(passed_order + dir, top_id)
}
SetSpacerHeight(height){
this.Spacer.Height := height
this.Spacer.CtrlCmd("Move", "h" this.Spacer.Height)
}
GetPluginOrder(guid){
for i, candidate in this.PluginOrder {
if (candidate == guid){
return i
}
}
return 0
}
}
class Plugin extends WrappedGui {
ypos := 0
__New(parent){
static short_id := 1
this.Guid := CreateGuid()
this.Parent := parent
base.__New(0)
this.AddControl("Text", 0, "y10", "Plugin #" short_id " - " this.Guid)
this.AddControl("Button", parent.RemovePlugin.Bind(parent, this.Guid), "x+5 yp-5", "Remove")
this.AddControl("Button", parent.ReorderPlugin.Bind(parent, this.Guid, -1), "x+5 yp", "Up")
this.AddControl("Button", parent.ReorderPlugin.Bind(parent, this.Guid, 1), "x+5 yp", "Down")
this.GuiCmd("-Caption")
this.GuiCmd("+Parent" parent.hwnd)
this.GuiCmd("Show", "Hide") ; Force layout, so we can get size
short_id++
}
Move(ypos, scroll_pos){
this.GuiCmd("Show", "x15 y" ypos - scroll_pos)
this.ypos := ypos
}
}
class WrappedGui {
__New(hwnd := 0, options := ""){
if (hwnd == 0){
Gui, New, hwndhwnd
}
this.hwnd := hwnd
}
GuiCmd(cmd, aParams*){
Gui, % this.hwnd ":" cmd, % aParams[1], % aParams[2], % aParams[3]
}
AddControl(type, callback := 0, aParams*){
return new WrappedControl(this, type, callback, aParams*)
}
GetScrollPos(){
static SCROLLINFO:="UINT cbSize;UINT fMask;int nMin;int nMax;UINT nPage;int nPos;int nTrackPos"
,scroll:=Struct(SCROLLINFO,{cbSize:sizeof(SCROLLINFO),fMask:4})
GetScrollInfo(this.hwnd,true,scroll[])
return scroll.nPos
}
GetHeight(){
ControlGetPos,,,,h,,% "ahk_id " this.hwnd
return h
}
}
class WrappedControl {
__New(parent, type, callback := 0, aParams*){
this.Parent := parent
Gui, % this.Parent.hwnd ":Add", % type, % "hwndhwnd " aParams[1], % aParams[2]
this.hwnd := hwnd
if (callback != 0){
this.CtrlCmd("+g", callback)
}
}
CtrlCmd(cmd, param3){
GuiControl, % cmd, % this.hwnd, % param3
}
}
CreateGUID(){
VarSetCapacity(foo_guid, 16, 0)
if !(DllCall("ole32.dll\CoCreateGuid", "Ptr", &foo_guid))
{
VarSetCapacity(tmp_guid, 38 * 2 + 1)
DllCall("ole32.dll\StringFromGUID2", "Ptr", &foo_guid, "Ptr", &tmp_guid, "Int", 38 + 1)
fin_guid := StrGet(&tmp_guid, "UTF-16")
}
return SubStr(fin_guid, 2, 36)
}