forgot to push for a while, got drag-and-drop mostly working

This commit is contained in:
2024-04-19 01:31:01 -05:00
parent 978690c2c2
commit 885bc5ad6e
25 changed files with 1320 additions and 1 deletions

18
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,18 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Play",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${env:GODOT4}",
"args": [],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
}
]
}

22
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build"
],
"problemMatcher": "$msCompile",
"presentation": {
"echo": true,
"reveal": "silent",
"focus": false,
"panel": "shared",
"showReuseMessage": true,
"clear": false
}
}
]
}

16
ContextMenu.cs Normal file
View File

@@ -0,0 +1,16 @@
using Godot;
using System;
public partial class ContextMenu : PopupMenu
{
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
}

22
ContextMenu.tscn Normal file
View File

@@ -0,0 +1,22 @@
[gd_scene load_steps=2 format=3 uid="uid://d4hfi3b6ysauo"]
[sub_resource type="CSharpScript" id="CSharpScript_u6vwj"]
script/source = "using Godot;
using System;
public partial class ContextMenu : PopupMenu
{
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
}
"
[node name="ContextMenu" type="PopupMenu"]
script = SubResource("CSharpScript_u6vwj")

41
ContextMeuItem.cs Normal file
View File

@@ -0,0 +1,41 @@
using Godot;
using System;
public partial class ContextMeuItem : Panel
{
[Export]
private string _ItemText;
public string ItemText
{
get => _ItemText;
set
{
_ItemText = value;
if (IsNodeReady())
PropogateText();
}
}
private void PropogateText()
{
GetNode<Label>("%ContextMenuItemLabel").Text = _ItemText;
}
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
GuiInput += HandleClick;
PropogateText();
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public void HandleClick(InputEvent @event)
{
// if (@event is InputEventMouseButton iemb)
// {
// if (iemb.ButtonIndex == MouseButton.Left && !iemb.Pressed)
// }
}
}

10
ContextMeuItem.tscn Normal file
View File

@@ -0,0 +1,10 @@
[gd_scene load_steps=2 format=3 uid="uid://b0ad6gmyog73u"]
[ext_resource type="Script" path="res://ContextMeuItem.cs" id="1_4p8yh"]
[node name="ContextMenuItem" type="Button"]
anchors_preset = 10
anchor_right = 1.0
offset_bottom = 8.0
grow_horizontal = 2
script = ExtResource("1_4p8yh")

89
Extensions.cs Normal file
View File

@@ -0,0 +1,89 @@
using System.Collections.Generic;
using System.Linq;
using Godot;
public static class ExtensionHelper
{
// public static Card GetCardWithId(this SceneTree tree, string id)
// {
// const string CardGroup = "Card";
// var cards = tree.GetNodesInGroup(CardGroup);
// foreach (var card in cards)
// {
// if (card is Card c)
// {
// if (c.Id == id)
// return c;
// }
// else
// throw new System.Exception($"Node in group {CardGroup} is not of type {nameof(Card)}");
// }
// return null;
// }
// public static Row GetRowWithId(this SceneTree tree, string id)
// {
// const string RowGroup = "Card";
// var rows = tree.GetNodesInGroup(RowGroup);
// foreach (var row in rows)
// {
// if (row is Row r)
// {
// if (r.Id == id)
// return r;
// }
// else
// throw new System.Exception($"Node in group {RowGroup} is not of type {nameof(Row)}");
// }
// return null;
// }
public static IEnumerable<Node> GetAllDescendents(this Node node, bool includeInternal = false)
{
foreach (Node n in node.GetChildren(includeInternal))
{
yield return n;
foreach (Node c in n.GetAllDescendents())
yield return c;
}
}
// gets all descendents of a given type (in undefined order)
public static IEnumerable<T> GetAllDescendents<T>(this Node node,
bool includeInternal = false)
{
foreach (var n in node.GetAllDescendents(includeInternal))
if (n is T t)
yield return t;
}
public static string GetUnusedRowId(this SceneTree tree)
{
var ids = tree.GetNodesInGroup("RowGroup").OfType<row>().Select(r => r.RowId).ToArray();
int i = 1;
while (true)
{
if (!ids.Contains(i.ToString()))
return i.ToString();
i++;
}
}
public static string GetUnusedCardId(this SceneTree tree)
{
//use hashset because there are (probably) more cards than rows
var ids = tree.GetNodesInGroup("CardGroup").OfType<card>().Select(c => c.CardId).ToHashSet();
int i = 1;
while (true)
{
if (!ids.Contains(i.ToString()))
return i.ToString();
i++;
}
}
public static TNode GetParentOfType<TNode>(this Node node) where TNode : Node
{
var par = node.GetParent();
if (par is null)
return null;
else if (par is TNode as_tnode)
return as_tnode;
else
return par.GetParentOfType<TNode>();
}
}

