tangled
alpha
login
or
join now
rockorager.dev
/
comlink
2
fork
atom
an experimental irc client
2
fork
atom
overview
issues
pulls
pipelines
buffers: implement clicking
rockorager.dev
1 year ago
aebbc4a5
ffdfcdf8
+101
-34
3 changed files
expand all
collapse all
unified
split
build.zig.zon
src
app.zig
irc.zig
+2
-2
build.zig.zon
···
7
7
.hash = "1220affeb3fe37ef09411b5a213b5fdf9bb6568e9913bade204694648983a8b2776d",
8
8
},
9
9
.vaxis = .{
10
10
-
.url = "git+https://github.com/rockorager/libvaxis#d8e5ec0d7bbeb6e70efc95734cd06082c3d518ff",
11
11
-
.hash = "1220717a916024027282ea35359f8348858f3f49601af55f817c44d9806d08a6e06b",
10
10
+
.url = "git+https://github.com/rockorager/libvaxis#4e07fb905ef40e3bd544a563914c769c1cf285d3",
11
11
+
.hash = "1220c42eb95ef849c0d4c131ed2042bfffd392cb61db2f30dbb41148e866b5756610",
12
12
},
13
13
.zeit = .{
14
14
.url = "git+https://github.com/rockorager/zeit?ref=main#d943bc4bfe9e18490460dfdd64f48e997065eba8",
+31
-12
src/app.zig
···
273
273
const self: *const App = @ptrCast(@alignCast(ptr));
274
274
var i: usize = 0;
275
275
for (self.clients.items) |client| {
276
276
-
if (i == idx and i == cursor) {
277
277
-
return .{
278
278
-
.userdata = client,
279
279
-
.drawFn = irc.Client.drawNameSelected,
280
280
-
};
281
281
-
}
282
282
-
if (i == idx) {
283
283
-
return .{
284
284
-
.userdata = client,
285
285
-
.drawFn = irc.Client.drawName,
286
286
-
};
287
287
-
}
276
276
+
if (i == idx) return client.nameWidget(i == cursor);
288
277
i += 1;
289
278
for (client.channels.items) |channel| {
290
279
if (i == idx) return channel.nameWidget(i == cursor);
···
1173
1162
}
1174
1163
}
1175
1164
return null;
1165
1165
+
}
1166
1166
+
1167
1167
+
pub fn selectBuffer(self: *App, buffer: irc.Buffer) void {
1168
1168
+
var i: u32 = 0;
1169
1169
+
switch (buffer) {
1170
1170
+
.client => |target| {
1171
1171
+
for (self.clients.items) |client| {
1172
1172
+
if (client == target) {
1173
1173
+
self.buffer_list.cursor = i;
1174
1174
+
self.buffer_list.ensureScroll();
1175
1175
+
return;
1176
1176
+
}
1177
1177
+
i += 1;
1178
1178
+
for (client.channels.items) |_| i += 1;
1179
1179
+
}
1180
1180
+
},
1181
1181
+
.channel => |target| {
1182
1182
+
for (self.clients.items) |client| {
1183
1183
+
i += 1;
1184
1184
+
for (client.channels.items) |channel| {
1185
1185
+
if (channel == target) {
1186
1186
+
self.buffer_list.cursor = i;
1187
1187
+
self.buffer_list.ensureScroll();
1188
1188
+
return;
1189
1189
+
}
1190
1190
+
i += 1;
1191
1191
+
}
1192
1192
+
}
1193
1193
+
},
1194
1194
+
}
1176
1195
}
1177
1196
1178
1197
fn draw(self: *App, input: *TextInput) !void {
+68
-20
src/irc.zig
···
184
184
fn typeErasedEventHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void {
185
185
const self: *Channel = @ptrCast(@alignCast(ptr));
186
186
switch (event) {
187
187
-
.mouse => {
187
187
+
.mouse => |mouse| {
188
188
try ctx.setMouseShape(.pointer);
189
189
+
if (mouse.type == .press and mouse.button == .left) {
190
190
+
self.client.app.selectBuffer(.{ .channel = self });
191
191
+
return ctx.consumeAndRedraw();
192
192
+
}
189
193
},
190
194
.mouse_enter => {
191
195
try ctx.setMouseShape(.pointer);
···
200
204
}
201
205
202
206
pub fn drawName(self: *Channel, ctx: vxfw.DrawContext, selected: bool) Allocator.Error!vxfw.Surface {
203
203
-
const style: vaxis.Style = if (selected)
204
204
-
.{ .reverse = true }
205
205
-
else if (self.has_mouse)
206
206
-
.{ .bg = .{ .index = 8 } }
207
207
-
else
208
208
-
.{};
207
207
+
var style: vaxis.Style = .{};
208
208
+
if (selected) style.reverse = true;
209
209
+
if (self.has_mouse) style.bg = .{ .index = 8 };
210
210
+
209
211
const text: vxfw.RichText = .{
210
212
.text = &.{
211
211
-
.{ .text = " ", .style = style },
213
213
+
.{ .text = " " },
212
214
.{ .text = self.name, .style = style },
213
215
},
214
216
.softwrap = false,
···
566
568
fifo: std.fifo.LinearFifo(Event, .Dynamic),
567
569
fifo_mutex: std.Thread.Mutex,
568
570
571
571
+
has_mouse: bool,
572
572
+
569
573
pub fn init(
570
574
alloc: std.mem.Allocator,
571
575
app: *comlink.App,
···
585
589
.redraw = std.atomic.Value(bool).init(false),
586
590
.fifo = std.fifo.LinearFifo(Event, .Dynamic).init(alloc),
587
591
.fifo_mutex = .{},
592
592
+
.has_mouse = false,
588
593
};
589
594
}
590
595
···
627
632
self.fifo.deinit();
628
633
}
629
634
630
630
-
pub fn drawName(ptr: *anyopaque, ctx: vxfw.DrawContext) Allocator.Error!vxfw.Surface {
631
631
-
const self: *Client = @ptrCast(@alignCast(ptr));
632
632
-
const text: vxfw.Text = .{
633
633
-
.text = self.config.name orelse self.config.server,
634
634
-
.softwrap = false,
635
635
+
pub fn nameWidget(self: *Client, selected: bool) vxfw.Widget {
636
636
+
return .{
637
637
+
.userdata = self,
638
638
+
.eventHandler = Client.typeErasedEventHandler,
639
639
+
.drawFn = if (selected)
640
640
+
Client.typeErasedDrawNameSelected
641
641
+
else
642
642
+
Client.typeErasedDrawName,
635
643
};
636
636
-
return text.draw(ctx);
637
644
}
638
645
639
639
-
pub fn drawNameSelected(ptr: *anyopaque, ctx: vxfw.DrawContext) Allocator.Error!vxfw.Surface {
640
640
-
const self: *Client = @ptrCast(@alignCast(ptr));
641
641
-
const text: vxfw.Text = .{
642
642
-
.text = self.config.name orelse self.config.server,
646
646
+
pub fn drawName(self: *Client, ctx: vxfw.DrawContext, selected: bool) Allocator.Error!vxfw.Surface {
647
647
+
var style: vaxis.Style = .{};
648
648
+
if (selected) style.reverse = true;
649
649
+
if (self.has_mouse) style.bg = .{ .index = 8 };
650
650
+
651
651
+
const name = self.config.name orelse self.config.server;
652
652
+
653
653
+
const text: vxfw.RichText = .{
654
654
+
.text = &.{
655
655
+
.{ .text = name, .style = style },
656
656
+
},
643
657
.softwrap = false,
644
644
-
.style = .{ .reverse = true },
645
658
};
646
646
-
return text.draw(ctx);
659
659
+
var surface = try text.draw(ctx);
660
660
+
// Replace the widget reference so we can handle the events
661
661
+
surface.widget = self.nameWidget(selected);
662
662
+
return surface;
663
663
+
}
664
664
+
665
665
+
fn typeErasedDrawName(ptr: *anyopaque, ctx: vxfw.DrawContext) Allocator.Error!vxfw.Surface {
666
666
+
const self: *Client = @ptrCast(@alignCast(ptr));
667
667
+
return self.drawName(ctx, false);
668
668
+
}
669
669
+
670
670
+
fn typeErasedDrawNameSelected(ptr: *anyopaque, ctx: vxfw.DrawContext) Allocator.Error!vxfw.Surface {
671
671
+
const self: *Client = @ptrCast(@alignCast(ptr));
672
672
+
return self.drawName(ctx, true);
673
673
+
}
674
674
+
675
675
+
fn typeErasedEventHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void {
676
676
+
const self: *Client = @ptrCast(@alignCast(ptr));
677
677
+
switch (event) {
678
678
+
.mouse => |mouse| {
679
679
+
try ctx.setMouseShape(.pointer);
680
680
+
if (mouse.type == .press and mouse.button == .left) {
681
681
+
self.app.selectBuffer(.{ .client = self });
682
682
+
return ctx.consumeAndRedraw();
683
683
+
}
684
684
+
},
685
685
+
.mouse_enter => {
686
686
+
try ctx.setMouseShape(.pointer);
687
687
+
self.has_mouse = true;
688
688
+
},
689
689
+
.mouse_leave => {
690
690
+
try ctx.setMouseShape(.default);
691
691
+
self.has_mouse = false;
692
692
+
},
693
693
+
else => {},
694
694
+
}
647
695
}
648
696
649
697
pub fn drainFifo(self: *Client, ctx: *vxfw.EventContext) void {