Skip to content

Commit

Permalink
Improve ScrollArea (#325)
Browse files Browse the repository at this point in the history
This PR adds a collection of small improvements and preparation for
freezing the first column (tab/page name column) of the SummaryView
ScrollArea. This is working almost fully working and I am using it
locally all the time: the only left-over issue is that the the
scrollbars are disappeared. (so the UX is a little off 😉 )
I pushed [this 'freeze-first-summary-column'
branch](https://github.com/veger/yafc-ce/tree/freeze-first-summary-column)
with this fix to my own fork, so it is be more publicly available, until
I (or someone) is able to fix the missing scrollbars, so we can actually
merge!

---

I have these changes for ages in my local repo, and I do think these are
suitable on their own to be committed. It will help me (re)fixing them
on style changes or other code changes.

Each change is a separate commit (as I think we should keep them), so it
is fairly easy if we do not like one of them (then I'll move back to my
[freeze-first-summary-column](https://github.com/veger/yafc-ce/tree/freeze-first-summary-column)
where most of them are required to make this feature work.

For testing I opened up YAFC and clicked around a bit, all still seem to
be working/rendering the same, except:
* empty Summary rows (now) properly render
(8930a9c)
* scrolling still works (without the fallback, see
b6e04c2 and
52491b1)
  • Loading branch information
shpaass authored Oct 29, 2024
2 parents de43a51 + e62af5f commit 4a68750
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 21 deletions.
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

0 comments on commit 4a68750

Please sign in to comment.