From 65febe82bd7131977f4355426cf73b76a743768c Mon Sep 17 00:00:00 2001
From: YozoZChomutova <jozozchomutova@email.cz>
Date: Tue, 2 Apr 2024 01:07:45 +0200
Subject: [PATCH 1/2] Simple "favourite" system for maps

---
 LuaMenu/images/star_off.png                   | Bin 0 -> 1223 bytes
 LuaMenu/images/star_on.png                    | Bin 0 -> 1283 bytes
 .../chobby/components/sortable_list.lua       |   8 ++
 LuaMenu/widgets/gui_maplist_panel.lua         |  80 ++++++++++++++++--
 4 files changed, 83 insertions(+), 5 deletions(-)
 create mode 100644 LuaMenu/images/star_off.png
 create mode 100644 LuaMenu/images/star_on.png

diff --git a/LuaMenu/images/star_off.png b/LuaMenu/images/star_off.png
new file mode 100644
index 0000000000000000000000000000000000000000..9ea94b17c5d65598e6a058c1c68d012269fedba1
GIT binary patch
literal 1223
zcmV;&1UUPNP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80004oX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmP!xqv(~2UM4t5Z6$WWauNEH!Wq>4qbP}&NuI+(ol51KS2
zDK3tJYr(;v#j1mgv#t)Vf*|+<;_Tq0=prTFmlRsWc;WFr&b#OE-hF`3tTNRMOaQ88
z8R<k^%;i_b-d6<RLkP2oNzBxfnZ+zT>+7C+sqUgY%e(K-8c+%*1AHR!9McVpc!PL)
z)6zNb6Ngz@Qi#uq#|^q5@gvt|m)|&-92R(H*vO{miNnNVsf*<<W@SSqo+6GYsz&)j
z&Si!37H73uXYG6P7X}O3N`~vSMv%Y~l1M>>j5;c)!a|gGjT94UI*)t!haG>4Tr#;T
zVB}ap4JstZ5B>+gXKNNGV{TF~4)na(_QxpDy9=}$w*7r<+pQD8{|sDd9e=F}%zTpG
z=xC86AhZo!Tz52i54hX`hMsiEkQ~WRODGnB_cQvYJTQ0*^sl*dYoFuv0m#y<mT!QA
zLtv~#+3Ozf?(3f0zdh~w{Q%Y>a?er*5%d5600v@9M??Ss0E7VcOQBy100009a7bBm
z001r2001r20T^M$X#fBK2XskIMF;2v0T2x+=fa0A0000PbVXQnLvL+uWo~o;Lvm$d
zbY)~9cWHEJAV*0}P*;Ht7XSbPok>JNR9M5s*H4I+RTKvB=MFP8)2LtsSx}M@F%d{u
z5G|sGWJEHNfk80PqD`w7wP;~(LJMk9(I$w3TD1wn5lLYd1s0S<A{a(BWB=@*DC%fq
z{#tY=UOr};`QGnqysLZ9d(L?t&N=s-`zAdsyo%>?xfXuFk;?^sEB^G)y0)#KfgU(K
zkYp;!p(LBzIw?IwU|*8`NmeHrE2V5-$?&hnC2YW5IEA5=BruMz>V616<Gz)wf$=1J
zlBAR}mt?Y+I%pGtU+`e#{0I)O6!@JuhbtPgwfGAgRw4ykl1!CSF8q6yN;#S2(<EEF
zbvB5xB%?_#CK;^q*(9eM0LL3P4<&hb0bhHQ+@Iu?Mr76{nZF%tl8n^-T$TSC%;<hy
zzd&j>w(#?L!Hr4YPO?79V@VD+m?p_B9a!f|DMuG;&q;<GqDx7RHO_NM?oIMmk|Rkb
z<_(9j0~fL5e=6QV?5gwQ>BW>b<2VlBx;}!h$3c9HJC;&ji+%VVTlxV0FwWpTtm?+_
zDa_(U47UKj60g^uG0~R&rW&@-x@j`F4To_IH}@LCQB2~;E^Pk58_S8@;F1r9QqE#J
z$(b&Af0E>6Ddl{>s`&fn@L7ib<M^^);J4S1j&xyjH7?+Wehi~+NhV7vvmGEq*o~bF
zr0usP2Wn^S%hP*XhwLhRh;QmFc^{(-q~TD%X8%BkYzBL=2J0||uj^!;*IR}2O<5ZP
zFW{ZV`3aoG^BsBvcnznqy&?Yq&-6lIrarfZ@MdkP<Nu-mXf3{%>-kB1(H8uk+KR{U
zQO)<pW!T+~Y3#3mPjFKk0=w&EoW`EcB3r`tnpzj%;U_%XhQQIverL-F4&bHg<Ku3P
lM{ojL`*4jXaAL9Ve*+Hs^88tg>i7Tv002ovPDHLkV1fjWIY9sb

literal 0
HcmV?d00001

diff --git a/LuaMenu/images/star_on.png b/LuaMenu/images/star_on.png
new file mode 100644
index 0000000000000000000000000000000000000000..6487bc117375f95d7ecb431831bace1de3b594d8
GIT binary patch
literal 1283
zcmV+e1^oJnP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F80004oX+uL$Nkc;*
zaB^>EX>4Tx04R}tkv&MmP!xqv(~2UM4t5Z6$WWauNEH!Wq>4qbP}&NuI+(ol51KS2
zDK3tJYr(;v#j1mgv#t)Vf*|+<;_Tq0=prTFmlRsWc;WFr&b#OE-hF`3tTNRMOaQ88
z8R<k^%;i_b-d6<RLkP2oNzBxfnZ+zT>+7C+sqUgY%e(K-8c+%*1AHR!9McVpc!PL)
z)6zNb6Ngz@Qi#uq#|^q5@gvt|m)|&-92R(H*vO{miNnNVsf*<<W@SSqo+6GYsz&)j
z&Si!37H73uXYG6P7X}O3N`~vSMv%Y~l1M>>j5;c)!a|gGjT94UI*)t!haG>4Tr#;T
zVB}ap4JstZ5B>+gXKNNGV{TF~4)na(_QxpDy9=}$w*7r<+pQD8{|sDd9e=F}%zTpG
z=xC86AhZo!Tz52i54hX`hMsiEkQ~WRODGnB_cQvYJTQ0*^sl*dYoFuv0m#y<mT!QA
zLtv~#+3Ozf?(3f0zdh~w{Q%Y>a?er*5%d5600v@9M??Ss0E7VcOQBy100009a7bBm
z001r2001r20T^M$X#fBK2XskIMF;2v0T2x_gQ+j=0000PbVXQnLvL+uWo~o;Lvm$d
zbY)~9cWHEJAV*0}P*;Ht7XSbP*-1n}R9M5kS4(RYK@k3`XLdrEaluD4LChfvo>cG!
z>LK6*3;~IOL__ctB6#r+cro}FJS&2rAf5ujs|unRJqQZH2a-!fS-~)~(Vd+x57nEQ
zeI+|HWE+~T9lGmXUsVG+7W=z3`-9ayJZ$7z0Re%Phl9#&eQ<dprl;?q+l&37kbReB
zAMvyDq3jB{3=~*+gdi`Vu7!YunM*=x2B78J>`?b|fIr?7A_5Sak4rDQ76SISvrrW+
zzm5WIChwQ(QWaDHfD?8wQ0`6+a4_;ts4$^`&>T!Y*zynv@|CPw^3@yDACmXgNri+Q
zjL!pq`vFw}w7Km326~s)wR9idjIWd|DZj9RRe^yYg?evI-v;y!`L}ius2JK>1EOA_
zxJXjZX_uv?0vb`hnjr~k^nSt$Ev}`+wi|XU;Q&xY^I5xr7iqwW4W_X<5?5V627dM?
z;a<j;EJsNN?WvOYt<aQ&91Jgm7xx+G=;l1jx-0;ZgolO~$z3?nvJA<6J_wqaF)*tD
zhw=;Wp;-9TNK*KQWyt=45LmGR2SBLnaHr!6FBq5aFO&DdO$9{ceJOy3-wFd(;>I*{
z4vTQQ_@tfiO_7k?g_EGG7fj<xQDRjEH~>u_C->=OZX}fEQvo{9N(B^|ycN~K!A_fx
z!)X8(Sfvg%-K_bHzG`khn=Ngc)70JE&4~R0ZLHC)frZ-vmjZT1<SpAdL$FFf54X5x
zN-QLysYMt{R<01lz5gHAmzXxda%BQEHfK(&`e#OD!Z1FcIRwq_w+X0HV}^72MiKh)
zAMr>JClppdUqs$_JEH<F#|&$Y<WPyc*SlJuKe`GmZ4>mY=$gVCjqIwu`_Fw&xYD57
z*_Z8v3wpjUg3f$0n4xNOBL@=?Gfch%I)3@M%)!k0&gaH!x9aX@dBDb(_ePmU_wtP*
t`+e(1q?~+bPszp8Kl8sK4+k45@E_#xSF^Tt%{%}A002ovPDHLkV1krzL;?T+

literal 0
HcmV?d00001

diff --git a/LuaMenu/widgets/chobby/components/sortable_list.lua b/LuaMenu/widgets/chobby/components/sortable_list.lua
index 2f6bbbeff..090580f1e 100644
--- a/LuaMenu/widgets/chobby/components/sortable_list.lua
+++ b/LuaMenu/widgets/chobby/components/sortable_list.lua
@@ -16,6 +16,7 @@ function SortableList:init(holder, headings, itemHeight, defaultSort, sortDirect
 	self.sortDataById = {}
 	self.items = 0
 	self.identifierList = {}
+	self.priorityList = {}
 
 	self.headingButtons = {}
 
@@ -218,6 +219,13 @@ end
 function SortableList:UpdateOrder()
 	local function SortFunction(a, b)
 		local noNil = self.sortDataById[a] and self.sortDataById[b] and self.sortDataById[a][self.sortBy] and self.sortDataById[b][self.sortBy]
+
+		if self.priorityList[a] == nil and self.priorityList[b] ~= nil then
+			return noNil and false
+		elseif self.priorityList[a] ~= nil and self.priorityList[b] == nil then
+			return noNil and true
+		end
+
 		if self.smallToLarge then
 			return noNil and self.sortDataById[a][self.sortBy] < self.sortDataById[b][self.sortBy]
 		else
diff --git a/LuaMenu/widgets/gui_maplist_panel.lua b/LuaMenu/widgets/gui_maplist_panel.lua
index 0435c3afd..97ba78a21 100644
--- a/LuaMenu/widgets/gui_maplist_panel.lua
+++ b/LuaMenu/widgets/gui_maplist_panel.lua
@@ -17,8 +17,12 @@ end
 local mapListWindow
 local lobby
 local loadRate = 1
-local IMG_READY    = LUA_DIRNAME .. "images/downloadready.png"
-local IMG_UNREADY  = LUA_DIRNAME .. "images/downloadnotready.png"
+local favMaps = {}
+local FILE_FAV_MAPS = "favourite_maps.txt"
+local IMG_READY    	= LUA_DIRNAME .. "images/downloadready.png"
+local IMG_UNREADY  	= LUA_DIRNAME .. "images/downloadnotready.png"
+local IMG_STAR_OFF  = LUA_DIRNAME .. "images/star_off.png"
+local IMG_STAR_ON  	= LUA_DIRNAME .. "images/star_on.png"
 
 local MINIMAP_TOOLTIP_PREFIX = "minimap_tooltip_"
 
@@ -134,6 +138,7 @@ local function CreateMapEntry(mapName, mapData, CloseFunc)--{"ResourceID":7098,"
 	local Configuration = WG.Chobby.Configuration
 
     local haveMap = VFS.HasArchive(mapName)
+	local isFavourite = favMaps[mapName] ~= nil;
 
     local mapButtonCaption = nil
 
@@ -143,15 +148,28 @@ local function CreateMapEntry(mapName, mapData, CloseFunc)--{"ResourceID":7098,"
 		mapButtonCaption = i18n("click_to_pick_map")
 	end
 
+	local root = Panel:New {
+		x = 0,
+		y = 0,
+		width = 774,
+		height = 60,
+		resizable = false,
+		draggable = false,
+		padding = {0,0,0,0},
+		noFont = true,
+	}
+
 	local mapButton = Button:New {
 		x = 0,
 		y = 0,
-		width = "100%",
+		width = 748,
+		height = "100%",
 		caption = "",
 		resizable = false,
 		draggable = false,
 		classname = "battle_default_button",
 		padding = {0, 0, 0, 0},
+		parent = root,
 		tooltip = MINIMAP_TOOLTIP_PREFIX .. mapName .. "|" .. mapButtonCaption,
 		objectOverrideFont = WG.Chobby.Configuration:GetFont(2),
 		OnClick = {
@@ -224,6 +242,28 @@ local function CreateMapEntry(mapName, mapData, CloseFunc)--{"ResourceID":7098,"
 			parent = mapButton,
 	}
 
+	local favouriteImg = Image:New {
+		x = 750,
+		y = 2,
+		width = 24,
+		height = 24,
+		file = (isFavourite and IMG_STAR_ON) or IMG_STAR_OFF,
+		parent = root,
+		OnClick = {
+			function (self)
+				if isFavourite then
+					isFavourite = false;
+					favMaps[mapName] = nil;
+				else
+					isFavourite = true;
+					favMaps[mapName] = 1;
+				end
+
+				self.file = (isFavourite and IMG_STAR_ON) or IMG_STAR_OFF;
+			end
+		}
+	}
+
 	local sortData
 	if mapData then
 		local mapSizeText = (mapData.Width or " ?") .. "x" .. (mapData.Height or " ?")
@@ -284,7 +324,7 @@ local function CreateMapEntry(mapName, mapData, CloseFunc)--{"ResourceID":7098,"
 		sortData[5] = (haveMap and 1) or 0 -- This line is pretty evil.
 	end
 
-	return mapButton, sortData, externalFunctions
+	return root, sortData, externalFunctions
 end
 
 --------------------------------------------------------------------------------
@@ -303,7 +343,7 @@ local function InitializeControls()
 		classname = "main_window",
 		parent = WG.Chobby.lobbyInterfaceHolder,
 		height = math.max(700, WG.Chobby.lobbyInterfaceHolder.height -100),
-		width = 810,
+		width = 834,
 		resizable = false,
 		draggable = false,
 		padding = {0, 0, 0, 0},
@@ -340,6 +380,14 @@ local function InitializeControls()
 
 	local function CloseFunc()
 		mapListWindow:Hide()
+
+		--Save "favourite maps" data to file
+		local favMapsFile = io.open(FILE_FAV_MAPS, "w");
+		favMapsFile:write(Spring.Utilities.GetEngineVersion() .. "\n"); --Game version is always first line
+		for mapName in pairs(favMaps) do
+			favMapsFile:write(mapName .. "\n");
+		end
+		io.close(favMapsFile);
 	end
 
 	local filterTerms
@@ -408,6 +456,7 @@ local function InitializeControls()
 	local featuredMapIndex = 1
 	local mapFuncs = {}
 	local mapList = WG.Chobby.SortableList(listHolder, headings, 60, 1, true, false, ItemInFilter)
+	mapList.priorityList = favMaps
 
 	local function AddTheNextBatchOfMaps()
 		local mapItems = {}
@@ -454,6 +503,27 @@ local function InitializeControls()
 		mapList:UpdateOrder()
 	end
 
+	local function FetchFavouriteMaps()
+		--Clear table first
+		for mapName, _ in pairs(favMaps) do
+			favMaps[mapName] = nil
+		end
+
+		--Load new
+		if VFS.FileExists(FILE_FAV_MAPS) then
+			local favouriteMapsData = VFS.LoadFile(FILE_FAV_MAPS)
+			local fileVersion --In which game version was file created (useful in case of changing file write/read structure in future)
+			for mapName in string.gmatch(favouriteMapsData, "[^\r\n]+") do
+				if fileVersion == nil then --First line will always be file version
+					fileVersion = mapName
+				else
+					favMaps[mapName] = 1
+				end
+			end
+		end --Otherwise -> no favourite maps/empty table
+	end
+
+	FetchFavouriteMaps()
 	WG.Delay(AddTheNextBatchOfMaps, 0.5 / loadRate)
 
 	-------------------------

From b76600f6ed6708b3bf4bbd33db15d23cc530c53b Mon Sep 17 00:00:00 2001
From: YozoZChomutova <jozozchomutova@email.cz>
Date: Tue, 2 Apr 2024 21:00:42 +0200
Subject: [PATCH 2/2] Star button centered on X axis

---
 LuaMenu/widgets/gui_maplist_panel.lua | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/LuaMenu/widgets/gui_maplist_panel.lua b/LuaMenu/widgets/gui_maplist_panel.lua
index 97ba78a21..d6b66fdd7 100644
--- a/LuaMenu/widgets/gui_maplist_panel.lua
+++ b/LuaMenu/widgets/gui_maplist_panel.lua
@@ -243,7 +243,7 @@ local function CreateMapEntry(mapName, mapData, CloseFunc)--{"ResourceID":7098,"
 	}
 
 	local favouriteImg = Image:New {
-		x = 750,
+		x = 748,
 		y = 2,
 		width = 24,
 		height = 24,