diff --git a/src/gui/components/Button.zig b/src/gui/components/Button.zig index 9f60f18c6f..12b415e489 100644 --- a/src/gui/components/Button.zig +++ b/src/gui/components/Button.zig @@ -54,6 +54,7 @@ pub var buttonUniforms: struct { pos: Vec2f, size: Vec2f, +disabled: bool = false, pressed: bool = false, hovered: bool = false, onAction: gui.Callback, @@ -127,20 +128,22 @@ pub fn mainButtonPressed(self: *Button, _: Vec2f) void { pub fn mainButtonReleased(self: *Button, mousePosition: Vec2f) void { if(self.pressed) { self.pressed = false; - if(GuiComponent.contains(self.pos, self.size, mousePosition)) { + if(!self.disabled and GuiComponent.contains(self.pos, self.size, mousePosition)) { self.onAction.run(); } } } pub fn render(self: *Button, mousePosition: Vec2f) void { - const textures = if(self.pressed) + const textures = if(self.disabled) + normalTextures + else if(self.pressed) pressedTextures else if(GuiComponent.contains(self.pos, self.size, mousePosition) and self.hovered) hoveredTextures else normalTextures; - draw.setColor(0xff000000); + draw.setColor(if(self.disabled) 0xa0000000 else 0xff000000); textures.texture.bindTo(0); pipeline.bind(draw.getScissor()); self.hovered = false; @@ -151,7 +154,7 @@ pub fn render(self: *Button, mousePosition: Vec2f) void { const lowerTexture = (textures.outlineTextureSize - Vec2f{1, 1})/Vec2f{2, 2}/textures.outlineTextureSize; const upperTexture = (textures.outlineTextureSize + Vec2f{1, 1})/Vec2f{2, 2}/textures.outlineTextureSize; textures.outlineTexture.bindTo(0); - draw.setColor(0xffffffff); + draw.setColor(if(self.disabled) 0xffa0a0a0 else 0xffffffff); // Corners: graphics.draw.boundSubImage(self.pos + Vec2f{0, 0}, cornerSize, .{0, 0}, cornerSizeUV); graphics.draw.boundSubImage(self.pos + Vec2f{self.size[0], 0} - Vec2f{cornerSize[0], 0}, cornerSize, .{upperTexture[0], 0}, cornerSizeUV); diff --git a/src/gui/windows/multiplayer.zig b/src/gui/windows/multiplayer.zig index c60a5751c1..7a9aac4374 100644 --- a/src/gui/windows/multiplayer.zig +++ b/src/gui/windows/multiplayer.zig @@ -19,6 +19,7 @@ pub var window = GuiWindow{ var ipAddressLabel: *Label = undefined; var ipAddressEntry: *TextInput = undefined; +var joinButton: *Button = undefined; const padding: f32 = 8; @@ -85,6 +86,24 @@ fn copyIp(_: usize) void { main.Window.setClipboardString(ipAddress); } +fn isValidAddress(str: []const u8) bool { + // min doamin name length is 2 + if(str.len < 2) return false; + + // check if port is valid + var iter = std.mem.splitScalar(u8, str, ':'); + const address = iter.first(); + const portPart = iter.rest(); + if(str.len > address.len) { + if(portPart.len == 0) return false; + + const port = if(portPart[0] == '?') portPart[1..] else portPart; + _ = std.fmt.parseUnsigned(u16, port, 10) catch return false; + } + + return std.net.isValidHostName(address); +} + pub fn onOpen() void { const list = VerticalList.init(.{padding, 16 + padding}, 300, 16); list.add(Label.init(.{0, 0}, width, "Please send your IP to the host of the game and enter the host's IP below.", .center)); @@ -94,7 +113,8 @@ pub fn onOpen() void { list.add(Button.initText(.{0, 0}, 100, "Copy IP", .{.callback = ©Ip})); ipAddressEntry = TextInput.init(.{0, 0}, width, 32, settings.lastUsedIPAddress, .{.callback = &join}, .{}); list.add(ipAddressEntry); - list.add(Button.initText(.{0, 0}, 100, "Join", .{.callback = &join})); + joinButton = Button.initText(.{0, 0}, 100, "Join", .{.callback = &join}); + list.add(joinButton); list.finish(.center); window.rootComponent = list.toComponent(); window.contentSize = window.rootComponent.?.pos() + window.rootComponent.?.size() + @as(Vec2f, @splat(padding)); @@ -131,4 +151,6 @@ pub fn update() void { gotIpAddress.store(false, .monotonic); ipAddressLabel.updateText(ipAddress); } + + joinButton.disabled = !isValidAddress(ipAddressEntry.currentString.items); }