Would LV_EX_GroupInsert overwrite the header if I use the same GroupId? And would I have to re-add the items to the group if I went this route?
MainScript
Code: Select all
#NoTrayIcon
#NoEnv
#SingleInstance Force
#KeyHistory, 0
#MaxMem 1024
Process, Priority,, A
SetBatchLines, -1
ListLines, Off
SetWorkingDir, % A_ScriptDir
if (!A_IsAdmin)
Run, *RunAs "%A_ScriptFullPath%"
#Include lib\functions.ahk
#Include lib\LV_Functions.ahk
#Include lib\classCharacter.ahk
testing := 1
CharactersArray := []
Mugen := { Folder: "", Exe: "", CharsFolder: "" }
SelectedRow := ""
SelectedIndex := ""
SelectedCharacter := ""
Columns := { name: 1, displayname: 2, author: 3, versiondate: 4, mugenversion: 5, path: 6, deffile: 7, index: 8 }
if (testing)
{
Mugen.Folder := "R:\roms\mugen\LEGACY"
Mugen.Folder := "R:\roms\mugen\Megaman Robot Master Mayhem"
Mugen.CharsFolder := Mugen.Folder "\chars"
}
else
{
if (A_Args.Length() > 0 && FileExist(A_Args[1]))
Mugen.Folder := A_Args[1]
else if (InStr(FileExist(A_ScriptDir "\chars"), "D"))
Mugen.Folder := A_ScriptDir
else
{
FileSelectFolder, mugenFolder,, 0, Select M.U.G.E.N. Folder
Mugen.Folder := mugenFolder
}
if (ErrorLevel || Mugen.Folder = "")
ExitApp
Mugen.CharsFolder := Mugen.Folder "\chars"
}
Loop, Files, % Mugen.CharsFolder "\*", DR
{
if (A_LoopFileName = "backup")
FileRemoveDir, % A_LoopFilePath, 1
}
Loop, Files, % Mugen.CharsFolder "\*.def", R
{
IniRead, sections, % A_LoopFilePath
if (sections = "" || sections = "ERROR" || !InStr(sections, "Info") || InStr(sections, "SceneDef") || InStr(sections, "StageInfo"))
continue
CharactersArray.Push(new Character(A_LoopFilePath))
}
GoSub, CreateListviewContextMenu
GoSub, CreateCharactersGui
EmptyMem()
return
#Include Character_ContexMenu.ahk
#Include DEF-CNS_Gui.ahk
#Include AddKey_Gui.ahk
CreateCharactersGui:
Gui, Characters:New, -DPIScale +HwndhCharacters +Resize MinSize400x400 +Label_Characters, M.U.G.E.N. Characters Manager
Gui, Characters:Margin, 20, 20
Gui, Characters:Font, s10 q5
Gui, Characters:Add, DropDownList, +HwndhCharsDDL vCharactersDDL g_CharactersDDL, No Grouping||Name|DisplayName|Author|VersionDate|MugenVersion|Path
Gui, Characters:Add, ListView, w600 h440 -Multi +ReadOnly +Report +AltSubmit +HwndhCharsLV vCharactersLV g_CharactersLV, Name|DisplayName|Author|Version|Mugen Version|Folder|Def File|Index
Gosub, FillListView
Gui, Characters:Show, center
return
FillListView:
for i, char in CharactersArray
LV_Add(""
, UnQuote(char.DEF.Info["name"])
, UnQuote(char.DEF.Info["displayname"])
, UnQuote(char.DEF.Info["author"])
, char.DEF.Info["versiondate"]
, char.DEF.Info["mugenversion"]
, char.Path
, char.DefName
, i)
LV_ModifyCol(8, "50 Integer")
return
_CharactersLV:
if (A_GuiEvent != "Normal")
return
_CharactersContextMenu:
if (A_GuiControl = "CharactersLV")
{
SelectedRow := LV_GetNext(0, "F")
if (!SelectedRow)
{
MsgBox, No Character Selected
return
}
WinGetPos, cX, cY, cW, cH, M.U.G.E.N. Characters Manager
nX := cX + 16, nY := cY + 26
, LV_GetText(SelectedIndex, SelectedRow, 8)
, SelectedCharacter := CharactersArray[SelectedIndex]
if (A_GuiEvent != "Normal")
Menu, CharacterContex, Show, % A_GuiX, % A_GuiY
}
return
_CharactersDDL:
Gui, Characters:Submit, NoHide
propName := Format("{:L}", CharactersDDL)
if (propName == prevPropName)
return
LV_EX_GroupRemoveAll(hCharsLV)
if (propName == "no grouping")
LV_EX_EnableGroupView(hCharsLV, false)
else
{
obj := {}
if (!LV_EX_IsGroupViewEnabled(hCharsLV))
LV_EX_EnableGroupView(hCharsLV)
for i, char in CharactersArray
{
key := propName == "path" ? char.Path : char.DEF.Info[propName]
if (key = "ERROR")
continue
if (!obj.HasKey(key))
obj[key] := []
obj[key].Push(i)
}
groupId := 10
, groupIndex := 1
for k, arr in obj
{
arrCount := arr.Count()
if (arrCount > 1)
{
LV_EX_GroupInsert(hCharsLV, groupId, k " - Count(" arrCount ")", 1, groupIndex)
, row := 1
Loop, % LV_GetCount()
{
LV_GetText(text, row, Columns[propName])
if (propName == "author" || propName == "name" || propName == "displayname")
text := Quoted(text)
if (text = k)
LV_EX_SetGroup(hCharsLV, row, groupId)
row += 1
}
LV_EX_GroupSetState(hCharsLV, groupId, "Collapsed", "Collapsible")
groupId += 10
, groupIndex += 1
}
}
}
prevPropName := propName
return
_CharactersSize:
If (A_EventInfo = 1)
Return
AutoXYWH("*wh", "CharactersLV")
return
_CharactersClose:
ExitApp
ContextMenu Script
Code: Select all
CreateListviewContextMenu:
Menu, RemoveCharcterMenu, Add, Rename DEF, RemoveChar_Rename
Menu, RemoveCharcterMenu, Add, Delete DEF, RemoveChar_Delete
Menu, RemoveCharcterMenu, Add, Delete Folder, RemoveChar_DeleteFolder
Menu, CharacterContex, Add, Open Char DEF, CreateCharDEFGui
Menu, CharacterContex, Add, Open Char CNS, CreateCharCNSGui
Menu, CharacterContex, Add, Open Char Folder, OpenCharacterFolder
Menu, CharacterContex, Add
Menu, CharacterContex, Add, Remove Charcter, :RemoveCharcterMenu
Menu, CharacterContex, Add
Menu, CharacterContex, Add, Move Char Folder, MoveCharacterFolder
return
RemoveChar_Rename:
Gui, Characters: +OwnDialogs
MsgBox, 0x40024, Confirm, % "Are you sure?`n`nThis will rename """ SelectedCharacter.DefName """ to """ SelectedCharacter.DefName ".bak"" and remove the character from the list."
IfMsgBox Yes
{
outFile := SelectedCharacter.DefFile ".bak"
while (FileExist(outFile))
outFile := SelectedCharacter.DefFile "(" A_Index ").bak"
FileMove, % SelectedCharacter.DefFile, % outFile
Gosub, DeleteListViewChar
}
return
RemoveChar_Delete:
Gui, Characters: +OwnDialogs
MsgBox, 0x40024, Confirm, % "Are you sure?`n`nThis will Delete """ SelectedCharacter.DefName """ and remove the character from the list."
IfMsgBox Yes
{
FileRecycle, % SelectedCharacter.DefFile
Gosub, DeleteListViewChar
}
return
RemoveChar_DeleteFolder:
Gui, Characters: +OwnDialogs
Gui, Characters:Default
path := SelectedCharacter.Path
, rows := LV_FindAllRows(path, Columns["path"], "path")
if (rows.Count() > 1)
{
charText := ""
, indexArray := []
for i, row in rows
{
LV_GetText(defName, row, 7)
, LV_GetText(index, row, 8)
, charText .= """" defName """`n"
, indexArray.Push({ Row: row, Index: index })
}
charText := RTrim(charText, "`n")
MsgBox, 0x40024, Confirm, % "Are you sure?`nThere is more than one def file in this folder.`n`nThis will Delete`n" charText "`nand remove the characters from the list."
IfMsgBox Yes
{
FileRemoveDir, % path, 1
deletedCount := 0
for i, obj in indexArray
{
CharactersArray.Delete(obj.Index)
if (A_Index = 1)
LV_Delete(obj.Row)
else
{
row := obj.Row - deletedCount
LV_Delete(row)
}
deletedCount += 1
}
}
}
else
{
MsgBox, 0x40024, Confirm, % "Are you sure?`n`nThis will Delete """ path """ and remove the character from the list."
IfMsgBox Yes
{
FileRemoveDir, % path, 1
Gosub, DeleteListViewChar
}
}
EmptyMem()
return
OpenCharacterFolder:
explorerWinTitle := SelectedCharacter.DirName
Run, % "explorer /e," SelectedCharacter.Path
return
MoveCharacterFolder:
Gui, Characters: +OwnDialogs
Gui, Characters:Default
FileSelectFolder, newFolder, % charsFolder, 1, Select New Folder
oldPath := SelectedCharacter.Path
, newPath := newFolder "\" SelectedCharacter.DirName
, rows := LV_FindAllRows(oldPath, Columns["path"], "path")
while (InStr(FileExist(newPath), "D"))
newPath := newFolder "\" SelectedCharacter.DirName "(" A_Index ")"
FileMoveDir, % oldPath, % newPath
if (rows.Count() > 1)
{
for i, row in rows
{
LV_GetText(defName, row, 7)
, LV_GetText(index, row, 8)
, newDefFile := newPath "\" defName
, CharactersArray[index] := new Character(newDefFile)
, LV_Modify(row,, UnQuote(CharactersArray[index].DEF.Info["name"]), UnQuote(CharactersArray[index].DEF.Info["displayname"]), UnQuote(CharactersArray[index].DEF.Info["author"]), CharactersArray[index].DEF.Info["versiondate"], CharactersArray[index].DEF.Info["mugenversion"], CharactersArray[index].Path, CharactersArray[index].DefName, index)
}
}
else
{
newDefFile := newPath "\" SelectedCharacter.DefName
, CharactersArray[SelectedIndex] := new Character(newDefFile)
, LV_Modify(SelectedRow,, UnQuote(CharactersArray[SelectedIndex].DEF.Info["name"]), UnQuote(CharactersArray[SelectedIndex].DEF.Info["displayname"]), UnQuote(CharactersArray[SelectedIndex].DEF.Info["author"]), CharactersArray[SelectedIndex].DEF.Info["versiondate"], CharactersArray[SelectedIndex].DEF.Info["mugenversion"], CharactersArray[SelectedIndex].Path, CharactersArray[SelectedIndex].DefName, SelectedIndex)
}
return
DeleteListViewChar:
Gui, Characters:Default
CharactersArray.Delete(SelectedIndex)
, LV_Delete(SelectedRow)
return
LV_Functions
there are more files to the script but this is all the relevant codeCode: Select all
LV_FindFirstRow(str, column, propName)
{
out := 0
Loop, % LV_GetCount()
{
row := A_Index
, LV_GetText(text, row, column)
if (propName == "author" || propName == "name" || propName == "displayname")
text := Quoted(text)
if (text = str)
{
out := row
break
}
}
return out
}
LV_FindAllRows(str, column, propName)
{
out := []
Loop, % LV_GetCount()
{
row := A_Index
, LV_GetText(text, row, column)
if (propName == "author" || propName == "name" || propName == "displayname")
text := Quoted(text)
if (text = str)
out.Push(row)
}
return out
}
; ======================================================================================================================
; LV_EX_GroupInsert - Inserts a group into a list-view control.
; ======================================================================================================================
LV_EX_GroupInsert(HLV, GroupID, Header, Align := "", Index := -1) {
; LVM_INSERTGROUP = 0x1091 -> msdn.microsoft.com/en-us/library/bb761103(v=vs.85).aspx
Static Alignment := {1: 1, 2: 2, 4: 4, C: 2, L: 1, R: 4}
Static SizeOfLVGROUP := (4 * 6) + (A_PtrSize * 4)
Static OffHeader := 8
Static OffGroupID := OffHeader + (A_PtrSize * 3) + 4
Static OffAlign := OffGroupID + 12
Static LVGF := 0x11 ; LVGF_GROUPID | LVGF_HEADER | LVGF_STATE
Static LVGF_ALIGN := 0x00000008
Align := (A := Alignment[SubStr(Align, 1, 1)]) ? A : 0
Mask := LVGF | (Align ? LVGF_ALIGN : 0)
PHeader := A_IsUnicode ? &Header : LV_EX_PWSTR(Header, WHeader)
VarSetCapacity(LVGROUP, SizeOfLVGROUP, 0)
NumPut(SizeOfLVGROUP, LVGROUP, 0, "UInt")
NumPut(Mask, LVGROUP, 4, "UInt")
NumPut(PHeader, LVGROUP, OffHeader, "Ptr")
NumPut(GroupID, LVGROUP, OffGroupID, "Int")
NumPut(Align, LVGROUP, OffAlign, "UInt")
SendMessage, 0x1091, %Index%, % &LVGROUP, , % "ahk_id " . HLV
Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GroupRemove - Removes a group from a list-view control.
; ======================================================================================================================
LV_EX_GroupRemove(HLV, GroupID) {
; LVM_REMOVEGROUP = 0x1096 -> msdn.microsoft.com/en-us/library/bb761149(v=vs.85).aspx
SendMessage, 0x10A0, %GroupID%, 0, , % "ahk_id " . HLV
Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GroupRemoveAll - Removes all groups from a list-view control.
; ======================================================================================================================
LV_EX_GroupRemoveAll(HLV) {
; LVM_REMOVEALLGROUPS = 0x10A0 -> msdn.microsoft.com/en-us/library/bb761147(v=vs.85).aspx
SendMessage, 0x10A0, 0, 0, , % "ahk_id " . HLV
Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GroupSetState - Set group state (requires Win Vista+ for most states).
; ======================================================================================================================
LV_EX_GroupSetState(HLV, GroupID, States*) {
; LVM_SETGROUPINFO = 0x1093 -> msdn.microsoft.com/en-us/library/bb761167(v=vs.85).aspx
Static LVGS := {Collapsed: 0x01, Collapsible: 0x08, Focused: 0x10, Hidden: 0x02, NoHeader: 0x04, Normal: 0x00
, Selected: 0x20, SubSeted: 0x40, SubSetedLinkFocused: 0x80, 0: 0, 1: 1, 2: 2, 4: 4, 8: 8, 16: 16
, 32: 32, 64: 64, 128: 128}
Static LVGF := 0x04 ; LVGF_STATE
Static SizeOfLVGROUP := (4 * 6) + (A_PtrSize * 4)
Static OffHeader := 8
Static OffStateMask := 8 + (A_PtrSize * 3) + 8
Static OffState := OffStateMask + 4
SetStates := 0
For Each, State In States {
If !LVGS.HasKey(State)
Return False
SetStates |= LVGS[State]
}
VarSetCapacity(LVGROUP, SizeOfLVGROUP, 0)
NumPut(SizeOfLVGROUP, LVGROUP, 0, "UInt")
NumPut(LVGF, LVGROUP, 4, "UInt")
NumPut(SetStates, LVGROUP, OffStateMask, "UInt")
NumPut(SetStates, LVGROUP, OffState, "UInt")
SendMessage, 0x1093, %GroupID%, % &LVGROUP, , % "ahk_id " . HLV
Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_GetGroup - Gets the ID of the group the list-view item belongs to.
; ======================================================================================================================
LV_EX_GetGroup(HLV, Row) {
; LVM_GETITEMA = 0x1005 -> http://msdn.microsoft.com/en-us/library/bb774953(v=vs.85).aspx
Static LVITEMSize := 48 + (A_PtrSize * 3)
Static OffGroupID := 28 + (A_PtrSize * 3)
VarSetCapacity(LVITEM, LVITEMSize, 0)
NumPut(0x00000100, LVITEM, 0, "UInt") ; LVIF_GROUPID
NumPut(Row - 1, LVITEM, 4, "Int")
SendMessage, 0x1005, 0, % &LVITEM, , % "ahk_id " . HLV
Return NumGet(LVITEM, OffGroupID, "UPtr")
}
; ======================================================================================================================
; LV_EX_SetGroup - Assigns a list-view item to an existing group.
; ======================================================================================================================
LV_EX_SetGroup(HLV, Row, GroupID) {
; LVM_SETITEMA = 0x1006 -> http://msdn.microsoft.com/en-us/library/bb761186(v=vs.85).aspx
Static LVITEMSize := 48 + (A_PtrSize * 3)
Static OffGroupID := 28 + (A_PtrSize * 3)
VarSetCapacity(LVITEM, LVITEMSize, 0)
NumPut(0x00000100, LVITEM, 0, "UInt") ; LVIF_GROUPID
NumPut(GroupID, LVITEM, OffGroupID, "UPtr")
NumPut(Row - 1, LVITEM, 4, "Int")
SendMessage, 0x1006, 0, % &LVITEM, , % "ahk_id " . HLV
Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_EnableGroupView - Enables or disables whether the items in a list-view control display as a group.
; ======================================================================================================================
LV_EX_EnableGroupView(HLV, Enable := True) {
; LVM_ENABLEGROUPVIEW = 0x109D -> msdn.microsoft.com/en-us/library/bb774900(v=vs.85).aspx
SendMessage, 0x109D, % (!!Enable), 0, , % "ahk_id " . HLV
Return (ErrorLevel >> 31) ? 0 : 1
}
; ======================================================================================================================
; LV_EX_HasGroup - Determines whether the list-view control has a specified group.
; ======================================================================================================================
LV_EX_HasGroup(HLV, GroupID) {
; LVM_HASGROUP = 0x10A1 -> msdn.microsoft.com/en-us/library/bb761097(v=vs.85).aspx
SendMessage, 0x10A1, %GroupID%, 0, , % "ahk_id " . HLV
Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_IsGroupViewEnabled - Checks whether the list-view control has group view enabled.
; ======================================================================================================================
LV_EX_IsGroupViewEnabled(HLV) {
; LVM_ISGROUPVIEWENABLED = 0x10AF -> msdn.microsoft.com/en-us/library/bb761133(v=vs.85).aspx
SendMessage, 0x10AF, 0, 0, , % "ahk_id " . HLV
Return ErrorLevel
}
; ======================================================================================================================
; LV_EX_PWSTR - Internal function needed for ANSI builts, returns a pointer to a Unicode string.
; ======================================================================================================================
LV_EX_PWSTR(Str, ByRef WSTR) {
VarSetCapacity(WSTR, StrPut(Str, "UTF-16") * 2, 0)
StrPut(Str, &WSTR, "UTF-16")
Return &WSTR
}