From b824f5cf33b433c716ad18f433f354486c4ac572 Mon Sep 17 00:00:00 2001 From: Tim Culverhouse Date: Tue, 4 Mar 2025 14:31:05 -0600 Subject: [PATCH] ui: query yellow, use blended for highlighted bg --- src/app.zig | 42 +++++++++++++++++++++++++++++++++++++++--- src/irc.zig | 25 ++++++++++++++++++++----- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/app.zig b/src/app.zig index f9cb9fd..59909c6 100644 --- a/src/app.zig +++ b/src/app.zig @@ -84,6 +84,7 @@ pub const App = struct { fg: ?[3]u8, bg: ?[3]u8, + yellow: ?[3]u8, const default_rhs: vxfw.Text = .{ .text = "TODO: update this text" }; @@ -126,6 +127,7 @@ pub const App = struct { .has_focus = true, .fg = null, .bg = null, + .yellow = null, }; self.lua = try Lua.init(&self.alloc); @@ -212,12 +214,18 @@ pub const App = struct { switch (color.kind) { .fg => self.fg = color.value, .bg => self.bg = color.value, - else => {}, + .index => |index| { + switch (index) { + 3 => self.yellow = color.value, + else => {}, + } + }, + .cursor => {}, } if (self.fg != null and self.bg != null) { for (self.clients.items) |client| { for (client.channels.items) |channel| { - channel.text_field.style.bg = self.blend(10); + channel.text_field.style.bg = self.blendBg(10); } } } @@ -288,6 +296,7 @@ pub const App = struct { try ctx.tick(8, self.widget()); try ctx.queryColor(.fg); try ctx.queryColor(.bg); + try ctx.queryColor(.{ .index = 3 }); }, .tick => { for (self.clients.items) |client| { @@ -411,7 +420,7 @@ pub const App = struct { /// Blend fg and bg, otherwise return index 8. amt will be clamped to [0,100]. amt will be /// interpreted as percentage of fg to blend into bg - pub fn blend(self: *App, amt: u8) vaxis.Color { + pub fn blendBg(self: *App, amt: u8) vaxis.Color { const bg = self.bg orelse return .{ .index = 8 }; const fg = self.fg orelse return .{ .index = 8 }; // Clamp to (0,100) @@ -436,6 +445,33 @@ pub const App = struct { }; } + /// Blend fg and bg, otherwise return index 8. amt will be clamped to [0,100]. amt will be + /// interpreted as percentage of fg to blend into bg + pub fn blendYellow(self: *App, amt: u8) vaxis.Color { + const bg = self.bg orelse return .{ .index = 3 }; + const yellow = self.yellow orelse return .{ .index = 3 }; + // Clamp to (0,100) + if (amt == 0) return .{ .rgb = bg }; + if (amt >= 100) return .{ .rgb = yellow }; + + const yellow_r: u16 = std.math.mulWide(u8, yellow[0], amt); + const yellow_g: u16 = std.math.mulWide(u8, yellow[1], amt); + const yellow_b: u16 = std.math.mulWide(u8, yellow[2], amt); + + const bg_multiplier: u8 = 100 - amt; + const bg_r: u16 = std.math.mulWide(u8, bg[0], bg_multiplier); + const bg_g: u16 = std.math.mulWide(u8, bg[1], bg_multiplier); + const bg_b: u16 = std.math.mulWide(u8, bg[2], bg_multiplier); + + return .{ + .rgb = .{ + @intCast((yellow_r + bg_r) / 100), + @intCast((yellow_g + bg_g) / 100), + @intCast((yellow_b + bg_b) / 100), + }, + }; + } + /// handle a command pub fn handleCommand(self: *App, buffer: irc.Buffer, cmd: []const u8) !void { const lua_state = self.lua; diff --git a/src/irc.zig b/src/irc.zig index 7d25632..a54f9d8 100644 --- a/src/irc.zig +++ b/src/irc.zig @@ -281,7 +281,7 @@ pub const Channel = struct { .completer = Completer.init(gpa), }; - self.text_field.style = .{ .bg = client.app.blend(10) }; + self.text_field.style = .{ .bg = client.app.blendBg(10) }; self.text_field.userdata = self; self.text_field.onSubmit = Channel.onSubmit; self.text_field.onChange = Channel.onChange; @@ -991,10 +991,17 @@ pub const Channel = struct { // Draw the message so we have it's wrapped height const text: vxfw.RichText = .{ .text = spans }; const child_ctx = ctx.withConstraints( - .{ .width = 0, .height = 0 }, + .{ .width = max.width -| gutter_width, .height = 1 }, .{ .width = max.width -| gutter_width, .height = null }, ); const surface = try text.draw(child_ctx); + if (self.client.app.yellow != null and msg.containsPhrase(self.client.nickname())) { + const bg = self.client.app.blendYellow(30); + for (surface.buffer) |*cell| { + if (cell.style.bg != .default) continue; + cell.style.bg = bg; + } + } // See if our message contains the mouse. We'll highlight it if it does const message_has_mouse: bool = blk: { @@ -1077,7 +1084,7 @@ pub const Channel = struct { }; // If the message has our nick, we'll highlight the time - if (std.mem.indexOf(u8, content, self.client.nickname())) |_| { + if (self.client.app.yellow == null and msg.containsPhrase(self.client.nickname())) { style.fg = .{ .index = 3 }; style.reverse = true; } @@ -1087,9 +1094,13 @@ pub const Channel = struct { .style = style, .softwrap = false, }; + const time_ctx = ctx.withConstraints( + .{ .width = 0, .height = 1 }, + .{ .width = max.width -| gutter_width, .height = null }, + ); try children.append(.{ .origin = .{ .row = row, .col = 0 }, - .surface = try time_text.draw(child_ctx), + .surface = try time_text.draw(time_ctx), }); var printed_sender: bool = false; @@ -1106,7 +1117,11 @@ pub const Channel = struct { .text = user.nick, .style = .{ .fg = user.color, .bold = true }, }; - const sender_surface = try sender_text.draw(child_ctx); + const sender_ctx = ctx.withConstraints( + .{ .width = 0, .height = 1 }, + .{ .width = max.width -| gutter_width, .height = null }, + ); + const sender_surface = try sender_text.draw(sender_ctx); try children.append(.{ .origin = .{ .row = row, .col = gutter_width }, .surface = sender_surface, -- 2.51.2