/* Copyright (c) 2013 yvt This file is part of OpenSpades. OpenSpades is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenSpades is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenSpades. If not, see . */ #include #include "MainWindow.h" #include "Main.h" #include "../Core/Debug.h" #include "SDLRunner.h" #include #include "../Core/Settings.h" #include "../Imports/SDL.h" #include #include "../Core/FileManager.h" #include "../Core/IStream.h" #include "SDLAsyncRunner.h" #include "DetailConfigWindow.h" #include "../Core/Math.h" #include "Serverbrowser.h" #include "ErrorDialog.h" #include "../Imports/OpenGL.h" //for gpu info using namespace spades::gui; SPADES_SETTING(cg_smp, "0"); SPADES_SETTING(cg_blood, "1"); SPADES_SETTING(cg_lastQuickConnectHost, "127.0.0.1"); SPADES_SETTING(cg_protocolVersion, ""); SPADES_SETTING(cg_playerName, "Deuce"); SPADES_SETTING(r_bloom, "0"); SPADES_SETTING(r_lens, "1"); SPADES_SETTING(r_cameraBlur, "1"); SPADES_SETTING(r_softParticles, "1"); SPADES_SETTING(r_mapSoftShadow, "0"); SPADES_SETTING(r_modelShadows, "1"); SPADES_SETTING(r_radiosity, "0"); SPADES_SETTING(r_dlights, "1"); SPADES_SETTING(r_water, "2"); SPADES_SETTING(r_multisamples, "0"); SPADES_SETTING(r_fxaa, "1"); SPADES_SETTING(r_depthBits, ""); SPADES_SETTING(r_colorBits, ""); SPADES_SETTING(r_videoWidth, "1024"); SPADES_SETTING(r_videoHeight, "640"); SPADES_SETTING(r_fullscreen, "0"); SPADES_SETTING(r_fogShadow, "0"); SPADES_SETTING(r_lensFlare, "1"); SPADES_SETTING(r_lensFlareDynamic, ""); SPADES_SETTING(r_blitFramebuffer, "1"); SPADES_SETTING(r_srgb, ""); SPADES_SETTING(r_shadowMapSize, ""); SPADES_SETTING(s_maxPolyphonics, "96"); SPADES_SETTING(s_eax, "1"); SPADES_SETTING(r_maxAnisotropy, "8"); SPADES_SETTING(r_colorCorrection, "1"); SPADES_SETTING(r_physicalLighting, ""); SPADES_SETTING(r_occlusionQuery, ""); SPADES_SETTING(r_depthOfField, ""); static std::vector g_modes; MainWindow::~MainWindow() { if( browser ) { delete browser; } } //lm: this doesnt really belong here, should be somewhere in core or client probably? // we might need to introduce some base object that will handle global state and whatnot.. // now all windows just spawn eachother, instead of being managed from a central place. void MainWindow::StartGame(const spades::ServerAddress &host) { SPADES_MARK_FUNCTION(); spades::StartClient(host, cg_playerName); } void MainWindow::QuickConnectPressed() { SPADES_MARK_FUNCTION(); spades::ServerAddress host(quickHostInput->value(), versionChoice->value() == 0 ? spades::ProtocolVersion::v075 : spades::ProtocolVersion::v076); hide(); StartGame(host); } void MainWindow::connectLocal075Pressed() { spades::ServerAddress host("aos://16777343:32887", spades::ProtocolVersion::v075 ); hide(); StartGame(host); } void MainWindow::connectLocal076Pressed() { spades::ServerAddress host("aos://16777343:32887", spades::ProtocolVersion::v076 ); hide(); StartGame(host); } void MainWindow::versionSelectionChanged() { cg_protocolVersion = versionChoice->value() + 3; } #pragma mark - Setup void MainWindow::LoadPrefs() { SPADES_MARK_FUNCTION(); SPLog("Loading Preferences to MainWindow"); // --- video // add modes char buf[64]; modeSelect->clear(); for(size_t i = 0; i < g_modes.size(); i++){ spades::IntVector3 mode = g_modes[i]; sprintf(buf, "%dx%d", mode.x, mode.y); modeSelect->add(buf); } sprintf(buf, "%dx%d", (int)r_videoWidth, (int)r_videoHeight); modeSelect->value(buf); msaaSelect->clear(); if(r_blitFramebuffer) { msaaSelect->add("Off"); msaaSelect->add("MSAA 2x"); msaaSelect->add("MSAA 4x"); msaaSelect->add("FXAA"); msaaSelect->add("Custom"); if(r_fxaa) { if(r_multisamples){ msaaSelect->value(4); }else{ msaaSelect->value(3); } }else{ switch((int)r_multisamples){ case 0: case 1: default: msaaSelect->value(0); break; case 2: msaaSelect->value(1); break; case 4: msaaSelect->value(2); break; } } }else { // MSAA is not supported with r_blitFramebuffer = 0 msaaSelect->add("Off"); msaaSelect->add("FXAA"); msaaSelect->add("Custom"); if(r_fxaa) { if(r_multisamples){ msaaSelect->value(2); }else{ msaaSelect->value(1); } }else{ switch((int)r_multisamples){ case 0: case 1: default: msaaSelect->value(0); break; case 2: case 4: msaaSelect->value(2); break; } } } quickHostInput->value(cg_lastQuickConnectHost.CString()); int v = (int)cg_protocolVersion; versionChoice->add( "0.75" ); versionChoice->add( "0.76" ); versionChoice->value( v == 3 ? 0 : 1 ); fullscreenCheck->value(r_fullscreen ? 1 : 0); // --- graphics postFilterSelect->clear(); postFilterSelect->add("Low"); postFilterSelect->add("Medium"); if(postFilterHighCapable){ postFilterSelect->add("High"); } postFilterSelect->add("Custom"); if(postFilterHighCapable){ postFilterSelect->value(3); }else{ postFilterSelect->value(2); } if(r_cameraBlur && r_bloom && r_lens && r_lensFlare && r_lensFlareDynamic && r_colorCorrection && r_depthOfField && postFilterHighCapable) { postFilterSelect->value(2); }else if(r_cameraBlur && (!r_bloom) && r_lens && r_lensFlare && (!r_lensFlareDynamic) && r_colorCorrection && (!r_depthOfField)) { postFilterSelect->value(1); }else if((!r_cameraBlur) && (!r_bloom) && (!r_lens) && (!r_lensFlare) && (!r_lensFlareDynamic) && (!r_colorCorrection) && (!r_depthOfField)) { postFilterSelect->value(0); } particleSelect->clear(); particleSelect->add("Low"); particleSelect->add("Medium"); if(particleHighCapable) { particleSelect->add("High"); } particleSelect->add("Custom"); particleSelect->value(particleHighCapable ? 3 : 2); if((int)r_softParticles >= 2 && particleHighCapable) { particleSelect->value(2); }else if((int)r_softParticles == 1) { particleSelect->value(1); }else if((int)r_softParticles == 0){ particleSelect->value(0); } radiosityCheck->value(r_radiosity ? 1 : 0); bloodCheck->value(cg_blood ? 1 : 0); directLightSelect->clear(); directLightSelect->add("Low"); directLightSelect->add("Medium"); directLightSelect->add("High"); directLightSelect->add("Ultra"); directLightSelect->add("Custom"); if((!r_mapSoftShadow) && (r_dlights) && (!r_modelShadows) && (!r_fogShadow) && (!r_physicalLighting)){ directLightSelect->value(0); }else if((!r_mapSoftShadow) && (r_dlights) && (r_modelShadows) && (!r_fogShadow) && (!r_physicalLighting)){ directLightSelect->value(1); }else if((r_mapSoftShadow) && (r_dlights) && (r_modelShadows) && (!r_fogShadow) && (r_physicalLighting)){ directLightSelect->value(2); }else if((r_mapSoftShadow) && (r_dlights) && (r_modelShadows) && (r_fogShadow) && (r_physicalLighting)){ directLightSelect->value(3); }else{ directLightSelect->value(4); } shaderSelect->clear(); shaderSelect->add("Low"); shaderSelect->add("Medium"); if(shaderHighCapable){ shaderSelect->add("High"); } shaderSelect->add("Custom"); if(shaderHighCapable){ if((!r_water)){ shaderSelect->value(0); }else if((int)r_water == 1){ shaderSelect->value(1); }else if((int)r_water == 2){ shaderSelect->value(2); }else{ shaderSelect->value(3); } }else{ if((!r_water)){ shaderSelect->value(0); }else if((int)r_water == 1){ shaderSelect->value(1); }else{ shaderSelect->value(2); } } // --- audio polyInput->step(16.); polyInput->range(32., 256.); polyInput->value((int)s_maxPolyphonics); eaxCheck->value(s_eax ? 1 : 0); // --- game playerNameInput->value(cg_playerName.CString()); playerNameInput->maximum_size(15); } void MainWindow::Init() { SPADES_MARK_FUNCTION(); // banner std::string data = spades::FileManager::ReadAllBytes("Gfx/Banner.png"); Fl_PNG_Image *img = new Fl_PNG_Image("Gfx/Banner.png", (const unsigned char *)data.data(), data.size()); bannerBox->image(img); // --- about std::string text, pkg; pkg = PACKAGE_STRING; text = std::string((const char *)aboutText, sizeof(aboutText)); text = spades::Replace(text, "${PACKAGE_STRING}", pkg); aboutView->value(text.c_str()); browser = new spades::Serverbrowser( serverListbox ); spades::ServerFilter::Flags flags = browser->Filter(); checkFilterEmpty->value( flags & spades::ServerFilter::flt_Empty ); checkFilterFull->value( flags & spades::ServerFilter::flt_Full ); checkFilterV75->value( flags & spades::ServerFilter::flt_Ver075 ); checkFilterV76->value( flags & spades::ServerFilter::flt_Ver076 ); checkFilterVOther->value( flags & spades::ServerFilter::flt_VerOther ); browser->startQuery(); mainTab->value(groupServerlist); groupServerlist->value(serverListbox); } /** This function is called after showing window. * Creating SDL window before showing MainWindow results in * internal error on Mac OS X. */ void MainWindow::CheckGLCapability() { SPADES_MARK_FUNCTION(); // check GL capabilities SPLog("Initializing SDL for capability query"); SDL_Init(SDL_INIT_VIDEO); SDL_Rect **modes = SDL_ListModes(NULL, SDL_OPENGL | SDL_FULLSCREEN | SDL_DOUBLEBUF); if(modes && modes != (SDL_Rect **)-1){ g_modes.clear(); for(size_t i = 0; modes[i]; i++){ SDL_Rect mode = *(modes[i]); if(mode.w < 800 || mode.h < 600) continue; g_modes.push_back(spades::IntVector3::Make(mode.w, mode.h, 0)); SPLog("Video Mode Found: %dx%d", mode.w, mode.h); } } bool capable = true; std::string msg; if(!SDL_SetVideoMode(1,1, 32, SDL_OPENGL|SDL_NOFRAME)){ // OpenGL initialization failed! outputGLRenderer->value("N/A"); outputGLVersion->value("N/A"); outputGLSLVersion->value("N/A"); std::string err = SDL_GetError(); SPLog("SDL_SetVideoMode failed: %s", err.c_str()); msg = "OpenGL/SDL couldn't be initialized. " "You cannot play OpenSpades.

