mirror of
https://github.com/IllusionMan1212/C2048.git
synced 2026-10-24 02:12:31 +00:00
WIP(zephr): window icon. basic ui button
- zephr: added ability to assign an icon to a window - zephr: added a basic ui button with hover and click states and cursor change
This commit is contained in:
Vendored
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "stb_image.h"
|
||||||
Vendored
+7985
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,9 @@
|
|||||||
BIN=c2048
|
BIN=c2048
|
||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-Wall -Wextra -Werror -Wfloat-conversion -Wimplicit-fallthrough -pedantic -g `pkg-config --cflags freetype2` -I3rdparty/glad/include -I3rdparty/fmod/include
|
CFLAGS=-Wall -Wextra -Werror -Wfloat-conversion -Wimplicit-fallthrough -pedantic -g `pkg-config --cflags freetype2` -I3rdparty/glad/include -I3rdparty/fmod/include -I3rdparty/stb/
|
||||||
OBJ=main.o game.o core.o shader.o text.o audio.o timer.o ui.o zephr.o zephr_math.o 3rdparty/glad/src/gl.o 3rdparty/glad/src/glx.o
|
OBJ=main.o game.o core.o shader.o text.o audio.o timer.o ui.o zephr.o zephr_math.o 3rdparty/glad/src/gl.o 3rdparty/glad/src/glx.o 3rdparty/stb/stb.o
|
||||||
LDFLAGS=`pkg-config --libs x11 freetype2` -lm -L3rdparty/fmod/lib -Wl,-rpath=3rdparty/fmod/lib -lfmod
|
LDFLAGS=`pkg-config --libs x11 freetype2` -lm -L3rdparty/fmod/lib -Wl,-rpath=3rdparty/fmod/lib -lfmod
|
||||||
DEPS=3rdparty/glad/include/glad/gl.h 3rdparty/glad/include/glad/glx.h 3rdparty/fmod/include/fmod.h
|
DEPS=3rdparty/glad/include/glad/gl.h 3rdparty/glad/include/glad/glx.h 3rdparty/fmod/include/fmod.h 3rdparty/stb/stb_image.h
|
||||||
|
|
||||||
%.o: %.c $(DEPS)
|
%.o: %.c $(DEPS)
|
||||||
$(CC) -c -o $@ $< $(CFLAGS)
|
$(CC) -c -o $@ $< $(CFLAGS)
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
@@ -5,13 +5,14 @@
|
|||||||
|
|
||||||
const char *font_path = "assets/fonts/Rubik/Rubik-VariableFont_wght.ttf";
|
const char *font_path = "assets/fonts/Rubik/Rubik-VariableFont_wght.ttf";
|
||||||
/* const char *font_path = "assets/fonts/Roboto/Roboto-Bold.ttf"; */
|
/* const char *font_path = "assets/fonts/Roboto/Roboto-Bold.ttf"; */
|
||||||
|
const char *game_icon_path = "assets/icon-128x128.png";
|
||||||
const char *title = "C2048";
|
const char *title = "C2048";
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
CORE_UNUSED(argc);
|
CORE_UNUSED(argc);
|
||||||
CORE_UNUSED(argv);
|
CORE_UNUSED(argv);
|
||||||
|
|
||||||
zephr_init(font_path, title, (Size){1200, 800});
|
zephr_init(font_path, game_icon_path, title, (Size){1200, 800});
|
||||||
zephr_make_window_non_resizable();
|
zephr_make_window_non_resizable();
|
||||||
/* zephr_toggle_fullscreen(); */
|
/* zephr_toggle_fullscreen(); */
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,7 @@ Shader ui_shader;
|
|||||||
unsigned int ui_vao;
|
unsigned int ui_vao;
|
||||||
unsigned int ui_vbo;
|
unsigned int ui_vbo;
|
||||||
|
|
||||||
int init_ui(const char* font_path, Size window_size) {
|
int init_ui(const char* font_path) {
|
||||||
zephr_ctx->window.size = window_size;
|
|
||||||
zephr_ctx->projection = orthographic_projection_2d(0.f, window_size.width, window_size.height, 0.f);
|
|
||||||
|
|
||||||
int res = init_fonts(font_path);
|
int res = init_fonts(font_path);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
printf("[ERROR]: could not initialize freetype library\n");
|
printf("[ERROR]: could not initialize freetype library\n");
|
||||||
@@ -122,6 +119,11 @@ void apply_constraints(UIConstraints *constraints, Vec2f *pos, Sizef *size) {
|
|||||||
*size = (Sizef){constraints->width, constraints->height};
|
*size = (Sizef){constraints->width, constraints->height};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void apply_constraints_rect(UIConstraints *constraints, Rect *rect) {
|
||||||
|
rect->pos = (Vec2f){constraints->x, constraints->y};
|
||||||
|
rect->size = (Sizef){constraints->width, constraints->height};
|
||||||
|
}
|
||||||
|
|
||||||
void apply_alignment(Alignment align, UIConstraints *constraints, Vec2f *pos, Sizef size) {
|
void apply_alignment(Alignment align, UIConstraints *constraints, Vec2f *pos, Sizef size) {
|
||||||
// if we don't have a parent then we're a top level element and we should align against the window
|
// if we don't have a parent then we're a top level element and we should align against the window
|
||||||
Sizef parent_size = (Sizef){zephr_ctx->window.size.width, zephr_ctx->window.size.height};
|
Sizef parent_size = (Sizef){zephr_ctx->window.size.width, zephr_ctx->window.size.height};
|
||||||
@@ -269,6 +271,57 @@ void draw_triangle(UIConstraints *constraints, const Color color, Alignment alig
|
|||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool inside_rect(Rect *rect, Vec2 *point) {
|
||||||
|
if (point->x >= rect->pos.x && point->x <= rect->pos.x + rect->size.width &&
|
||||||
|
point->y >= rect->pos.y && point->y <= rect->pos.y + rect->size.height) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool draw_button(UIConstraints *constraints, const Color color, const char *text, f32 radius, Alignment align) {
|
||||||
|
Rect rect = {0};
|
||||||
|
|
||||||
|
apply_constraints(constraints, &rect.pos, &rect.size);
|
||||||
|
apply_alignment(align, constraints, &rect.pos, rect.size);
|
||||||
|
|
||||||
|
if (inside_rect(&rect, &zephr_ctx->mouse.pos)) {
|
||||||
|
zephr_set_cursor(ZEPHR_CURSOR_HAND);
|
||||||
|
|
||||||
|
if (zephr_ctx->mouse.pressed) {
|
||||||
|
Color new_color = mult_color(color, 0.8f);
|
||||||
|
draw_quad(constraints, new_color, radius, align);
|
||||||
|
} else {
|
||||||
|
Color new_color = mult_color(color, 0.9f);
|
||||||
|
draw_quad(constraints, new_color, radius, align);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zephr_set_cursor(ZEPHR_CURSOR_ARROW);
|
||||||
|
draw_quad(constraints, color, radius, align);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text) {
|
||||||
|
UIConstraints text_constraints = {0};
|
||||||
|
|
||||||
|
set_parent_constraint(&text_constraints, constraints);
|
||||||
|
set_x_constraint(&text_constraints, 0, UI_CONSTRAINT_RELATIVE_PIXELS);
|
||||||
|
set_y_constraint(&text_constraints, 0, UI_CONSTRAINT_RELATIVE_PIXELS);
|
||||||
|
set_width_constraint(&text_constraints, 1.5, UI_CONSTRAINT_RELATIVE_PIXELS);
|
||||||
|
|
||||||
|
u8 font_size = (u8)(constraints->width * 0.2 / text_constraints.width * 0.2 * 100.f);
|
||||||
|
|
||||||
|
// TODO: need to adjust the font size based on the text height
|
||||||
|
|
||||||
|
draw_text(text, font_size, text_constraints, COLOR_BLACK, ALIGN_CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inside_rect(&rect, &zephr_ctx->mouse.pos) && zephr_ctx->mouse.released && zephr_ctx->mouse.button == ZEPHR_MOUSE_BUTTON_LEFT) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* enum Element { */
|
/* enum Element { */
|
||||||
/* Rect, */
|
/* Rect, */
|
||||||
/* Circle, */
|
/* Circle, */
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
#include "zephr_math.h"
|
#include "zephr_math.h"
|
||||||
|
|
||||||
|
typedef struct Rect {
|
||||||
|
Vec2f pos;
|
||||||
|
Sizef size;
|
||||||
|
} Rect;
|
||||||
|
|
||||||
typedef enum Alignment {
|
typedef enum Alignment {
|
||||||
ALIGN_TOP_LEFT,
|
ALIGN_TOP_LEFT,
|
||||||
ALIGN_TOP_CENTER,
|
ALIGN_TOP_CENTER,
|
||||||
@@ -30,7 +35,7 @@ typedef struct UIConstraints {
|
|||||||
struct UIConstraints *parent;
|
struct UIConstraints *parent;
|
||||||
} UIConstraints;
|
} UIConstraints;
|
||||||
|
|
||||||
int init_ui(const char* font_path, Size window_size);
|
int init_ui(const char* font_path);
|
||||||
void set_parent_constraint(UIConstraints *constraints, UIConstraints *parent_constraints);
|
void set_parent_constraint(UIConstraints *constraints, UIConstraints *parent_constraints);
|
||||||
void set_x_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
void set_x_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
||||||
void set_y_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
void set_y_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
||||||
@@ -42,3 +47,4 @@ void apply_alignment(Alignment align, UIConstraints *constraints, Vec2f *pos, Si
|
|||||||
void draw_quad(UIConstraints *constraints, const Color color, float border_radius, Alignment align);
|
void draw_quad(UIConstraints *constraints, const Color color, float border_radius, Alignment align);
|
||||||
void draw_circle(UIConstraints *constraints, const Color color, Alignment align);
|
void draw_circle(UIConstraints *constraints, const Color color, Alignment align);
|
||||||
void draw_triangle(UIConstraints *constraints, const Color color, Alignment align);
|
void draw_triangle(UIConstraints *constraints, const Color color, Alignment align);
|
||||||
|
bool draw_button(UIConstraints *constraints, const Color color, const char *text, f32 radius, Alignment align);
|
||||||
|
|||||||
@@ -3,7 +3,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/cursorfont.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
#include <glad/glx.h>
|
#include <glad/glx.h>
|
||||||
|
#include <stb_image.h>
|
||||||
|
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
@@ -484,6 +487,8 @@ void x11_resize_window(void) {
|
|||||||
glViewport(0, 0, win_attrs.width, win_attrs.height);
|
glViewport(0, 0, win_attrs.width, win_attrs.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BUG: fullscreen doesn't work on gnome. may or may not be related to the window being
|
||||||
|
// opened as a dialog window
|
||||||
void x11_go_fullscreen(void) {
|
void x11_go_fullscreen(void) {
|
||||||
XEvent xev;
|
XEvent xev;
|
||||||
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
|
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
|
||||||
@@ -524,25 +529,60 @@ void x11_toggle_fullscreen(bool fullscreen) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int x11_create_window(const char* title, int window_width, int window_height) {
|
void x11_assign_window_icon(const char *icon_path) {
|
||||||
|
int icon_width, icon_height;
|
||||||
|
unsigned char *icon_data = stbi_load(icon_path, &icon_width, &icon_height, NULL, STBI_rgb_alpha);
|
||||||
|
CORE_ASSERT(icon_data, "Failed to load icon image\n");
|
||||||
|
|
||||||
|
u32 target_size = 2 + icon_width * icon_height;
|
||||||
|
|
||||||
|
u64 *data = malloc(target_size * sizeof(u64));
|
||||||
|
u64 *target = data;
|
||||||
|
|
||||||
|
// first two elements are width and height
|
||||||
|
*target++ = icon_width;
|
||||||
|
*target++ = icon_height;
|
||||||
|
|
||||||
|
for (int i = 0; i < icon_width * icon_height; i++) {
|
||||||
|
*target++ = (icon_data[i * 4] << 16) | (icon_data[i * 4 + 1] << 8) | (icon_data[i * 4 + 2] << 0) | (icon_data[i * 4 + 3] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
Atom net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
|
||||||
|
|
||||||
|
XChangeProperty(x11_display, x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)data, target_size);
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
stbi_image_free(icon_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
int x11_create_window(const char* title, int window_width, int window_height, const char *icon_path) {
|
||||||
x11_display = XOpenDisplay(NULL);
|
x11_display = XOpenDisplay(NULL);
|
||||||
CORE_ASSERT(x11_display, "Cannot open x11 display connection\n");
|
CORE_ASSERT(x11_display, "Cannot open x11 display connection\n");
|
||||||
|
|
||||||
int screen = DefaultScreen(x11_display);
|
int screen_num = DefaultScreen(x11_display);
|
||||||
Window root = RootWindow(x11_display, screen);
|
Window root = RootWindow(x11_display, screen_num);
|
||||||
Visual *visual = DefaultVisual(x11_display, screen);
|
Visual *visual = DefaultVisual(x11_display, screen_num);
|
||||||
|
|
||||||
x11_colormap = XCreateColormap(x11_display, root, visual, AllocNone);
|
x11_colormap = XCreateColormap(x11_display, root, visual, AllocNone);
|
||||||
|
|
||||||
XSetWindowAttributes attributes;
|
XSetWindowAttributes attributes;
|
||||||
attributes.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
|
attributes.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
|
||||||
StructureNotifyMask | ButtonPressMask | ButtonReleaseMask;
|
StructureNotifyMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
|
||||||
attributes.colormap = x11_colormap;
|
attributes.colormap = x11_colormap;
|
||||||
|
|
||||||
x11_window = XCreateWindow(x11_display, root, 0, 0, window_width, window_height, 0,
|
Screen *screen = DefaultScreenOfDisplay(x11_display);
|
||||||
DefaultDepth(x11_display, screen), InputOutput, visual,
|
|
||||||
|
int window_start_x = screen->width / 2 - window_width / 2;
|
||||||
|
int window_start_y = screen->height / 2 - window_height / 2;
|
||||||
|
|
||||||
|
x11_window = XCreateWindow(x11_display, root, window_start_x, window_start_y, window_width, window_height, 0,
|
||||||
|
DefaultDepth(x11_display, screen_num), InputOutput, visual,
|
||||||
CWColormap | CWEventMask, &attributes);
|
CWColormap | CWEventMask, &attributes);
|
||||||
|
|
||||||
|
if (icon_path) {
|
||||||
|
x11_assign_window_icon(icon_path);
|
||||||
|
}
|
||||||
|
|
||||||
// Hints to the WM that the window is a dialog window which makes it a floating
|
// Hints to the WM that the window is a dialog window which makes it a floating
|
||||||
// window in tiling WMs (only tested on DWM though)
|
// window in tiling WMs (only tested on DWM though)
|
||||||
// Of course this is only a hint and the WM can ignore it
|
// Of course this is only a hint and the WM can ignore it
|
||||||
@@ -554,12 +594,21 @@ int x11_create_window(const char* title, int window_width, int window_height) {
|
|||||||
XSetWMProtocols(x11_display, x11_window, &wm_delete_window, 1);
|
XSetWMProtocols(x11_display, x11_window, &wm_delete_window, 1);
|
||||||
zephr_ctx->window_delete_atom = wm_delete_window;
|
zephr_ctx->window_delete_atom = wm_delete_window;
|
||||||
|
|
||||||
XMapWindow(x11_display, x11_window);
|
// BUG: window title is broken on gnome's sidebar but works on the window itself.
|
||||||
|
// sidebar shows "Unknown"
|
||||||
XStoreName(x11_display, x11_window, title);
|
XStoreName(x11_display, x11_window, title);
|
||||||
|
XTextProperty text_property;
|
||||||
|
text_property.value = (unsigned char *)title;
|
||||||
|
text_property.format = 8;
|
||||||
|
text_property.encoding = XA_STRING;
|
||||||
|
text_property.nitems = strlen(title);
|
||||||
|
XSetWMName(x11_display, x11_window, &text_property);
|
||||||
|
|
||||||
|
XMapWindow(x11_display, x11_window);
|
||||||
|
|
||||||
CORE_ASSERT(x11_window, "Failed to create window\n");
|
CORE_ASSERT(x11_window, "Failed to create window\n");
|
||||||
|
|
||||||
int glx_version = gladLoaderLoadGLX(x11_display, screen);
|
int glx_version = gladLoaderLoadGLX(x11_display, screen_num);
|
||||||
|
|
||||||
if (!glx_version) {
|
if (!glx_version) {
|
||||||
printf("[FATAL] Failed to load GLX\n");
|
printf("[FATAL] Failed to load GLX\n");
|
||||||
@@ -579,7 +628,7 @@ int x11_create_window(const char* title, int window_width, int window_height) {
|
|||||||
|
|
||||||
int num_fbc = 0;
|
int num_fbc = 0;
|
||||||
GLXFBConfig *fbc =
|
GLXFBConfig *fbc =
|
||||||
glXChooseFBConfig(x11_display, screen, visual_attributes, &num_fbc);
|
glXChooseFBConfig(x11_display, screen_num, visual_attributes, &num_fbc);
|
||||||
|
|
||||||
GLint context_attributes[] = {
|
GLint context_attributes[] = {
|
||||||
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
|
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
|
||||||
@@ -623,8 +672,8 @@ int x11_create_window(const char* title, int window_width, int window_height) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x11_init(const char* title, int window_width, int window_height) {
|
int x11_init(const char* title, int window_width, int window_height, const char *icon_path) {
|
||||||
int res = x11_create_window(title, window_width, window_height);
|
int res = x11_create_window(title, window_width, window_height, icon_path);
|
||||||
|
|
||||||
/* // loads the XMODIFIERS environment variable to see what IME to use */
|
/* // loads the XMODIFIERS environment variable to see what IME to use */
|
||||||
/* XSetLocaleModifiers(""); */
|
/* XSetLocaleModifiers(""); */
|
||||||
@@ -704,19 +753,28 @@ void x11_make_window_non_resizable(int width, int height) {
|
|||||||
///////////////////////////
|
///////////////////////////
|
||||||
|
|
||||||
|
|
||||||
void zephr_init(const char* font_path, const char* window_title, Size window_size) {
|
void zephr_init(const char* font_path, const char* icon_path, const char* window_title, Size window_size) {
|
||||||
zephr_ctx = malloc(sizeof(ZephrContext));
|
zephr_ctx = malloc(sizeof(ZephrContext));
|
||||||
|
|
||||||
// TODO: should I initalize the audio here or let the game handle that??
|
// TODO: should I initalize the audio here or let the game handle that??
|
||||||
int res = audio_init();
|
int res = audio_init();
|
||||||
CORE_ASSERT(res == 0, "Failed to initialize audio");
|
CORE_ASSERT(res == 0, "Failed to initialize audio");
|
||||||
|
|
||||||
res = x11_init(window_title, window_size.width, window_size.height);
|
res = x11_init(window_title, window_size.width, window_size.height, icon_path);
|
||||||
CORE_ASSERT(res == 0, "Failed to initialize X11");
|
CORE_ASSERT(res == 0, "Failed to initialize X11");
|
||||||
|
|
||||||
res = init_ui(font_path, (Size){ .width = window_size.width, .height = window_size.height });
|
res = init_ui(font_path);
|
||||||
CORE_ASSERT(res == 0, "Failed to initialize UI");
|
CORE_ASSERT(res == 0, "Failed to initialize UI");
|
||||||
|
|
||||||
|
zephr_ctx->window.size = window_size;
|
||||||
|
zephr_ctx->projection = orthographic_projection_2d(0.f, window_size.width, window_size.height, 0.f);
|
||||||
|
zephr_ctx->cursors[ZEPHR_CURSOR_ARROW] = XCreateFontCursor(x11_display, XC_left_ptr);
|
||||||
|
zephr_ctx->cursors[ZEPHR_CURSOR_IBEAM] = XCreateFontCursor(x11_display, XC_xterm);
|
||||||
|
zephr_ctx->cursors[ZEPHR_CURSOR_CROSSHAIR] = XCreateFontCursor(x11_display, XC_crosshair);
|
||||||
|
zephr_ctx->cursors[ZEPHR_CURSOR_HAND] = XCreateFontCursor(x11_display, XC_hand1);
|
||||||
|
zephr_ctx->cursors[ZEPHR_CURSOR_HRESIZE] = XCreateFontCursor(x11_display, XC_sb_h_double_arrow);
|
||||||
|
zephr_ctx->cursors[ZEPHR_CURSOR_VRESIZE] = XCreateFontCursor(x11_display, XC_sb_v_double_arrow);
|
||||||
|
|
||||||
x11_get_screen_size(&zephr_ctx->screen_size.width, &zephr_ctx->screen_size.height);
|
x11_get_screen_size(&zephr_ctx->screen_size.width, &zephr_ctx->screen_size.height);
|
||||||
start_internal_timer();
|
start_internal_timer();
|
||||||
}
|
}
|
||||||
@@ -741,6 +799,8 @@ bool zephr_should_quit(void) {
|
|||||||
void zephr_swap_buffers(void) {
|
void zephr_swap_buffers(void) {
|
||||||
CORE_DEBUG_ASSERT(zephr_ctx, "Zephr context not initialized");
|
CORE_DEBUG_ASSERT(zephr_ctx, "Zephr context not initialized");
|
||||||
|
|
||||||
|
zephr_ctx->mouse.released = false;
|
||||||
|
|
||||||
glXSwapBuffers(x11_display, x11_window);
|
glXSwapBuffers(x11_display, x11_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,7 +808,7 @@ Size zephr_get_window_size(void) {
|
|||||||
return zephr_ctx->window.size;
|
return zephr_ctx->window.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This MUST be called after calling init_zephr()
|
// This MUST be called after calling zephr_init()
|
||||||
void zephr_make_window_non_resizable(void) {
|
void zephr_make_window_non_resizable(void) {
|
||||||
CORE_DEBUG_ASSERT(zephr_ctx, "Zephr context not initialized");
|
CORE_DEBUG_ASSERT(zephr_ctx, "Zephr context not initialized");
|
||||||
|
|
||||||
@@ -901,16 +961,20 @@ bool zephr_iter_events(ZephrEvent *event_out) {
|
|||||||
} else if (xev.type == ButtonPress) {
|
} else if (xev.type == ButtonPress) {
|
||||||
event_out->type = ZEPHR_EVENT_MOUSE_BUTTON_PRESSED;
|
event_out->type = ZEPHR_EVENT_MOUSE_BUTTON_PRESSED;
|
||||||
event_out->mouse.position = (Vec2){ .x = xev.xbutton.x, .y = xev.xbutton.y };
|
event_out->mouse.position = (Vec2){ .x = xev.xbutton.x, .y = xev.xbutton.y };
|
||||||
|
zephr_ctx->mouse.pressed = true;
|
||||||
|
|
||||||
switch (xev.xbutton.button) {
|
switch (xev.xbutton.button) {
|
||||||
case Button1:
|
case Button1:
|
||||||
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_LEFT;
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_LEFT;
|
||||||
|
zephr_ctx->mouse.button = ZEPHR_MOUSE_BUTTON_LEFT;
|
||||||
break;
|
break;
|
||||||
case Button2:
|
case Button2:
|
||||||
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_MIDDLE;
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_MIDDLE;
|
||||||
|
zephr_ctx->mouse.button = ZEPHR_MOUSE_BUTTON_MIDDLE;
|
||||||
break;
|
break;
|
||||||
case Button3:
|
case Button3:
|
||||||
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_RIGHT;
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_RIGHT;
|
||||||
|
zephr_ctx->mouse.button = ZEPHR_MOUSE_BUTTON_RIGHT;
|
||||||
break;
|
break;
|
||||||
case Button4:
|
case Button4:
|
||||||
event_out->type = ZEPHR_EVENT_MOUSE_SCROLL;
|
event_out->type = ZEPHR_EVENT_MOUSE_SCROLL;
|
||||||
@@ -922,9 +986,11 @@ bool zephr_iter_events(ZephrEvent *event_out) {
|
|||||||
break;
|
break;
|
||||||
case 8: // Back
|
case 8: // Back
|
||||||
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_BACK;
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_BACK;
|
||||||
|
zephr_ctx->mouse.button = ZEPHR_MOUSE_BUTTON_BACK;
|
||||||
break;
|
break;
|
||||||
case 9: // Forward
|
case 9: // Forward
|
||||||
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_FORWARD;
|
event_out->mouse.button = ZEPHR_MOUSE_BUTTON_FORWARD;
|
||||||
|
zephr_ctx->mouse.button = ZEPHR_MOUSE_BUTTON_FORWARD;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("[WARN] Unknown mouse button pressed: %d\n", xev.xbutton.button);
|
printf("[WARN] Unknown mouse button pressed: %d\n", xev.xbutton.button);
|
||||||
@@ -935,6 +1001,8 @@ bool zephr_iter_events(ZephrEvent *event_out) {
|
|||||||
} else if (xev.type == ButtonRelease) {
|
} else if (xev.type == ButtonRelease) {
|
||||||
event_out->type = ZEPHR_EVENT_MOUSE_BUTTON_RELEASED;
|
event_out->type = ZEPHR_EVENT_MOUSE_BUTTON_RELEASED;
|
||||||
event_out->mouse.position = (Vec2){ .x = xev.xbutton.x, .y = xev.xbutton.y };
|
event_out->mouse.position = (Vec2){ .x = xev.xbutton.x, .y = xev.xbutton.y };
|
||||||
|
zephr_ctx->mouse.released = true;
|
||||||
|
zephr_ctx->mouse.pressed = false;
|
||||||
|
|
||||||
switch (xev.xbutton.button) {
|
switch (xev.xbutton.button) {
|
||||||
case Button1:
|
case Button1:
|
||||||
@@ -957,12 +1025,49 @@ bool zephr_iter_events(ZephrEvent *event_out) {
|
|||||||
XRefreshKeyboardMapping(&xev.xmapping);
|
XRefreshKeyboardMapping(&xev.xmapping);
|
||||||
/* x11_keyboard_map_update(); */
|
/* x11_keyboard_map_update(); */
|
||||||
break;
|
break;
|
||||||
|
} else if (xev.type == MotionNotify) {
|
||||||
|
event_out->type = ZEPHR_EVENT_MOUSE_MOVED;
|
||||||
|
event_out->mouse.position = (Vec2){ .x = xev.xmotion.x, .y = xev.xmotion.y };
|
||||||
|
zephr_ctx->mouse.pos = event_out->mouse.position;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void zephr_set_cursor(ZephrCursor cursor) {
|
||||||
|
if (zephr_ctx->cursor == cursor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
zephr_ctx->cursor = cursor;
|
||||||
|
|
||||||
|
switch (cursor) {
|
||||||
|
case ZEPHR_CURSOR_ARROW:
|
||||||
|
XDefineCursor(x11_display, x11_window, zephr_ctx->cursors[ZEPHR_CURSOR_ARROW]);
|
||||||
|
break;
|
||||||
|
case ZEPHR_CURSOR_IBEAM:
|
||||||
|
XDefineCursor(x11_display, x11_window, zephr_ctx->cursors[ZEPHR_CURSOR_IBEAM]);
|
||||||
|
break;
|
||||||
|
case ZEPHR_CURSOR_CROSSHAIR:
|
||||||
|
XDefineCursor(x11_display, x11_window, zephr_ctx->cursors[ZEPHR_CURSOR_CROSSHAIR]);
|
||||||
|
break;
|
||||||
|
case ZEPHR_CURSOR_HAND:
|
||||||
|
XDefineCursor(x11_display, x11_window, zephr_ctx->cursors[ZEPHR_CURSOR_HAND]);
|
||||||
|
break;
|
||||||
|
case ZEPHR_CURSOR_HRESIZE:
|
||||||
|
XDefineCursor(x11_display, x11_window, zephr_ctx->cursors[ZEPHR_CURSOR_HRESIZE]);
|
||||||
|
break;
|
||||||
|
case ZEPHR_CURSOR_VRESIZE:
|
||||||
|
XDefineCursor(x11_display, x11_window, zephr_ctx->cursors[ZEPHR_CURSOR_VRESIZE]);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
XDefineCursor(x11_display, x11_window, zephr_ctx->cursors[ZEPHR_CURSOR_ARROW]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* bool zephr_keyboard_scancode_is_pressed(ZephrScancode scancode) { */
|
/* bool zephr_keyboard_scancode_is_pressed(ZephrScancode scancode) { */
|
||||||
/* return core_bitset_is_set(zephr_ctx.keyboard.scancode_is_pressed_bitset, scancode); */
|
/* return core_bitset_is_set(zephr_ctx.keyboard.scancode_is_pressed_bitset, scancode); */
|
||||||
/* } */
|
/* } */
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ typedef enum ZephrEventType {
|
|||||||
ZEPHR_EVENT_MOUSE_BUTTON_RELEASED,
|
ZEPHR_EVENT_MOUSE_BUTTON_RELEASED,
|
||||||
ZEPHR_EVENT_MOUSE_SCROLL,
|
ZEPHR_EVENT_MOUSE_SCROLL,
|
||||||
ZEPHR_EVENT_WINDOW_RESIZED,
|
ZEPHR_EVENT_WINDOW_RESIZED,
|
||||||
ZEPHR_EVENT_WINDOW_CLOSED
|
ZEPHR_EVENT_WINDOW_CLOSED,
|
||||||
|
ZEPHR_EVENT_MOUSE_MOVED,
|
||||||
} ZephrEventType;
|
} ZephrEventType;
|
||||||
|
|
||||||
typedef enum ZephrMouseScrollDirection {
|
typedef enum ZephrMouseScrollDirection {
|
||||||
@@ -53,6 +54,17 @@ typedef enum ZephrMouseButton {
|
|||||||
ZEPHR_MOUSE_BUTTON_7,
|
ZEPHR_MOUSE_BUTTON_7,
|
||||||
} ZephrMouseButton;
|
} ZephrMouseButton;
|
||||||
|
|
||||||
|
typedef enum ZephrCursor {
|
||||||
|
ZEPHR_CURSOR_ARROW,
|
||||||
|
ZEPHR_CURSOR_IBEAM,
|
||||||
|
ZEPHR_CURSOR_CROSSHAIR,
|
||||||
|
ZEPHR_CURSOR_HAND,
|
||||||
|
ZEPHR_CURSOR_HRESIZE,
|
||||||
|
ZEPHR_CURSOR_VRESIZE,
|
||||||
|
|
||||||
|
ZEPHR_CURSOR_COUNT,
|
||||||
|
} ZephrCursor;
|
||||||
|
|
||||||
|
|
||||||
typedef u16 ZephrScancode;
|
typedef u16 ZephrScancode;
|
||||||
typedef u16 ZephrKeycode;
|
typedef u16 ZephrKeycode;
|
||||||
@@ -351,12 +363,22 @@ typedef struct ZephrEvent {
|
|||||||
} ZephrEvent;
|
} ZephrEvent;
|
||||||
/* CORE_DEFINE_STACK(ZephrEvent); */
|
/* CORE_DEFINE_STACK(ZephrEvent); */
|
||||||
|
|
||||||
|
typedef struct ZephrMouse {
|
||||||
|
Vec2 pos;
|
||||||
|
bool pressed;
|
||||||
|
bool released;
|
||||||
|
ZephrMouseButton button;
|
||||||
|
} ZephrMouse;
|
||||||
|
|
||||||
typedef struct ZephrContext {
|
typedef struct ZephrContext {
|
||||||
Atom window_delete_atom;
|
Atom window_delete_atom;
|
||||||
bool should_quit;
|
bool should_quit;
|
||||||
Size screen_size;
|
Size screen_size;
|
||||||
ZephrWindow window;
|
ZephrWindow window;
|
||||||
ZephrFont font;
|
ZephrFont font;
|
||||||
|
ZephrMouse mouse;
|
||||||
|
ZephrCursor cursor;
|
||||||
|
ZephrCursor cursors[ZEPHR_CURSOR_COUNT];
|
||||||
/* ZephrKeyboard keyboard; */
|
/* ZephrKeyboard keyboard; */
|
||||||
/* XkbDescPtr xkb; */
|
/* XkbDescPtr xkb; */
|
||||||
/* XIM xim; */
|
/* XIM xim; */
|
||||||
@@ -366,7 +388,7 @@ typedef struct ZephrContext {
|
|||||||
Matrix4x4 projection;
|
Matrix4x4 projection;
|
||||||
} ZephrContext;
|
} ZephrContext;
|
||||||
|
|
||||||
void zephr_init(const char* font_path, const char* window_title, Size window_size);
|
void zephr_init(const char* font_path, const char* icon_path, const char* window_title, Size window_size);
|
||||||
void zephr_deinit(void);
|
void zephr_deinit(void);
|
||||||
bool zephr_should_quit(void);
|
bool zephr_should_quit(void);
|
||||||
void zephr_swap_buffers(void);
|
void zephr_swap_buffers(void);
|
||||||
@@ -376,6 +398,7 @@ void zephr_toggle_fullscreen(void);
|
|||||||
void zephr_quit(void);
|
void zephr_quit(void);
|
||||||
Color ColorRGBA(u8 r, u8 g, u8 b, u8 a);
|
Color ColorRGBA(u8 r, u8 g, u8 b, u8 a);
|
||||||
bool zephr_iter_events(ZephrEvent *event_out);
|
bool zephr_iter_events(ZephrEvent *event_out);
|
||||||
|
void zephr_set_cursor(ZephrCursor cursor);
|
||||||
|
|
||||||
/* bool zephr_keyboard_keycode_is_pressed(ZephrKeycode keycode); */
|
/* bool zephr_keyboard_keycode_is_pressed(ZephrKeycode keycode); */
|
||||||
/* bool zephr_keyboard_keycode_has_been_pressed(ZephrKeycode keycode); */
|
/* bool zephr_keyboard_keycode_has_been_pressed(ZephrKeycode keycode); */
|
||||||
|
|||||||
Reference in New Issue
Block a user