#include "stdafx.h" #include "launcher/vehicle_picker.h" #include "renderer.h" #include "translation.h" ui::vehiclepicker_panel::vehiclepicker_panel() : ui_panel(STR("Select vehicle"), false), placeholder_mini("textures/mini/other") { bank.scan_textures(); } void ui::vehiclepicker_panel::render_contents() { ImGui::Columns(3); ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.0f, 0.5f)); if (ImGui::BeginChild("box1")) { for (auto const &e : type_names) { deferred_image *image = nullptr; auto it = bank.category_icons.find(e.first); if (it != bank.category_icons.end()) image = &it->second; if (selectable_image(Translations.lookup_s(e.second).c_str(), e.first == selected_type, image)) selected_type = e.first; } } ImGui::EndChild(); ImGui::NextColumn(); ImGui::TextUnformatted(STR_C("Group by: ")); ImGui::SameLine(); if (ImGui::RadioButton(STR_C("type"), !display_by_groups)) display_by_groups = false; ImGui::SameLine(); if (ImGui::RadioButton(STR_C("texture group"), display_by_groups)) display_by_groups = true; std::vector skinset_list; if (display_by_groups) { std::vector model_list; for (auto const &kv : bank.group_map) { const std::string &group = kv.first; bool model_added = false; bool can_break = false; bool map_sel_eq = (selected_group && group == *selected_group); for (auto const &vehicle : kv.second) { if (vehicle->type != selected_type) continue; for (auto const &skinset : vehicle->matching_skinsets) { bool map_group_eq = (skinset->group == group); bool sel_group_eq = (selected_group && skinset->group == *selected_group); if (!model_added && map_group_eq) { model_list.push_back(&group); model_added = true; } if (map_sel_eq) { if (sel_group_eq) skinset_list.push_back(skinset.get()); } else if (model_added) { can_break = true; break; } } if (can_break) break; } } if (ImGui::BeginChild("box2")) { ImGuiListClipper clipper(model_list.size()); while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { auto group = model_list[i]; deferred_image *image = nullptr; auto it = bank.group_icons.find(*group); if (it != bank.group_icons.end()) image = &it->second; if (selectable_image(group->c_str(), group == selected_group, image)) selected_group = group; } } } else { std::vector> model_list; for (auto const &v : bank.vehicles) { auto desc = v.second; if (selected_type == desc->type && desc->matching_skinsets.size() > 0) model_list.push_back(desc); if (selected_vehicle == desc && selected_type == desc->type) { for (auto &skin : desc->matching_skinsets) skinset_list.push_back(skin.get()); } } if (ImGui::BeginChild("box2")) { ImGuiListClipper clipper(model_list.size()); while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { auto &desc = model_list[i]; const deferred_image *image = nullptr; for (auto const &skinset : desc->matching_skinsets) { if (skinset->mini) { image = &skinset->mini; break; } } std::string label = desc->path.stem().string(); if (selectable_image(label.c_str(), desc == selected_vehicle, image)) selected_vehicle = desc; } } } ImGui::EndChild(); ImGui::NextColumn(); ImGui::SetNextItemWidth(-1); ImGui::InputText("##search", search_query.data(), search_query.size()); auto query_info = parse_search_query(search_query.data()); if (!query_info.empty()) skinset_list.erase(std::remove_if(skinset_list.begin(), skinset_list.end(), std::bind(&vehiclepicker_panel::skin_filter, this, std::placeholders::_1, query_info)), skinset_list.end()); if (ImGui::BeginChild("box3")) { ImGuiListClipper clipper(skinset_list.size()); while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { auto skin = skinset_list[i]; //std::string label = skin->skins[0].stem().string(); std::string label = skin->skin; if (skin->meta && !skin->meta->name.empty() && skin->meta->name != "?") label = skin->meta->name; auto mini = skin->mini ? &skin->mini : &placeholder_mini; if (selectable_image(label.c_str(), skin == selected_skinset, mini, skin)) selected_skinset = skin; if (skin->meta && ImGui::IsItemHovered()) { ImGui::BeginTooltip(); ImGui::Text(STR_C("Skin: %s\nType: %s\nCarrier code: %s\nDepot: %s\nMaintenance: %s, by %s\nSkin author: %s\nPhoto author: %s"), skin->skin.c_str(), skin->vehicle.lock()->path.string().c_str(), skin->meta->short_id.c_str(), skin->meta->location.c_str(), skin->meta->rev_date.c_str(), skin->meta->rev_company.c_str(), skin->meta->texture_author.c_str(), skin->meta->photo_author.c_str()); ImGui::EndTooltip(); } } } ImGui::EndChild(); ImGui::PopStyleVar(); } std::vector ui::vehiclepicker_panel::parse_search_query(const std::string &str) { std::vector info_list; std::istringstream query_stream(ToLower(str)); std::string term; while (std::getline(query_stream, term, ' ')) { size_t offset = 0; search_info info; if (offset < term.size() && term[offset] == '|') { info.alternative = true; offset++; } if (offset < term.size() && term[offset] == '!') { info.negation = true; offset++; } if (offset < term.size() && term[offset] == '<') { info.mode = search_info::YEAR_MAX; offset++; } if (offset < term.size() && term[offset] == '>') { info.mode = search_info::YEAR_MIN; offset++; } term = term.substr(offset); if (term.empty()) continue; if (info.mode == search_info::TEXT) { info.text = term; } else { std::istringstream num_parser(term); num_parser >> info.number; } info_list.push_back(info); } return info_list; } bool ui::vehiclepicker_panel::skin_filter(const skin_set *skin, std::vector &info_list) { bool any = false; bool alternative_present = false; for (auto const &term : info_list) { alternative_present |= term.alternative; bool found = false; if (term.mode == search_info::TEXT) { if (skin->skin.find(term.text) != -1) found = true; else if (skin->meta && skin->meta->search_lowered.find(term.text) != -1) found = true; } else if (skin->meta && skin->meta->rev_year != -1) { if (term.mode == search_info::YEAR_MIN) { if (skin->meta->rev_year >= term.number) found = true; } else if (term.mode == search_info::YEAR_MAX) { if (skin->meta->rev_year <= term.number) found = true; } } if (term.negation) found = !found; if (found && term.alternative) any = true; if (!found && !term.alternative) return true; } return alternative_present ? (!any) : false; } bool ui::vehiclepicker_panel::selectable_image(const char *desc, bool selected, const deferred_image* image, const skin_set *pickable) { ImGui::PushID(pickable); bool ret = ImGui::Selectable(desc, selected, 0, ImVec2(0, 30)); if (pickable) ImGui::SetItemAllowOverlap(); if (!image) { ImGui::PopID(); return ret; } GLuint tex = image->get(); if (tex != -1) { glm::ivec2 size = image->size(); float width = 30.0f / size.y * size.x; ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); ImGui::Image(reinterpret_cast(tex), ImVec2(width, 30), ImVec2(0, 1), ImVec2(1, 0)); if (pickable) { ImGui::PushID((void*)image); ImGui::SameLine(ImGui::GetContentRegionAvail().x - width); ImGui::InvisibleButton(desc, ImVec2(width, 30)); if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAutoExpirePayload)) { ImGui::Image(reinterpret_cast(tex), ImVec2(width, 30), ImVec2(0, 1), ImVec2(1, 0)); ImGui::SetDragDropPayload("vehicle_pure", &pickable, sizeof(skin_set*)); ImGui::EndDragDropSource(); } ImGui::PopID(); } } ImGui::PopID(); return ret; }