an experimental irc client

ui: crude message drawing

+74
+74
src/irc.zig
··· 409 409 try children.append(topic_border); 410 410 } 411 411 412 + const msg_view_ctx = ctx.withConstraints(.{ .height = 0, .width = 0 }, .{ 413 + .height = max.height - 4, 414 + .width = max.width, 415 + }); 416 + const message_view = try self.drawMessageView(msg_view_ctx); 417 + try children.append(.{ 418 + .origin = .{ .row = 2, .col = 0 }, 419 + .surface = message_view, 420 + }); 421 + 412 422 // Draw the text field 413 423 try children.append(.{ 414 424 .origin = .{ .col = 0, .row = max.height - 1 }, 415 425 .surface = try self.text_field.draw(ctx), 416 426 }); 427 + 428 + return .{ 429 + .size = max, 430 + .widget = self.contentWidget(), 431 + .buffer = &.{}, 432 + .children = children.items, 433 + }; 434 + } 435 + 436 + fn drawMessageView(self: *Channel, ctx: vxfw.DrawContext) Allocator.Error!vxfw.Surface { 437 + const max = ctx.max.size(); 438 + if (max.width == 0 or max.height == 0) { 439 + return .{ 440 + .size = max, 441 + .widget = self.contentWidget(), 442 + .buffer = &.{}, 443 + .children = &.{}, 444 + }; 445 + } 446 + 447 + var children = std.ArrayList(vxfw.SubSurface).init(ctx.arena); 448 + 449 + // Row is the row we are printing on. 450 + var row: i17 = max.height; 451 + var iter = std.mem.reverseIterator(self.messages.items); 452 + const gutter_width = 6; 453 + while (iter.next()) |msg| { 454 + // Break if we have gone past the top of the screen 455 + if (row < 0) break; 456 + 457 + // Draw the message so we have it's wrapped height 458 + const text: vxfw.Text = .{ .text = msg.bytes }; 459 + const child_ctx = ctx.withConstraints( 460 + .{ .height = 0, .width = 0 }, 461 + .{ .width = max.width - gutter_width, .height = null }, 462 + ); 463 + const surface = try text.draw(child_ctx); 464 + 465 + // Adjust the row we print on for the wrapped height of this message 466 + row -= surface.size.height; 467 + try children.append(.{ 468 + .origin = .{ .row = row, .col = gutter_width }, 469 + .surface = surface, 470 + }); 471 + 472 + // If we have a time, print it in the gutter 473 + if (msg.localTime(&self.client.app.tz)) |instant| { 474 + const time = instant.time(); 475 + const buf = try std.fmt.allocPrint( 476 + ctx.arena, 477 + "{d:0>2}:{d:0>2}", 478 + .{ time.hour, time.minute }, 479 + ); 480 + const time_text: vxfw.Text = .{ 481 + .text = buf, 482 + .style = .{ .dim = true }, 483 + .softwrap = false, 484 + }; 485 + try children.append(.{ 486 + .origin = .{ .row = row, .col = 0 }, 487 + .surface = try time_text.draw(child_ctx), 488 + }); 489 + } 490 + } 417 491 418 492 return .{ 419 493 .size = max,