" "Message from SDL
" + err; capable = false; shaderHighCapable = false; postFilterHighCapable = false; particleHighCapable = false; }else{ shaderHighCapable = true; postFilterHighCapable = true; particleHighCapable = true; const char *str; GLint maxTextureSize; GLint max3DTextureSize; GLint maxCombinedTextureUnits; GLint maxVertexTextureUnits; GLint maxVaryingComponents; SPLog("--- OpenGL Renderer Info ---"); if((str = (const char*)glGetString(GL_VENDOR)) != NULL) { SPLog("Vendor: %s", str); } if((str = (const char *)glGetString(GL_RENDERER)) != NULL) { outputGLRenderer->value(str); SPLog("Name: %s", str); }else{ outputGLRenderer->value("(unknown)"); } if((str = (const char *)glGetString(GL_VERSION)) != NULL) { double ver = atof(str); if( ver <= 0.1 ) { //TODO: determine required version! std::string tmp = str; tmp += " (too old)"; outputGLVersion->textcolor( FL_RED ); outputGLVersion->value( tmp.c_str() ); capable = false; }else{ outputGLVersion->value( str ); } SPLog("Version: %s", str); }else{ outputGLVersion->value("(unknown)"); } if((str = (const char *)glGetString(GL_SHADING_LANGUAGE_VERSION)) != NULL) { outputGLSLVersion->value(str); SPLog("Shading Language Version: %s", str); }else{ outputGLSLVersion->value("(unknown)"); } maxTextureSize = 0; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); if(maxTextureSize > 0) { SPLog("Max Texture Size: %d", (int)maxTextureSize); } max3DTextureSize = 0; glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DTextureSize); if(max3DTextureSize > 0) { SPLog("Max 3D Texture Size: %d", (int)max3DTextureSize); } maxCombinedTextureUnits = 0; glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxCombinedTextureUnits); if(maxCombinedTextureUnits > 0) { SPLog("Max Combined Texture Image Units: %d", (int)maxCombinedTextureUnits); } maxVertexTextureUnits = 0; glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &maxVertexTextureUnits); if(maxVertexTextureUnits > 0) { SPLog("Max Vertex Texture Image Units: %d", (int)maxVertexTextureUnits); } maxVaryingComponents = 0; glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &maxVaryingComponents); if(maxVaryingComponents > 0) { SPLog("Max Varying Components: %d", (int)maxVaryingComponents); } str = (const char*)glGetString(GL_EXTENSIONS); std::string extensions; if(str) extensions = str; const char * const requiredExtensions[] = { "GL_ARB_multitexture", "GL_ARB_shader_objects", "GL_ARB_shading_language_100", "GL_ARB_texture_non_power_of_two", "GL_ARB_vertex_buffer_object", "GL_EXT_framebuffer_object", NULL }; SPLog("--- Extensions ---"); std::vector strs = spades::Split(str, " "); for(size_t i = 0; i < strs.size(); i++) SPLog("%s", strs[i].c_str()); SPLog("------------------"); for(size_t i = 0; requiredExtensions[i]; i++) { const char *ex = requiredExtensions[i]; if(extensions.find(ex) == std::string::npos) { // extension not found msg += ""; msg += ex; msg += " NOT SUPPORTED!"; msg += ""; capable = false; }else{ msg += ""; msg += ex; msg += " is supported"; msg += ""; } msg += "
"; } msg += "
 
