Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent mouse interactions with map and other UI elements when popup is open #447

Merged
merged 3 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion C7/C7Game.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ anchors_preset = 11
anchor_left = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -108.0
offset_top = 80.0
offset_right = -108.0
offset_bottom = -170.0
Expand Down
6 changes: 3 additions & 3 deletions C7/Credits.tscn
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=2]
[gd_scene load_steps=2 format=3 uid="uid://pfefjvwiljdp"]

[ext_resource path="res://Credits.cs" type="Script" id=1]
[ext_resource type="Script" path="res://Credits.cs" id="1"]

[node name="Node2D" type="Node2D"]
script = ExtResource( 1 )
script = ExtResource("1")
6 changes: 3 additions & 3 deletions C7/GlobalSingleton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
using QueryCiv3;

/****
Need to pass values from one scene to another, particularly when loading
a game in main menu. This script is set to auto load in project settings.
See https://docs.godotengine.org/en/stable/getting_started/step_by_step/singletons_autoload.html
Need to pass values from one scene to another, particularly when loading
a game in main menu. This script is set to auto load in project settings.
See https://docs.godotengine.org/en/stable/getting_started/step_by_step/singletons_autoload.html
****/
public partial class GlobalSingleton : Node {
// Will have main menu file picker set this and Game.cs pass it to C7Engine.createGame
Expand Down
2 changes: 1 addition & 1 deletion C7/UIElements/GameStatus/LowerRightInfoBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public partial class LowerRightInfoBox : TextureRect
Label yearAndGold = new Label();

Timer blinkingTimer = new Timer();
Boolean timerStarted = false; //This "isStopped" returns false if it's never been started. So we need this to know if we've ever started it.
bool timerStarted = false; //This "isStopped" returns false if it's never been started. So we need this to know if we've ever started it.

// Called when the node enters the scene tree for the first time.
public override void _Ready()
Expand Down
52 changes: 41 additions & 11 deletions C7/UIElements/Popups/PopupOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public partial class PopupOverlay : HBoxContainer

public static readonly string NodePath = "/root/C7Game/CanvasLayer/PopupOverlay";

private static readonly string ControlNodePath = "/root/C7Game/CanvasLayer/Control";

public enum PopupCategory {
Advisor,
Console,
Expand All @@ -23,9 +25,18 @@ public enum PopupCategory {

public void OnHidePopup()
{
// 1. enable mouse interaction with non-UI nodes
MouseFilter = MouseFilterEnum.Pass;
RemoveChild(currentChild);
currentChild = null;
Hide();

Control control = getControlNode();
// 2. enable mouse interactions with other UI elements
setMouseFilter(control, MouseFilterEnum.Pass);

// 3. enable clicking other UI elements
control.ProcessMode = ProcessModeEnum.Inherit;
}

public bool ShowingPopup => currentChild is not null;
Expand All @@ -37,6 +48,19 @@ public void PlaySound(AudioStreamWav wav)
player.Play();
}

private Control getControlNode() {
return GetNode<Control>(ControlNodePath);
}

private void setMouseFilter(Node n, MouseFilterEnum filter) {
foreach (Node child in n?.GetChildren()) {
setMouseFilter(child, filter);
}
if (n is Control control) {
control.MouseFilter = filter;
}
}

public void ShowPopup(Popup child, PopupCategory category)
{
if (child is null) {
Expand Down Expand Up @@ -64,6 +88,18 @@ public void ShowPopup(Popup child, PopupCategory category)
log.Error("Invalid popup category");
}
AudioStreamWav wav = Util.LoadWAVFromDisk(Util.Civ3MediaPath(soundFile));

// 1. prevent mouse interaction with non-UI elements (ie. the map)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Long term, need to learn how to use Godot UI properly. Couldn't find a more idiomatic solution on line for this particular problem though.

Short term, I plan to decouple UI from game logic as much as possible. This is kinda a prerequisite for decoupling game from server so that someday we could implement multiplayer.

MouseFilter = MouseFilterEnum.Stop;

Control control = getControlNode();

// 2. prevent clicking other UI elements
control.ProcessMode = ProcessModeEnum.Disabled;

// 3. ignore all mouse input on other UI elements (ie. button color changes on hover)
setMouseFilter(control, MouseFilterEnum.Ignore);

Show();
PlaySound(wav);
}
Expand All @@ -77,17 +113,11 @@ public void ShowPopup(Popup child, PopupCategory category)
**/
public override void _UnhandledInput(InputEvent @event)
{
if (this.Visible) {
if (@event is InputEventKey eventKey)
{
//As I've added more shortcuts, I've realized checking all of them here could be irksome.
//For now, I'm thinking it would make more sense to process or allow through the ones that should go through,
//as most of the global ones should *not* go through here.
if (eventKey.Pressed)
{
GetViewport().SetInputAsHandled();
}
}
if (Visible && @event is InputEventKey eventKey && eventKey.Pressed) {
// As I've added more shortcuts, I've realized checking all of them here could be irksome.
// For now, I'm thinking it would make more sense to process or allow through the ones that should go through,
// as most of the global ones should *not* go through here.
GetViewport().SetInputAsHandled();
}
}
}