summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorAldrik Ramaekers <aldrikboy@gmail.com>2024-11-23 21:52:24 +0100
committerAldrik Ramaekers <aldrikboy@gmail.com>2024-11-23 21:52:24 +0100
commit6f7374c2fa58c8692b51018864b802e6b876d305 (patch)
treea7e8ead757e9f4de1920395336dcac1c8a989576 /src/ui
A new start
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/animation.c18
-rw-r--r--src/ui/button.c101
-rw-r--r--src/ui/panel.c29
-rw-r--r--src/ui/portrait.c21
-rw-r--r--src/ui/selectors.c212
5 files changed, 381 insertions, 0 deletions
diff --git a/src/ui/animation.c b/src/ui/animation.c
new file mode 100644
index 0000000..62775bf
--- /dev/null
+++ b/src/ui/animation.c
@@ -0,0 +1,18 @@
+animation animation_create(s32 duration)
+{
+ animation an;
+ an.time = 0;
+ an.started = false;
+ an.duration = duration;
+ an.percentage = 0.0f;
+ return an;
+}
+
+float animation_update(animation* an)
+{
+ if (!an->started) return an->percentage;
+ an->time += frame_delta*1000.0f;
+ if (an->time > an->duration) an->time = an->duration;
+ an->percentage = an->time/an->duration;
+ return an->percentage;
+} \ No newline at end of file
diff --git a/src/ui/button.c b/src/ui/button.c
new file mode 100644
index 0000000..773fb7b
--- /dev/null
+++ b/src/ui/button.c
@@ -0,0 +1,101 @@
+bool button_draw_background_percentage(float scale, s32 x, s32 y, s32 w, s32 h, color tint, color fill, float percentage, color bar_fill)
+{
+ s32 cornor_size = img_button_topleft->width*(scale/2);
+ s32 top_width = w - (cornor_size*2);
+ s32 size_height = h - (cornor_size*2);
+
+ // top
+ renderer->render_image_tint(img_button_topleft, x, y, cornor_size, cornor_size, tint);
+ renderer->render_image_tint(img_button_top, x + cornor_size, y, top_width, cornor_size, tint);
+ renderer->render_image_tint(img_button_topright, x + cornor_size + top_width, y, cornor_size, cornor_size, tint);
+
+ // left
+ renderer->render_image_tint(img_button_left, x, y + cornor_size-1, cornor_size, size_height+2, tint);
+
+ // right
+ renderer->render_image_tint(img_button_right, x + cornor_size + top_width, y + cornor_size-1, cornor_size, size_height+2, tint);
+
+ // bottom
+ renderer->render_image_tint(img_button_bottomleft, x, y + cornor_size + size_height, cornor_size, cornor_size, tint);
+ renderer->render_image_tint(img_button_bottom, x + cornor_size, y + cornor_size + size_height, top_width, cornor_size, tint);
+ renderer->render_image_tint(img_button_bottomright, x + cornor_size + top_width, y + cornor_size + size_height, cornor_size, cornor_size, tint);
+
+ // fill
+ s32 pad = cornor_size-1;
+ renderer->render_rectangle(x+pad, y+pad, w-(pad*2), h-(pad*2), fill);
+ renderer->render_rectangle(x+pad, y+pad, (w-(pad*2))*percentage, h-(pad*2), bar_fill);
+
+ return _global_mouse.x >= x && _global_mouse.x <= x + w && _global_mouse.y >= y && _global_mouse.y <= y + h;
+}
+
+bool button_draw_background(float scale, s32 x, s32 y, s32 w, s32 h, color tint, color fill)
+{
+ s32 cornor_size = img_button_topleft->width*(scale/2);
+ s32 top_width = w - (cornor_size*2);
+ s32 size_height = h - (cornor_size*2);
+
+ // top
+ renderer->render_image_tint(img_button_topleft, x, y, cornor_size, cornor_size, tint);
+ renderer->render_image_tint(img_button_top, x + cornor_size, y, top_width, cornor_size, tint);
+ renderer->render_image_tint(img_button_topright, x + cornor_size + top_width, y, cornor_size, cornor_size, tint);
+
+ // left
+ renderer->render_image_tint(img_button_left, x, y + cornor_size-1, cornor_size, size_height+2, tint);
+
+ // right
+ renderer->render_image_tint(img_button_right, x + cornor_size + top_width, y + cornor_size-1, cornor_size, size_height+2, tint);
+
+ // bottom
+ renderer->render_image_tint(img_button_bottomleft, x, y + cornor_size + size_height, cornor_size, cornor_size, tint);
+ renderer->render_image_tint(img_button_bottom, x + cornor_size, y + cornor_size + size_height, top_width, cornor_size, tint);
+ renderer->render_image_tint(img_button_bottomright, x + cornor_size + top_width, y + cornor_size + size_height, cornor_size, cornor_size, tint);
+
+ // fill
+ s32 pad = cornor_size-1;
+ renderer->render_rectangle(x+pad, y+pad, w-(pad*2), h-(pad*2), fill);
+
+ return _global_mouse.x >= x && _global_mouse.x <= x + w && _global_mouse.y >= y && _global_mouse.y <= y + h;
+}
+
+bool button_render(float scale, button_type enabled, char* text, s32 x, s32 y, s32 w, s32 h)
+{
+ bool result = false;
+
+ color tint = COLOR_WHITE;
+ color fill = COLOR_BUTTON;
+
+ if (enabled == BUTTON_ENABLED || enabled == BUTTON_HIGHLIGHTED) {
+ if (mouse_interacts(x,y,w,h)) {
+ platform_set_cursor(main_window, CURSOR_POINTER);
+ if (is_left_clicked()) {
+ result = true;
+ audio_play_sound(snd_click, AUDIO_CHANNEL_SFX_1);
+ }
+ tint = COLOR_BUTTON_ACTIVE_TINT;
+ fill = COLOR_BUTTON_ACTIVE;
+ }
+
+ if (enabled == BUTTON_HIGHLIGHTED) {
+ tint = COLOR_BUTTON_HIGHLIGHTED_TINT;
+ fill = COLOR_BUTTON_HIGHLIGHTED_ACTIVE;
+ }
+ }
+ else if (enabled == BUTTON_DISABLED) {
+ tint = COLOR_BUTTON_DISABLED_TINT;
+ fill = COLOR_BUTTON_DISABLED;
+ }
+
+ button_draw_background(scale,x,y,w,h,tint,fill);
+
+ // text
+ if (text) {
+ font* font_sml = fnt_rd24;
+ s32 text_y = y + (h/2) - (font_sml->px_h/2);
+ s32 game_title_width = renderer->calculate_text_width(font_sml, text);
+ s32 text_x = x + (w/2) - (game_title_width/2);
+
+ renderer->render_text(font_sml, text_x+1, text_y+1, text, COLOR_TEXT_SHADOW);
+ renderer->render_text(font_sml, text_x, text_y, text, COLOR_TEXT);
+ }
+ return result;
+} \ No newline at end of file
diff --git a/src/ui/panel.c b/src/ui/panel.c
new file mode 100644
index 0000000..af24e66
--- /dev/null
+++ b/src/ui/panel.c
@@ -0,0 +1,29 @@
+
+void panel_render(float scale, s32 x, s32 y, s32 w, s32 h)
+{
+ s32 cornor_size = img_panel_topleft->width*(scale/2);
+ log_assert(w > cornor_size*2, "Panel width too small");
+ log_assert(h > cornor_size*2, "Panel height too small");
+ s32 top_width = w - (cornor_size*2);
+ s32 size_height = h - (cornor_size*2);
+
+ // top
+ renderer->render_image(img_panel_topleft, x, y, cornor_size, cornor_size);
+ renderer->render_image(img_panel_top, x + cornor_size, y, top_width, cornor_size);
+ renderer->render_image(img_panel_topright, x + cornor_size + top_width, y, cornor_size, cornor_size);
+
+ // left
+ renderer->render_image(img_panel_left, x, y + cornor_size-1, cornor_size, size_height+2);
+
+ // right
+ renderer->render_image(img_panel_right, x + cornor_size + top_width, y + cornor_size-1, cornor_size, size_height+2);
+
+ // bottom
+ renderer->render_image(img_panel_bottomleft, x, y + cornor_size + size_height, cornor_size, cornor_size);
+ renderer->render_image(img_panel_bottom, x + cornor_size, y + cornor_size + size_height, top_width, cornor_size);
+ renderer->render_image(img_panel_bottomright, x + cornor_size + top_width, y + cornor_size + size_height, cornor_size, cornor_size);
+
+ // fill
+ s32 pad = cornor_size-1;
+ renderer->render_rectangle(x+pad, y+pad, w-(pad*2), h-(pad*2), COLOR_PANEL_BACKGROUND);
+} \ No newline at end of file
diff --git a/src/ui/portrait.c b/src/ui/portrait.c
new file mode 100644
index 0000000..09301fe
--- /dev/null
+++ b/src/ui/portrait.c
@@ -0,0 +1,21 @@
+void draw_employee_portrait(employee* emp, float x, float y, float w, float h)
+{
+ float body_s = h*0.8f;
+ float body_x = x + (w/2)-(body_s/2);
+ float body_y = y+h-body_s;
+
+ float head_s = h*0.45f;
+ float head_x = x + (w/2)-(head_s/2);
+ float head_y = y+(h*0.11f);
+
+ float hair_s = h*0.6f;
+ float hair_x = x + (w/2)-(hair_s/2);
+ float hair_y = y;
+
+ //renderer->render_image(img_portrait, x,y,w,h);
+
+ renderer->render_image_tint(img_portrait_head, head_x, head_y, head_s, head_s, emp->face_color);
+ renderer->render_image_tint(img_portrait_body, body_x, body_y, body_s, body_s, emp->body_color);
+ renderer->render_image_tint(img_portrait_hair[emp->portrait_hair_type], hair_x, hair_y, hair_s, hair_s, emp->hair_color);
+
+} \ No newline at end of file
diff --git a/src/ui/selectors.c b/src/ui/selectors.c
new file mode 100644
index 0000000..dc5a6bc
--- /dev/null
+++ b/src/ui/selectors.c
@@ -0,0 +1,212 @@
+
+employee* employee_selector_render(platform_window* window, float scale, bool enabled, employee* current_val, s32 x, s32 y, s32 w, s32 h, animation an, scheduled_job* offer) {
+ #define ANIMATION_OFFSET (-30*scale)
+ color text_color = AN_LI_TINT(COLOR_TEXT, an);
+ color c_tb_tint = AN_LI_TINT(COLOR_TEXTBOX_TINT, an);
+ color c_tb_fill = AN_LI_TINT(COLOR_TEXTBOX_FILL, an);
+ color c_white = AN_LI_TINT(COLOR_WHITE, an);
+ color c_correct = AN_LI_TINT(COLOR_CORRECT, an);
+ color c_wrong = AN_LI_TINT(COLOR_WRONG, an);
+ color c_btn = AN_LI_TINT(COLOR_BUTTON, an);
+
+ employee* result = current_val;
+
+ s32 tb_pad = 20*scale;
+ button_render(scale, BUTTON_STATIC, 0, x,y,w,h);
+
+ s32 tb_width = 220*scale;
+ s32 tb_height = h-(tb_pad*2);
+ s32 tb_y = y+tb_pad;
+ s32 tb_x = x+tb_pad + (ANIMATION_OFFSET - (ANIMATION_OFFSET*an.percentage));
+
+ {
+ // Start taking input on click.
+ if (button_draw_background(scale, tb_x,tb_y,tb_width,tb_height, c_tb_tint, c_tb_fill) && enabled) {
+ platform_set_cursor(window, CURSOR_POINTER);
+ if (is_left_clicked()) {
+ _global_keyboard.take_input = true;
+ _global_keyboard.input_mode = INPUT_NUMERIC;
+ }
+ }
+ // Clear on outside click or enter.
+ else if (is_left_clicked_peak()) {
+ _global_keyboard.take_input = false;
+ }
+ if (keyboard_is_key_pressed(KEY_ENTER)) {
+ _global_keyboard.take_input = false;
+ }
+
+ bool is_editing = _global_keyboard.take_input;
+
+ // Limit input length
+ if (is_editing) {
+ if (_global_keyboard.input_text_len > MAX_INPUT_LENGTH_FOR_EMPLOYEE_SELECTOR)
+ {
+ _global_keyboard.input_text_len = MAX_INPUT_LENGTH_FOR_EMPLOYEE_SELECTOR;
+ _global_keyboard.cursor = MAX_INPUT_LENGTH_FOR_EMPLOYEE_SELECTOR;
+ _global_keyboard.input_text[MAX_INPUT_LENGTH_FOR_EMPLOYEE_SELECTOR] = 0;
+ }
+
+ {
+ // Activation underline.
+ s32 linew = tb_width*0.95f;
+ s32 offsetw = (tb_width - linew)/2;
+ renderer->render_rectangle(tb_x+offsetw, tb_y+tb_height - 6, linew, 2, COLOR_SELECTOR_UNDERLINE);
+ }
+ }
+
+ font* fnt_big = fnt_rd32;
+ s32 textx = tb_x+(10*scale);
+ s32 texty = tb_y+(tb_height/2)-(fnt_big->px_h/2);
+
+ u32 text_id = string_to_u32(_global_keyboard.input_text);
+ employee* emp = is_editing ? get_global_employee_by_id(_active_world, text_id) : current_val;
+
+ if (is_editing || emp || _global_keyboard.input_text_len) // Editing, employee is selected, or player is typing.
+ {
+ s32 cursorh = tb_height*0.6f;
+
+ // Either display keyboard input or selected employee.
+ char idbuf[20];
+ if (is_editing || !emp) sprintf(idbuf, "ID: %s", _global_keyboard.input_text);
+ else if (emp) sprintf(idbuf, "ID: %d", emp->id);
+
+ s32 textw = renderer->render_text(fnt_big, textx, texty, idbuf, text_color);
+ if (is_editing) renderer->render_rectangle(textx+textw, tb_y+(tb_height/2)-(cursorh/2), 3, cursorh, text_color);
+ result = emp;
+ }
+ else if (!is_editing && !emp) { // Not editing and no employee selected.
+ renderer->render_text(fnt_big, textx, texty, "Search by ID..", text_color);
+ }
+
+ s32 status_s = tb_height/2;
+ s32 status_x = tb_x + tb_width - (status_s/4*3);
+ s32 status_y = tb_y - (status_s/4);
+ button_draw_background(scale,status_x,status_y,status_s,status_s,c_white,c_btn);
+ s32 status_icon_s = status_s*0.5f;
+ s32 status_icon_offset = (status_s - status_icon_s)/2;
+ renderer->render_image_tint(result ? img_checkmark : img_questionmark,
+ status_x+status_icon_offset, status_y+status_icon_offset, status_icon_s, status_icon_s, result ? c_correct : c_wrong);
+ }
+
+ // Draw employee data
+ if (result) {
+ s32 por_x = tb_x + tb_width + tb_pad;
+ draw_employee_portrait(result, por_x, tb_y, tb_height, tb_height);
+
+ s32 text_x = por_x + tb_height + tb_pad;
+ font* fnt = fnt_rd24;
+ font* fnt_s = fnt_rd20;
+ renderer->render_text(fnt,text_x,tb_y,result->name,text_color);
+
+ tb_y += fnt->px_h + (5*scale);
+
+ {
+ world_location* origin = get_world_location_by_id(_active_world, result->original_location_id);
+ char buf[100];
+ sprintf(buf, "Works at %s", origin->name);
+ renderer->render_text(fnt_s,text_x,tb_y,buf,text_color);
+ tb_y += fnt->px_h + (12*scale);
+ }
+
+ float hours_for_this_job = (offer->offer.duration_sec_min * get_shiptime_factor(result)) / 3600.0f;
+ float total_hours = get_worked_hours_per_week_for_employee(_active_world, result, (_active_schedule_state == RESCHEDULING_JOB ? _active_selected_scheduled_job : 0));
+
+ // If being scheduled, also add timeslots that are currently being scheduled.
+ if (enabled) {
+ for (s32 i = 0; i < MAX_SHIPDAYS; i++) {
+ scheduled_job_time slot = offer->timeslots[i];
+ if (slot.assignee == result) {
+ total_hours += hours_for_this_job;
+ if (!slot.stay_at_destination) total_hours += hours_for_this_job;
+ }
+ }
+ }
+ bool overworked = (total_hours > MAX_WORKED_HOURS_WEEKLY);
+ total_hours = ceil(total_hours);
+
+ color c = COLOR_TEXT;
+ if (overworked) c = COLOR_TEXT_NEGATIVE;
+ char txt_status[50];
+ sprintf(txt_status, "Currently scheduled for %.0fh/week", total_hours);
+ renderer->render_text(fnt_s,text_x,tb_y,txt_status,c);
+ }
+
+ return result;
+ #undef ANIMATION_OFFSET
+}
+
+world_location* location_selector_render(platform_window* window, float scale, bool enabled, world_location* current_val, s32 x, s32 y, s32 w, s32 h)
+{
+ world_location* result = current_val;
+ button_render(scale, BUTTON_STATIC, 0, x,y,w,h);
+
+ s32 tb_width = w;
+ s32 tb_height = h;
+ s32 tb_y = y;
+ s32 tb_x = x;
+
+ {
+ // Start taking input on click.
+ if (button_draw_background(scale, tb_x,tb_y,tb_width,tb_height, COLOR_TEXTBOX_TINT, COLOR_TEXTBOX_FILL) && enabled) {
+ platform_set_cursor(window, CURSOR_POINTER);
+ if (is_left_clicked()) {
+ _global_keyboard.take_input = true;
+ _global_keyboard.input_mode = INPUT_FULL;
+ }
+ }
+ // Clear on outside click or enter.
+ else if (is_left_clicked_peak()) {
+ _global_keyboard.take_input = false;
+ }
+ if (keyboard_is_key_pressed(KEY_ENTER)) {
+ _global_keyboard.take_input = false;
+ }
+
+ bool is_editing = _global_keyboard.take_input;
+
+ // Limit input length
+ if (is_editing) {
+ if (_global_keyboard.input_text_len > MAX_WORLD_LOCATION_NAME_LENGTH)
+ {
+ _global_keyboard.input_text_len = MAX_WORLD_LOCATION_NAME_LENGTH;
+ _global_keyboard.cursor = MAX_WORLD_LOCATION_NAME_LENGTH;
+ _global_keyboard.input_text[MAX_WORLD_LOCATION_NAME_LENGTH] = 0;
+ }
+ }
+
+ font* fnt_big = fnt_rd32;
+ s32 textx = tb_x+(10*scale);
+ s32 texty = tb_y+(tb_height/2)-(fnt_big->px_h/2);
+
+ world_location* emp = is_editing ? get_world_location_by_name(_active_world, _global_keyboard.input_text) : current_val;
+
+ if (is_editing || emp || _global_keyboard.input_text_len) // Editing, employee is selected, or player is typing.
+ {
+ s32 cursorh = tb_height*0.6f;
+
+ // Either display keyboard input or selected employee.
+ char idbuf[50];
+ if (is_editing || !emp) sprintf(idbuf, "Name: %s", _global_keyboard.input_text);
+ else if (emp) sprintf(idbuf, "Name: %s", emp->name);
+
+ s32 textw = renderer->render_text(fnt_big, textx, texty, idbuf, COLOR_TEXT);
+ if (is_editing) renderer->render_rectangle(textx+textw, tb_y+(tb_height/2)-(cursorh/2), 3, cursorh, COLOR_TEXT);
+ result = emp;
+ }
+ else if (!is_editing && !emp) { // Not editing and no employee selected.
+ renderer->render_text(fnt_big, textx, texty, "Filter location..", COLOR_TEXT);
+ }
+
+ s32 status_s = tb_height/2;
+ s32 status_x = tb_x + tb_width - (status_s/4*3);
+ s32 status_y = tb_y - (status_s/4);
+ button_draw_background(scale,status_x,status_y,status_s,status_s,COLOR_WHITE,COLOR_BUTTON);
+ s32 status_icon_s = status_s*0.5f;
+ s32 status_icon_offset = (status_s - status_icon_s)/2;
+ renderer->render_image_tint(result ? img_checkmark : img_questionmark,
+ status_x+status_icon_offset, status_y+status_icon_offset, status_icon_s, status_icon_s, result ? COLOR_CORRECT : COLOR_WRONG);
+ }
+
+ return result;
+} \ No newline at end of file