Skip to content

Implement Responsive Client-Side Autoscaling#90

Open
Lightning11wins wants to merge 107 commits intomasterfrom
apos_autoscale9-slim5
Open

Implement Responsive Client-Side Autoscaling#90
Lightning11wins wants to merge 107 commits intomasterfrom
apos_autoscale9-slim5

Conversation

@Lightning11wins
Copy link
Contributor

After extracting changes into #87, #88, #89, and removing a few minor/unnecessary changes; this PR is hopefully slightly more manageable.

GitHub Relationships:

This PR includes several TODOs:

  • 3 TODOs for Israel to handle after Update Duplicate Detection #77 is merged into master.
  • 4 TODOs for Greg (although other reviewers are welcome to handle these if they have the requisite knowledge), in the following files: ht_render.c, htdrv_page.c, htdrv_tab.c, and htdrv_table.c.

There are several known issues with this code:

  • Table row details sometimes don't appear.
    • e.g. Broken left menus on the Kardia home page.
  • Code that breaks responsive layout.
    • widget/pane: resize action (test apps/kardia/modules/payroll/pay_form.app)
    • widget/image: offset & scale actions (not used anywhere)
    • widget/objcanvas: add_osrc_object()
  • ht_get_parent_w/h__INTERNAL() & wgtrGetContainerWidth/Height() should be merged.
    • They appear to give almost identical results, except when checking a top-level widget. In this case, ht_get_parent_h__INTERNAL() (mine) gives a height 2px taller.
  • Flexibility calculations that depend on page size cause breakage since the client assumes widget flexibility scale is constant.
    • This would be very hard to fix! The best solution I can think of so far is to rewrite the entire layout system to convert px -> % on the server, then do all layout client-side. However, I'm not sure this system could handle flexibility values at all.

…yout, button, editbox, html, image, label, scrollpane, textbutton, & treeview.
Fixes components, dropdowns, and images.
Renames flex variables to be more clear.
Send parent_w and parent_h to client.
Add tab-height support to apos.c.
Add design support to apos.c.
Add IsDesign to the WgtrClientInfo struct.

Fix spelling mistakes.
Clean up.
Add an error message when cxsecVerifySymbol_n() fails.
Improve an existing error message when htr_internal_WriteWgtrProperty() fails to write a property of an unknown type.
Set Centrallix event listener to be explicitly non-passive, fixing a console error when later code assumes that calling preventDefault() is allowed.
Fix a bug in qprintf() that caused % and & characters inside conditional printing areas to always print, regardless of the condition.
Improve documentation for qpfPrintf_va_internal() and qpf_grow_fn_t().
Clean up.
Add shortcut functions: ht_flex_x(), ht_flex_y(), ht_flex_w(), ht_flex_h().
Rename fl_scale_x (was total_fl_x).
Rename fl_scale_y (was total_fl_y).
Rename fl_scale_w (was total_fl_w).
Rename fl_scale_h (was total_fl_h).
Rename fl_parent_w (was parent_w).
Rename fl_parent_h (was parent_h).
Remove ht_flex_format_all and ht_flex_all().
Improve usage of new feature in previously updated widgets.

Fix spelling mistakes.
Clean up.
Clean up some apps.
Add Math.clamp() and Math.isBetween().
Add getParentSize(), getParentW(), and getParentH().
Refactor getRelativeX/Y/W/H() to call the new getRelative().
Refactor setRelativeX/Y/W/H() to call the new setRelative().
Add fast_setRelativeX/Y().
Add setResponsiveX/Y/W/H() using a new shared setResponsive().
Add responsiveness to moveTo() with the new functions.

Fix style guide mistakes.
Clean up.
Add support for more edge cases with undefined values to wgtrGetServerProperty().
Add the Log action (and docs).
Add the ReloadPage action (and docs).
Improve documentation for the Alert widget.
Add htr_action_point() to ht_render.js to handle the point action responsively.
Refactor pane and window widgets to use the htr_action_point().
Improve documentation and code clarity for htutil_point().
Improve documentation for the point action.
Update al_reflow() to create responsive CSS using the setResponsive() functions.
Improve documentation for al_childresize().
Optimize and clean up inefficient code.
Rewrite C & JS code to use responsive styling.
Fix a bug that allowed multiple tabs to be selected at once.

Fix spelling errors.
Clean up.
Remove the moveable attribute.
Simplify clock widget event code.
Clean up cl_get_time().
Add dragging cursor styles for window widgets.
Add cursor styles for the checkbox, radiobutton, scrollpane, treeview, and window widgets.
Update existing cursor styles for the button, datetime, dropdown, imagebutton, tab, and textbutton widgets.
Add the .dt_dropdown CSS class to make styling the datetime dropdown easier.
Update table columns to use col-resize instead of move.
Clean up cursor CSS styles to follow consistent code styling.
…atives.