"; msg += "Other Extensions:
"; // non-requred extensions if(extensions.find("GL_ARB_framebuffer_sRGB") == std::string::npos) { if(r_srgb) { r_srgb = 0; SPLog("Disabling r_srgb: no GL_ARB_framebuffer_sRGB"); } msg += "GL_ARB_framebuffer_sRGB is NOT SUPPORTED
"; msg += "  r_srgb is disabled.
"; }else{ msg += ""; msg += "GL_ARB_framebuffer_sRGB is supported"; msg += "
"; } if(extensions.find("GL_EXT_framebuffer_blit") == std::string::npos) { if(r_blitFramebuffer) { r_blitFramebuffer = 0; SPLog("Disabling r_blitFramebuffer: no GL_EXT_framebuffer_blit"); } if(r_multisamples) { r_multisamples = 0; SPLog("Disabling r_multisamples: no GL_EXT_framebuffer_blit"); } msg += "GL_EXT_framebuffer_blit is NOT SUPPORTED
"; msg += "  MSAA is disabled.
"; msg += "  r_blitFramebuffer is disabled.
"; }else{ msg += ""; msg += "GL_EXT_framebuffer_blit is supported"; msg += "
"; } if(extensions.find("GL_EXT_texture_filter_anisotropic") == std::string::npos) { if((float)r_maxAnisotropy > 1.1f) { r_maxAnisotropy = 1; SPLog("Setting r_maxAnisotropy to 1: no GL_EXT_texture_filter_anisotropic"); } msg += "GL_EXT_texture_filter_anisotropic is NOT SUPPORTED
"; msg += "  r_maxAnisotropy is disabled.
"; }else{ msg += ""; msg += "GL_EXT_texture_filter_anisotropic is supported"; msg += "
"; } if(extensions.find("GL_ARB_occlusion_query") == std::string::npos) { if(r_occlusionQuery) { r_occlusionQuery = 0; SPLog("Disabling r_occlusionQuery: no GL_ARB_occlusion_query"); } msg += "GL_ARB_occlusion_query is NOT SUPPORTED
"; msg += "  r_occlusionQuery is disabled
"; }else{ msg += ""; msg += "GL_ARB_occlusion_query is supported"; msg += "
"; } if(extensions.find("GL_NV_conditional_render") == std::string::npos) { if(r_occlusionQuery) { r_occlusionQuery = 0; SPLog("Disabling r_occlusionQuery: no GL_NV_conditional_render"); } msg += "GL_NV_conditional_render is NOT SUPPORTED
"; msg += "  r_occlusionQuery is disabled
"; }else{ msg += ""; msg += "GL_NV_conditional_render is supported"; msg += "
"; } msg += "
 
