From 6f7374c2fa58c8692b51018864b802e6b876d305 Mon Sep 17 00:00:00 2001 From: Aldrik Ramaekers Date: Sat, 23 Nov 2024 21:52:24 +0100 Subject: A new start --- src/ui/animation.c | 18 +++++ src/ui/button.c | 101 +++++++++++++++++++++++++ src/ui/panel.c | 29 ++++++++ src/ui/portrait.c | 21 ++++++ src/ui/selectors.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 381 insertions(+) create mode 100644 src/ui/animation.c create mode 100644 src/ui/button.c create mode 100644 src/ui/panel.c create mode 100644 src/ui/portrait.c create mode 100644 src/ui/selectors.c (limited to 'src/ui') 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 -- cgit v1.2.3-70-g09d2