diff --git a/C7/Lua/civ3/textures.lua b/C7/Lua/civ3/textures.lua index 815980df5..dac37593b 100644 --- a/C7/Lua/civ3/textures.lua +++ b/C7/Lua/civ3/textures.lua @@ -23,6 +23,7 @@ local SPACE_RACE = "Art/SpaceShip/" local POPUP_BORDERS = "Art/popupborders.pcx" local CURSORS = "Art/Cursor.pcx" +local SCROLL = "Art/SCROLL.PCX" -- Texture definitions local textures = {} @@ -250,7 +251,195 @@ textures.ui = { path = CURSORS, crop_region = { 199, 1, 32, 32 }, } - } + }, + scrollbar = { + grabber = { + large = { + path = SCROLL, + crop_region = { 46, 139, 20, 20 }, + shadows = false, + }, + small = { + path = SCROLL, + crop_region = { 51, 254, 10, 10 }, + shadows = false, + }, + }, + scroll = { + vertical = { + large = { + path = SCROLL, + crop_region = { 9, 139, 20, 20 }, + shadows = false, + }, + small = { + path = SCROLL, + crop_region = { 14, 249, 10, 20 }, + shadows = false, + }, + }, + horizontal = { + large = { + path = SCROLL, + crop_region = { 9, 380, 20, 20 }, + shadows = false, + }, + small = { + path = SCROLL, + crop_region = { 119, 385, 20, 10 }, + shadows = false, + }, + }, + }, + decrement = { + vertical = { + large = { + normal = { + path = SCROLL, + crop_region = { 2, 25, 20, 20 }, + shadows = false, + }, + hover = { + path = SCROLL, + crop_region = { 25, 25, 20, 20 }, + shadows = false, + }, + pressed = { + path = SCROLL, + crop_region = { 48, 25, 20, 20 }, + shadows = false, + }, + }, + small = { + normal = { + path = SCROLL, + crop_region = { 117, 15, 10, 10 }, + shadows = false, + }, + hover = { + path = SCROLL, + crop_region = { 130, 15, 10, 10 }, + shadows = false, + }, + pressed = { + path = SCROLL, + crop_region = { 143, 15, 10, 10 }, + shadows = false, + }, + }, + }, + horizontal = { + large = { + normal = { + path = SCROLL, + crop_region = { 94, 2, 20, 20 }, + shadows = false, + }, + hover = { + path = SCROLL, + crop_region = { 94, 25, 20, 20 }, + shadows = false, + }, + pressed = { + path = SCROLL, + crop_region = { 94, 48, 20, 20 }, + shadows = false, + }, + }, + small = { + normal = { + path = SCROLL, + crop_region = { 169, 2, 10, 10 }, + shadows = false, + }, + hover = { + path = SCROLL, + crop_region = { 169, 15, 10, 10 }, + shadows = false, + }, + pressed = { + path = SCROLL, + crop_region = { 169, 28, 10, 10 }, + shadows = false, + }, + }, + }, + }, + increment = { + vertical = { + large = { + normal = { + path = SCROLL, + crop_region = { 2, 2, 20, 20 }, + shadows = false, + }, + hover = { + path = SCROLL, + crop_region = { 25, 2, 20, 20 }, + shadows = false, + }, + pressed = { + path = SCROLL, + crop_region = { 48, 2, 20, 20 }, + shadows = false, + }, + }, + small = { + normal = { + path = SCROLL, + crop_region = { 117, 2, 10, 10 }, + shadows = false, + }, + hover = { + path = SCROLL, + crop_region = { 130, 2, 10, 10 }, + shadows = false, + }, + pressed = { + path = SCROLL, + crop_region = { 143, 2, 10, 10 }, + shadows = false, + }, + }, + }, + horizontal = { + large = { + normal = { + path = SCROLL, + crop_region = { 71, 2, 20, 20 }, + shadows = false, + }, + hover = { + path = SCROLL, + crop_region = { 71, 25, 20, 20 }, + shadows = false, + }, + pressed = { + path = SCROLL, + crop_region = { 71, 48, 20, 20 }, + shadows = false, + }, + }, + small = { + normal = { + path = SCROLL, + crop_region = { 156, 2, 10, 10 }, + shadows = false, + }, + hover = { + path = SCROLL, + crop_region = { 156, 15, 10, 10 }, + shadows = false, + }, + pressed = { + path = SCROLL, + crop_region = { 156, 28, 10, 10 }, + shadows = false, + }, + }, + }, + }, + }, } textures.terrain = require "textures.terrain" diff --git a/C7/Lua/standalone/textures.lua b/C7/Lua/standalone/textures.lua index 56f0194e7..cc966dd37 100644 --- a/C7/Lua/standalone/textures.lua +++ b/C7/Lua/standalone/textures.lua @@ -105,6 +105,7 @@ local c7_texture_list = { "Art/city screen/buildings-small.png", "Art/city screen/buildings-large.png", "Art/Cursor.png", + "Art/SCROLL.png", "Art/interface/box trans color.png", "Art/SpaceShip/SHIPbackground.png", "Art/Advisors/trade.png", diff --git a/C7/UIElements/Advisors/DomesticAdvisor.cs b/C7/UIElements/Advisors/DomesticAdvisor.cs index e1e5756eb..6dba61349 100644 --- a/C7/UIElements/Advisors/DomesticAdvisor.cs +++ b/C7/UIElements/Advisors/DomesticAdvisor.cs @@ -300,7 +300,7 @@ private HBoxContainer MakeCityRow(City city) { // Use an empty pany container to make it blank, unlike an HSeparator PanelContainer hSeparator1 = new(); - hSeparator1.CustomMinimumSize = new Vector2(30, 50); + hSeparator1.CustomMinimumSize = new Vector2(30, 45); hSeparator1.AddThemeStyleboxOverride("panel", new StyleBoxEmpty()); hboxContainer.AddChild(hSeparator1); @@ -399,7 +399,7 @@ private HBoxContainer MakeCityRow(City city) { hboxContainer.AddChild(popuplationContainer); PanelContainer productionContainer = new(); - productionContainer.CustomMinimumSize = new Vector2(50, 0); + productionContainer.CustomMinimumSize = new Vector2(45, 0); productionContainer.AddThemeStyleboxOverride("panel", new StyleBoxEmpty()); hboxContainer.AddChild(productionContainer); @@ -494,7 +494,7 @@ void AddPopHeads(City city, Node node, int maxWidth) { private int AddCitizen(Node node, CityResident cr, int xPos, int spacer, int eraNum) { TextureRect tr = new(); tr.Texture = PopHead.GetTexture(cr, eraNum); - tr.SetPosition(new Vector2(xPos, 0)); + tr.SetPosition(new Vector2(xPos, -3)); node.AddChild(tr); return xPos + spacer; } diff --git a/C7/UIElements/Advisors/domestic_advisor.tscn b/C7/UIElements/Advisors/domestic_advisor.tscn index 4f57b218f..de9bf16a3 100644 --- a/C7/UIElements/Advisors/domestic_advisor.tscn +++ b/C7/UIElements/Advisors/domestic_advisor.tscn @@ -1,9 +1,13 @@ -[gd_scene load_steps=8 format=3 uid="uid://da7hbbufyfllg"] +[gd_scene load_steps=12 format=3 uid="uid://da7hbbufyfllg"] [ext_resource type="Script" uid="uid://ch2d6f1o1sxh2" path="res://UIElements/Advisors/DomesticAdvisor.cs" id="1"] [ext_resource type="Script" uid="uid://doqipc4rnaotx" path="res://UIElements/Civ3TextureRect.cs" id="2"] [ext_resource type="Script" uid="uid://dcrdcjop64t6t" path="res://UIElements/Civ3TextureButton.cs" id="3"] +[ext_resource type="Script" uid="uid://bqhqd45omq70l" path="res://UIElements/Civ3ScrollBarControl.cs" id="4_8ldo1"] [ext_resource type="Script" uid="uid://clv4mgavtlrul" path="res://UIElements/Civ3HSlider.cs" id="4_gltop"] +[ext_resource type="Script" uid="uid://c0pjvkxsd8l6i" path="res://UIElements/Civ3HScrollBar.cs" id="5_bbtrj"] +[ext_resource type="Script" uid="uid://cmr1nj4edk0qc" path="res://UIElements/Civ3VScrollBar.cs" id="5_n8go8"] +[ext_resource type="Script" uid="uid://be03jafarm1i8" path="res://UIElements/Civ3ScrollHandle.cs" id="6_bbtrj"] [sub_resource type="LabelSettings" id="LabelSettings_0b8py"] font_size = 13 @@ -36,7 +40,7 @@ incomeSummary = NodePath("Background/IncomeSummary") expenseSummary = NodePath("Background/ExpenseSummary") sumSummary = NodePath("Background/SumSummary") growth = NodePath("Background/Growth") -cityListContainer = NodePath("Background/ScrollContainer/VBoxContainer") +cityListContainer = NodePath("Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer") eatenFood = NodePath("Background/EatenFood") fullFood = NodePath("Background/FullFood") wastedShield = NodePath("Background/WastedShield") @@ -49,6 +53,7 @@ beaker = NodePath("Background/Beaker") treasuryIcon = NodePath("Background/TreasuryIcon") scienceSlider = NodePath("Background/ScienceSlider") luxurySlider = NodePath("Background/LuxurySlider") +metadata/_edit_vertical_guides_ = [1038.0] [node name="Background" type="TextureRect" parent="."] layout_mode = 2 @@ -186,24 +191,207 @@ offset_right = 967.0 offset_bottom = 272.0 text = "Producing" -[node name="ScrollContainer" type="ScrollContainer" parent="Background"] +[node name="Control" type="Control" parent="Background"] +anchors_preset = 0 + +[node name="ScrollContainer" type="ScrollContainer" parent="Background/Control"] +layout_mode = 0 +offset_left = 66.0 +offset_top = 716.0 +offset_right = 466.0 +offset_bottom = 756.0 +mouse_filter = 0 + +[node name="HBoxContainer" type="HBoxContainer" parent="Background/Control/ScrollContainer"] +layout_mode = 2 + +[node name="ColorRect" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect2" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="ColorRect3" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect4" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="ColorRect5" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect6" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="ColorRect7" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect8" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="ColorRect9" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect10" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="ColorRect11" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect12" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="ColorRect13" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect14" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="ColorRect15" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect16" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="ColorRect17" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect18" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="ColorRect19" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect20" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="ColorRect21" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect22" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="ColorRect23" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(1, 0.18, 0.18, 1) + +[node name="ColorRect24" type="ColorRect" parent="Background/Control/ScrollContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 30) +layout_mode = 2 +color = Color(0.41948, 0.615308, 0.390975, 1) + +[node name="Civ3ScrollBarControl" type="Control" parent="Background/Control" node_paths=PackedStringArray("TargetContainer", "ScrollBar", "ScrollHandle")] +visible = false +anchors_preset = 0 +offset_left = 145.0 +offset_top = 750.0 +offset_right = 395.0 +offset_bottom = 760.0 +script = ExtResource("4_8ldo1") +Direction = 1 +SizePreset = 1 +TargetContainer = NodePath("../ScrollContainer") +ScrollBar = NodePath("Civ3HScrollBar") +ScrollHandle = NodePath("Civ3ScrollHandle") +ArrowScrollInterval = 0.1 +metadata/_custom_type_script = "uid://bqhqd45omq70l" + +[node name="Civ3HScrollBar" type="HScrollBar" parent="Background/Control/Civ3ScrollBarControl"] layout_mode = 0 -offset_left = 72.0 -offset_top = 298.0 -offset_right = 986.0 -offset_bottom = 676.0 +offset_right = 250.0 +offset_bottom = 10.0 +max_value = 812.0 +step = 30.0 +page = 400.0 +script = ExtResource("5_bbtrj") +metadata/_custom_type_script = "uid://c0pjvkxsd8l6i" + +[node name="Civ3ScrollHandle" type="TextureButton" parent="Background/Control/Civ3ScrollBarControl"] +z_index = 10 +layout_mode = 0 +offset_left = 20.0 +offset_right = 40.0 +offset_bottom = 20.0 +script = ExtResource("6_bbtrj") +metadata/_custom_type_script = "uid://be03jafarm1i8" + +[node name="CitiesScrollBarControl" type="Control" parent="Background"] +anchors_preset = 0 +offset_left = -1.0 +offset_right = -1.0 + +[node name="ScrollContainer" type="ScrollContainer" parent="Background/CitiesScrollBarControl"] +layout_mode = 1 +anchors_preset = 8 +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +offset_left = 75.0 +offset_top = 303.0 +offset_right = 975.0 +offset_bottom = 708.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 0 -[node name="VBoxContainer" type="VBoxContainer" parent="Background/ScrollContainer"] +[node name="VBoxContainer" type="VBoxContainer" parent="Background/CitiesScrollBarControl/ScrollContainer"] layout_mode = 2 +theme_override_constants/separation = 0 -[node name="HBoxContainer" type="HBoxContainer" parent="Background/ScrollContainer/VBoxContainer"] +[node name="HBoxContainer" type="HBoxContainer" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer"] layout_mode = 2 -[node name="HSeparator" type="HSeparator" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] -custom_minimum_size = Vector2(30, 50) +[node name="HSeparator" type="HSeparator" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] +custom_minimum_size = Vector2(30, 45) layout_mode = 2 -[node name="Label" type="Label" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="Label" type="Label" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(127, 0) layout_mode = 2 text = "Placeholder that gets " @@ -211,29 +399,29 @@ vertical_alignment = 1 clip_text = true text_overrun_behavior = 3 -[node name="Label2" type="Label" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="Label2" type="Label" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(40, 0) layout_mode = 2 text = "10.20" horizontal_alignment = 1 -[node name="Label3" type="Label" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="Label3" type="Label" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(40, 0) layout_mode = 2 text = "10.20" horizontal_alignment = 1 -[node name="Label4" type="Label" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="Label4" type="Label" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(40, 0) layout_mode = 2 text = "10.20" horizontal_alignment = 1 -[node name="HSeparator2" type="HSeparator" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="HSeparator2" type="HSeparator" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(25, 0) layout_mode = 2 -[node name="Label5" type="Label" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="Label5" type="Label" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(40, 0) layout_mode = 2 text = "20" @@ -242,7 +430,7 @@ vertical_alignment = 1 clip_text = true text_overrun_behavior = 3 -[node name="Label6" type="Label" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="Label6" type="Label" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(40, 0) layout_mode = 2 text = "20" @@ -251,7 +439,7 @@ vertical_alignment = 1 clip_text = true text_overrun_behavior = 3 -[node name="Label7" type="Label" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="Label7" type="Label" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(40, 0) layout_mode = 2 text = "20" @@ -260,7 +448,7 @@ vertical_alignment = 1 clip_text = true text_overrun_behavior = 3 -[node name="Label8" type="Label" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="Label8" type="Label" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(40, 0) layout_mode = 2 text = "20" @@ -269,21 +457,21 @@ vertical_alignment = 1 clip_text = true text_overrun_behavior = 3 -[node name="HSeparator3" type="HSeparator" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="HSeparator3" type="HSeparator" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(25, 0) layout_mode = 2 -[node name="PanelContainer" type="PanelContainer" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="PanelContainer" type="PanelContainer" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(220, 0) layout_mode = 2 theme_override_styles/panel = SubResource("StyleBoxEmpty_5hkgh") -[node name="PanelContainer2" type="PanelContainer" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="PanelContainer2" type="PanelContainer" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(50, 0) layout_mode = 2 theme_override_styles/panel = SubResource("StyleBoxEmpty_5hkgh") -[node name="Label9" type="Label" parent="Background/ScrollContainer/VBoxContainer/HBoxContainer"] +[node name="Label9" type="Label" parent="Background/CitiesScrollBarControl/ScrollContainer/VBoxContainer/HBoxContainer"] custom_minimum_size = Vector2(75, 0) layout_mode = 2 text = "Statue of Ze @@ -292,6 +480,39 @@ vertical_alignment = 1 clip_text = true text_overrun_behavior = 3 +[node name="Civ3ScrollBarControl" type="Control" parent="Background/CitiesScrollBarControl" node_paths=PackedStringArray("TargetContainer", "ScrollBar", "ScrollHandle")] +visible = false +anchors_preset = 0 +offset_left = 965.0 +offset_top = 303.0 +offset_right = 975.0 +offset_bottom = 708.0 +script = ExtResource("4_8ldo1") +TargetContainer = NodePath("../ScrollContainer") +ScrollBar = NodePath("Civ3VScrollBar") +Step = true +ScrollHandle = NodePath("Civ3ScrollHandle") +metadata/_custom_type_script = "uid://bqhqd45omq70l" + +[node name="Civ3VScrollBar" type="VScrollBar" parent="Background/CitiesScrollBarControl/Civ3ScrollBarControl"] +layout_mode = 0 +offset_right = 10.0 +offset_bottom = 405.0 +max_value = 45.0 +step = 45.0 +page = 45.0 +script = ExtResource("5_n8go8") +metadata/_custom_type_script = "uid://cmr1nj4edk0qc" + +[node name="Civ3ScrollHandle" type="TextureButton" parent="Background/CitiesScrollBarControl/Civ3ScrollBarControl"] +z_index = 10 +layout_mode = 0 +offset_top = 10.0 +offset_right = 10.0 +offset_bottom = 20.0 +script = ExtResource("6_bbtrj") +metadata/_custom_type_script = "uid://be03jafarm1i8" + [node name="EatenFood" type="TextureButton" parent="Background"] layout_mode = 0 offset_left = 241.0 diff --git a/C7/UIElements/Civ3HScrollBar.cs b/C7/UIElements/Civ3HScrollBar.cs new file mode 100644 index 000000000..738a83f75 --- /dev/null +++ b/C7/UIElements/Civ3HScrollBar.cs @@ -0,0 +1,17 @@ +using Godot; + +namespace C7.UIElements; + +[GlobalClass] +[Tool] +public partial class Civ3HScrollBar : HScrollBar, ICiv3Range { + public Civ3RangeTheme rangeTheme { get; init; } + + public Civ3HScrollBar() { + this.rangeTheme = new Civ3RangeTheme(this); + } + + public override void _Notification(int what) { + this.rangeTheme.ClearAndRestoreOverrides(what); + } +} diff --git a/C7/UIElements/Civ3HScrollBar.cs.uid b/C7/UIElements/Civ3HScrollBar.cs.uid new file mode 100644 index 000000000..5940b1060 --- /dev/null +++ b/C7/UIElements/Civ3HScrollBar.cs.uid @@ -0,0 +1 @@ +uid://c0pjvkxsd8l6i diff --git a/C7/UIElements/Civ3ScrollBarControl.cs b/C7/UIElements/Civ3ScrollBarControl.cs new file mode 100644 index 000000000..3c5c61326 --- /dev/null +++ b/C7/UIElements/Civ3ScrollBarControl.cs @@ -0,0 +1,342 @@ +using System.ComponentModel.DataAnnotations; +using System.Dynamic; +using Godot; + +namespace C7.UIElements; + +[GlobalClass] +[Tool] +public partial class Civ3ScrollBarControl : Control { + public enum ScrollDirection { + Vertical, + Horizontal + } + + public enum ScrollBarSize { + Small, + Large + } + + public enum ArrowScrollDirection { + None = 0, + Decrement = -1, + Increment = 1 + } + + // Control + // │ + // ├── ScrollContainer + // │ └── VBoxContainer + // │ ├── Item (HBoxContainer or whatever) + // │ ├── Item + // │ ├── Item + // │ └── Item + // │ + // └── Civ3ScrollBarControl + // ├── ScrollBar (Civ3VScrollBar or Civ3HScrollBar) + // └── Civ3ScrollHandle + + // ScrollBar replaces the ScrollContainer's scroll bar completely. + // This way we can place it wherever we want, left, right, top bottom, middle, + // have it have a different size to the container, etc. + // ScrollBar, while the visible scroll bar, controls the ScrollContainer (hidden) scroll bar. + // Civ3ScrollHandle replaces ScrollBar's grabber, because we want to control its texture size. + // So all in all, when we scroll, the ScrollContainer's bar is actually scrolling, + // but we see the ScrollBar's scroll textures updating. + // When we "scroll" using the grabber (Civ3ScrollHandle), + // we actually update the ScrollContainer's scroll bar, + // and "fake" its position along our custom scroll bar, + // to make it seem like it's moving. + + [Export] public ScrollDirection Direction { get; set; } = ScrollDirection.Vertical; + [Export] public ScrollBarSize SizePreset { get; set; } = ScrollBarSize.Small; + [Export] public ScrollContainer TargetContainer { get; set; } + [Export] public ScrollBar ScrollBar { get; set; } + [Export] public bool Step { get; set; } + [Export] public Civ3ScrollHandle ScrollHandle { get; set; } + // Time we wait before we start repeatedly increment/decrement when pushing the respective buttons + [Export] public double ArrowScrollInitialWaitTime { get; set; } = 0.3; + // Time we wait before each repeated increment/decrement action when pushing the respective buttons + [Export] public double ArrowScrollInterval { get; set; } = 0.2; + + public ScrollBar targetScrollBar { get; private set; } + public float topPadding { get; private set; } // which is also the decrement icon height (when vertical) + public float bottomPadding { get; private set; } // which is also the increment icon height (when vertical) + public float leftPadding { get; private set; } // which is also the decrement icon width (when horizontal) + public float rightPadding { get; private set; }// which is also the increment icon width (when horizontal) + + private bool syncing; + + private Timer arrowScrollTimer; + + private double lastPressedValue; + private ArrowScrollDirection arrowScrollDirection = ArrowScrollDirection.None; + + public override void _Ready() { + this.Visible = false; + // this.SizePreset = ScrollBarSize.Large; + + if (this.PreLaunchCheckFailed()) { + return; + } + + this.TargetContainer.MouseFilter = Control.MouseFilterEnum.Stop; + + this.targetScrollBar = Direction == ScrollDirection.Vertical + ? this.TargetContainer.GetVScrollBar() + : this.TargetContainer.GetHScrollBar(); + + this.SetupScrollBar(); + + ScrollHandle.Initialize(this, this.SizePreset); + + this.SetupArrowScrolling(); + + CallDeferred(nameof(ConnectScrollBars)); + + this.targetScrollBar.VisibilityChanged += () => { + this.Visible = this.targetScrollBar.Visible; + }; + } + + private bool PreLaunchCheckFailed() { + var error = false; + if (this.TargetContainer is null) { + GD.PushError($"TargetContainer (ScrollContainer) should be assigned in the editor"); + error = true; + } + if (this.ScrollBar is null) { + GD.PushError($"ScrollBar (Civ3VScrollBar or Civ3HScrollBar) should be assigned in the editor"); + error = true; + } + if (this.ScrollHandle is null) { + GD.PushError($"ScrollHandle (Civ3ScrollHandle) should be assigned in the editor"); + error = true; + } + if (this.ScrollBar is not Civ3VScrollBar && this.ScrollBar is not Civ3HScrollBar) { + GD.PushError($"ScrollBar should either be a Civ3VScrollBar or a Civ3HScrollBar node"); + error = true; + } + return error; + } + + private void SetupScrollBar() { + ApplyTheme(); + + if (this.TargetContainer.GetChild(0) is BoxContainer mainContainer && mainContainer.GetChildCount() > 0) { + if (mainContainer.GetChild(0) is Control firstItem) { + if (Step) { + float step = this.Direction == ScrollDirection.Vertical + ? firstItem.Size.Y + : firstItem.Size.X; + this.targetScrollBar.Step = step; + } else { + this.targetScrollBar.Step = 20.0f; + } + } + } + + this.ScrollBar.MouseFilter = MouseFilterEnum.Stop; + } + + private void ConnectScrollBars() { + this.SyncFromTarget(); + + this.targetScrollBar.ValueChanged += value => { + if (this.syncing) + return; + + this.syncing = true; + this.ScrollBar.Value = value; + this.syncing = false; + + if (!this.ScrollHandle.IsDragging) + this.ScrollHandle.UpdatePosition(); + }; + + this.ScrollBar.ValueChanged += value => { + if (this.syncing) + return; + + this.syncing = true; + this.targetScrollBar.Value = value; + this.syncing = false; + + if (!this.ScrollHandle.IsDragging) + this.ScrollHandle.UpdatePosition(); + }; + + this.targetScrollBar.Changed += SyncFromTarget; + this.TargetContainer.Resized += SyncFromTarget; + + CallDeferred(nameof(SyncFromTarget)); + } + + private void SyncFromTarget() { + syncing = true; + + this.ScrollBar.MinValue = this.targetScrollBar.MinValue; + this.ScrollBar.MaxValue = this.targetScrollBar.MaxValue; + this.ScrollBar.Page = this.targetScrollBar.Page; + this.ScrollBar.Step = this.targetScrollBar.Step; + this.ScrollBar.Value = this.targetScrollBar.Value; + + this.syncing = false; + + this.ScrollHandle.UpdatePosition(); + } + + public float GetScrollRatio() { + float range = (float)(this.ScrollBar.MaxValue - this.ScrollBar.Page); + + if (range <= 0) + return 0; + + return (float)this.ScrollBar.Value / range; + } + + public float GetHandleTravel() { + float trackLength; + float handleLength; + float padding; + + if (Direction == ScrollDirection.Vertical) { + trackLength = this.ScrollBar.Size.Y; + handleLength = this.ScrollHandle.Size.Y; + padding = this.topPadding + this.bottomPadding; + } else { + trackLength = this.ScrollBar.Size.X; + handleLength = this.ScrollHandle.Size.X; + padding = this.leftPadding + this.rightPadding; + } + + return Mathf.Max(0, trackLength - handleLength - padding); + } + + public void SetHandlePosition(float position) { + if (Direction == ScrollDirection.Vertical) { + this.ScrollHandle.Position = new Vector2(this.ScrollHandle.Position.X, this.topPadding + position); + } else { + this.ScrollHandle.Position = new Vector2(this.leftPadding + position, this.ScrollHandle.Position.Y); + } + } + + public void SetValueFromHandle(float position) { + float travel = this.GetHandleTravel(); + + if (travel <= 0) + return; + + float ratio = position / travel; + float value = (float)(ratio * (this.ScrollBar.MaxValue - this.ScrollBar.Page)); + + this.ScrollBar.Value = value; + } + + private void SetupArrowScrolling() { + this.arrowScrollTimer = new Timer { + WaitTime = this.ArrowScrollInterval, + OneShot = false + }; + + this.AddChild(this.arrowScrollTimer); + this.arrowScrollTimer.Timeout += ScrollArrowRepeat; + this.ScrollBar.GuiInput += OnScrollBarInput; + } + + private void OnScrollBarInput(InputEvent @event) { + if (@event is not InputEventMouseButton mouse || mouse.ButtonIndex != MouseButton.Left) + return; + + if (mouse.Pressed) { + this.lastPressedValue = this.targetScrollBar.Value; + CallDeferred(nameof(DetermineArrowDirection)); + } else { + this.StopArrowScrolling(); + } + } + + private void DetermineArrowDirection() { + if (targetScrollBar.Value > this.lastPressedValue) + this.arrowScrollDirection = ArrowScrollDirection.Increment; + else if (this.targetScrollBar.Value < this.lastPressedValue) + this.arrowScrollDirection = ArrowScrollDirection.Decrement; + else + this.arrowScrollDirection = ArrowScrollDirection.None; + + if (this.arrowScrollDirection == ArrowScrollDirection.None) + return; + + this.arrowScrollTimer.WaitTime = this.ArrowScrollInitialWaitTime; + this.arrowScrollTimer.OneShot = true; + this.arrowScrollTimer.Start(); + } + + private void StartArrowRepeat() { + this.arrowScrollTimer.WaitTime = this.ArrowScrollInterval; + this.arrowScrollTimer.OneShot = false; + + this.arrowScrollTimer.Start(); + } + + private void ScrollArrowRepeat() { + if (this.arrowScrollDirection == 0) + return; + + // switch from initial delay to repeat interval + this.arrowScrollTimer.WaitTime = this.ArrowScrollInterval; + this.arrowScrollTimer.OneShot = false; + this.arrowScrollTimer.Start(); + + this.targetScrollBar.Value += (int)this.arrowScrollDirection * this.targetScrollBar.Step; + } + + private void ScrollArrowOnce() { + this.targetScrollBar.Value += (int)this.arrowScrollDirection * this.targetScrollBar.Step; + } + + private void StopArrowScrolling() { + this.arrowScrollTimer.Stop(); + this.arrowScrollDirection = 0; + } + + private void ApplyTheme() { + string size = this.SizePreset.ToString().ToLower(); + string direction = this.Direction.ToString().ToLower(); + + StyleBoxEmpty empty = new(); + + if (this.ScrollBar is ICiv3Range scrl) { + scrl.rangeTheme + .AddScrollStyleBox(new StyleBoxTexture { + Texture = TextureLoader.Load($"ui.scrollbar.scroll.{direction}.{size}"), + AxisStretchHorizontal = StyleBoxTexture.AxisStretchMode.Tile, + AxisStretchVertical = StyleBoxTexture.AxisStretchMode.Tile + }) + .AddIncrement(TextureLoader.Load($"ui.scrollbar.increment.{direction}.{size}.normal")) + .AddIncrementHighlight(TextureLoader.Load($"ui.scrollbar.increment.{direction}.{size}.hover")) + .AddIncrementPressed(TextureLoader.Load($"ui.scrollbar.increment.{direction}.{size}.pressed")) + .AddDecrement(TextureLoader.Load($"ui.scrollbar.decrement.{direction}.{size}.normal")) + .AddDecrementHighlight(TextureLoader.Load($"ui.scrollbar.decrement.{direction}.{size}.hover")) + .AddDecrementPressed(TextureLoader.Load($"ui.scrollbar.decrement.{direction}.{size}.pressed")) + .AddGrabberStyleBox(empty) + .AddGrabberHighlightStyleBox(empty) + .AddGrabberPressedStyleBox(empty); + + if (Direction == ScrollDirection.Vertical) { + this.topPadding = scrl.rangeTheme.Decrement.GetHeight(); + this.bottomPadding = scrl.rangeTheme.Increment.GetHeight(); + } else { + this.leftPadding = scrl.rangeTheme.Decrement.GetWidth(); + this.rightPadding = scrl.rangeTheme.Increment.GetWidth(); + } + } + + Civ3RangeTheme targetScrollBarTheme = new Civ3RangeTheme(this.targetScrollBar); + + targetScrollBarTheme.AddScrollStyleBox(empty) + .AddGrabberStyleBox(empty) + .AddGrabberHighlightStyleBox(empty) + .AddGrabberPressedStyleBox(empty); + } +} diff --git a/C7/UIElements/Civ3ScrollBarControl.cs.uid b/C7/UIElements/Civ3ScrollBarControl.cs.uid new file mode 100644 index 000000000..a0709bcd9 --- /dev/null +++ b/C7/UIElements/Civ3ScrollBarControl.cs.uid @@ -0,0 +1 @@ +uid://bqhqd45omq70l diff --git a/C7/UIElements/Civ3ScrollHandle.cs b/C7/UIElements/Civ3ScrollHandle.cs new file mode 100644 index 000000000..dc2fe75d4 --- /dev/null +++ b/C7/UIElements/Civ3ScrollHandle.cs @@ -0,0 +1,97 @@ +using Godot; +using static C7.UIElements.Civ3ScrollBarControl; + +namespace C7.UIElements; + +[GlobalClass] +[Tool] +public partial class Civ3ScrollHandle : Civ3TextureButton { + [Export] public bool UseTextureSize { get; set; } = true; + + private Civ3ScrollBarControl owner; + public bool IsDragging => dragging; + private bool dragging; + // private Vector2 dragOffset; + private double savedStep; + + public override void _Ready() { + // This means that when scrolling using the mouse wheel, + // if the mouse happens to come over the grabber texture, + // it will not scroll! + this.MouseFilter = MouseFilterEnum.Stop; + this.ZIndex = 10; + } + + public void Initialize(Civ3ScrollBarControl scrollBarControl, ScrollBarSize scrollSize) { + this.owner = scrollBarControl; + + this.savedStep = this.owner.targetScrollBar.Step; + + ApplyTexture(scrollSize); + + UpdatePosition(); + + ButtonDown += StartDrag; + } + + private void ApplyTexture(ScrollBarSize scrollSize) { + var grabberTexture = TextureLoader.Load($"ui.scrollbar.grabber.{scrollSize.ToString().ToLower()}"); + + this.TextureNormal = grabberTexture; + + if (this.UseTextureSize) + this.Size = grabberTexture.GetSize(); + } + + public void UpdatePosition() { + // if (owner == null) + // return; + + float position = owner.GetHandleTravel() * owner.GetScrollRatio(); + + this.owner.SetHandlePosition(position); + } + + public override void _Input(InputEvent @event) { + if (@event is InputEventMouseButton mouseButton) { + if (mouseButton.ButtonIndex == MouseButton.Left && !mouseButton.Pressed) { + StopDrag(); + } + } + + if (@event is InputEventMouseMotion && this.dragging) + Drag(); + } + + private void StartDrag() { + if (!this.owner.Step) { + this.savedStep = owner.targetScrollBar.Step; + this.owner.targetScrollBar.Step = 0; + } + + this.dragging = true; + } + + private void StopDrag() { + if (!this.owner.Step) { + this.owner.targetScrollBar.Step = this.savedStep; + } + this.dragging = false; + } + + private void Drag() { + Vector2 mouse = GetParent().GetGlobalMousePosition(); + + float position; + + if (this.owner.Direction == ScrollDirection.Vertical) + position = mouse.Y - this.owner.ScrollBar.GlobalPosition.Y - this.owner.topPadding; + else + position = mouse.X - this.owner.ScrollBar.GlobalPosition.X - this.owner.leftPadding; + + position = Mathf.Clamp(position, 0, this.owner.GetHandleTravel()); + + this.owner.SetHandlePosition(position); + this.owner.SetValueFromHandle(position); + } +} diff --git a/C7/UIElements/Civ3ScrollHandle.cs.uid b/C7/UIElements/Civ3ScrollHandle.cs.uid new file mode 100644 index 000000000..e84a9592b --- /dev/null +++ b/C7/UIElements/Civ3ScrollHandle.cs.uid @@ -0,0 +1 @@ +uid://be03jafarm1i8 diff --git a/C7/UIElements/Civ3VScrollBar.cs b/C7/UIElements/Civ3VScrollBar.cs new file mode 100644 index 000000000..9cdeccc9c --- /dev/null +++ b/C7/UIElements/Civ3VScrollBar.cs @@ -0,0 +1,17 @@ +using Godot; + +namespace C7.UIElements; + +[GlobalClass] +[Tool] +public partial class Civ3VScrollBar : VScrollBar, ICiv3Range { + public Civ3RangeTheme rangeTheme { get; init; } + + public Civ3VScrollBar() { + this.rangeTheme = new Civ3RangeTheme(this); + } + + public override void _Notification(int what) { + this.rangeTheme.ClearAndRestoreOverrides(what); + } +} diff --git a/C7/UIElements/Civ3VScrollBar.cs.uid b/C7/UIElements/Civ3VScrollBar.cs.uid new file mode 100644 index 000000000..e0bc6b609 --- /dev/null +++ b/C7/UIElements/Civ3VScrollBar.cs.uid @@ -0,0 +1 @@ +uid://cmr1nj4edk0qc