Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
5 changes: 4 additions & 1 deletion Yafc.Model/Model/Project.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class Project : ModelObject {
public static Version currentYafcVersion { get; set; } = new Version(0, 4, 0);
public uint projectVersion => undo.version;
public string? attachedFileName { get; private set; }

public bool justCreated { get; private set; } = true;
public ProjectSettings settings { get; }
public ProjectPreferences preferences { get; }
Expand Down Expand Up @@ -183,6 +184,7 @@ public void Save(string fileName) {

public void Save(Stream stream) {
using Utf8JsonWriter writer = new Utf8JsonWriter(stream, JsonUtils.DefaultWriterOptions);

SerializationMap<Project>.SerializeToJson(this, writer);
}

Expand Down Expand Up @@ -291,7 +293,8 @@ public class ProjectSettings(Project project) : ModelObject<Project>(project) {
public int reactorSizeX { get; set; } = 2;
public int reactorSizeY { get; set; } = 2;
public float PollutionCostModifier { get; set; } = 0;
public float spoilingRate { get; set; } = 1;
public float spoilingRate { get; set; } = 1;
public bool isPagesListPinned { get; set; }
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should go in ProjectPreferences instead. I haven't added a comment about this yet, but Preferences is for things that don't require the solver to run again, and Settings is for things that do.

Copy link
Owner

Choose a reason for hiding this comment

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

Thank you for catching that.

Preferences is for things that don't require the solver to run again, and Settings is for things that do.

This info should go to the javadoc. I'll make a ticket for that just to not forget.


public event Action<bool>? changed;
protected internal override void ThisChanged(bool visualOnly) => changed?.Invoke(visualOnly);
Expand Down
57 changes: 51 additions & 6 deletions Yafc.UI/Core/Window.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ public abstract class Window : IDisposable {

private Tooltip? tooltip;
private SimpleTooltip? simpleTooltip;
protected DropDownPanel? dropDown;
protected DropDownPanel? commonDropDown;
private SimpleDropDown? simpleDropDown;
protected DropDownPanel? pagesDropDown;
private SimpleDropDown? pagesSimpleDropDown;
Comment on lines +26 to +29
Copy link
Collaborator

Choose a reason for hiding this comment

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

It is not clear to me (by names) what all of these dropdown are (doing).
I know it wasn't very clear before, but since we are touching this, it might be nice to clarify this a little

Copy link
Author

Choose a reason for hiding this comment

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

I haven't checked too much DropDownPanel x SimpleDropDown

I just needed to use separate dropdown for pages search to be able to open for example the dropdown for recipe column and keep the pages search opened - until now just one dropdown could be opened at the same time while reusing the single one shared DropDownPanel and SimpleDropDown

Copy link
Collaborator

Choose a reason for hiding this comment

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

Whatever's going on with commonDropDown vs simpleDropDown is quite tortured. I'd love to see that refactored, but it seems like a lot of work.

I would like to see the two new fields renamed to better explain why we need two fields for one dropdown.

private ImGui.DragOverlay? draggingOverlay;
private bool disposedValue;

public bool PagesSimpleDropPinned => pagesSimpleDropDown?.pinnedMode ?? false;

public DrawingSurface? surface { get; protected set; }

public int displayIndex => SDL.SDL_GetWindowDisplayIndex(window);
Expand Down Expand Up @@ -215,7 +219,7 @@ public void ShowTooltip(ImGui targetGui, Rect target, GuiBuilder builder, float
}

public void ShowDropDown(DropDownPanel dropDown) {
this.dropDown = dropDown;
this.commonDropDown = dropDown;
Rebuild();
}

Expand All @@ -226,16 +230,57 @@ public void ShowDropDown(ImGui targetGui, Rect target, GuiBuilder builder, Paddi
ShowDropDown(simpleDropDown);
}

public void ShowPagesListDropDown(ImGui targetGui, Rect target, GuiBuilder builder, Padding padding, float width = 20f, bool pinned = false) {

if (simpleDropDown?.active == true) {
simpleDropDown.Close();
}

pagesSimpleDropDown ??= new SimpleDropDown();

pagesSimpleDropDown.SetPadding(padding);
pagesSimpleDropDown.SetFocus(targetGui, target, builder, width, pinned);

this.pagesDropDown = pagesSimpleDropDown;
this.
Rebuild();
Comment on lines +245 to +246
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
this.
Rebuild();
this.Rebuild();

No idea if you meant to explicitly wanted/needed to include this, if not please just call Rebuild() instead

}

public bool ClosePagesListDropDown(ImGui targetGui, Rect target) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Function documentation would be appreciated for (new) functions. In this case even more, as it is unclear what the returned bool is suppose to represent.

(Later I figured, it seems to be true when the dropdown was not closed?)

pagesSimpleDropDown ??= new SimpleDropDown();
// If a pinned dropdown is already open for this source/rect and caller asked to open pinned, close it.
if (pagesSimpleDropDown.active && pagesSimpleDropDown.pinnedMode && pagesSimpleDropDown.MatchesSource(targetGui, target)) {
pagesSimpleDropDown.pinnedMode = false;
pagesSimpleDropDown.Close();
// Ensure top-level reference is cleared so Build won't try to render it next frame
if (pagesDropDown == pagesSimpleDropDown) {
pagesDropDown = null;
}
Rebuild();

return true;
}

return false;
}

private void Build(ImGui gui) {
if (closed) {
return;
}

BuildContents(gui);
if (dropDown != null) {
dropDown.Build(gui);
if (!dropDown.active) {
dropDown = null;
if (commonDropDown != null) {
commonDropDown.Build(gui);
if (!commonDropDown.active) {
commonDropDown = null;
}
}

if (pagesDropDown != null) {
pagesDropDown.Build(gui);
if (!pagesDropDown.active) {
pagesDropDown = null;
}
}

Expand Down
19 changes: 18 additions & 1 deletion Yafc.UI/ImGui/DropDownPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@ public void Build(ImGui gui) {
protected abstract Vector2 CalculatePosition(ImGui gui, Rect targetRect, Vector2 contentSize);
protected abstract bool ShouldBuild(ImGui source, Rect sourceRect, ImGui parent, Rect parentRect);
protected abstract void BuildContents(ImGui gui);

// Expose a way to check whether this panel was focused from a given source/rect
public bool MatchesSource(ImGui source, Rect rect) => this.source == source && this.sourceRect.Equals(rect);
}

public abstract class DropDownPanel(Padding padding, float width) : AttachedPanel(padding, width), IMouseFocus {
private bool focused;
private bool pinned;

protected override bool ShouldBuild(ImGui source, Rect sourceRect, ImGui parent, Rect parentRect) => focused;

Expand All @@ -75,9 +79,20 @@ public bool FilterPanel(IPanel? panel) {
}

public void FocusChanged(bool focused) {
// If we're pinned, ignore losing focus so dropdown remains open.
if (!focused && pinned) {
return;
}

this.focused = focused;
contents.parent?.Rebuild();
}

// Allow external code to control pinned state
public bool pinnedMode {
get => pinned;
set => pinned = value;
}
}

public class SimpleDropDown : DropDownPanel {
Expand All @@ -94,9 +109,11 @@ private bool HandleDropdownClosed(ImGuiUtils.CloseDropdownEvent _) {

public void SetPadding(Padding padding) => contents.initialPadding = padding;

public void SetFocus(ImGui source, Rect rect, GuiBuilder builder, float width = 20f) {
// Added pinned parameter
public void SetFocus(ImGui source, Rect rect, GuiBuilder builder, float width = 20f, bool pinned = false) {
this.width = width;
this.builder = builder;
this.pinnedMode = pinned;
base.SetFocus(source, rect);
}

Expand Down
11 changes: 9 additions & 2 deletions Yafc.UI/ImGui/ImGuiUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,13 +198,13 @@ public static ButtonEvent BuildRedButton(this ImGui gui, Icon icon, float size =
}

public static ButtonEvent BuildButton(this ImGui gui, Icon icon, SchemeColor normal = SchemeColor.None,
SchemeColor over = SchemeColor.Grey, SchemeColor down = SchemeColor.None, float size = 1.5f) {
SchemeColor over = SchemeColor.Grey, SchemeColor down = SchemeColor.None, float size = 1.5f, uint button = SDL.SDL_BUTTON_LEFT) {

using (gui.EnterGroup(new Padding(0.3f))) {
gui.BuildIcon(icon, size);
}

return gui.BuildButton(gui.lastRect, normal, over, down);
return gui.BuildButton(gui.lastRect, normal, over, down, button);
}

public static ButtonEvent BuildButton(this ImGui gui, Icon icon, string text, SchemeColor normal = SchemeColor.None,
Expand All @@ -225,6 +225,13 @@ public static bool WithTooltip(this ButtonEvent evt, ImGui gui, string tooltip,

return evt;
}
public static bool WithTooltipConditional(this ButtonEvent evt, bool condition, ImGui gui, string tooltip, Rect? rect = null) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

@shpaass Same as in #529 I guess, we need to make sure we are not duplicating this function when merged both PRs

if (evt == ButtonEvent.MouseOver && condition) {
gui.ShowTooltip(rect ?? gui.lastRect, tooltip);
}

return evt;
}

public static bool BuildCheckBox(this ImGui gui, string text, bool value, out bool newValue, SchemeColor color = SchemeColor.None,
RectAllocator allocator = RectAllocator.LeftRow, string? tooltip = null) {
Expand Down
2 changes: 1 addition & 1 deletion Yafc/Data/locale/en/yafc.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ copy-to-clipboard-with-shortcut=Copy to clipboard (Ctrl+__1__)
; MainScreen.cs
full-name-with-version=Yet Another Factorio Calculator CE v__1__
create-production-sheet=Create production sheet (Ctrl+__1__)
list-and-search-all=List and search all pages (Ctrl+Shift+__1__)
list-and-search-all=List and search all pages (Ctrl+Shift+__1__)\nRight click to open pinned
menu-open-neie=Open NEIE
search-header=Find on page:
undo=Undo
Expand Down
67 changes: 55 additions & 12 deletions Yafc/Windows/MainScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.IO;
using System.Net.Http;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Threading.Tasks;
using SDL2;
Expand Down Expand Up @@ -137,7 +138,9 @@ private void BuildPage(ImGui gui, ProjectPage element, int index) {
if (evt) {
if (gui.actionParameter == SDL.SDL_BUTTON_MIDDLE) {
ProjectPageSettingsPanel.Show(element);
dropDown?.Close();
commonDropDown?.Close();
pagesDropDown?.Close();
HideTooltip();
}
else {
SetActivePage(element);
Expand All @@ -152,6 +155,8 @@ private void ProjectOnMetaInfoChanged() {
if (_activePage != null && project.FindPage(_activePage.guid) != _activePage) {
SetActivePage(null);
}
// Keep the missing-pages dropdown list in sync with project changes (add/remove/rename)
UpdatePageList();
}

private void ChangePage(ref ProjectPage? activePage, ProjectPage? newPage, ref ProjectPageView? activePageView, ProjectPageView? newPageView) {
Expand Down Expand Up @@ -254,29 +259,59 @@ private void BuildTabBar(ImGui gui) {
ProductionTableView.CreateProductionSheet();
}

var padding = new Padding(0f, 0f, 0f, 0.5f);

gui.allocator = RectAllocator.RightRow;
if (gui.BuildButton(Icon.DropDown, SchemeColor.None, SchemeColor.Grey).WithTooltip(gui, LSs.ListAndSearchAll.L(ImGuiUtils.ScanToString(SDL.SDL_Scancode.SDL_SCANCODE_F))) || showSearchAll) {

var isPinned = PagesSimpleDropPinned || this.project.settings.isPagesListPinned;

if (isPinned) {
gui.window?.HideTooltip();
}

if (gui.BuildButton(isPinned ? Icon.Close : Icon.DropDown, SchemeColor.None, SchemeColor.Grey, button: 0).WithTooltipConditional(!isPinned, gui, LSs.ListAndSearchAll.L(ImGuiUtils.ScanToString(SDL.SDL_Scancode.SDL_SCANCODE_F))) || showSearchAll) {
showSearchAll = false;
updatePageList();
ShowDropDown(gui, gui.lastRect, missingPagesDropdown, new Padding(0f, 0f, 0f, 0.5f), 30f);
UpdatePageList();

// determine pinned by right-click (mouse button == 3)
bool pin = InputSystem.Instance.mouseDownButton == 3;

if (InputSystem.Instance.mouseDownButton == 1 || InputSystem.Instance.mouseDownButton == 3) {
if (!ClosePagesListDropDown(gui, gui.lastRect)) {
showPagesListDropDown(pin);
this.project.settings.isPagesListPinned = pin;

}
else {
this.project.settings.isPagesListPinned = false;
}
Comment on lines +280 to +287
Copy link
Collaborator

Choose a reason for hiding this comment

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

As a follow-up to veger's comment about ClosePagesListDropDown, I think this would be better as

Suggested change
if (!ClosePagesListDropDown(gui, gui.lastRect)) {
showPagesListDropDown(pin);
this.project.settings.isPagesListPinned = pin;
}
else {
this.project.settings.isPagesListPinned = false;
}
bool isDropdownOpen = /*something*/;
if (isDropdownOpen) {
ClosePagesListDropDown(gui);
project.settings.isPagesListPinned = false;
}
else {
showPagesListDropDown(pin);
project.settings.isPagesListPinned = pin;
}

}
}

if (this.project.settings.isPagesListPinned && pagesDropDown == null && pseudoScreens.Count == 0) {
showPagesListDropDown(true);
}

tabBar.Build(gui);
}
gui.DrawRectangle(gui.lastRect, SchemeColor.PureBackground);

void updatePageList() {
List<ProjectPage> sortedAndFilteredPageList = [.. pageListSearch.Search(project.pages)];
sortedAndFilteredPageList.Sort((a, b) => a.visible == b.visible ? string.Compare(a.name, b.name, StringComparison.InvariantCultureIgnoreCase) : a.visible ? -1 : 1);
allPages.data = sortedAndFilteredPageList;
void showPagesListDropDown(bool pinned) => ShowPagesListDropDown(gui, gui.lastRect, missingPagesDropdown, padding, 30f, pinned);
}
gui.DrawRectangle(gui.lastRect, SchemeColor.PureBackground);

void missingPagesDropdown(ImGui gui) {
pageListSearch.Build(gui, updatePageList);
pageListSearch.Build(gui, UpdatePageList);
allPages.Build(gui);
}
}

// Centralized update for the pages list shown in the dropdown so callers (e.g. after renaming)
// can refresh the list.
public void UpdatePageList() {
List<ProjectPage> sortedAndFilteredPageList = [.. pageListSearch.Search(project.pages)];
sortedAndFilteredPageList.Sort((a, b) => a.visible == b.visible ? string.Compare(a.name, b.name, StringComparison.InvariantCultureIgnoreCase) : a.visible ? -1 : 1);
allPages.data = sortedAndFilteredPageList;
}

private void BuildPage(ImGui gui) {
float usedHeaderSpace = gui.statePosition.Y;
var pageVisibleSize = size;
Expand Down Expand Up @@ -305,13 +340,15 @@ private void BuildPage(ImGui gui) {
}
}

public ProjectPage AddProjectPage(string name, FactorioObject? icon, Type contentType, bool setActive, bool initNew) {
public ProjectPage AddProjectPage(String name, FactorioObject? icon, Type contentType, bool setActive, bool initNew) {
ProjectPage page = new ProjectPage(project, contentType) { name = name, icon = icon };
if (initNew) {
page.content.InitNew();
}

project.RecordUndo().pages.Add(page);
// Ensure any visible page lists are updated immediately
UpdatePageList();
if (setActive) {
SetActivePage(page);
}
Expand Down Expand Up @@ -543,6 +580,12 @@ public bool ShowPseudoScreen(PseudoScreen screen) {
if (topScreen == null) {
Ui.DispatchInMainThread(x => fadeDrawer.CreateDownscaledImage(), null);
}

if (pagesDropDown != null) {
pagesDropDown.Close();
pagesDropDown = null;
}

project.undo.Suspend();
screen.Rebuild();
pseudoScreens.Insert(0, screen);
Expand Down
2 changes: 2 additions & 0 deletions Yafc/Windows/ProjectPageSettingsPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ protected override void ReturnPressed() {
else if (editingPage.name != name || editingPage.icon != icon) {
editingPage.RecordUndo(true).name = name!; // null-forgiving: The button is disabled if name is null or empty.
editingPage.icon = icon;
// Ensure the main screen's page list is refreshed to show the new name in dropdowns
MainScreen.Instance.UpdatePageList();
}
Close();
}
Expand Down
2 changes: 2 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
----------------------------------------------------------------------------------------------------------------------
Version:
Date:
Features:
- Add Right-click option to show the Page Search dropdown pinned to keep it open.
Copy link
Collaborator

Choose a reason for hiding this comment

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

You read my mind 😉

Fixes:
- Fix rendering of multi-icon technologies (e.g. shooting speed techs)
- Add simplified support for debug.getinfo(), only returns short_src. Fixes #455, #504.
Expand Down