float MENUS::ui_do_scrollbar_v(const void *id, const RECT *rect, float current) { RECT handle; static float offset_y; ui_hsplit_t(rect, 33, &handle, 0); handle.y += (rect->h-handle.h)*current; /* logic */ float ret = current; int inside = ui_mouse_inside(&handle); if(ui_active_item() == id) { if(!ui_mouse_button(0)) ui_set_active_item(0); float min = rect->y; float max = rect->h-handle.h; float cur = ui_mouse_y()-offset_y; ret = (cur-min)/max; if(ret < 0.0f) ret = 0.0f; if(ret > 1.0f) ret = 1.0f; } else if(ui_hot_item() == id) { if(ui_mouse_button(0)) { ui_set_active_item(id); offset_y = ui_mouse_y()-handle.y; } } if(inside) ui_set_hot_item(id); // render RECT rail; ui_vmargin(rect, 5.0f, &rail); ui_draw_rect(&rail, vec4(1,1,1,0.25f), 0, 0.0f); RECT slider = handle; slider.w = rail.x-slider.x; ui_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_L, 2.5f); slider.x = rail.x+rail.w; ui_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_R, 2.5f); slider = handle; ui_margin(&slider, 5.0f, &slider); ui_draw_rect(&slider, vec4(1,1,1,0.25f)*button_color_mul(id), CORNER_ALL, 2.5f); return ret; }
MENUS::LISTBOXITEM MENUS::ui_do_listbox_nextitem(void *id) { RECT row; LISTBOXITEM item = {0}; ui_hsplit_t(&listbox_view, listbox_rowheight-2.0f, &row, &listbox_view); ui_hsplit_t(&listbox_view, 2.0f, 0, &listbox_view); RECT select_hit_box = row; item.visible = 1; if(listbox_selected_index == listbox_itemindex) item.selected = 1; // make sure that only those in view can be selected if(row.y+row.h > listbox_originalview.y) { if(select_hit_box.y < listbox_originalview.y) // clip the selection { select_hit_box.h -= listbox_originalview.y-select_hit_box.y; select_hit_box.y = listbox_originalview.y; } if(ui_do_button(id, "", listbox_selected_index==listbox_itemindex, &select_hit_box, 0, 0)) listbox_new_selected = listbox_itemindex; } else item.visible = 0; item.rect = row; // check if we need to do more if(row.y > listbox_originalview.y+listbox_originalview.h) item.visible = 0; if(listbox_selected_index==listbox_itemindex) { //selected_index = i; RECT r = row; ui_margin(&r, 1.5f, &r); ui_draw_rect(&r, vec4(1,1,1,0.5f), CORNER_ALL, 4.0f); } listbox_itemindex++; ui_vmargin(&item.rect, 5.0f, &item.rect); return item; }
void MENUS::ui_do_listbox_start(void *id, const RECT *rect, float row_height, const char *title, int num_items, int selected_index) { RECT scroll, row; RECT view = *rect; RECT header, footer; // draw header ui_hsplit_t(&view, listheader_height, &header, &view); ui_draw_rect(&header, vec4(1,1,1,0.25f), CORNER_T, 5.0f); ui_do_label(&header, title, header.h*fontmod_height, 0); // draw footers ui_hsplit_b(&view, listheader_height, &view, &footer); ui_draw_rect(&footer, vec4(1,1,1,0.25f), CORNER_B, 5.0f); ui_vsplit_l(&footer, 10.0f, 0, &footer); // background ui_draw_rect(&view, vec4(0,0,0,0.15f), 0, 0); // prepare the scroll ui_vsplit_r(&view, 15, &view, &scroll); // setup the variables listbox_originalview = view; listbox_selected_index = selected_index; listbox_new_selected = selected_index; listbox_itemindex = 0; listbox_rowheight = row_height; //int num_servers = client_serverbrowse_sorted_num(); // do the scrollbar ui_hsplit_t(&view, listbox_rowheight, &row, 0); int num = (int)(listbox_originalview.h/row.h); static float scrollvalue = 0; ui_hmargin(&scroll, 5.0f, &scroll); scrollvalue = ui_do_scrollbar_v(id, &scroll, scrollvalue); int start = (int)(num*scrollvalue); if(start < 0) start = 0; // the list listbox_view = listbox_originalview; ui_vmargin(&listbox_view, 5.0f, &listbox_view); ui_clip_enable(&listbox_view); listbox_view.y -= scrollvalue*num*row.h; }
int MENUS::render() { RECT screen = *ui_screen(); gfx_mapscreen(screen.x, screen.y, screen.w, screen.h); static bool first = true; if(first) { if(config.ui_page == PAGE_INTERNET) client_serverbrowse_refresh(0); else if(config.ui_page == PAGE_LAN) client_serverbrowse_refresh(1); first = false; } if(client_state() == CLIENTSTATE_ONLINE) { color_tabbar_inactive = color_tabbar_inactive_ingame; color_tabbar_active = color_tabbar_active_ingame; } else { render_background(); color_tabbar_inactive = color_tabbar_inactive_outgame; color_tabbar_active = color_tabbar_active_outgame; } RECT tab_bar; RECT main_view; // some margin around the screen ui_margin(&screen, 10.0f, &screen); if(popup == POPUP_NONE) { // do tab bar ui_hsplit_t(&screen, 24.0f, &tab_bar, &main_view); ui_vmargin(&tab_bar, 20.0f, &tab_bar); render_menubar(tab_bar); // news is not implemented yet if(config.ui_page <= PAGE_NEWS || config.ui_page > PAGE_SETTINGS || (client_state() == CLIENTSTATE_OFFLINE && config.ui_page >= PAGE_GAME && config.ui_page <= PAGE_CALLVOTE)) { client_serverbrowse_refresh(BROWSETYPE_INTERNET); config.ui_page = PAGE_INTERNET; } // render current page if(client_state() != CLIENTSTATE_OFFLINE) { if(game_page == PAGE_GAME) render_game(main_view); else if(game_page == PAGE_SERVER_INFO) render_serverinfo(main_view); else if(game_page == PAGE_CALLVOTE) render_servercontrol(main_view); else if(game_page == PAGE_SETTINGS) render_settings(main_view); } else if(config.ui_page == PAGE_NEWS) render_news(main_view); else if(config.ui_page == PAGE_INTERNET) render_serverbrowser(main_view); else if(config.ui_page == PAGE_LAN) render_serverbrowser(main_view); else if(config.ui_page == PAGE_DEMOS) render_demolist(main_view); else if(config.ui_page == PAGE_FAVORITES) render_serverbrowser(main_view); else if(config.ui_page == PAGE_SETTINGS) render_settings(main_view); // else if(config.ui_page == PAGE_TEE-NG) // renger_settings(main_teeng); } else { // make sure that other windows doesn't do anything funnay! //ui_set_hot_item(0); //ui_set_active_item(0); char buf[128]; const char *title = ""; const char *extra_text = ""; const char *button_text = ""; int extra_align = 0; if(popup == POPUP_MESSAGE) { title = message_topic; extra_text = message_body; button_text = message_button; } else if(popup == POPUP_CONNECTING) { title = localize("Connecting to"); extra_text = config.ui_server_address; // TODO: query the client about the address button_text = localize("Abort"); if(client_mapdownload_totalsize() > 0) { title = localize("Downloading map"); str_format(buf, sizeof(buf), "%d/%d KiB", client_mapdownload_amount()/1024, client_mapdownload_totalsize()/1024); extra_text = buf; } } else if(popup == POPUP_DISCONNECTED) { title = localize("Disconnected"); extra_text = client_error_string(); button_text = localize("Ok"); extra_align = -1; } else if(popup == POPUP_PURE) { title = localize("Disconnected"); extra_text = localize("The server is running a non-standard tuning on a pure game type."); button_text = localize("Ok"); extra_align = -1; } else if(popup == POPUP_PASSWORD) { title = localize("Password Incorrect"); extra_text = client_error_string(); button_text = localize("Try again"); } else if(popup == POPUP_QUIT) { title = localize("Quit"); extra_text = localize("Are you sure that you want to quit?"); } else if(popup == POPUP_FIRST_LAUNCH) { title = localize("Welcome to Teeworlds"); extra_text = localize("As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server."); button_text = localize("Ok"); extra_align = -1; } RECT box, part; box = screen; ui_vmargin(&box, 150.0f, &box); ui_hmargin(&box, 150.0f, &box); // render the box ui_draw_rect(&box, vec4(0,0,0,0.5f), CORNER_ALL, 15.0f); ui_hsplit_t(&box, 20.f, &part, &box); ui_hsplit_t(&box, 24.f, &part, &box); ui_do_label(&part, title, 24.f, 0); ui_hsplit_t(&box, 20.f, &part, &box); ui_hsplit_t(&box, 24.f, &part, &box); ui_vmargin(&part, 20.f, &part); if(extra_align == -1) ui_do_label(&part, extra_text, 20.f, -1, (int)part.w); else ui_do_label(&part, extra_text, 20.f, 0, -1); if(popup == POPUP_QUIT) { RECT yes, no; ui_hsplit_b(&box, 20.f, &box, &part); ui_hsplit_b(&box, 24.f, &box, &part); ui_vmargin(&part, 80.0f, &part); ui_vsplit_mid(&part, &no, &yes); ui_vmargin(&yes, 20.0f, &yes); ui_vmargin(&no, 20.0f, &no); static int button_abort = 0; if(ui_do_button(&button_abort, localize("No"), 0, &no, ui_draw_menu_button, 0) || escape_pressed) popup = POPUP_NONE; static int button_tryagain = 0; if(ui_do_button(&button_tryagain, localize("Yes"), 0, &yes, ui_draw_menu_button, 0) || enter_pressed) client_quit(); } else if(popup == POPUP_PASSWORD) { RECT label, textbox, tryagain, abort; ui_hsplit_b(&box, 20.f, &box, &part); ui_hsplit_b(&box, 24.f, &box, &part); ui_vmargin(&part, 80.0f, &part); ui_vsplit_mid(&part, &abort, &tryagain); ui_vmargin(&tryagain, 20.0f, &tryagain); ui_vmargin(&abort, 20.0f, &abort); static int button_abort = 0; if(ui_do_button(&button_abort, localize("Abort"), 0, &abort, ui_draw_menu_button, 0) || escape_pressed) { if(config.cl_autoconnect) config.cl_autoconnect == 0; else popup = POPUP_NONE; } static int button_tryagain = 0; if(ui_do_button(&button_tryagain, localize("Try again"), 0, &tryagain, ui_draw_menu_button, 0) || enter_pressed) { client_connect(config.ui_server_address); } ui_hsplit_b(&box, 60.f, &box, &part); ui_hsplit_b(&box, 24.f, &box, &part); ui_vsplit_l(&part, 60.0f, 0, &label); ui_vsplit_l(&label, 100.0f, 0, &textbox); ui_vsplit_l(&textbox, 20.0f, 0, &textbox); ui_vsplit_r(&textbox, 60.0f, &textbox, 0); ui_do_label(&label, localize("Password"), 20, -1); ui_do_edit_box(&config.password, &textbox, config.password, sizeof(config.password), 14.0f, true); } else if(popup == POPUP_FIRST_LAUNCH) { RECT label, textbox; ui_hsplit_b(&box, 20.f, &box, &part); ui_hsplit_b(&box, 24.f, &box, &part); ui_vmargin(&part, 80.0f, &part); static int enter_button = 0; if(ui_do_button(&enter_button, localize("Enter"), 0, &part, ui_draw_menu_button, 0) || enter_pressed) popup = POPUP_NONE; ui_hsplit_b(&box, 40.f, &box, &part); ui_hsplit_b(&box, 24.f, &box, &part); ui_vsplit_l(&part, 60.0f, 0, &label); ui_vsplit_l(&label, 100.0f, 0, &textbox); ui_vsplit_l(&textbox, 20.0f, 0, &textbox); ui_vsplit_r(&textbox, 60.0f, &textbox, 0); ui_do_label(&label, localize("Nickname"), 20, -1); ui_do_edit_box(&config.player_name, &textbox, config.player_name, sizeof(config.player_name), 14.0f); } else { ui_hsplit_b(&box, 20.f, &box, &part); ui_hsplit_b(&box, 24.f, &box, &part); ui_vmargin(&part, 120.0f, &part); static int button = 0; if(ui_do_button(&button, button_text, 0, &part, ui_draw_menu_button, 0) || escape_pressed || enter_pressed) { if(popup == POPUP_CONNECTING) client_disconnect(); popup = POPUP_NONE; } } } return 0; }
int MENUS::ui_do_edit_box(void *id, const RECT *rect, char *str, unsigned str_size, float font_size, bool hidden) { int inside = ui_mouse_inside(rect); int r = 0; static int at_index = 0; if(ui_last_active_item() == id) { int len = strlen(str); if (inside && ui_mouse_button(0)) { int mx_rel = (int)(ui_mouse_x() - rect->x); for (int i = 1; i <= len; i++) { if (gfx_text_width(0, font_size, str, i) + 10 > mx_rel) { at_index = i - 1; break; } if (i == len) at_index = len; } } for(int i = 0; i < num_inputevents; i++) { len = strlen(str); LINEINPUT::manipulate(inputevents[i], str, str_size, &len, &at_index); } } bool just_got_active = false; if(ui_active_item() == id) { if(!ui_mouse_button(0)) ui_set_active_item(0); } else if(ui_hot_item() == id) { if(ui_mouse_button(0)) { if (ui_last_active_item() != id) just_got_active = true; ui_set_active_item(id); } } if(inside) ui_set_hot_item(id); RECT textbox = *rect; ui_draw_rect(&textbox, vec4(1,1,1,0.5f), CORNER_ALL, 5.0f); ui_vmargin(&textbox, 5.0f, &textbox); const char *display_str = str; char stars[128]; if(hidden) { unsigned s = strlen(str); if(s >= sizeof(stars)) s = sizeof(stars)-1; memset(stars, '*', s); stars[s] = 0; display_str = stars; } ui_do_label(&textbox, display_str, font_size, -1); if (ui_last_active_item() == id && !just_got_active) { float w = gfx_text_width(0, font_size, display_str, at_index); textbox.x += w*ui_scale(); ui_do_label(&textbox, "_", font_size, -1); } return r; }