void RoR::GUI::MultiplayerSelector::MultiplayerSelector::Draw() { const float TABS_BOTTOM_PADDING = 4.f; // They're actually buttons in role of tabs. const float CONTENT_TOP_PADDING = 4.f; // Extra space under top horizontal separator bar. const float BUTTONS_EXTRA_SPACE = 6.f; const float TABLE_PADDING_LEFT = 4.f; int window_flags = ImGuiWindowFlags_NoCollapse; ImGui::SetNextWindowSize(ImVec2(750.f, 400.f), ImGuiSetCond_FirstUseEver); if (!ImGui::Begin(m_window_title, &m_is_visible, window_flags)) { return; } if (!m_is_visible) // If the window was closed... { App::GetGuiManager()->SetVisible_GameMainMenu(true); } // Window mode buttons MultiplayerSelector::Mode next_mode = m_mode; if (ImGui::Button("Online (click to refresh)")) { if (m_mode == Mode::ONLINE) this->RefreshServerlist(); else next_mode = Mode::ONLINE; } ImGui::SameLine(); if (ImGui::Button("Direct IP")) { next_mode = Mode::DIRECT; } ImGui::SameLine(); if (ImGui::Button("Setup")) { next_mode = Mode::SETUP; } ImGui::SetCursorPosY(ImGui::GetCursorPosY() + TABS_BOTTOM_PADDING); ImGui::Separator(); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + CONTENT_TOP_PADDING); m_mode = next_mode; if (m_mode == Mode::SETUP) { ImGui::PushID("setup"); DrawGCheckbox(App::mp_join_on_startup, "Auto connect"); DrawGCheckbox(App::mp_chat_auto_hide, "Auto hide chat"); DrawGCheckbox(App::mp_hide_net_labels, "Hide net labels"); DrawGCheckbox(App::mp_hide_own_net_label, "Hide own net label"); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + BUTTONS_EXTRA_SPACE); ImGui::Separator(); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + CONTENT_TOP_PADDING); ImGui::PushItemWidth(250.f); DrawGTextEdit(App::mp_player_name, "Player nickname", m_player_name_buf); DrawGTextEdit(App::mp_server_password, "Default server password", m_password_buf); ImGui::PopItemWidth(); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + BUTTONS_EXTRA_SPACE); ImGui::Separator(); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + CONTENT_TOP_PADDING); ImGui::PushItemWidth(250.f); ImGui::InputText("Player token", m_user_token_buf.GetBuffer(), m_user_token_buf.GetCapacity()); ImGui::PopItemWidth(); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + BUTTONS_EXTRA_SPACE); if (ImGui::Button("Update saved hash") && (m_user_token_buf.GetLength() > 0)) { RoR::CSHA1 sha1; uint8_t* input_text = (uint8_t *)m_user_token_buf.GetBuffer(); uint32_t input_size = (uint32_t)m_user_token_buf.GetLength(); sha1.UpdateHash(input_text, input_size); sha1.Final(); Str<250> hash; sha1.ReportHash(hash.GetBuffer(), RoR::CSHA1::REPORT_HEX_SHORT); App::mp_player_token_hash.SetActive(hash.ToCStr()); m_user_token_buf.Clear(); } ImGui::SameLine(); ImGui::TextDisabled(" Hash: [%s]", App::mp_player_token_hash.GetActive()); ImGui::PopID(); } else if (m_mode == Mode::DIRECT) { ImGui::PushID("direct"); ImGui::PushItemWidth(250.f); DrawGTextEdit(App::mp_server_host, "Server host", m_server_host_buf); DrawGIntBox(App::mp_server_port, "Server port"); DrawGTextEdit(App::mp_server_password, "Server password (default)", m_password_buf); ImGui::PopItemWidth(); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + BUTTONS_EXTRA_SPACE); if (ImGui::Button("Join")) { App::mp_state.SetPending (MpState::CONNECTED); } ImGui::PopID(); } else if (m_mode == Mode::ONLINE) { const char* draw_label_text = nullptr; ImVec4 draw_label_color; bool draw_table = false; // DETERMINE WHAT TO DRAW if (m_is_refreshing) { draw_label_text = "... refreshing ..."; draw_label_color = App::GetGuiManager()->GetTheme().in_progress_text_color; } else if (m_serverlist_data != nullptr) { if (m_serverlist_data->success == true) { draw_table = true; if (m_serverlist_data->servers.size() == 0) { draw_label_text = "There are no available servers :/"; // Draw empty table _and_ the label. draw_label_color = App::GetGuiManager()->GetTheme().no_entries_text_color; } } else { draw_label_text = m_serverlist_data->message.c_str(); draw_label_color = App::GetGuiManager()->GetTheme().error_text_color; } } // DRAW SERVERLIST TABLE if (draw_table) { // Setup serverlist table ... the scroll area const float table_height = ImGui::GetWindowHeight() - ((2.f * ImGui::GetStyle().WindowPadding.y) + (3.f * ImGui::GetItemsLineHeightWithSpacing()) + TABS_BOTTOM_PADDING + CONTENT_TOP_PADDING - ImGui::GetStyle().ItemSpacing.y); ImGui::BeginChild("scrolling", ImVec2(0.f, table_height), false); // ... and the table itself const float table_width = ImGui::GetWindowContentRegionWidth(); ImGui::Columns(6, "mp-selector-columns"); // Col #0: Passwd ImGui::SetColumnOffset(1, 0.08f * table_width); // Col #1: Server name ImGui::SetColumnOffset(2, 0.35f * table_width); // Col #2: Terrain name ImGui::SetColumnOffset(3, 0.70f * table_width); // Col #3: Users/Max ImGui::SetColumnOffset(4, 0.77f * table_width); // Col #4: Ping ImGui::SetColumnOffset(5, 0.82f * table_width); // Col #5: Host/Port // Draw table header ImGui::SetCursorPosX(ImGui::GetCursorPosX() + TABLE_PADDING_LEFT); DrawTableHeader("Passwd?"); DrawTableHeader("Name"); DrawTableHeader("Terrain"); DrawTableHeader("Users"); DrawTableHeader("Ping"); DrawTableHeader("Host/Port"); ImGui::Separator(); // Draw table body int num_servers = static_cast<int>(m_serverlist_data->servers.size()); for (int i = 0; i < num_servers; i++) { ImGui::PushID(i); // First column - selection control ImGui::SetCursorPosX(ImGui::GetCursorPosX() + TABLE_PADDING_LEFT); MpServerlistData::ServerInfo& server = m_serverlist_data->servers[i]; if (ImGui::Selectable(server.display_passwd, m_selected_item == i, ImGuiSelectableFlags_SpanAllColumns)) { m_selected_item = i; } ImGui::NextColumn(); // Other collumns ImGui::Text("%s", server.display_name.ToCStr()); ImGui::NextColumn(); ImGui::Text("%s", server.display_terrn.ToCStr()); ImGui::NextColumn(); ImGui::Text("%s", server.display_users.ToCStr()); ImGui::NextColumn(); ImGui::Text("~"); ImGui::NextColumn(); // TODO: ping ImGui::Text("%s", server.display_host.ToCStr()); ImGui::NextColumn(); ImGui::PopID(); } ImGui::Columns(1); ImGui::EndChild(); // End of scroll area // Simple join button if (m_selected_item != -1) { if (ImGui::Button("Join", ImVec2(200.f, 0.f))) { App::mp_server_host.SetActive(m_serverlist_data->servers[m_selected_item].net_host); App::mp_server_port.SetActive(m_serverlist_data->servers[m_selected_item].net_port); App::mp_state.SetPending(MpState::CONNECTED); } } } // DRAW CENTERED LABEL if (draw_label_text != nullptr) { const ImVec2 label_size = ImGui::CalcTextSize(draw_label_text); ImGui::SetCursorPosX((ImGui::GetWindowSize().x / 2.f) - (label_size.x / 2.f)); ImGui::SetCursorPosY((ImGui::GetWindowSize().y / 2.f) - (label_size.y / 2.f)); ImGui::TextColored(draw_label_color, "%s", draw_label_text); } } ImGui::End(); }
void RoR::GUI::GameSettings::Draw() { bool is_visible = true; const int flags = ImGuiWindowFlags_NoCollapse; ImGui::SetNextWindowSize(ImVec2(600.f, 400.f), ImGuiSetCond_FirstUseEver); ImGui::SetNextWindowPosCenter(ImGuiSetCond_Appearing); ImGui::Begin(_LC("GameSettings", "Game settings"), &is_visible, flags); if (! is_visible) { this->SetVisible(false); if (App::app_state.GetActive() == RoR::AppState::MAIN_MENU) { App::GetGuiManager()->SetVisible_GameMainMenu(true); } ImGui::End(); return; } // 'Tabs' buttons ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.f, 8.f)); if (ImGui::Button(_LC("GameSettings", "Render System"))) { m_tab = SettingsTab::RENDER_SYSTEM; } ImGui::SameLine(); if (ImGui::Button(_LC("GameSettings", "General"))) { m_tab = SettingsTab::GENERAL; } ImGui::SameLine(); if (ImGui::Button(_LC("GameSettings", "Graphics"))) { m_tab = SettingsTab::GRAPHICS; } ImGui::SameLine(); #ifdef USE_OPENAL if (ImGui::Button(_LC("GameSettings", "Audio"))) { m_tab = SettingsTab::AUDIO; } ImGui::SameLine(); #endif // USE_OPENAL if (ImGui::Button(_LC("GameSettings", "Controls"))) { m_tab = SettingsTab::CONTROL; } ImGui::SameLine(); if (ImGui::Button(_LC("GameSettings", "Diagnostic"))) { m_tab = SettingsTab::DIAG; } ImGui::SameLine(); if (ImGui::Button(_LC("GameSettings", "Update cache"))) { App::app_force_cache_udpate.SetActive(true); } ImGui::PopStyleVar(1); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 4.f); ImGui::Separator(); if (m_tab == SettingsTab::RENDER_SYSTEM) { ImGui::TextDisabled(_LC("GameSettings", "Render system (changes require a restart)")); const auto ogre_root = App::GetOgreSubsystem()->GetOgreRoot(); const auto render_systems = ogre_root->getAvailableRenderers(); std::string render_system_names; for (auto rs : render_systems) { render_system_names += rs->getName() + '\0'; } const auto ro = ogre_root->getRenderSystemByName(App::app_rendersys_override.GetActive()); const auto rs = ro ? ro : ogre_root->getRenderSystem(); const auto it = std::find(render_systems.begin(), render_systems.end(), rs); int render_id = it != render_systems.end() ? std::distance(render_systems.begin(), it) : 0; /* Combobox for selecting the Render System*/ if (ImGui::Combo(_LC ("GameSettings", "Render System"), &render_id, render_system_names.c_str())) { App::app_rendersys_override.SetActive(render_systems[render_id]->getName().c_str()); } const auto config_options = ogre_root->getRenderSystem()->getConfigOptions(); std::set<std::string> filter = {"Allow NVPerfHUD", "Colour Depth", "Fixed Pipeline Enabled", "Floating-point mode", "Resource Creation Policy", "VSync Interval", "sRGB Gamma Conversion"}; for (auto opt : config_options) { auto co = opt.second; if (co.immutable) continue; if (co.possibleValues.empty()) continue; if (filter.find(co.name) != filter.end()) continue; std::sort(co.possibleValues.rbegin(), co.possibleValues.rend()); std::string option_values; for (auto value : co.possibleValues) { option_values += value + '\0'; } const auto it = std::find(co.possibleValues.begin(), co.possibleValues.end(), opt.second.currentValue); int option_id = it != co.possibleValues.end() ? std::distance(co.possibleValues.begin(), it) : 0; if (ImGui::Combo(co.name.c_str(), &option_id, option_values.c_str())) { rs->setConfigOption(co.name, co.possibleValues[option_id]); if (rs->validateConfigOptions().empty()) { ogre_root->saveConfig(); } } } } else if (m_tab == SettingsTab::GENERAL) { ImGui::TextDisabled(_LC("GameSettings", "Application settings")); #ifndef NOLANG std::vector<std::pair<std::string, std::string>> languages = LanguageEngine::getSingleton().getLanguages(); std::string lang_values; for (auto value : languages) { lang_values += value.first + '\0'; } const auto it = std::find_if(languages.begin(), languages.end(), [](const std::pair<std::string, std::string>& l) { return l.second == App::app_language.GetActive(); }); int lang_selection = it != languages.end() ? std::distance(languages.begin(), it) : 0; if (ImGui::Combo(_LC("GameSettings", "Language"), &lang_selection, lang_values.c_str())) { App::app_language.SetActive(languages[lang_selection].second.c_str()); LanguageEngine::getSingleton().setup(); } #endif // Country selection static Ogre::FileInfoListPtr fl = Ogre::ResourceGroupManager::getSingleton().findResourceFileInfo("FlagsRG", "*"); if (!fl->empty()) { static std::vector<std::string> countries; if (countries.empty()) { for (auto& file : *fl) { std::string country = Ogre::StringUtil::replaceAll(file.filename, ".png", ""); if (country.size() == 2) // RoR protocol limitation { countries.push_back(country); } } std::sort(countries.begin(), countries.end()); } std::string country_values; for (auto value : countries) { country_values += value + '\0'; } const auto it = std::find(countries.begin(), countries.end(), std::string(App::app_country.GetActive())); int country_selection = it != countries.end() ? std::distance(countries.begin(), it) : 0; if (ImGui::Combo(_LC("GameSettings", "Country"), &country_selection, country_values.c_str())) { App::app_country.SetActive(countries[country_selection].c_str()); } } int sshot_select = (std::strcmp(App::app_screenshot_format.GetActive(),"jpg") == 0) ? 1 : 0; // Hardcoded; TODO: list available formats. /* Screenshot format: Can be png or jpg*/ if (ImGui::Combo(_LC("GameSettings", "Screenshot format"), &sshot_select, "png\0jpg\0\0")) { App::app_screenshot_format.SetActive((sshot_select == 1) ? "jpg" : "png"); } DrawGTextEdit(App::app_extra_mod_path, _LC("GameSettings", "Extra mod path"), m_buf_app_extra_mod_dir); DrawGCheckbox(App::app_skip_main_menu, _LC("GameSettings", "Skip main menu")); DrawGCheckbox(App::app_async_physics, _LC("GameSettings", "Async physics")); DrawGCheckbox(App::app_disable_online_api, _LC("GameSettings", "Disable online api")); ImGui::Separator(); ImGui::TextDisabled(_LC("GameSettings", "Simulation settings")); DrawGCombo(App::sim_gearbox_mode, _LC("GameSettings", "Gearbox mode"), "Automatic shift\0" "Manual shift - Auto clutch\0" "Fully Manual: sequential shift\0" "Fully manual: stick shift\0" "Fully Manual: stick shift with ranges\00"); DrawGCheckbox(App::gfx_speedo_digital, _LC("GameSettings", "Digital speedometer")); DrawGCheckbox(App::gfx_speedo_imperial, _LC("GameSettings", "Imperial speedometer")); //DrawGCheckbox(App::gfx_flexbody_lods, "Enable flexbody LODs"); //DrawGCheckbox(App::gfx_flexbody_cache, "Enable flexbody cache"); DrawGCheckbox(App::sim_spawn_running, _LC("GameSettings", "Engines spawn running")); DrawGCheckbox(App::sim_replay_enabled, _LC("GameSettings", "Replay mode")); if (App::sim_replay_enabled.GetActive()) { DrawGIntBox(App::sim_replay_length, _LC("GameSettings", "Replay length")); DrawGIntBox(App::sim_replay_stepping, _LC("GameSettings", "Replay stepping")); } DrawGCheckbox(App::sim_realistic_commands, _LC("GameSettings", "Realistic forward commands")); DrawGCheckbox(App::sim_races_enabled, _LC("GameSettings", "Enable races")); DrawGCheckbox(App::sim_direction_arrow, _LC("GameSettings", "Direction arrow")); DrawGCheckbox(App::sim_no_self_collisions, _LC("GameSettings", "No intra truck collisions")); DrawGCheckbox(App::sim_no_collisions, _LC("GameSettings", "No inter truck collisions")); } #ifdef USE_OPENAL else if (m_tab == SettingsTab::AUDIO) { ImGui::TextDisabled(_LC("GameSettings", "Audio settings")); static const ALCchar *devices = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); const ALCchar *device = devices, *next = devices + 1; std::vector<std::string> audio_devices; while (device && *device != '\0' && next && *next != '\0') { audio_devices.push_back(device); size_t len = strlen(device); device += (len + 1); next += (len + 2); } const auto it = std::find(audio_devices.begin(), audio_devices.end(), App::audio_device_name.GetActive()); int device_id = it != audio_devices.end() ? std::distance(audio_devices.begin(), it) : 0; if (ImGui::Combo(_LC("GameSettings", "Audio device"), &device_id, devices)) { App::audio_device_name.SetActive(audio_devices[device_id].c_str()); } DrawGCheckbox(App::audio_enable_creak, _LC("GameSettings", "Creak sound")); DrawGCheckbox(App::audio_menu_music, _LC("GameSettings", "Main menu music")); DrawGFloatSlider(App::audio_master_volume, _LC("GameSettings", "Master volume"), 0, 1); } #endif // USE_OPENAL else if (m_tab == SettingsTab::GRAPHICS) { ImGui::TextDisabled(_LC("GameSettings", "Video settings")); DrawGCombo(App::gfx_flares_mode, _LC("GameSettings", "Lights"), "None (fastest)\0" "No light sources\0" "Only current vehicle, main lights\0" "All vehicles, main lights\0" "All vehicles, all lights\0\0"); DrawGCombo(App::gfx_shadow_type, _LC("GameSettings", "Shadow type"), "Disabled\0" "Texture\0" "PSSM\0\0"); if (App::gfx_shadow_type.GetActive() != GfxShadowType::NONE) { DrawGCheckbox(App::gfx_reduce_shadows, _LC("GameSettings", "Shadow optimizations")); if (App::gfx_shadow_type.GetActive() == GfxShadowType::PSSM) { DrawGIntSlider(App::gfx_shadow_quality, _LC("GameSettings", "Shadow quality"), 0, 3); } } DrawGCombo(App::gfx_sky_mode, "Sky gfx", "Sandstorm (fastest)\0" "Caelum (best looking, slower)\0" "SkyX (best looking, slower)\0\0"); DrawGIntSlider(App::gfx_sight_range, _LC("GameSettings", "Sight range (meters)"), 100, 5000); DrawGCombo(App::gfx_texture_filter , _LC("GameSettings", "Texture filtering"), "None\0" "Bilinear\0" "Trilinear\0" "Anisotropic\0\0"); if (App::gfx_texture_filter.GetActive() == GfxTexFilter::ANISOTROPIC) { int anisotropy = Ogre::Math::Clamp(App::gfx_anisotropy.GetActive(), 1, 16); int selection = std::log2(anisotropy); if (ImGui::Combo(_LC("GameSettings", "Anisotropy"), &selection, "1\0""2\0""4\0""8\0""16\0\0")) { App::gfx_anisotropy.SetActive(std::pow(2, selection)); } } DrawGCombo(App::gfx_vegetation_mode, _LC("GameSettings", "Vegetation density"), "None\0" "20%\0" "50%\0" "Full\0\0"); DrawGCombo(App::gfx_water_mode, _LC("GameSettings", "Water gfx"), "None\0" "Basic (fastest)\0" "Reflection\0" "Reflection + refraction (speed optimized)\0" "Reflection + refraction (quality optimized)\0" "HydraX\0\0"); DrawGIntSlider(App::gfx_fps_limit, _LC("GameSettings", "FPS limit"), 0, 240); DrawGIntCheck(App::gfx_particles_mode, _LC("GameSettings", "Enable particle gfx")); DrawGIntCheck(App::gfx_skidmarks_mode, _LC("GameSettings", "Enable skidmarks")); DrawGCheckbox(App::gfx_envmap_enabled, _LC("GameSettings", "Realtime reflections")); if (App::gfx_envmap_enabled.GetActive()) { ImGui::PushItemWidth(125.f); // Width includes [+/-] buttons DrawGIntSlider(App::gfx_envmap_rate, _LC("GameSettings", "Realtime refl. update rate"), 0, 6); ImGui::PopItemWidth(); } DrawGCheckbox(App::gfx_enable_videocams, _LC("GameSettings", "Render video cameras")); DrawGCheckbox(App::gfx_surveymap_icons, _LC("GameSettings", "Overview map icons")); if (App::gfx_surveymap_icons.GetActive()) { DrawGCheckbox(App::gfx_declutter_map, _LC("GameSettings", "Declutter overview map")); } DrawGCheckbox(App::gfx_water_waves, _LC("GameSettings", "Waves on water")); DrawGCombo(App::gfx_extcam_mode, "Exterior camera mode", "None\0" "Static\0" "Pitching\0\0"); DrawGIntSlider(App::gfx_camera_height, _LC("GameSettings", "Static camera height (meters)"), 1, 50); DrawGIntSlider(App::gfx_fov_external, _LC("GameSettings", "Exterior field of view"), 10, 120); DrawGIntSlider(App::gfx_fov_internal, _LC("GameSettings", "Interior field of view"), 10, 120); } else if (m_tab == SettingsTab::DIAG) { ImGui::TextDisabled(_LC("GameSettings", "Diagnostic options")); int physics_fps = std::round(1.0f / App::diag_physics_dt.GetActive()); if (ImGui::SliderInt(_LC("GameSettings", "Physics frames per second"), &physics_fps, 2000, 10000)) { App::diag_physics_dt.SetActive(Ogre::Math::Clamp(1.0f / physics_fps, 0.0001f, 0.0005f)); } DrawGTextEdit(App::diag_preset_terrain, _LC("GameSettings", "Preselected terrain"), m_buf_diag_preset_terrain, false); DrawGTextEdit(App::diag_preset_vehicle, _LC("GameSettings", "Preselected vehicle"), m_buf_diag_preset_vehicle, true); DrawGTextEdit(App::diag_preset_veh_config, _LC("GameSettings", "Presel. veh. config"), m_buf_diag_preset_veh_config); DrawGCheckbox(App::diag_preset_veh_enter, _LC("GameSettings", "Enter preselected vehicle")); DrawGCheckbox(App::diag_auto_spawner_report, _LC("GameSettings", "Auto actor spawner report")); DrawGCheckbox(App::diag_rig_log_node_import, _LC("GameSettings", "Log node import (spawn)")); DrawGCheckbox(App::diag_rig_log_node_stats, _LC("GameSettings", "Log node stats (spawn)")); DrawGCheckbox(App::diag_rig_log_messages, _LC("GameSettings", "Log messages (spawn)")); DrawGCheckbox(App::diag_camera, _LC("GameSettings", "Debug camera (rails)")); DrawGCheckbox(App::diag_collisions, _LC("GameSettings", "Debug collisions")); DrawGCheckbox(App::diag_truck_mass, _LC("GameSettings", "Debug actor mass")); DrawGCheckbox(App::diag_envmap, _LC("GameSettings", "Debug realtime reflections")); DrawGCheckbox(App::diag_videocameras, _LC("GameSettings", "Debug videocameras")); DrawGCheckbox(App::diag_warning_texture, _LC("GameSettings", "Debug textures")); DrawGCheckbox(App::diag_hide_broken_beams, _LC("GameSettings", "Hide broken beams")); DrawGCheckbox(App::diag_hide_wheel_info, _LC("GameSettings", "Hide wheel info")); DrawGCheckbox(App::diag_hide_wheels, _LC("GameSettings", "Hide wheels")); DrawGCheckbox(App::diag_hide_nodes, _LC("GameSettings", "Hide nodes")); DrawGCheckbox(App::diag_log_console_echo, _LC("GameSettings", "Echo log to console")); DrawGCheckbox(App::diag_log_beam_break, _LC("GameSettings", "Log beam breaking")); DrawGCheckbox(App::diag_log_beam_deform, _LC("GameSettings", "Log beam deforming")); DrawGCheckbox(App::diag_log_beam_trigger, _LC("GameSettings", "Log beam triggers")); if (ImGui::Button(_LC("GameSettings", "Rebuild cache"))) { App::app_force_cache_purge.SetActive(true); } } else if (m_tab == SettingsTab::CONTROL) { ImGui::TextDisabled(_LC("GameSettings", "Controller options")); DrawGCombo(App::io_input_grab_mode, _LC("GameSettings", "Input grab mode"), "None\0" "All\0" "Dynamic\0\0"); DrawGFloatSlider(App::io_analog_smoothing, _LC("GameSettings", "Analog Input Smoothing"), 0.5f, 2.0f); DrawGFloatSlider(App::io_analog_sensitivity, _LC("GameSettings", "Analog Input Sensitivity"), 0.5f, 2.0f); DrawGCheckbox(App::io_arcade_controls, _LC("GameSettings", "Use arcade controls")); DrawGCheckbox(App::io_ffb_enabled, _LC("GameSettings", "Enable ForceFeedback")); if (App::io_ffb_enabled.GetActive()) { ImGui::PushItemWidth(125.f); DrawGFloatBox(App::io_ffb_camera_gain, _LC("GameSettings", "FFB camera gain")); DrawGFloatBox(App::io_ffb_center_gain, _LC("GameSettings", "FFB center gain")); DrawGFloatBox(App::io_ffb_master_gain, _LC("GameSettings", "FFB master gain")); DrawGFloatBox(App::io_ffb_stress_gain, _LC("GameSettings", "FFB stress gain")); ImGui::PopItemWidth(); } DrawGIntCheck(App::io_outgauge_mode, _LC("GameSettings", "Enable OutGauge protocol")); if (App::io_outgauge_mode.GetActive()) { DrawGTextEdit(App::io_outgauge_ip, _LC("GameSettings", "OutGauge IP"), m_buf_io_outgauge_ip); ImGui::PushItemWidth(125.f); DrawGIntBox(App::io_outgauge_port, _LC("GameSettings", "OutGauge port")); DrawGIntBox(App::io_outgauge_id, _LC("GameSettings", "OutGauge ID")); DrawGFloatBox(App::io_outgauge_delay, _LC("GameSettings", "OutGauge delay")); ImGui::PopItemWidth(); } } ImGui::End(); }