Rewrite getters and setters in the ClipObject polyfill to replace __defineGetter__() and __defineSetter__().
Rewrite getters in the datetime, dropdown, and radiobutton widgets to replace __defineGetter__().
Rewrite pg_area() constructor to replace __defineGetter__().
Define a base when parsing relative properties to fix edge cases.
Remove unused debug setters in the table widget.
Remove unused debug code.
…aster.

Replace calls to fast_setRelativeX/Y() with calls to setRelativeX/Y().
Remove obsolete workaround code.
Remove a completed todo.
Improve a comment.
Fix windows failing to release when the mouseup event comes from outside the web page.
Update responsive event listener to use a pattern more similar to other resize code.
Add .titlebar to window object.
Add global wn_windows array that stores all windows.
@greptile-apps
Copy link

greptile-apps bot commented Mar 4, 2026

Greptile Summary

This PR implements client-side autoscaling/responsive layout for Centrallix by computing per-widget flexibility coefficients (fl_scale_x/y/w/h) on the server during the auto-positioning pass and transmitting them to the browser as wgtr properties, where JavaScript uses CSS calc() expressions (calc(Npx + (100% - Mpx) * flex)) to adapt dimensions when the viewport is resized.

Key changes:

  • apos.c: Extended aposSpaceOutLines() to compute loc_fl/my_fl per AposLine; extended aposSnapWidgetsToGrid() to write fl_scale_* onto each WgtrNode using the new IsDesign flag to suppress flexibility in design mode.
  • ht_render.h: New macro API (ht_flex_format, ht_flex_x/y/w/h, ht_get_parent_w/h) consumed by all 40+ widget renderer files to emit responsive CSS.
  • ht_render.c: Serialises new fl_* and fl_scale_* wgtr properties to the client; adds DATA_T_DOUBLE, DATA_T_DATETIME, DATA_T_INTVEC, and DATA_T_STRINGVEC handling to htr_internal_WriteWgtrProperty.
  • ht_geom_dom1html.js: Adds getParentSize/W/H, unified getRelative/setRelative, and new setResponsive helpers; introduces opt-in clipping-CSS suppression (disableClippingCSS).
  • htdrv_scrollpane.js: Full rewrite with ResizeObserver-based thumb updates and configurable scroll speed constants.
  • htdrv_page.js: Replaces pg_mkbox with pg_init_box/pg_init_box_side; adds pg_area_resize_handlers global dispatch for resize events.
  • The PR author openly documents several known issues (broken table row details, broken pane/image resize actions, and flexibility calculations that depend on page size causing breakage).

Issues found:

  • Multiple strcpy() calls in htdrv_tab.c (lines 224, 231, 372–376) and htdrv_radiobutton.c (line 105) should use strtcpy() per project convention to respect buffer size and guarantee null-termination.
  • The substantially rewritten htrbRender() in htdrv_radiobutton.c uses bare return -1 for all error paths rather than goto error, which is inconsistent with the project's error-handling guideline for nontrivial functions.
  • A redundant ternary expression (is_design) ? 0.0 : CurrLine->my_fl appears inside an if (!is_design) guard in aposSnapWidgetsToGrid() (lines 1679, 1681), where is_design is guaranteed to be false, always evaluating to CurrLine->my_fl.