23
InputSingleton.cs Normal file
View File

@@ -0,0 +1,23 @@
using Godot;
public class InputSingleton
{
private static InputSingleton _SingletonCache;
public static InputSingleton Instance
{
get
{
_SingletonCache ??= new();
return _SingletonCache;
}
}
private InputSingleton()
{
}
public Node ClickedOn { get; set; }
private void HandleMouseRelease()
{
}
}

34
PictureDropHandler.cs Normal file
View File

@@ -0,0 +1,34 @@
using Godot;
using System;
using System.Collections;
using System.Collections.Generic;
public partial class PictureDropHandler : Control
{
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
GetTree().Root.FilesDropped += HandleDroppedFiles;
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public void HandleDroppedFiles(IEnumerable<string> paths)
{
//var cont = GetNode<HFlowContainer>("%UnassignedCardContainer");
var g = GetNode<game>("/root/Game");
foreach (var path in paths)
{
var img = new Image();
img.Load(path);
var tex = ImageTexture.CreateFromImage(img);
if (tex is null)
continue;
var c = card.MakeCard(GetTree());
c.SetImage(tex);
g.AddUnassignedCard(c);
}
}
}

23
RowCardContainer.cs Normal file
View File

@@ -0,0 +1,23 @@
using Godot;
using System;
public partial class RowCardContainer : HFlowContainer
{
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public override bool _CanDropData(Vector2 atPosition, Variant data)
{
return data.As<card>() is not null;
}
public override void _DropData(Vector2 atPosition, Variant data)
{
this.GetParentOfType<row>().DropOn(atPosition, data);
}
}

61
RowGrid.cs Normal file
View File

