diff --git a/include/pgpl/gui/helpers.h b/include/pgpl/gui/helpers.h index 0d40863..a37b8a7 100644 --- a/include/pgpl/gui/helpers.h +++ b/include/pgpl/gui/helpers.h @@ -7,6 +7,13 @@ extern "C" { #endif +/* This function adjusts the values of the parameters that are passed to the + * event method to match the values that are passed to the render function. */ +void pgpl_gui_widget_adjust_event_params(PGPL_GuiWidget *widget, + PGPL_GuiTheme *theme, double *x, + double *y, double *max_width, + double *max_height); + /* This function basically subtracts margin, border and padding from the * max_width and max_height, and then return that through the width and height * pointers. */ @@ -31,6 +38,11 @@ void pgpl_gui_widget_render_full(PGPL_GuiWidget *widget, double x, double y, double max_width, double max_height); +/* Checks if a point is within the bounds of the area. */ +bool pgpl_gui_widget_within_area(double x, double y, double area_x, + double area_y, double area_width, + double area_height); + /* Checks if x and y lie within the visible bounds of a widget, accounting for * margin, border and padding and returns true or false. */ bool pgpl_gui_widget_within_bounds(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, diff --git a/include/pgpl/gui/widgets.h b/include/pgpl/gui/widgets.h index 57d002d..74d7495 100644 --- a/include/pgpl/gui/widgets.h +++ b/include/pgpl/gui/widgets.h @@ -89,6 +89,30 @@ PGPL_GuiWidget *pgpl_gui_empty_widget_create(void); /* Destroys a empty widget. */ void pgpl_gui_empty_widget_destroy(PGPL_GuiWidget *empty_widget); +/* This is the struct for a slider widget. The inversed option inverses its + * slide direction, vertical determines if it's vertical or horizontal. The + * bar_height is the height of the slider bar. The slide_callback gets called + * whenever there is sliding activity. */ +typedef struct PGPL_GuiSliderWidget { + PGPL_GuiWidget parent; + uint32_t bar_height; + bool inversed; + bool vertical; + double current_value; + void (*slide_callback)(void *app_data, double value); + /* Do not modify the following two attributes manually. */ + bool sliding; + double last_pos; +} PGPL_GuiSliderWidget; + +/* This creates a new slider with the given properties. */ +PGPL_GuiSliderWidget *pgpl_gui_slider_widget_create( + uint32_t bar_height, bool inversed, bool vertical, double value, + void (*slide_callback)(void *app_data, double value)); + +/* This destorys a slider widget. */ +void pgpl_gui_slider_widget_destroy(PGPL_GuiSliderWidget *slider_widget); + #ifdef __cplusplus } #endif diff --git a/include/pgpl/log.h b/include/pgpl/log.h index 5d36191..a878c45 100644 --- a/include/pgpl/log.h +++ b/include/pgpl/log.h @@ -7,17 +7,24 @@ extern "C" { #endif +/* These are the different supported logging levels. */ typedef enum PGPL_LogLevel { - PGPL_LOG_LEVEL_DEBUG, - PGPL_LOG_LEVEL_INFO, - PGPL_LOG_LEVEL_WARN, - PGPL_LOG_LEVEL_ERROR, + PGPL_LOG_LEVEL_DEBUG, /* For frequent debug prints, use this. */ + PGPL_LOG_LEVEL_INFO, /* For general info, that isn't spammed. */ + PGPL_LOG_LEVEL_WARN, /* For non-critical problems. */ + PGPL_LOG_LEVEL_ERROR, /* For critical problems that could halt the program */ } PGPL_LogLevel; +/* This sets the minimum level required for a message to be displayed. */ void pgpl_log_set_minimum_level(PGPL_LogLevel level); +/* This selects the file that things should be outputted to. By default this is + * goes to stderr. */ void pgpl_log_output_file(FILE *file); +/* This logs a message. This function can be used like printf. The output + * follows the following scheme: [ERROR] + * It is also terminated by a newline. */ void pgpl_log_message(PGPL_LogLevel level, const char *message, ...); #ifdef __cplusplus diff --git a/include/pgpl/window/thread.h b/include/pgpl/window/thread.h index 592d158..abcf21a 100644 --- a/include/pgpl/window/thread.h +++ b/include/pgpl/window/thread.h @@ -14,8 +14,9 @@ extern "C" { * can be any custom pointer to anything that might be needed inside of the * event_loop. If the user_data is not needed it can also be NULL. * - * Returning false from the event_loop will close the window. - */ + * Returning false from the event_loop will close the window. Do not call any of + * the window_thread functions from within the event loop, as this will cause + * the thread to lock up. Use the window functions directly. */ PGPL_WindowThread *pgpl_window_thread_create( const char *title, uint32_t width, uint32_t height, int32_t x, int32_t y, bool (*event_loop)(PGPL_Window *window, PGPL_WindowEventType event, @@ -93,8 +94,7 @@ void pgpl_window_thread_reparent_to(PGPL_WindowThread *window_thread, * pgpl_window_get_raw_window for more information. */ void *pgpl_window_thread_get_raw_window(PGPL_WindowThread *window_thread); -/* This function halts until the window_thread is destroyed. This function only - * works once per window_thread. */ +/* This function halts until the window_thread is destroyed. */ void pgpl_window_thread_await_destruction(PGPL_WindowThread *window_thread); #ifdef __cplusplus diff --git a/meson.build b/meson.build index ec059d5..a68962e 100644 --- a/meson.build +++ b/meson.build @@ -31,11 +31,13 @@ lib = both_libraries( 'src/render/shapes.c', 'src/render/texture.c', 'src/render/font.c', + 'src/render/render.c', 'src/gui/gui.c', 'src/gui/helpers.c', 'src/gui/widgets/text.c', 'src/gui/widgets/button.c', 'src/gui/widgets/container.c', + 'src/gui/widgets/slider.c', include_directories: include, dependencies: [ dependency('gl'), diff --git a/src/gui/helpers.c b/src/gui/helpers.c index dfb442c..78a8776 100644 --- a/src/gui/helpers.c +++ b/src/gui/helpers.c @@ -34,6 +34,71 @@ void pgpl_gui_theme_configure(PGPL_GuiTheme *theme, PGPL_Color base_color, theme->font = font; } +void pgpl_gui_widget_adjust_event_params(PGPL_GuiWidget *widget, + PGPL_GuiTheme *theme, double *x, + double *y, double *max_width, + double *max_height) { + double width, height; + + pgpl_gui_widget_max_content_size(widget, theme, &width, &height, *max_width, + *max_height); + + widget->get_content_size(widget, theme, &width, &height, width, height); + + if (!widget->expand_x) { + *max_width = width; + if (!widget->ignore_margin) { + *max_width += theme->margin.left + theme->margin.right; + } + if (!widget->ignore_border) { + *max_width += theme->border.left + theme->border.right; + } + if (!widget->ignore_padding) { + *max_width += theme->padding.left + theme->padding.right; + } + } + + if (!widget->expand_y) { + *max_height = height; + if (!widget->ignore_margin) { + *max_height += theme->margin.top + theme->margin.bottom; + } + if (!widget->ignore_border) { + *max_height += theme->border.top + theme->border.bottom; + } + if (!widget->ignore_padding) { + *max_height += theme->padding.top + theme->padding.bottom; + } + } + + if (!widget->ignore_margin) { + *x += theme->margin.left; + *y += theme->margin.top; + + *max_width -= theme->margin.left + theme->margin.right; + *max_height -= theme->margin.top + theme->margin.bottom; + } + + if (!widget->ignore_border) { + *x += theme->border.left; + *y += theme->border.top; + + *max_width -= theme->border.left + theme->border.right; + *max_height -= theme->border.top + theme->border.bottom; + } + + if (!widget->ignore_padding) { + *x += theme->padding.left; + *y += theme->padding.top; + + *max_width -= theme->padding.left + theme->padding.right; + *max_height -= theme->padding.top + theme->padding.bottom; + } + + *x += (*max_width - width) / 2; + *y += (*max_height - height) / 2; +} + void pgpl_gui_widget_max_content_size(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, double *width, double *height, double max_width, @@ -67,11 +132,13 @@ void pgpl_gui_widget_render_full(PGPL_GuiWidget *widget, theme = &widget->theme_override; } - x += +widget->offset_x; - y += +widget->offset_y; + x += widget->offset_x; + y += widget->offset_y; - widget->get_content_size(widget, theme, &width, &height, max_width, - max_height); + pgpl_gui_widget_max_content_size(widget, theme, &width, &height, max_width, + max_height); + + widget->get_content_size(widget, theme, &width, &height, width, height); if (!widget->expand_x) { max_width = width; @@ -143,6 +210,13 @@ void pgpl_gui_widget_render_full(PGPL_GuiWidget *widget, widget->render_content(widget, renderer, theme, x, y, max_width, max_height); } +bool pgpl_gui_widget_within_area(double x, double y, double area_x, + double area_y, double area_width, + double area_height) { + return (x >= area_x && x <= (area_x + area_width)) && + (y >= area_y && y <= (area_y + area_height)); +} + bool pgpl_gui_widget_within_bounds(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, double widget_x, double widget_y, double max_width, double max_height, @@ -155,12 +229,8 @@ bool pgpl_gui_widget_within_bounds(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, max_width -= theme->margin.left + theme->margin.right; max_height -= theme->margin.top + theme->margin.bottom; - if ((x >= widget_x && x <= (widget_x + max_width)) && - (y >= widget_y && y <= (widget_y + max_height))) { - return true; - } - - return false; + return pgpl_gui_widget_within_area(x, y, widget_x, widget_y, max_width, + max_height); } void pgpl_gui_widget_configure(PGPL_GuiWidget *widget, double offset_x, diff --git a/src/gui/widgets/container.c b/src/gui/widgets/container.c index ca4636e..a485309 100644 --- a/src/gui/widgets/container.c +++ b/src/gui/widgets/container.c @@ -5,8 +5,10 @@ static void get_content_size(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, double *width, double *height, double max_width, double max_height) { (void)widget; - pgpl_gui_widget_max_content_size(widget, theme, width, height, max_width, - max_height); + (void)theme; + + *width = max_width; + *height = max_height; } static void render_content(PGPL_GuiWidget *widget, PGPL_Renderer *renderer, @@ -79,12 +81,15 @@ static void event(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, PGPL_Gui *gui, for (uint32_t i = 0; i < length; i++) { PGPL_GuiWidget *child_widget = *(PGPL_GuiWidget **)pgpl_vector_get_index(container_layout->widgets, i); + PGPL_GuiTheme *child_theme; if (child_widget->use_theme_override) { - theme = &child_widget->theme_override; + child_theme = &child_widget->theme_override; + } else { + child_theme = theme; } - child_widget->event(child_widget, theme, gui, event_type, event_data, + child_widget->event(child_widget, child_theme, gui, event_type, event_data, x + child_widget->offset_x, y + child_widget->offset_y, max_width, max_height); diff --git a/src/gui/widgets/slider.c b/src/gui/widgets/slider.c new file mode 100644 index 0000000..9ca403c --- /dev/null +++ b/src/gui/widgets/slider.c @@ -0,0 +1,201 @@ +#include +#include + +static void get_slider_size(PGPL_GuiSliderWidget *slider_widget, + double *slider_x, double *slider_y, double x, + double y, double max_width, double max_height) { + double offset; + + if (slider_widget->inversed) { + offset = 1.0 - slider_widget->current_value; + } else { + offset = slider_widget->current_value; + } + + if (slider_widget->vertical) { + *slider_x = x - slider_widget->bar_height / 2.0; + *slider_y = y + offset * (max_height - slider_widget->bar_height) - + slider_widget->bar_height / 2.0; + } else { + *slider_x = x + offset * (max_width - slider_widget->bar_height) - + slider_widget->bar_height / 2.0; + *slider_y = y - slider_widget->bar_height / 2.0; + } +} + +static void get_content_size(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, + double *width, double *height, double max_width, + double max_height) { + PGPL_GuiSliderWidget *slider_widget = (PGPL_GuiSliderWidget *)widget; + + (void)theme; + + if (slider_widget->vertical) { + *width = slider_widget->bar_height; + *height = max_height; + } else { + *width = max_width; + *height = slider_widget->bar_height; + } +} + +static void render_content(PGPL_GuiWidget *widget, PGPL_Renderer *renderer, + PGPL_GuiTheme *theme, double x, double y, + double max_width, double max_height) { + PGPL_GuiSliderWidget *slider_widget = (PGPL_GuiSliderWidget *)widget; + + double slider_x; + double slider_y; + + double completion_x; + double completion_y; + double completion_width; + double completion_height; + + get_slider_size(slider_widget, &slider_x, &slider_y, x, y, max_width, + max_height); + + if (slider_widget->vertical) { + max_width = slider_widget->bar_height; + } else { + max_height = slider_widget->bar_height; + } + + pgpl_render_rectangle(renderer, theme->text_color[widget->gui_color], x, y, + max_width, max_height); + + pgpl_render_rectangle(renderer, theme->background_color, + x + slider_widget->bar_height / 4.0, + y + slider_widget->bar_height / 4.0, + max_width - slider_widget->bar_height / 2.0, + max_height - slider_widget->bar_height / 2.0); + + max_width -= slider_widget->bar_height / 2.0; + max_height -= slider_widget->bar_height / 2.0; + + if (slider_widget->inversed) { + if (slider_widget->vertical) { + completion_x = x + slider_widget->bar_height / 4.0; + completion_y = y + slider_widget->bar_height / 4.0 + + max_height * (1.0 - slider_widget->current_value); + completion_width = max_width; + completion_height = max_height * slider_widget->current_value; + } else { + completion_x = x + slider_widget->bar_height / 4.0 + + max_width * (1.0 - slider_widget->current_value); + completion_y = y + slider_widget->bar_height / 4.0; + completion_width = max_width * slider_widget->current_value; + completion_height = max_height; + } + } else { + completion_x = x + slider_widget->bar_height / 4.0; + completion_y = y + slider_widget->bar_height / 4.0; + + if (slider_widget->vertical) { + completion_width = max_width; + completion_height = max_height * slider_widget->current_value; + } else { + completion_width = max_width * slider_widget->current_value; + completion_height = max_height; + } + } + + pgpl_render_rectangle( + renderer, theme->widget_background_color[widget->gui_color], completion_x, + completion_y, completion_width, completion_height); + + pgpl_render_circle(renderer, theme->text_color[widget->gui_color], slider_x, + slider_y, slider_widget->bar_height, 32); +} + +static void event(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, PGPL_Gui *gui, + PGPL_WindowEventType event_type, + PGPL_WindowEventData *event_data, double x, double y, + double max_width, double max_height) { + if (event_type == PGPL_WINDOW_EVENT_MOUSE_PRESS || + event_type == PGPL_WINDOW_EVENT_MOUSE_RELEASE || + event_type == PGPL_WINDOW_EVENT_MOUSE_MOVE) { + PGPL_GuiSliderWidget *slider_widget = (PGPL_GuiSliderWidget *)widget; + double slider_x; + double slider_y; + + pgpl_gui_widget_adjust_event_params(widget, theme, &x, &y, &max_width, + &max_height); + + get_slider_size(slider_widget, &slider_x, &slider_y, x, y, max_width, + max_height); + + if (event_type == PGPL_WINDOW_EVENT_MOUSE_PRESS) { + if (pgpl_gui_widget_within_area(event_data->input_event.x, + event_data->input_event.y, slider_x, + slider_y, slider_widget->bar_height * 2, + slider_widget->bar_height * 2)) { + slider_widget->sliding = true; + if (slider_widget->vertical) { + slider_widget->last_pos = event_data->input_event.y; + } else { + slider_widget->last_pos = event_data->input_event.x; + } + } + } else if (event_type == PGPL_WINDOW_EVENT_MOUSE_RELEASE) { + slider_widget->sliding = false; + } else if (slider_widget->sliding) { + double new_pos; + double axis_length; + + if (slider_widget->vertical) { + new_pos = event_data->input_event.y; + axis_length = max_height; + } else { + new_pos = event_data->input_event.x; + axis_length = max_width; + } + + axis_length -= slider_widget->bar_height; + + if (slider_widget->inversed) { + slider_widget->current_value -= + (new_pos - slider_widget->last_pos) / axis_length; + } else { + slider_widget->current_value += + (new_pos - slider_widget->last_pos) / axis_length; + } + + if (slider_widget->current_value > 1.0) { + slider_widget->current_value = 1.0; + } else if (slider_widget->current_value < 0.0) { + slider_widget->current_value = 0.0; + } + + slider_widget->slide_callback(gui->app_data, + slider_widget->current_value); + + slider_widget->last_pos = new_pos; + } + } +} + +static void destroy(PGPL_GuiWidget *widget) { + pgpl_gui_slider_widget_destroy((PGPL_GuiSliderWidget *)widget); +} + +PGPL_GuiSliderWidget *pgpl_gui_slider_widget_create( + uint32_t bar_height, bool inversed, bool vertical, double value, + void (*slide_callback)(void *app_data, double value)) { + PGPL_GuiSliderWidget *slider_widget = calloc(1, sizeof(*slider_widget)); + slider_widget->parent.id = "PGPL_GuiSliderWidget"; + slider_widget->parent.get_content_size = get_content_size; + slider_widget->parent.render_content = render_content; + slider_widget->parent.event = event; + slider_widget->parent.destroy = destroy; + slider_widget->bar_height = bar_height; + slider_widget->inversed = inversed; + slider_widget->vertical = vertical; + slider_widget->current_value = value; + slider_widget->slide_callback = slide_callback; + return slider_widget; +} + +void pgpl_gui_slider_widget_destroy(PGPL_GuiSliderWidget *slider_widget) { + free(slider_widget); +} diff --git a/src/pgpl.c b/src/pgpl.c index bc498ae..bbf5bb6 100644 --- a/src/pgpl.c +++ b/src/pgpl.c @@ -1,3 +1,4 @@ +#include #include PGPL_Mutex *pgpl_internal_render_lock; @@ -5,6 +6,7 @@ PGPL_Mutex *pgpl_internal_log_lock; FILE *pgpl_internal_log_file; void pgpl_init(void) { + setlocale(LC_ALL, "C.UTF-8"); pgpl_internal_render_lock = pgpl_mutex_create(); pgpl_internal_log_lock = pgpl_mutex_create(); pgpl_internal_log_file = stderr; diff --git a/src/render/font.c b/src/render/font.c index 1d06cef..9151cb5 100644 --- a/src/render/font.c +++ b/src/render/font.c @@ -9,8 +9,8 @@ #define STBTT_STATIC #include -#define CHAR_AMOUNT 256 -#define BANK_AMOUNT 256 +#define CHAR_AMOUNT 8 +#define BANK_AMOUNT (65536 / CHAR_AMOUNT) typedef struct PGPL_FontBank { stbtt_bakedchar baked[CHAR_AMOUNT]; @@ -93,8 +93,8 @@ void pgpl_font_render_glyph(PGPL_Renderer *renderer, PGPL_Font *font, wchar_t c, PGPL_Color color, double x, double y, double size, double *xoff, double *yoff) { stbtt_aligned_quad q; - uint32_t bank_index = c / 256; - uint32_t bank_offset = c % 256; + uint32_t bank_index = c / CHAR_AMOUNT; + uint32_t bank_offset = c % CHAR_AMOUNT; double factor = size / font->glyph_size; float xoff_stb = *xoff; float yoff_stb = *yoff; @@ -121,7 +121,7 @@ void pgpl_font_render_glyph(PGPL_Renderer *renderer, PGPL_Font *font, wchar_t c, pgpl_render_texture_extended( renderer, font->banks[bank_index]->texture, (x + q.x0 * factor), - (y + q.y0 * factor + size / 1.75), (q.x1 - q.x0) * factor, + (y + q.y0 * factor + size / 1.6), (q.x1 - q.x0) * factor, (q.y1 - q.y0) * factor, color, q.s0, q.t0, q.s1, q.t1); *xoff = xoff_stb; @@ -164,8 +164,8 @@ void pgpl_font_glyph_dimensions(PGPL_Font *font, wchar_t c, double size, double *xoff, double *yoff, PGPL_Rectangle *rectangle) { stbtt_aligned_quad q; - uint32_t bank_index = c / 256; - uint32_t bank_offset = c % 256; + uint32_t bank_index = c / CHAR_AMOUNT; + uint32_t bank_offset = c % CHAR_AMOUNT; double factor = size / font->glyph_size; float xoff_stb = *xoff; float yoff_stb = *yoff; @@ -179,9 +179,9 @@ void pgpl_font_glyph_dimensions(PGPL_Font *font, wchar_t c, double size, font->glyph_size * font->chars_vertical, bank_offset, &xoff_stb, &yoff_stb, &q, 0); - rectangle->top = q.y0 * factor + size / 1.5; + rectangle->top = q.y0 * factor + size / 1.6; rectangle->left = q.x0 * factor; - rectangle->bottom = q.y1 * factor + size / 1.5; + rectangle->bottom = q.y1 * factor + size / 1.6; rectangle->right = q.x1 * factor; *xoff = xoff_stb; diff --git a/src/render/internal.h b/src/render/internal.h index eca7af3..a0ebcb4 100644 --- a/src/render/internal.h +++ b/src/render/internal.h @@ -13,3 +13,5 @@ struct PGPL_Texture { GLuint id; }; + +void pgpl_render_internal_handle_opengl_error(int line, const char *file); diff --git a/src/render/render.c b/src/render/render.c new file mode 100644 index 0000000..a0b844a --- /dev/null +++ b/src/render/render.c @@ -0,0 +1,42 @@ +#include "internal.h" + +void pgpl_render_internal_handle_opengl_error(int line, const char *file) { + GLenum error = glGetError(); + + if (error != GL_NO_ERROR) { + switch (error) { + case GL_INVALID_ENUM: + pgpl_log_message(PGPL_LOG_LEVEL_WARN, + "OpenGL invalid enum at line %d in file %s", line, file); + break; + case GL_INVALID_VALUE: + pgpl_log_message(PGPL_LOG_LEVEL_WARN, + "OpenGL invalid value at line %d in file %s", line, + file); + break; + case GL_INVALID_OPERATION: + pgpl_log_message(PGPL_LOG_LEVEL_WARN, + "OpenGL invalid operation at line %d", line); + break; + case GL_STACK_OVERFLOW: + pgpl_log_message(PGPL_LOG_LEVEL_WARN, + "OpenGL stack overflow at line %d in file %s", line, + file); + break; + case GL_STACK_UNDERFLOW: + pgpl_log_message(PGPL_LOG_LEVEL_WARN, + "OpenGL stack underflow at line %d in file %s", line, + file); + break; + case GL_OUT_OF_MEMORY: + pgpl_log_message(PGPL_LOG_LEVEL_ERROR, + "OpenGL out of memory at line %d in file %s", line, + file); + break; + default: + pgpl_log_message(PGPL_LOG_LEVEL_ERROR, + "Unknown OpenGL error at line %d in file %s", line, + file); + } + } +} diff --git a/src/render/texture.c b/src/render/texture.c index 871a721..6a81e0b 100644 --- a/src/render/texture.c +++ b/src/render/texture.c @@ -1,6 +1,4 @@ #include "internal.h" -#include -#include #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_STATIC @@ -94,6 +92,8 @@ PGPL_Texture *pgpl_render_create_texture(PGPL_Renderer *renderer, glTexImage2D(GL_TEXTURE_2D, 0, gl_format, width, height, 0, gl_format, GL_UNSIGNED_BYTE, data); + pgpl_render_internal_handle_opengl_error(__LINE__, __FILE__); + glBindTexture(GL_TEXTURE_2D, 0); return texture; diff --git a/src/string.c b/src/string.c index 4b83387..df2d1ab 100644 --- a/src/string.c +++ b/src/string.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -11,13 +10,11 @@ wchar_t *pgpl_string_to_wide_string(const char *str) { size_t length = strlen(str); wchar_t *wstr = malloc((length + 1) * sizeof(*wstr)); - setlocale(LC_ALL, "en_US.UTF-8"); - /* mbstowcs works just fine with UTF-8 strings on most platforms, except on * Windows, where we have to use MultiByteToWideChar to do the exact same * thing. */ #if defined(__WIN32__) - MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, str, -1, wstr, length + 1); + MultiByteToWideChar(CP_UTF8, 0, str, -1, wstr, length + 1); #else mbstowcs(wstr, str, length + 1); #endif diff --git a/src/window/window-win32.c b/src/window/window-win32.c index 0c29fe7..096f565 100644 --- a/src/window/window-win32.c +++ b/src/window/window-win32.c @@ -14,6 +14,7 @@ struct PGPL_Window { PGPL_Vector *window_proc_event_type; PGPL_Vector *window_proc_event_data; int32_t last_mouse_x, last_mouse_y; + int32_t scroll_accumulator; char title[128]; }; @@ -44,18 +45,30 @@ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, return DefWindowProc(hwnd, uMsg, wParam, lParam); } break; - case WM_KEYDOWN: + case WM_KEYDOWN: { + wchar_t buffer[16]; + BYTE keyboard_state[256]; + GetKeyboardState(keyboard_state); + buffer[ToUnicode(wParam, (lParam >> 16) & 0x00ff, keyboard_state, buffer, + 15, 0)] = 0; event_type = PGPL_WINDOW_EVENT_KEY_PRESS; - event_data.input_event.key = wParam; + event_data.input_event.key = buffer[0]; event_data.input_event.x = window->last_mouse_x; event_data.input_event.y = window->last_mouse_y; break; - case WM_KEYUP: + } + case WM_KEYUP: { + wchar_t buffer[16]; + BYTE keyboard_state[256]; + GetKeyboardState(keyboard_state); + buffer[ToUnicode(wParam, (lParam >> 16) & 0x00ff, keyboard_state, buffer, + 15, 0)] = 0; event_type = PGPL_WINDOW_EVENT_KEY_RELEASE; - event_data.input_event.key = wParam; + event_data.input_event.key = buffer[0]; event_data.input_event.x = window->last_mouse_x; event_data.input_event.y = window->last_mouse_y; break; + } case WM_LBUTTONDOWN: { POINTS points = MAKEPOINTS(lParam); event_type = PGPL_WINDOW_EVENT_MOUSE_PRESS; @@ -105,15 +118,18 @@ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, break; } case WM_MOUSEWHEEL: { - /* TODO: This code probably doesn't work that well. Unlike X11, this only - * returns a MOUSE_PRESS event, and if the scrolls are more granular, this - * will scroll really fast. - */ POINTS points = MAKEPOINTS(lParam); + window->scroll_accumulator += GET_WHEEL_DELTA_WPARAM(wParam); event_type = PGPL_WINDOW_EVENT_MOUSE_PRESS; event_data.input_event.x = points.x; event_data.input_event.y = points.y; - event_data.input_event.key = GET_WHEEL_DELTA_WPARAM(wParam) > 0 ? 4 : 5; + if (window->scroll_accumulator >= 120) { + event_data.input_event.key = 4; + window->scroll_accumulator -= 120; + } else if (window->scroll_accumulator <= -120) { + event_data.input_event.key = 5; + window->scroll_accumulator += 120; + } break; } case WM_MOUSEMOVE: { @@ -121,7 +137,7 @@ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, event_type = PGPL_WINDOW_EVENT_MOUSE_MOVE; window->last_mouse_x = points.x; window->last_mouse_y = points.y; - event_data.input_event.key = -1; + event_data.input_event.key = 0; event_data.input_event.x = points.x; event_data.input_event.y = points.y; break; diff --git a/src/window/window.c b/src/window/window.c index 59634bc..3d8e3bd 100644 --- a/src/window/window.c +++ b/src/window/window.c @@ -1,6 +1,5 @@ #include "internal.h" #include -#include #include /* Platform agnostic functions for our PGPL_Window "class" */ diff --git a/tests/program.c b/tests/program.c index fb86688..ba3f191 100644 --- a/tests/program.c +++ b/tests/program.c @@ -1,60 +1,48 @@ #include +#include #include #include #include #include struct AppData { - int counter; - char counter_buffer[128]; PGPL_Gui *gui; + char buffer[128]; }; -static void on_counter_button_click(void *data) { - struct AppData *app = data; - app->counter++; - snprintf(app->counter_buffer, sizeof(app->counter_buffer), "%d", - app->counter); - - if (app->counter % 10 == 0) { - pgpl_gui_theme_configure( - &app->gui->theme, - pgpl_color_create(rand() % 256, rand() % 256, rand() % 256, 255), 48, - app->gui->theme.font); - } +static void slide_callback(void *data, double value) { + struct AppData *app_data = data; + snprintf(app_data->buffer, 127, "%d", (int)(value * 100)); } static void configure_widget_default(PGPL_GuiWidget *widget) { - pgpl_gui_widget_configure(widget, 0, 0, true, true, true, true, + pgpl_gui_widget_configure(widget, 0, 0, true, true, false, false, PGPL_GUI_FONT_SIZE_CONTENT, NULL, false, false, false, false); } PGPL_GuiWidget *create_main_view(struct AppData *app) { - PGPL_GuiContainerLayout *column_layout; - PGPL_GuiButtonWidget *counter_button; - PGPL_GuiTextWidget *counter; + PGPL_GuiContainerLayout *layout; + PGPL_GuiSliderWidget *slider; + PGPL_GuiTextWidget *text; - column_layout = pgpl_gui_container_layout_create( - PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_VERTICAL); - pgpl_gui_widget_configure(&column_layout->parent, 0, 0, true, true, false, - false, PGPL_GUI_FONT_SIZE_CONTENT, NULL, false, - true, true, false); + layout = pgpl_gui_container_layout_create( + PGPL_GUI_CONTAINER_LAYOUT_DIRECTION_HORIZONTAL); + pgpl_gui_widget_configure(&layout->parent, 0, 0, true, true, false, false, + PGPL_GUI_FONT_SIZE_CONTENT, NULL, false, true, true, + false); - counter_button = - pgpl_gui_button_widget_create("Click me!", on_counter_button_click); - configure_widget_default(&counter_button->parent); + slider = pgpl_gui_slider_widget_create(16, true, true, 0.0, slide_callback); + configure_widget_default(&slider->parent); - counter = pgpl_gui_text_widget_create(app->counter_buffer); - configure_widget_default(&counter->parent); - counter->parent.font_size = PGPL_GUI_FONT_SIZE_TITLE; - counter->parent.background = false; - counter->parent.border = false; + text = pgpl_gui_text_widget_create(app->buffer); + configure_widget_default(&text->parent); + text->parent.font_size = PGPL_GUI_FONT_SIZE_TITLE; - pgpl_gui_container_layout_widget_add(column_layout, &counter->parent); - pgpl_gui_container_layout_widget_add(column_layout, &counter_button->parent); + pgpl_gui_container_layout_widget_add(layout, &text->parent); + pgpl_gui_container_layout_widget_add(layout, &slider->parent); - return (PGPL_GuiWidget *)column_layout; + return (PGPL_GuiWidget *)layout; } int32_t main(void) { @@ -67,15 +55,14 @@ int32_t main(void) { srand(time(NULL)); - strcpy(app.counter_buffer, "0"); - app.counter = 0; + strcpy(app.buffer, "0"); - font = pgpl_font_create_from_file("../roboto.ttf", 256); + font = pgpl_font_create_from_file("../roboto.ttf", 128); pgpl_gui_theme_configure(&theme, pgpl_color_create(255, 255, 255, 255), 48, font); - gui = pgpl_gui_create("PGPL Test", 320, 320, 0, 0, &theme, &app); + gui = pgpl_gui_create("PGPL Test", 480, 240, 0, 0, &theme, &app); app.gui = gui; diff --git a/todo.md b/todo.md index f02dbe1..6efbf13 100644 --- a/todo.md +++ b/todo.md @@ -1,9 +1,5 @@ # TODO -Win32 Blockers: -Translate keymaps on windows. -Fix the windows scrolling - Fun Features: - Further error handling on X11, Win32 API and more.