"; msg += "Miscellaneous:
"; char buf[256]; sprintf(buf, "Max Texture Size: %d
", (int)maxTextureSize); msg += buf; if(maxTextureSize < 1024) { capable = false; msg += ""; msg += "  TOO SMALL (1024 required)"; msg += "
"; } if((int)r_shadowMapSize > maxTextureSize) { SPLog("Changed r_shadowMapSize from %d to %d: too small GL_MAX_TEXTURE_SIZE", (int)r_shadowMapSize, maxTextureSize); r_shadowMapSize = maxTextureSize; } sprintf(buf, "Max 3D Texture Size: %d
", (int)max3DTextureSize); msg += buf; if(max3DTextureSize < 512) { msg += "  Global Illumation is disabled (512 required)
"; if(r_radiosity) { r_radiosity = 0; SPLog("Disabling r_radiosity: too small GL_MAX_3D_TEXTURE_SIZE"); radiosityCheck->deactivate(); } } sprintf(buf, "Max Combined Texture Image Units: %d
", (int)maxCombinedTextureUnits); msg += buf; if(maxCombinedTextureUnits < 12) { msg += "  Global Illumation is disabled (12 required)
"; if(r_radiosity) { r_radiosity = 0; SPLog("Disabling r_radiosity: too small GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS"); radiosityCheck->deactivate(); } } sprintf(buf, "Max Vertex Texture Image Units: %d
", (int)maxVertexTextureUnits); msg += buf; if(maxVertexTextureUnits < 3) { msg += "  Water 2 is disabled (3 required)
"; msg += "  (Shader Effects is limited to Medium)
"; shaderHighCapable = false; if((int)r_water >= 2) { r_water = 1; SPLog("Disabling Water 2: too small GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS"); } } sprintf(buf, "Max Varying Components: %d
", (int)maxVaryingComponents); msg += buf; if(maxVaryingComponents < 37) { msg += "  Shaded Particle is disabled (37 required)
"; msg += "  (Particle is limited to Medium)
"; particleHighCapable = false; if((int)r_softParticles >= 2) { r_softParticles = 1; SPLog("Disabling Water 2: too small GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS"); } } if(capable){ msg = "Your video card supports all " "required OpenGL extensions/features.
 