Confidence Score: 2/5

  • This PR is not ready to merge — the author documents multiple known functional regressions (broken table row details, broken pane/image resize actions, and layout instability on window resize), combined with code convention violations that require fixes.
  • The core autoscaling algorithm and responsive CSS macro API are well-structured and logically sound. However, the PR description explicitly lists several known functional regressions (broken Kardia left menus, broken pane resize, broken image offset/scale actions, and layout instability for flex calculations that depend on page size). Additionally, there are multiple strcpystrtcpy convention violations in newly written code, and the rewritten htrbRender() does not follow the goto error pattern required for nontrivial C functions. The scope is very large (99 files) and the feature is described as a replacement for earlier attempts (Implement Responsive Client-Side Autoscaling #84, Implement Responsive Client-Side Autoscaling #85), suggesting it is still actively stabilising.
  • centrallix/htmlgen/htdrv_tab.c (strcpy → strtcpy fixes), centrallix/htmlgen/htdrv_radiobutton.c (strcpy → strtcpy and goto error pattern), and centrallix/wgtr/apos.c (redundant ternary simplification).

Sequence Diagram

sequenceDiagram
    participant Browser
    participant Server as Server (C)
    participant APOS as apos.c
    participant HTR as ht_render.c
    participant JS as Client JS

    Browser->>Server: Page Request
    Server->>APOS: wgtrVerify() → aposAutoPositionWidgetTree()
    APOS->>APOS: aposBuildGrid() — draw lines & sections
    APOS->>APOS: aposSetFlexibilities() — compute flex per section
    APOS->>APOS: aposSetLimits() — enforce min/max
    APOS->>APOS: aposSpaceOutLines() — compute loc_fl / my_fl per line
    APOS->>APOS: aposSnapWidgetsToGrid() — write fl_scale_x/y/w/h to WgtrNode
    APOS-->>Server: Positioned widget tree with fl_scale_* values
    Server->>HTR: htrRender() — generate HTML + JS
    HTR->>HTR: htr_internal_WriteWgtrProperty() — emit fl_scale_* as wgtr props
    HTR->>HTR: Emit CSS using ht_flex_format (calc(px + (100% - total) * flex))
    HTR-->>Browser: HTML + CSS + JS bundle
    Browser->>JS: startup() → build_wgtr_*()
    JS->>JS: setResponsive() — set dimensions using server fl_scale values
    Browser->>JS: window resize event
    JS->>JS: pg_area_resize_handlers dispatch
    JS->>JS: sp_resize_observer → UpdateThumb()
    JS-->>Browser: Re-rendered responsive layout
Loading

Last reviewed commit: 9ced9a7

@greptile-apps
Copy link

greptile-apps bot commented Mar 4, 2026

Additional Comments (1)

centrallix/htmlgen/ht_render.c
Missing thExcessiveRecursion() guard and NULL parent check in recursive helpers

ht_get_parent_w__INTERNAL and ht_get_parent_h__INTERNAL both recurse upward through the widget tree without:

  1. A thExcessiveRecursion() check — required for all deeply recursive functions to prevent stack exhaustion.
  2. A NULL guard on parent — if every ancestor has a negative width/height, the recursion will walk past the root node (Root->Parent == NULL) and dereference a null pointer.
int
ht_get_parent_w__INTERNAL(pWgtrNode widget)
    {
    if (thExcessiveRecursion())
        {
        mssError(1, "HTRND", "Resource exhaustion in ht_get_parent_w__INTERNAL");
        return 0;
        }
    const int cached_value = widget->fl_parent_w;
    if (cached_value != -1) return cached_value;
    const pWgtrNode parent = widget->Parent;
    if (!parent) return widget->fl_parent_w = 0;
    const int parentWidth = parent->width;
    return widget->fl_parent_w = (parentWidth >= 0)
        ? parentWidth - (parent->left + parent->right)
        : ht_get_parent_w__INTERNAL(parent);
    }

Apply the same fix to ht_get_parent_h__INTERNAL.

Context Used: Rule from dashboard - What: Use thExcessiveRecursion() checks in any deeply recursive functions.

Why: This prevents sta... (source)

Fix critical invalid HTML generation for pgstat.
Add null guards and stack exhaustion checks to ht_get_parent_w/h__INTERNAL().
Add explicit initialization for fl_scale_* fields.
Fix quotes breaking CSS background-color.
Fix incorrect CSS styling.
Replace Math.clamp() & Math.isBetween() debug versions with their development versions.
Improve naming in thExcessiveRecursion().
Clean up.
@Lightning11wins
Copy link
Contributor Author

@greptileai Can you rereview this and let me know if you have any other comments? Did I resolve your issues?

Add copyright notice to htdrv_button.c.
Fix incorrect line wrap in copyright notice for net_http_conn.c.
@Lightning11wins
Copy link
Contributor Author

@greptileai Can you rereview this and let me know if you have any other comments? Did I resolve your issues?

Rewrite part of htr_extract_bgcolor() to make it more robust and readable.
Improve tab widget error handling.
Fix code that gets the type of tab pages (and improve its readability).
Fix a missing space that caused malformed scrollpane HTML to be generated for Netscape browsers.
Fix tab_features.app not updating tabs properly.

Remove code that checks the type of tabs because this data is not used.
Remove unused debug function: getClipped().
Clean up.
@Lightning11wins
Copy link
Contributor Author

@greptileai Can you rereview this and let me know if you have any other comments? Did I resolve your issues?

@Lightning11wins
Copy link
Contributor Author

PR cleared for human review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-review Request AI review of this PR enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Autoscaling/responsive widgets using CSS calc()

1 participant