Add background gradients, corner cuts, and reversed StackView - #63
Conversation
A View could only ever be a flat rectangle, rounded or not. Two properties widen that: a background gradient, and a horizontal inset per corner that slants the edge it shares with the corner above or below it. Together they draw the angled, gradient filled cards a HUD or a panel wants, from CSS alone, with no new View subclass. MVC_Vertex::color was already a per vertex attribute that both shaders interpolate, but pushDrawArrays overwrote it with its color argument, so no caller could reach it. That argument is now optional: NULL keeps the colors the vertices carry, which is what makes a gradient expressible. Renderer gains drawPolygon, drawPolygonFilled and drawRoundedRectGradientFilled, and drawLines factors out the stroking it shares with drawPolygon so a border can follow a slanted edge at any width. The gradient interpolant is a vertex's projection onto the gradient axis, normalized by the extent of the bounds along it. That makes the color an affine function of position, which barycentric interpolation reproduces exactly, so a gradient at any angle is right from colors assigned only at the four corners. A cut corner leaves the rounded rectangle shader, which is what supplies the anti aliasing band, so its diagonals are hard edged and View::borderRadius does not apply to it. Cuts are clamped to the width, so an over large one degenerates to a triangle rather than crossing over itself.
A StackView lays its subviews out in the order they were added, and that order is baked into whatever built the view. A HUD element that wants its icon leading in one variant and trailing in another had no way to say so from CSS. reversed mirrors the positions along the axis, the way flexbox's row-reverse does, and composes with both axes. Only the placement is mirrored. View::subviews keeps its order, so drawing and hit testing are unaffected.
There was a problem hiding this comment.
🟡 Changes recommended
There are confirmed rendering correctness/portability issues (corner-cut point clamping can self-intersect; odd-width border expansion is wrong; M_PI usage can break builds on some platforms).
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This pull request expands the UI rendering capabilities by adding polygon drawing/filling (including linear gradients), enabling View background gradients and corner-cut rectangles, and introducing a reversed layout option for StackView.
Changes:
- Added renderer primitives for polygon outlines, filled convex polygons with optional gradients, and rounded-rect gradient fills.
- Extended
Viewstyling/rendering to support background gradients and corner cuts (including corresponding style inlets and default angle initialization). - Added
StackView::reversedto mirror layout order along the main axis without changing draw/hit-test order.
File summaries
| File | Description |
|---|---|
| Sources/ObjectivelyMVC/View.h | Adds ViewCornerCut plus new View fields for background gradients and corner cuts. |
| Sources/ObjectivelyMVC/View.c | Adds style inlets and rendering logic for gradients and corner-cut polygon rendering. |
| Sources/ObjectivelyMVC/StackView.h | Introduces reversed layout flag. |
| Sources/ObjectivelyMVC/StackView.c | Applies reversed by indexing subviews in reverse during layout. |
| Sources/ObjectivelyMVC/Renderer.h | Extends renderer interface with polygon + gradient fill APIs; allows per-vertex colors via pushDrawArrays(color=NULL). |
| Sources/ObjectivelyMVC/Renderer.c | Implements polygon stroking/filling, gradient color computation, and per-vertex color support. |
| configure.ac | Bumps package version to 2.4.7. |
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (cut) { | ||
|
|
||
| // The stroke is centered on the outline, so grow by half of it to sit outside the fill | ||
| const int inset = self->borderWidth / 2; |
There was a problem hiding this comment.
Not taking this one, and I want to be explicit about why rather than silently skip it.
The border is drawn after the fill, over it. With floor (current), a 1px border insets by 0 and the centered stroke covers -0.5..+0.5 of the fill edge: it overlaps the fill by half a pixel, which is invisible. With ceil, it insets by 1 and covers +0.5..+1.5, leaving a half-pixel gap between fill and border that shows the background through. Even widths are identical either way, so ceil only changes the odd case, and changes it for the worse.
1px is the common case here -- it's what the HUD uses on a selected weapon slot and on the local player's scoreboard row -- so this would be a visible regression. Leaving the thread open for your call.
M_PI is not standard C and needs a feature macro on MSVC. Mathlib.h defines it when the platform does not, and offers float_radians, which says what the conversion is for. Clamping each of an edge's two insets to the width independently still let them sum past it: two over-large cuts on one edge crossed the quad over itself rather than closing it, as the comment claimed. Each is now clamped against what the other leaves.
The vertex buffer is created only when a frame has drawn something, but endFrame bound it either way, so any frame that drew nothing dereferenced NULL. A View culled to an empty frame before its first layout is enough to reach it.
|
Pushed Renderer::endFrame creates vertexBuffer only inside Reproduced with a minimal harness: segfault before, clean exit after, with a frame that does draw unaffected. |
This pull request adds support for advanced shape rendering and gradient fills in the UI framework, with a focus on customizable polygons, rounded rectangles, and corner-cut rectangles. It introduces new rendering primitives for polygons (both outlines and filled, including gradients), enables background gradients and corner cuts in views, and adds the ability to reverse the layout order in stack views. The changes also include improvements to the rendering pipeline to support these new features.
Rendering enhancements:
drawPolygon,drawPolygonFilled, anddrawRoundedRectGradientFilledmethods to theRendererandRendererInterfacefor drawing outlined polygons, filled convex polygons (with optional gradients), and rounded rectangles with linear gradients. [1] [2] [3] [4] [5] [6]gradientColorutility for per-vertex gradient color calculation, and refactored the rendering pipeline to allow per-vertex coloring (including gradients) by making thecolorparameter inpushDrawArraysoptional. [1] [2] [3] [4]View background and border customization:
background-gradient-angle,background-gradient-color) and corner cuts (corner-cut,corner-cut-*) toView, including style inlets, default initialization, and rendering logic for both fills and borders. [1] [2] [3] [4] [5]StackView improvements:
reversedproperty toStackViewto allow subviews to be laid out in reverse order along the main axis, including style inlet and layout logic. [1] [2] [3]These changes collectively provide much more flexibility and visual richness for UI components, making it easier to create modern, visually distinct interfaces.