@@ -1537,8 +1537,148 @@ pub const App = struct {
15371537 }
15381538 }
15391539
1540+ fn applyDimToStyle (self : * App , style : vaxis.Style , dim_factor : f32 ) vaxis.Style {
1541+ if (dim_factor == 0.0 ) return style ;
1542+
1543+ var dimmed = style ;
1544+
1545+ // Apply dimming to foreground color
1546+ if (dimmed .fg != .default ) {
1547+ const fg_rgb = self .resolveColor (dimmed .fg );
1548+ if (fg_rgb ) | rgb | {
1549+ dimmed .fg = .{ .rgb = Surface .TerminalColors .reduceContrast (rgb , dim_factor * 0.5 ) };
1550+ }
1551+ }
1552+
1553+ // Apply dimming to background color
1554+ if (dimmed .bg != .default ) {
1555+ const bg_rgb = self .resolveColor (dimmed .bg );
1556+ if (bg_rgb ) | rgb | {
1557+ dimmed .bg = .{ .rgb = Surface .TerminalColors .reduceContrast (rgb , dim_factor ) };
1558+ }
1559+ }
1560+
1561+ return dimmed ;
1562+ }
1563+
1564+ fn resolveColor (self : * App , color : vaxis.Cell.Color ) ? [3 ]u8 {
1565+ return switch (color ) {
1566+ .rgb = > | rgb | rgb ,
1567+ .index = > | idx | blk : {
1568+ if (idx >= 16 ) break :blk null ;
1569+ if (self .colors .palette [idx ]) | c_val | {
1570+ break :blk switch (c_val ) {
1571+ .rgb = > | rgb | rgb ,
1572+ else = > null ,
1573+ };
1574+ }
1575+ break :blk null ;
1576+ },
1577+ .default = > blk : {
1578+ if (self .colors .bg ) | bg | {
1579+ break :blk switch (bg ) {
1580+ .rgb = > | rgb | rgb ,
1581+ else = > null ,
1582+ };
1583+ }
1584+ break :blk null ;
1585+ },
1586+ };
1587+ }
1588+
15401589 fn renderWidget (self : * App , w : widget.Widget , win : vaxis.Window ) ! void {
1541- try w .renderTo (win , self .allocator );
1590+ switch (w .kind ) {
1591+ .surface = > | surf | {
1592+ if (self .surfaces .get (surf .pty_id )) | surface | {
1593+ // Check for resize mismatch and send resize request if needed
1594+ if (surface .rows != w .height or surface .cols != w .width ) {
1595+ log .debug ("renderWidget: surface resize needed for pty {}: {}x{} -> {}x{}" , .{
1596+ surf .pty_id ,
1597+ surface .cols ,
1598+ surface .rows ,
1599+ w .width ,
1600+ w .height ,
1601+ });
1602+ self .sendResize (surf .pty_id , w .height , w .width ) catch | err | {
1603+ log .err ("Failed to send resize: {}" , .{err });
1604+ };
1605+ }
1606+ // Calculate dim factor based on focus
1607+ const dim_factor : f32 = if (w .focus ) 0.0 else self .ui .dim_factor ;
1608+ surface .render (win , w .focus , & self .colors , dim_factor );
1609+ }
1610+ },
1611+ .text = > {
1612+ // Use renderTo for text widgets
1613+ try w .renderTo (win , self .allocator );
1614+ },
1615+ .box = > | b | {
1616+ const chars = b .borderChars ();
1617+ // Apply dimming to border style if not focused
1618+ const dim_factor : f32 = if (w .focus ) 0.0 else self .ui .dim_factor ;
1619+ const style = self .applyDimToStyle (b .style , dim_factor );
1620+
1621+ log .debug ("render box: w={} h={} focus={} dim_factor={d}" , .{ win .width , win .height , w .focus , dim_factor });
1622+
1623+ // Fill background for the entire box area
1624+ if (style .bg != .default ) {
1625+ for (0.. win .height ) | row | {
1626+ for (0.. win .width ) | col | {
1627+ win .writeCell (@intCast (col ), @intCast (row ), .{
1628+ .char = .{ .grapheme = " " , .width = 1 },
1629+ .style = style ,
1630+ });
1631+ }
1632+ }
1633+ }
1634+
1635+ // Render border if not none
1636+ if (b .border != .none and win .width >= 2 and win .height >= 2 ) {
1637+ win .writeCell (0 , 0 , .{ .char = .{ .grapheme = chars .tl , .width = 1 }, .style = style });
1638+ win .writeCell (win .width - 1 , 0 , .{ .char = .{ .grapheme = chars .tr , .width = 1 }, .style = style });
1639+ win .writeCell (0 , win .height - 1 , .{ .char = .{ .grapheme = chars .bl , .width = 1 }, .style = style });
1640+ win .writeCell (win .width - 1 , win .height - 1 , .{ .char = .{ .grapheme = chars .br , .width = 1 }, .style = style });
1641+
1642+ for (1.. win .width - 1 ) | col | {
1643+ win .writeCell (@intCast (col ), 0 , .{ .char = .{ .grapheme = chars .h , .width = 1 }, .style = style });
1644+ win .writeCell (@intCast (col ), win .height - 1 , .{ .char = .{ .grapheme = chars .h , .width = 1 }, .style = style });
1645+ }
1646+
1647+ for (1.. win .height - 1 ) | row | {
1648+ win .writeCell (0 , @intCast (row ), .{ .char = .{ .grapheme = chars .v , .width = 1 }, .style = style });
1649+ win .writeCell (win .width - 1 , @intCast (row ), .{ .char = .{ .grapheme = chars .v , .width = 1 }, .style = style });
1650+ }
1651+ }
1652+
1653+ // Render child widget if present
1654+ const inner_win = win .child (.{
1655+ .x_off = if (b .border != .none ) 1 else 0 ,
1656+ .y_off = if (b .border != .none ) 1 else 0 ,
1657+ .width = if (b .border != .none and win .width >= 2 ) win .width - 2 else win .width ,
1658+ .height = if (b .border != .none and win .height >= 2 ) win .height - 2 else win .height ,
1659+ });
1660+ try self .renderWidget (b .child .* , inner_win );
1661+ },
1662+ .positioned = > | pos | {
1663+ const child_win = win .child (.{
1664+ .x_off = pos .x orelse 0 ,
1665+ .y_off = pos .y orelse 0 ,
1666+ .width = pos .child .width ,
1667+ .height = pos .child .height ,
1668+ });
1669+ try self .renderWidget (pos .child .* , child_win );
1670+ },
1671+ .text_input ,
1672+ .list ,
1673+ .padding ,
1674+ .column ,
1675+ .row ,
1676+ .stack ,
1677+ = > {
1678+ // These widgets use renderTo for now
1679+ try w .renderTo (win , self .allocator );
1680+ },
1681+ }
15421682 }
15431683
15441684 pub fn scheduleRender (self : * App ) ! void {
0 commit comments