@@ -0,0 +1,61 @@
using Godot;
using System;
public partial class RowGrid : PanelContainer
{
protected Vector2 _CardSize;
public Vector2 CardSize
{
get => CardSize;
set
{
_CardSize = value;
UpdateCardSize();
}
}
protected Color _RowColor;
public Color RowColor
{
get => _RowColor;
set
{
_RowColor = value;
UpdateRowColor();
}
}
protected void UpdateCardSize()
{
foreach (var c in this.GetAllDescendents<card>())
c.CustomMinimumSize = _CardSize;
}
public const float RowBackgroundColorScale = 2;
private static Color ScaleColor(Color color)
{
return new Color
{
R = 1 - (1 - color.R) / RowBackgroundColorScale,
G = 1 - (1 - color.G) / RowBackgroundColorScale,
B = 1 - (1 - color.B) / RowBackgroundColorScale,
A = color.A,
};
}
protected void UpdateRowColor()
{
var sbf = GetThemeStylebox("panel").Duplicate() as StyleBoxFlat;
sbf.BgColor = ScaleColor(_RowColor);
AddThemeStyleboxOverride("panel", sbf);
sbf = GetNode<Panel>("%RowTitleBoxBackground").GetThemeStylebox("panel").Duplicate() as StyleBoxFlat;
sbf.BgColor = _RowColor;
GetNode<Panel>("%RowTitleBoxBackground").AddThemeStyleboxOverride("panel", sbf);
}
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 B

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cx356vif8tsrc"
path="res://.godot/imported/SingleWhitePixel.png-24ae9a98b3e2a24518720903e0c57636.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://Sprites/SingleWhitePixel.png"
dest_files=["res://.godot/imported/SingleWhitePixel.png-24ae9a98b3e2a24518720903e0c57636.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

8
TierMakerControl.csproj Normal file
View File

@@ -0,0 +1,8 @@
<Project Sdk="Godot.NET.Sdk/4.2.1">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net7.0</TargetFramework>
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
<EnableDynamicLoading>true</EnableDynamicLoading>
</PropertyGroup>
</Project>

19
TierMakerControl.sln Normal file
View File

@@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TierMakerControl", "TierMakerControl.csproj", "{1F95EF81-46A9-4A59-8CA0-BD90825EBB84}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
ExportDebug|Any CPU = ExportDebug|Any CPU
ExportRelease|Any CPU = ExportRelease|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1F95EF81-46A9-4A59-8CA0-BD90825EBB84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1F95EF81-46A9-4A59-8CA0-BD90825EBB84}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1F95EF81-46A9-4A59-8CA0-BD90825EBB84}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU
{1F95EF81-46A9-4A59-8CA0-BD90825EBB84}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU
{1F95EF81-46A9-4A59-8CA0-BD90825EBB84}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU
{1F95EF81-46A9-4A59-8CA0-BD90825EBB84}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU
EndGlobalSection
EndGlobal

32
UnassignedCardPanel.cs Normal file
View File

@@ -0,0 +1,32 @@
using Godot;
using System;
public partial class UnassignedCardPanel : PanelContainer
{
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public override bool _CanDropData(Vector2 atPosition, Variant data)
{
return data.As<card>() is not null;
}
public override void _DropData(Vector2 atPosition, Variant data)
{
card c = data.As<card>()
?? throw new Exception("invalid drag data");
var g = this.GetParentOfType<game>()
?? throw new Exception("game instance not found");
if (g.ClaimCard(c.CardId) is card _c)
{
if (!ReferenceEquals(c, _c))
throw new Exception($"card move mismatch");
GetNode<HFlowContainer>("%UnassignedCardContainer").AddChild(c);
}
}
}

127
card.cs Normal file
View File

@@ -0,0 +1,127 @@
using Godot;
using System;
public partial class card : Control
{
[Export]
private string _CardName;
public string CardName
{
get => _CardName;
set
{
_CardName = value;
if (IsNodeReady())
PropogateCardName();
}
}
private void PropogateCardName()
{
GetNode<Label>("CardNameLabel").Text = _CardName;
}
[Export]
private string _CardId;
public string CardId
{
get => _CardId;
set
{
_CardId = value;
if (IsNodeReady())
PropogateCardId();
}
}
private void PropogateCardId()
{
GetNode<Label>("%CardIdLabel").Text = _CardId;
}
private Texture2D _Texture;
public void SetTexture(Texture2D texture)
{
_Texture = texture;
if (IsNodeReady())
PropogateTexture();
}
private void PropogateTexture()
{
if (_Texture is not null)
{
GetNode<TextureRect>("%CardImage").Texture = _Texture;
_Texture = null;
}
}
public Texture2D GetTexture()
=> GetNode<TextureRect>("%CardImage").Texture;
public Vector2 Center
=> Size / 2;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
PropogateCardName();
PropogateCardId();
PropogateTexture();
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public override Variant _GetDragData(Vector2 atPosition)
{
GD.Print($"starting to drag {CardId}");
var prev = card_preview.MakePreview(this);
var prev_root = new Control();
//prev.Position = atPosition;
prev.Position = prev.Size / -2;
prev_root.AddChild(prev);
SetDragPreview(prev_root);
return this;
}
public void SetImage(Texture2D texture)
{
Ready += () => InnerSetImage(texture);
if (IsNodeReady())
InnerSetImage(texture);
}
//only called while ready
private void InnerSetImage(Texture2D texture)
{
var node = GetNode<TextureRect>("%CardImage");
node.Texture = texture;
}
// private void HandleInput(InputEvent @event)
// {
// if (@event is InputEventMouseButton iemb)
// {
// if (iemb.ButtonIndex == MouseButton.Left)
// {
// if (iemb.Pressed)
// {
// InputSingleton.Instance.ClickedOn = this;
// StartDrag();
// }
// else
// {
// InputSingleton.Instance.ClickedOn = null;
// StopDrag();
// }
// }
// }
// }
// private void StartDrag()
// {
// }
// private void StopDrag()
// {
// }
public static card MakeCard(SceneTree tree)
{
var scene = GD.Load<PackedScene>("res://card.tscn");
var c = scene.Instantiate<card>();
c.CardId = tree.GetUnusedCardId();
return c;
}
}

