raylib-zig/examples/gui/floating_window.zig
2026-01-12 19:20:29 +01:00

167 lines
7.2 KiB
Zig

const std = @import("std");
const rl = @import("raylib");
const rg = @import("raygui");
const WINDOW_STATUS_BAR_HEIGHT = 24;
const WINDOW_CLOSE_BUTTON_SIZE = 18;
const CLOSE_TITLE_SIZE_DELTA_HALF = (WINDOW_STATUS_BAR_HEIGHT - WINDOW_CLOSE_BUTTON_SIZE) / 2;
const DrawContentFn = *const fn(rl.Vector2, rl.Vector2) void;
fn floatingWindow(
position: *rl.Vector2,
size: *rl.Vector2,
minimized: *bool,
moving: *bool,
resizing: *bool,
draw_content: DrawContentFn,
content_size: rl.Vector2,
scroll: *rl.Vector2,
title: []const u8
) void {
var title_buf: [64]u8 = undefined;
const title_text = std.fmt.bufPrintZ(&title_buf, "{s}", .{ title }) catch "";
const mouse_position = rl.getMousePosition();
const is_left_pressed = rl.isMouseButtonPressed(rl.MouseButton.left);
if(is_left_pressed and !(moving.*) and !(resizing.*)) {
const title_collsion_rect = rl.Rectangle{.x = position.x, .y = position.y, .width = size.x - WINDOW_CLOSE_BUTTON_SIZE - CLOSE_TITLE_SIZE_DELTA_HALF, .height = WINDOW_STATUS_BAR_HEIGHT};
const resize_collision_rect = rl.Rectangle{.x = position.x + size.x - 20, .y = position.y + size.y - 20, .width = 20, .height = 20};
_ = rl.drawRectangleLinesEx(title_collsion_rect, 15, rl.Color.red);
_ = rl.drawRectangleLinesEx(resize_collision_rect, 15, rl.Color.green);
if(rl.checkCollisionPointRec(mouse_position, title_collsion_rect)) {
moving.* = true;
} else if(!(minimized.*) and rl.checkCollisionPointRec(mouse_position, resize_collision_rect)) {
resizing.* = true;
}
}
const screen_width = rl.getScreenWidth();
const screen_width_f32 = @as(f32, @floatFromInt(screen_width));
const screen_height = rl.getScreenHeight();
const screen_height_f32 = @as(f32, @floatFromInt(screen_height));
// window movement and resize update
if(moving.*) {
const mouse_delta = rl.getMouseDelta();
position.x += mouse_delta.x;
position.y += mouse_delta.y;
if(rl.isMouseButtonReleased(rl.MouseButton.left)) {
moving.* = false;
if(position.x < 0) {
position.x = 0;
} else if(position.x > screen_width_f32 - size.x) {
position.x = screen_width_f32 - size.x;
}
if(position.y < 0) {
position.x = 0;
} else if(position.y > screen_height_f32) {
position.y = screen_height_f32 - WINDOW_STATUS_BAR_HEIGHT;
}
}
} else if(resizing.*) {
if (mouse_position.x > position.x) {
size.x = mouse_position.x - position.x;
}
if (mouse_position.y > position.y) {
size.y = mouse_position.y - position.y;
}
// clamp window size to an arbitrary minimum value and the window size as the maximum
const min_window_size = 100;
if(size.x < min_window_size) {
size.x = min_window_size;
} else if(size.x > screen_width_f32) {
size.x = screen_width_f32;
}
if(size.y < min_window_size) {
size.y = min_window_size;
} else if(size.y > screen_height_f32) {
size.y = screen_height_f32;
}
if (rl.isMouseButtonReleased(rl.MouseButton.left)) {
resizing.* = false;
}
}
// window and content drawing with scissor and scroll area
if(minimized.*) {
_ = rg.statusBar(rl.Rectangle{ .x = position.x, .y = position.y, .width = size.x, .height = WINDOW_STATUS_BAR_HEIGHT}, title_text);
if (rg.button(rl.Rectangle{ .x = position.x + size.x - WINDOW_CLOSE_BUTTON_SIZE - CLOSE_TITLE_SIZE_DELTA_HALF,
.y = position.y + CLOSE_TITLE_SIZE_DELTA_HALF,
.width = WINDOW_CLOSE_BUTTON_SIZE,
.height = WINDOW_CLOSE_BUTTON_SIZE},
"#120#")) {
minimized.* = false;
}
} else {
minimized.* = rg.windowBox(rl.Rectangle{ .x = position.x, .y = position.y, .width = size.x, .height = size.y}, title_text) > 0;
// scissor and draw content within a scroll panel
var scissor: rl.Rectangle = undefined;
_ = rg.scrollPanel(rl.Rectangle{ .x = position.x, .y = position.y + WINDOW_STATUS_BAR_HEIGHT, .width = size.x, .height = size.y - WINDOW_STATUS_BAR_HEIGHT},
null,
rl.Rectangle{ .x = position.x, .y = position.y, .width = content_size.x, .height = content_size.y },
scroll,
&scissor);
_ = rl.drawRectangleRec(scissor, rl.Color.gold);
const require_scissor = size.x < content_size.x or size.y < content_size.y;
if(require_scissor) {
rl.beginScissorMode(@intFromFloat(scissor.x), @intFromFloat(scissor.y), @intFromFloat(scissor.width), @intFromFloat(scissor.height));
}
draw_content(position.*, scroll.*);
if(require_scissor) {
rl.endScissorMode();
}
// draw the resize button/icon
_ = rg.drawIcon(71, @intFromFloat(position.x + size.x - 20), @intFromFloat(position.y + size.y - 20), 1, rl.Color.gray);
}
}
fn drawContent(position: rl.Vector2, window_scroll: rl.Vector2) void {
_ = rg.button(rl.Rectangle{ .x = position.x + 20 + window_scroll.x, .y = position.y + 50 + window_scroll.y, .width = 100, .height = 25 }, "Button 1");
_ = rg.button(rl.Rectangle{ .x = position.x + 20 + window_scroll.x, .y = position.y + 100 + window_scroll.y, .width = 100, .height = 25 }, "Button 2");
_ = rg.button(rl.Rectangle{ .x = position.x + 20 + window_scroll.x, .y = position.y + 150 + window_scroll.y, .width = 100, .height = 25 }, "Button 3");
_ = rg.label(rl.Rectangle{ .x = position.x + 20 + window_scroll.x, .y = position.y + 200 + window_scroll.y, .width = 250, .height = 25 }, "A Label");
_ = rg.label(rl.Rectangle{ .x = position.x + 20 + window_scroll.x, .y = position.y + 250 + window_scroll.y, .width = 250, .height = 25 }, "Another Label");
_ = rg.label(rl.Rectangle{ .x = position.x + 20 + window_scroll.x, .y = position.y + 300 + window_scroll.y, .width = 250, .height = 25 }, "Yet Another Label");
}
pub fn main() !void {
var window_position = rl.Vector2{ .x = 10, .y = 10};
var window2_position = rl.Vector2{ .x = 250, .y = 10};
var window_size = rl.Vector2{ .x = 200, .y = 400};
var window2_size = rl.Vector2{ .x = 200, .y = 400};
var minimized = false;
var minimized2 = false;
var moving = false;
var moving2 = false;
var resizing = false;
var resizing2 = false;
var scroll: rl.Vector2 = rl.Vector2{ .x = -1, .y = -1};
var scroll2: rl.Vector2 = rl.Vector2{ .x = -1, .y = -1};
rl.initWindow(960, 560, "raygui - floating window example");
rl.setTargetFPS(60);
while(!rl.windowShouldClose()) {
rl.beginDrawing();
defer rl.endDrawing();
floatingWindow(&window_position, &window_size, &minimized, &moving, &resizing, &drawContent, rl.Vector2{ .x = 140, .y = 320 }, &scroll, "Movable & Scalable Window");
floatingWindow(&window2_position, &window2_size, &minimized2, &moving2, &resizing2, &drawContent, rl.Vector2{ .x = 140, .y = 320 }, &scroll2, "Another window");
rl.clearBackground(rl.Color.ray_white);
}
rl.closeWindow();
}