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

Improve ScrollArea #325

Merged
merged 6 commits into from
Oct 29, 2024
Merged
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
68 changes: 51 additions & 17 deletions Yafc.UI/ImGui/ScrollArea.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public abstract class Scrollable(bool vertical, bool horizontal, bool collapsibl

protected abstract void PositionContent(ImGui gui, Rect viewport);

/// <param name="availableHeight">Available height without in parent context for the Scrollable</param>
/// <param name="availableHeight">Available height in parent context for the Scrollable</param>
public void Build(ImGui gui, float availableHeight, bool useBottomPadding = false) {
this.gui = gui;
var rect = gui.statePosition;
Expand Down Expand Up @@ -75,14 +75,11 @@ public void Build(ImGui gui, float availableHeight, bool useBottomPadding = fals
}

if (gui.action == ImGuiAction.MouseScroll) {
if (gui.ConsumeEvent(rect)) {
if (vertical && (!horizontal || !InputSystem.Instance.control)) {
scrollY += gui.actionParameter * 3f;
}
else {
scrollX += gui.actionParameter * 3f;
}
}
if (vertical && !InputSystem.Instance.control && gui.ConsumeEvent(rect))
scrollY += gui.actionParameter * 3f;

else if (horizontal && InputSystem.Instance.control && gui.ConsumeEvent(rect))
scrollX += gui.actionParameter * 3f;
}
else {
if (horizontal && maxScroll.X > 0f) {
Expand Down Expand Up @@ -150,47 +147,83 @@ public float scrollX {

///<summary>This method is called when the required area of the <see cref="Scrollable"/> for the provided <paramref name="width"/> is needed.</summary>
/// <returns>The required area of the contents of the <see cref="Scrollable"/>.</returns>
protected abstract Vector2 MeasureContent(float width, ImGui gui);
public abstract Vector2 MeasureContent(float width, ImGui gui);

public bool KeyDown(SDL.SDL_Keysym key) {
bool ctrl = InputSystem.Instance.control;
bool shift = InputSystem.Instance.shift;

switch ((ctrl, shift, key.scancode)) {
case (false, false, SDL.SDL_Scancode.SDL_SCANCODE_UP):
if (!vertical) {
return false;
}
scrollY -= 3;
return true;
case (true, false, SDL.SDL_Scancode.SDL_SCANCODE_UP):
scrollY = 0; // ctrl+up = home
case (true, false, SDL.SDL_Scancode.SDL_SCANCODE_UP): // ctrl+up = home
if (!vertical) {
return false;
}
scrollY = 0;
return true;
case (false, false, SDL.SDL_Scancode.SDL_SCANCODE_DOWN):
if (!vertical) {
return false;
}
scrollY += 3;
return true;
case (true, false, SDL.SDL_Scancode.SDL_SCANCODE_DOWN):
scrollY = maxScroll.Y; // ctrl+down = end
case (true, false, SDL.SDL_Scancode.SDL_SCANCODE_DOWN): // ctrl+down = end
if (!vertical) {
return false;
}
scrollY = maxScroll.Y;
return true;
case (false, false, SDL.SDL_Scancode.SDL_SCANCODE_LEFT):
if (!horizontal) {
return false;
}
scrollX -= 3;
return true;
case (true, false, SDL.SDL_Scancode.SDL_SCANCODE_LEFT):
case (true, false, SDL.SDL_Scancode.SDL_SCANCODE_LEFT): // ctrl+left = start of line
if (!horizontal) {
return false;
}
scrollX = 0;
return true;
case (false, false, SDL.SDL_Scancode.SDL_SCANCODE_RIGHT):
if (!horizontal) {
return false;
}
scrollX += 3;
return true;
case (true, false, SDL.SDL_Scancode.SDL_SCANCODE_RIGHT):
case (true, false, SDL.SDL_Scancode.SDL_SCANCODE_RIGHT): // ctrl+right = end of line
if (!horizontal) {
return false;
}
scrollX = maxScroll.X;
return true;
case (false, false, SDL.SDL_Scancode.SDL_SCANCODE_PAGEDOWN):
if (!vertical) {
return false;
}
scrollY += contentRect.Height;
return true;
case (false, false, SDL.SDL_Scancode.SDL_SCANCODE_PAGEUP):
if (!vertical) {
return false;
}
scrollY -= contentRect.Height;
return true;
case (false, false, SDL.SDL_Scancode.SDL_SCANCODE_HOME):
scrollY = 0;
if (!vertical) {
return false;
}
return true;
case (false, false, SDL.SDL_Scancode.SDL_SCANCODE_END):
if (!vertical) {
return false;
}
scrollY = maxScroll.Y;
return true;
default:
Expand Down Expand Up @@ -226,7 +259,8 @@ protected override void PositionContent(ImGui gui, Rect viewport) {

public void RebuildContents() => contents.Rebuild();

protected override Vector2 MeasureContent(float width, ImGui gui) => contents.CalculateState(width, gui.pixelsPerUnit);
///<summary>Calculates the content dimensions by (re)building the contents using <see cref="BuildContents"/></summary>
public override Vector2 MeasureContent(float width, ImGui gui) => contents.CalculateState(width, gui.pixelsPerUnit);
}

///<summary>Area with scrollbars, which will be visible if it does not fit in the parent area in order to let the user fully view the content of the area.</summary>
Expand Down
2 changes: 1 addition & 1 deletion Yafc/Widgets/DataGrid.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public virtual void BuildMenu(ImGui gui) { }

public class DataGrid<TData> where TData : class {
public readonly List<DataColumn<TData>> columns;
private readonly Padding innerPadding = new Padding(0.2f);
public static readonly Padding innerPadding = new Padding(0.2f);
public float width { get; private set; }
private readonly float spacing;
private Vector2 buildingStart;
Expand Down
4 changes: 2 additions & 2 deletions Yafc/Widgets/ImmediateWidgets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ public static void BuildInlineObjectListAndButtonWithNone<T>(this ImGui gui, ICo
/// <param name="useScale">If <see langword="true"/>, this icon will be displayed at <see cref="ProjectPreferences.iconScale"/>, instead of at 100% scale.</param>
public static Click BuildFactorioObjectWithAmount(this ImGui gui, FactorioObject? goods, DisplayAmount amount, ButtonDisplayStyle buttonDisplayStyle, TextBlockDisplayStyle? textDisplayStyle = null, ObjectTooltipOptions tooltipOptions = default) {
textDisplayStyle ??= new(Alignment: RectAlignment.Middle);
using (gui.EnterFixedPositioning(3f, 3f, default)) {
using (gui.EnterFixedPositioning(buttonDisplayStyle.Size, buttonDisplayStyle.Size, default)) {
gui.allocator = RectAllocator.Stretch;
gui.spacing = 0f;
Click clicked = gui.BuildFactorioObjectButton(goods, buttonDisplayStyle, tooltipOptions);
Expand Down Expand Up @@ -319,7 +319,7 @@ public static GoodsWithAmountEvent BuildFactorioObjectWithEditableAmount(this Im
bool allowScroll = true, ObjectTooltipOptions tooltipOptions = default, SetKeyboardFocus setKeyboardFocus = SetKeyboardFocus.No) {

using var group = gui.EnterGroup(default, RectAllocator.Stretch, spacing: 0f);
group.SetWidth(3f);
group.SetWidth(buttonDisplayStyle.Size);
GoodsWithAmountEvent evt = (GoodsWithAmountEvent)gui.BuildFactorioObjectButton(obj, buttonDisplayStyle, tooltipOptions);

if (gui.BuildFloatInput(amount, TextBoxDisplayStyle.FactorioObjectInput, setKeyboardFocus)) {
Expand Down
2 changes: 1 addition & 1 deletion Yafc/Workspace/ProjectPageView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void Build(ImGui gui, Vector2 visibleSize) {
base.Build(gui, visibleSize.Y - headerHeight, true);
}

protected override Vector2 MeasureContent(float _, ImGui gui) => new Vector2(contentWidth, contentHeight);
public override Vector2 MeasureContent(float _, ImGui gui) => new Vector2(contentWidth, contentHeight);

protected override void PositionContent(ImGui gui, Rect viewport) {
headerContent.offset = new Vector2(-scrollX, 0);
Expand Down
12 changes: 12 additions & 0 deletions Yafc/Workspace/SummaryView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
namespace Yafc;

public class SummaryView : ProjectPageView<Summary> {
/// <summary>Height of each row</summary>
private float rowHeight;

/// <summary>Some padding to have the contents of the first column not 'stick' to the rest of the UI</summary>
private readonly Padding FirstColumnPadding = new Padding(1f, 1.5f, 0, 0);
private static float firstColumnWidth;
Expand Down Expand Up @@ -59,10 +62,12 @@ public override void BuildElement(ImGui gui, ProjectPage page) {
foreach ((string name, GoodDetails details, bool enoughProduced) in view.GoodsToDisplay()) {
ProductionLink? link = table.links.Find(x => x.goods.name == name);
grid.Next();
bool isDrawn = false;

if (link != null) {
if (link.amount != 0f) {
DrawProvideProduct(gui, link, page, details, enoughProduced);
isDrawn = true;
}
}
else {
Expand All @@ -72,9 +77,15 @@ public override void BuildElement(ImGui gui, ProjectPage page) {
if (Math.Abs(flow.amount) > Epsilon) {

DrawRequestProduct(gui, flow, enoughProduced);
isDrawn = true;
}
}
}
if (!isDrawn) {
// Reserve empty space to prevent 'compressing' empty rows
_ = gui.AllocateRect(0f, view.rowHeight);
}

}
}

Expand Down Expand Up @@ -263,6 +274,7 @@ protected override async void BuildContent(ImGui gui) {

if (gui.isBuilding) {
firstColumnWidth = CalculateFirstColumWidth(gui);
rowHeight = ButtonDisplayStyle.ProductionTableUnscaled.Size + gui.PixelsToUnits(gui.GetFontSize().lineSize);
}

scrollArea.Build(gui);
Expand Down