" + msg; }else{ msg = "Your video card/driver doesn't support " "at least one of required OpenGL extensions/features." " You cannot play OpenSpades.
 
" + msg; } } msg = "" + msg + ""; glInfoView->value(msg.c_str()); SDL_QuitSubSystem(SDL_INIT_VIDEO); SPLog("SDL video subsystem finalized"); SPLog("System is OpenSpades capable: %s", capable ? "YES": "NO"); if(!capable) { mainTab->value(groupReport); connectButton->deactivate(); } LoadPrefs(); inited = true; } void MainWindow::SavePrefs() { SPADES_MARK_FUNCTION(); if(!inited) return; std::string modeStr = modeSelect->value(); size_t pos = modeStr.find('x'); if(pos != std::string::npos){ int w = atoi(modeStr.substr(0, pos).c_str()); int h = atoi(modeStr.substr(pos + 1).c_str()); if(w >= 256 && h >= 256){ r_videoWidth = w; r_videoHeight = h; } } cg_lastQuickConnectHost = quickHostInput->value(); cg_protocolVersion = versionChoice->value() + 3; //0 = 3 = 0.75, 1 = 4 = 0.76 r_fullscreen = fullscreenCheck->value() ? 1 : 0; switch(msaaSelect->value()){ case 0: r_multisamples = 0; r_fxaa = 0; break; case 1: r_multisamples = 2; r_fxaa = 0; break; case 2: r_multisamples = 4; r_fxaa = 0; break; case 3: r_multisamples = 0; r_fxaa = 1; break; } // --- graphics cg_blood = bloodCheck->value() ? 1 : 0; switch(postFilterSelect->value()){ case 0: r_bloom = 0; r_lens = 0; r_lensFlare = 0; r_lensFlareDynamic = 0; r_cameraBlur = 0; r_colorCorrection = 0; r_depthOfField = 0; break; case 1: r_bloom = 0; r_lens = 1; r_lensFlare = 1; r_lensFlareDynamic = 0; r_cameraBlur = 1; r_colorCorrection = 1; r_depthOfField = 0; break; case 2: if(postFilterHighCapable){ r_bloom = 1; r_lens = 1; r_lensFlare = 1; r_lensFlareDynamic = 1; r_cameraBlur = 1; r_colorCorrection = 1; r_depthOfField = 1; } break; } switch(particleSelect->value()){ case 0: r_softParticles = 0; break; case 1: r_softParticles = 1; break; case 2: if(particleHighCapable){ r_softParticles = 2; } break; } r_radiosity = radiosityCheck->value() ? 1 : 0; switch(directLightSelect->value()){ case 0: r_modelShadows = 0; r_dlights = 1; r_mapSoftShadow = 0; r_fogShadow = 0; r_physicalLighting = 0; break; case 1: r_modelShadows = 1; r_dlights = 1; r_mapSoftShadow = 0; r_fogShadow = 0; r_physicalLighting = 0; break; case 2: r_modelShadows = 1; r_dlights = 1; r_mapSoftShadow = 1; r_fogShadow = 0; r_physicalLighting = 1; break; case 3: r_modelShadows = 1; r_dlights = 1; r_mapSoftShadow = 1; r_fogShadow = 1; r_physicalLighting = 1; break; } if(shaderHighCapable){ switch(shaderSelect->value()){ case 0: r_water = 0; break; case 1: r_water = 1; break; case 2: r_water = 2; break; } }else{ switch(shaderSelect->value()){ case 0: r_water = 0; break; case 1: r_water = 1; break; } } // --- audio s_maxPolyphonics = (int)polyInput->value(); s_eax = eaxCheck->value() ? 1 : 0; // --- game cg_playerName = playerNameInput->value(); } void MainWindow::DisableMSAA() { if(r_blitFramebuffer){ if(msaaSelect->value() >= 1 && msaaSelect->value() <= 2) msaaSelect->value(3); } } void MainWindow::MSAAEnabled() { if(msaaSelect->value() >= 1 && msaaSelect->value() <= 2 && r_blitFramebuffer){ if(shaderSelect->value() == 1) shaderSelect->value(0); if(directLightSelect->value() == 3) directLightSelect->value(2); } } void MainWindow::OpenDetailConfig() { SPADES_MARK_FUNCTION(); DetailConfigWindow cfg; cfg.icon( icon() ); //use the icon from the main window cfg.set_modal(); cfg.show(); while(cfg.visible()){ Fl::wait(); } LoadPrefs(); } void MainWindow::ServerSelectionChanged() { SPADES_MARK_FUNCTION(); if( browser ) { int item = serverListbox->value(); if( item > 1 ) { browser->onSelection( serverListbox->data( item ), quickHostInput, versionChoice ); } else if( item == 1 ) { browser->onHeaderClick( Fl::event_x() - serverListbox->x() ); } } } void MainWindow::updateFilters() { if( browser ) { spades::ServerFilter::Flags flags = spades::ServerFilter::flt_None; if( checkFilterEmpty->value() ) { flags |= spades::ServerFilter::flt_Empty; } if( checkFilterFull->value() ) { flags |= spades::ServerFilter::flt_Full; } if( checkFilterV75->value() ) { flags |= spades::ServerFilter::flt_Ver075; } if( checkFilterV76->value() ) { flags |= spades::ServerFilter::flt_Ver076; } if( checkFilterVOther->value() ) { flags |= spades::ServerFilter::flt_VerOther; } browser->setFilter( flags ); browser->refreshList(); } }