69
card.tscn Normal file
View File

@@ -0,0 +1,69 @@
[gd_scene load_steps=5 format=3 uid="uid://wpe6vmdco84g"]
[ext_resource type="Script" path="res://card.cs" id="1_dysu7"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ndhi0"]
bg_color = Color(1, 1, 1, 1)
[sub_resource type="LabelSettings" id="LabelSettings_ui6ue"]
outline_size = 2
outline_color = Color(0, 0, 0, 1)
[sub_resource type="LabelSettings" id="LabelSettings_gncft"]
outline_size = 2
outline_color = Color(0, 0, 0, 1)
[node name="Card" type="Control" groups=["CardGroup"]]
custom_minimum_size = Vector2(200, 200)
layout_mode = 3
anchors_preset = 0
offset_right = 200.0
offset_bottom = 200.0
mouse_filter = 1
script = ExtResource("1_dysu7")
[node name="CardBackground" type="Panel" parent="."]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 1
theme_override_styles/panel = SubResource("StyleBoxFlat_ndhi0")
[node name="CardImage" type="TextureRect" parent="CardBackground"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
expand_mode = 1
stretch_mode = 5
[node name="CardNameLabel" type="Label" parent="."]
unique_name_in_owner = true
z_index = 1
layout_mode = 0
offset_right = 40.0
offset_bottom = 23.0
mouse_filter = 1
text = "Name"
label_settings = SubResource("LabelSettings_ui6ue")
[node name="CardIdLabel" type="Label" parent="."]
unique_name_in_owner = true
z_index = 1
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_top = -23.0
offset_right = 40.0
grow_vertical = 0
mouse_filter = 1
text = "ID"
label_settings = SubResource("LabelSettings_gncft")

92
card_preview.cs Normal file
View File

@@ -0,0 +1,92 @@
using Godot;
using System;
public partial class card_preview : Control
{
[Export]
private string _CardName;
public string CardName
{
get => _CardName;
set
{
_CardName = value;
if (IsNodeReady())
PropogateCardName();
}
}
private void PropogateCardName()
{
GetNode<Label>("%CardPreviewNameLabel").Text = _CardName;
}
[Export]
private string _CardId;
public string CardId
{
get => _CardId;
set
{
_CardId = value;
if (IsNodeReady())
PropogateCardId();
}
}
private void PropogateCardId()
{
GetNode<Label>("%CardPreviewIdLabel").Text = _CardId;
}
private Texture2D _Texture;
public void SetTexture(Texture2D texture)
{
_Texture = texture;
if (IsNodeReady())
PropogateTexture();
}
private void PropogateTexture()
{
if (_Texture is not null)
{
GetNode<TextureRect>("%CardPreviewImage").Texture = _Texture;
_Texture = null;
}
}
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
PropogateCardId();
PropogateCardName();
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public void SetImage(Texture2D texture)
{
Ready += () => InnerSetImage(texture);
if (IsNodeReady())
InnerSetImage(texture);
}
//only called while ready
private void InnerSetImage(Texture2D texture)
{
var node = GetNode<TextureRect>("%CardPreviewImage");
node.Texture = texture;
}
public static card_preview MakePreview(card c)
{
const float TRANSPARENCY = 0.25f;
var scene = GD.Load<PackedScene>("res://card_preview.tscn");
var prev = scene.Instantiate() as card_preview;
prev.CardName = c.CardName;
prev.CardId = c.CardId;
prev.SetTexture(c.GetTexture());
prev.Size = c.Size;
prev.Scale = c.Scale;
prev.Modulate = new(1, 1, 1, TRANSPARENCY);
return prev;
// var preview = new Control();
// preview.AddChild(prev);
// prev.Position = prev.Size * -0.5f;
}
}

63
card_preview.tscn Normal file
View File

@@ -0,0 +1,63 @@
[gd_scene load_steps=5 format=3 uid="uid://dh6xfgsoquxdc"]
[ext_resource type="Script" path="res://card_preview.cs" id="1_o00ln"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ndhi0"]
bg_color = Color(1, 1, 1, 1)
[sub_resource type="LabelSettings" id="LabelSettings_ui6ue"]
outline_size = 2
outline_color = Color(0, 0, 0, 1)
[sub_resource type="LabelSettings" id="LabelSettings_gncft"]
outline_size = 2
outline_color = Color(0, 0, 0, 1)
[node name="CardPreview" type="Control" groups=["CardGroup"]]
custom_minimum_size = Vector2(200, 200)
layout_mode = 3
anchors_preset = 0
offset_right = 200.0
offset_bottom = 200.0
script = ExtResource("1_o00ln")
[node name="CardPreviewBackground" type="Panel" parent="."]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_ndhi0")
[node name="CardPreviewImage" type="TextureRect" parent="CardPreviewBackground"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
expand_mode = 1
stretch_mode = 5
[node name="CardPreviewNameLabel" type="Label" parent="."]
unique_name_in_owner = true
layout_mode = 0
offset_right = 40.0
offset_bottom = 23.0
text = "Name"
label_settings = SubResource("LabelSettings_ui6ue")
[node name="CardPreviewIdLabel" type="Label" parent="."]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
offset_top = -23.0
offset_right = 40.0
grow_vertical = 0
text = "ID"
label_settings = SubResource("LabelSettings_gncft")

169
game.cs Normal file
View File

@@ -0,0 +1,169 @@
using Godot;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public partial class game : Control
{
[Export]
private Vector2 _CardSize = new(200, 200);
public Vector2 CardSize
{
get => _CardSize;
set
{
_CardSize = value;
if (IsNodeReady())
PropogateCardSize();
}
}
protected void PropogateCardSize()
{
foreach (var r in GetNode("%RowContainer").GetChildren().OfType<row>())
r.CardSize = _CardSize;
foreach (var c in GetNode("%UnassignedCardContainer").GetChildren().OfType<card>())
c.CustomMinimumSize = _CardSize;
SetContainerMinima();
}
public IEnumerable<row> Rows
=> GetNode<VBoxContainer>("%RowContainer").GetChildren().OfType<row>();
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
var rows = this.GetAllDescendents<row>().ToArray();
for (int i = 0; i < 50; i++)
{
var c = card.MakeCard(GetTree());
GD.Print(c.CardId);
c.CardName = $"Card {i}";
if (GD.RandRange(0, 1) == 1)
{
//add to a row
var r = rows[GD.RandRange(0, rows.Length - 1)];
r.AddCard(c);
}
else
{
AddUnassignedCard(c);
}
}
PropogateCardSize();
}
// public override void _UnhandledInput(InputEvent @event)
// {
// if (@event is InputEventMouseButton iemb)
// {
// if (iemb.ButtonIndex == MouseButton.Right)
// {
// }
// }
// else if (@event is InputEventKey iek)
// {
// }
// }
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public void SetContainerMinima()
{
var node = GetNode<VBoxContainer>("%RowContainer");
node.CustomMinimumSize = new Vector2(0, _CardSize.Y * node.GetChildCount());
}
public row GetRowById(string id)
=> GetTree().GetNodesInGroup("RowGroup").OfType<row>().FirstOrDefault(r => r.RowId == id);
public void AddRow(row row, string after = null)
{
if (after is not null)
{
var r = GetRowById(after) ?? throw new Exception("row id does not exist");
r.AddSibling(row);
}
else
{
var node = GetNode<VBoxContainer>("%RowContainer");
node.AddChild(row);
node.MoveChild(row, 0);
}
SetContainerMinima();
}
public void RemoveRow(string id)
{
var r = GetRowById(id);
GetNode<VBoxContainer>("%RowContainer").RemoveChild(r);
SetContainerMinima();
}
public void AddUnassignedCard(card c)
{
c.CustomMinimumSize = _CardSize;
var node = GetNode<HFlowContainer>("%UnassignedCardContainer");
node.AddChild(c);
}
public card RemoveUnassignedCard(string id)
{
var node = GetNode<HFlowContainer>("%UnassignedCardContainer");
var c = node.GetAllDescendents<card>().FirstOrDefault(x => x.CardId == id);
if (c is not null)
{
node.RemoveChild(c);
}
return c;
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <param name="target_row">null to unassign card</param>
/// <returns>false if something goes wrong</returns>
// public bool MoveCard(string id, row target_row, float horizontal)
// {
// foreach (row r in Rows)
// {
// if (r.TryRemoveCard(id) is card c)
// {
// //add to row
// if (target_row is not null)
// {
// target_row.AddCard(c);
// return true;
// }
// //unassign
// else
// {
// AddUnassignedCard(c);
// return true;
// }
// }
// }
// if (RemoveUnassignedCard(id) is card cc)
// {
// //add to row
// if (target_row is not null)
// {
// target_row.AddCard(cc);
// return true;
// }
// //unassign
// else
// {
// AddUnassignedCard(cc);
// return true;
// }
// }
// return false;
// }
public card ClaimCard(string id)
{
foreach (row r in Rows)
{
if (r.TryRemoveCard(id) is card c)
return c;
}
return RemoveUnassignedCard(id);
}
}

92
game.tscn Normal file
View File

@@ -0,0 +1,92 @@
[gd_scene load_steps=6 format=3 uid="uid://ck0t4k3guvmfm"]
[ext_resource type="PackedScene" uid="uid://b7pebyti48f7b" path="res://row.tscn" id="1_numg7"]
[ext_resource type="Script" path="res://game.cs" id="1_vl33u"]
[ext_resource type="Script" path="res://UnassignedCardPanel.cs" id="3_dbs2t"]
[ext_resource type="Script" path="res://PictureDropHandler.cs" id="3_owd27"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_yj5pd"]
bg_color = Color(0.788235, 0.788235, 0.788235, 1)
[node name="Game" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_vertical = 3
script = ExtResource("1_vl33u")
_CardSize = Vector2(150, 150)
[node name="GameContainer" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
[node name="RowContainer" type="VBoxContainer" parent="GameContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
[node name="Row_A" parent="GameContainer/RowContainer" instance=ExtResource("1_numg7")]
layout_mode = 2
_RowColor = Color(0.964706, 0.482353, 0.494118, 1)
_RowText = "A"
RowId = "1"
[node name="Row_B" parent="GameContainer/RowContainer" instance=ExtResource("1_numg7")]
layout_mode = 2
_RowColor = Color(0.996078, 0.878431, 0.541176, 1)
_RowText = "B"
RowId = "2"
[node name="Row_C" parent="GameContainer/RowContainer" instance=ExtResource("1_numg7")]
layout_mode = 2
_RowColor = Color(0.988235, 1, 0.494118, 1)
_RowText = "C"
RowId = "3"
[node name="Row_D" parent="GameContainer/RowContainer" instance=ExtResource("1_numg7")]
layout_mode = 2
_RowColor = Color(0.639216, 0.937255, 0.34902, 1)
_RowText = "D"
RowId = "4"
[node name="Row_F" parent="GameContainer/RowContainer" instance=ExtResource("1_numg7")]
layout_mode = 2
_RowColor = Color(0.298039, 0.87451, 0.952941, 1)
_RowText = "F"
RowId = "5"
[node name="UnassignedCardPanel" type="PanelContainer" parent="GameContainer"]
layout_mode = 2
size_flags_vertical = 3
theme_override_styles/panel = SubResource("StyleBoxFlat_yj5pd")
script = ExtResource("3_dbs2t")
[node name="UnassignedCardContainer" type="HFlowContainer" parent="GameContainer/UnassignedCardPanel"]
unique_name_in_owner = true
layout_mode = 2
[node name="PictureDropHandler" type="Control" parent="."]
unique_name_in_owner = true
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("3_owd27")
[node name="CardContextMenu" type="PopupMenu" parent="."]
item_count = 2
item_0/text = "Rename"
item_0/id = 0
item_1/text = "Change Picture"
item_1/id = 1
[node name="RowContextMenu" type="PopupMenu" parent="."]
item_count = 1
item_0/text = ""
item_0/id = 0

View File

@@ -11,7 +11,8 @@ config_version=5
[application]
config/name="TierMakerControl"
config/features=PackedStringArray("4.2", "Forward Plus")
run/main_scene="res://game.tscn"
config/features=PackedStringArray("4.2", "C#", "Forward Plus")
config/icon="res://icon.svg"
[dotnet]

163
row.cs Normal file
View File

@@ -0,0 +1,163 @@
using Godot;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public partial class row : Control
{
[Export]
private Color _RowColor;
public Color RowColor
{
get => _RowColor;
set
{
_RowColor = value;
if (IsNodeReady())
PropogateColor();
}
}
[Export]
private Vector2 _CardSize;
public Vector2 CardSize
{
get => _CardSize;
set
{
_CardSize = value;
if (IsNodeReady())
PropogateCardSize();
}
}
[Export]
private string _RowText;
public string RowText
{
get => _RowText;
set
{
_RowText = value;
if (IsNodeReady())
PropogateRowText();
}
}
private string _RowId;
[Export]
public string RowId
{
get => _RowId;
set
{
_RowId = value;
if (IsNodeReady())
PropogateRowId();
}
}
public IEnumerable<card> Cards
=> GetNode("%RowCardContainer").GetChildren().OfType<card>();
private void PropogateColor()
{
GetNode<RowGrid>("%RowGrid").RowColor = _RowColor;
}
private void PropogateCardSize()
{
//CustomMinimumSize = new Vector2(0, _CardSize.Y);
GetNode<RowGrid>("%RowGrid").CardSize = _CardSize;
GetNode<Panel>("%RowTitleBoxBackground").CustomMinimumSize = _CardSize;
}
private void PropogateRowText()
{
GetNode<Label>("%RowTitleBoxLabel").Text = _RowText;
}
private void PropogateRowId()
{
GetNode<Label>("%RowTitleBoxIdLabel").Text = _RowId;
}
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
if (false)
{
RowColor = new Color
{
R = 1,
G = 0,
B = 0,
A = 1,
};
var scene = GD.Load<PackedScene>("res://card.tscn");
var card = scene.Instantiate<card>();
//GD.Print(card);
card.CardId = "new id";
card.CardName = "new name";
AddCard(card);
}
//needs to wait until ready first
PropogateColor();
PropogateCardSize();
PropogateRowText();
PropogateRowId();
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public void DropOn(Vector2 atPosition, Variant data)
{
GD.Print($"Dropping at {atPosition}");
card c = data.As<card>()
?? throw new Exception("invalid drag data");
var g = this.GetParentOfType<game>()
?? throw new Exception("game instance not found");
// if (!g.MoveCard(c.CardId, this, atPosition.X))
// throw new Exception("failed to move card");
if (g.ClaimCard(c.CardId) is card _c)
{
if (!ReferenceEquals(c, _c))
throw new Exception("card move mismatch");
//cards sorted with index
foreach (var pair in Cards.Select((c, i) => (c.Position.X, i)))
{
if (atPosition.X >= (pair.X - c.Size.X / 2) && atPosition.X <= (pair.X + c.Size.X / 2))
{
GetNode("%RowCardContainer").AddChild(c);
GetNode("%RowCardContainer").MoveChild(c, pair.i);
return;
}
}
GetNode("%RowCardContainer").AddChild(c);
return;
}
else
{
throw new Exception($"Can't find card {c.CardId}");
}
}
public void AddCard(card card)
{
GetNode("%RowCardContainer").AddChild(card);
}
public card GetCard(string id)
{
//inefficient to iterate through all children
return GetNode("%RowCardContainer").GetChildren().OfType<card>().FirstOrDefault(c => c.CardId == id);
}
public card TryRemoveCard(string id)
{
var c = GetCard(id);
if (c is not null)
{
GetNode("%RowCardContainer").RemoveChild(c);
}
return c;
}
public static row MakeRow(SceneTree tree)
{
var scene = GD.Load<PackedScene>("res://row.tscn");
var r = scene.Instantiate<row>();
r.RowId = tree.GetUnusedRowId();
return r;
}
}

91
row.tscn Normal file
View File

@@ -0,0 +1,91 @@
[gd_scene load_steps=8 format=3 uid="uid://b7pebyti48f7b"]
[ext_resource type="Script" path="res://row.cs" id="1_dodxa"]
[ext_resource type="Script" path="res://RowGrid.cs" id="2_h4wwk"]
[ext_resource type="Script" path="res://RowCardContainer.cs" id="3_0etg2"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_spa1m"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_22f0d"]
bg_color = Color(0.839216, 0.839216, 0.839216, 1)
[sub_resource type="LabelSettings" id="LabelSettings_p0x7q"]
font_size = 18
outline_size = 2
outline_color = Color(0, 0, 0, 1)
[sub_resource type="LabelSettings" id="LabelSettings_7hvr3"]
outline_size = 2
outline_color = Color(0, 0, 0, 1)
[node name="Row" type="MarginContainer" groups=["RowGroup"]]
anchors_preset = 10
anchor_right = 1.0
grow_horizontal = 2
size_flags_vertical = 2
script = ExtResource("1_dodxa")
[node name="RowGrid" type="PanelContainer" parent="."]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_spa1m")
script = ExtResource("2_h4wwk")
[node name="RowBaseContainer" type="HSplitContainer" parent="RowGrid"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
dragger_visibility = 2
[node name="RowTitleBoxBackground" type="Panel" parent="RowGrid/RowBaseContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 0
size_flags_vertical = 0
mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_22f0d")
[node name="RowTitleBoxLabel" type="Label" parent="RowGrid/RowBaseContainer/RowTitleBoxBackground"]
unique_name_in_owner = true
z_index = 1
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -42.0
offset_top = -13.0
offset_right = 42.0
offset_bottom = 13.0
grow_horizontal = 2
grow_vertical = 2
text = "RowLabel"
label_settings = SubResource("LabelSettings_p0x7q")
horizontal_alignment = 1
vertical_alignment = 1
autowrap_mode = 2
justification_flags = 161
[node name="RowTitleBoxIdLabel" type="Label" parent="RowGrid/RowBaseContainer/RowTitleBoxBackground"]
unique_name_in_owner = true
z_index = 1
layout_mode = 1
anchors_preset = 12
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -24.0
offset_top = -23.0
offset_right = 24.0
grow_horizontal = 2
grow_vertical = 0
text = "RowId"
label_settings = SubResource("LabelSettings_7hvr3")
[node name="RowCardContainer" type="HFlowContainer" parent="RowGrid/RowBaseContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
script = ExtResource("3_0etg2")