/* ZTextureEditorPanel::onTextTranslationEnter * Called when the enter key is pressed in the translation text box *******************************************************************/ void ZTextureEditorPanel::onTextTranslationEnter(wxCommandEvent& e) { // Parse translation text line Tokenizer tz; tz.openString(text_translation->GetValue()); Translation trans; string token = tz.getToken(); while (!token.IsEmpty()) { // Parse the translation component trans.parse(token); // Skip , if (tz.peekToken() == ",") tz.getToken(); // Next component token = tz.getToken(); } // Copy updated translation to all selected patches wxArrayInt selection = list_patches->selectedItems(); for (unsigned a = 0; a < selection.size(); a++) { CTPatchEx* patchx = (CTPatchEx*)tex_current->getPatch(selection[a]); patchx->getTranslation().copy(trans); } // Update UI updatePatchControls(); tex_canvas->redraw(true); tex_modified = true; }
/* SCallTip::loadArgSet * Opens and displays the arg set [set] from the current function *******************************************************************/ void SCallTip::loadArgSet(int set) { args.clear(); if (!function->getArgSet(set).empty()) { Tokenizer tz; tz.setSpecialCharacters("[],"); tz.openString(function->getArgSet(set)); string token = tz.getToken(); vector<string> tokens; while (true) { tokens.push_back(token); string next = tz.peekToken(); if (next == "," || next == "") { addArg(tokens); tokens.clear(); tz.getToken(); } if (next == "") break; token = tz.getToken(); } } updateSize(); Update(); Refresh(); }
/* KeyBind::readBinds * Reads keybind defeinitions from tokenizer [tz] *******************************************************************/ bool KeyBind::readBinds(Tokenizer& tz) { // Parse until ending } string name = tz.getToken(); while (name != "}" && !tz.atEnd()) { // Clear any current binds for the key getBind(name).keys.clear(); // Read keys while (1) { string keystr = tz.getToken(); // Finish if no keys are bound if (keystr == "unbound") break; // Parse key string string key, mods; if (keystr.Find("|") >= 0) { mods = keystr.BeforeFirst('|'); key = keystr.AfterFirst('|'); } else key = keystr; // Add the key addBind(name, keypress_t(key, mods.Find('a') >= 0, mods.Find('c') >= 0, mods.Find('s') >= 0)); // Check for more keys if (tz.peekToken() == ",") tz.getToken(); // Skip , else break; } // Next keybind name = tz.getToken(); } // Create sorted list keybinds_sorted = keybinds; std::sort(keybinds_sorted.begin(), keybinds_sorted.end()); return true; }
/* MainWindow::loadLayout * Loads the previously saved layout file for the window *******************************************************************/ void MainWindow::loadLayout() { // Open layout file Tokenizer tz; if (!tz.openFile(appPath("mainwindow.layout", DIR_USER))) return; // Parse layout wxAuiManager *m_mgr = wxAuiManager::GetManager(this); while (true) { // Read component+layout pair string component = tz.getToken(); string layout = tz.getToken(); // Load layout to component if (!component.IsEmpty() && !layout.IsEmpty()) m_mgr->LoadPaneInfo(layout, m_mgr->GetPane(component)); // Check if we're done if (tz.peekToken().IsEmpty()) break; } }
/* MainWindow::loadLayout * Loads the previously saved layout file for the window *******************************************************************/ void MainWindow::loadLayout() { // Open layout file Tokenizer tz; if (!tz.openFile(App::path("mainwindow.layout", App::Dir::User))) return; // Parse layout while (true) { // Read component+layout pair string component = tz.getToken(); string layout = tz.getToken(); // Load layout to component if (!component.IsEmpty() && !layout.IsEmpty()) m_mgr->LoadPaneInfo(layout, m_mgr->GetPane(component)); // Check if we're done if (tz.peekToken().IsEmpty()) break; } }
/* Translation::parse * Parses a text definition [def] (in zdoom format, detailed here: * http://zdoom.org/wiki/Translation) *******************************************************************/ void Translation::parse(string def) { // Open definition string for processing w/tokenizer Tokenizer tz; tz.setSpecialCharacters("[]:%,="); tz.openString(def); //wxLogMessage("Parse translation \"%s\"", CHR(def)); // Read original range uint8_t o_start, o_end; o_start = tz.getInteger(); if (tz.peekToken() == "=") o_end = o_start; else if (!tz.checkToken(":")) return; else o_end = tz.getInteger(); if (!tz.checkToken("=")) return; // Check for reverse origin range bool reverse = (o_start > o_end); // Type of translation depends on next token if (tz.peekToken() == "[") { // Colour translation rgba_t start, end; tz.getToken(); // Skip [ // Read start colour start.r = tz.getInteger(); if (!tz.checkToken(",")) return; start.g = tz.getInteger(); if (!tz.checkToken(",")) return; start.b = tz.getInteger(); if (!tz.checkToken("]")) return; if (!tz.checkToken(":")) return; if (!tz.checkToken("[")) return; // Read end colour end.r = tz.getInteger(); if (!tz.checkToken(",")) return; end.g = tz.getInteger(); if (!tz.checkToken(",")) return; end.b = tz.getInteger(); if (!tz.checkToken("]")) return; // Add translation TransRangeColour* tr = new TransRangeColour(); if (reverse) { tr->o_start = o_end; tr->o_end = o_start; tr->d_start.set(end); tr->d_end.set(start); } else { tr->o_start = o_start; tr->o_end = o_end; tr->d_start.set(start); tr->d_end.set(end); } translations.push_back(tr); //wxLogMessage("Added colour translation"); } else if (tz.peekToken() == "%") { // Desat colour translation float sr, sg, sb, er, eg, eb; tz.getToken(); // Skip % if (!tz.checkToken("[")) return; // Read start colour sr = tz.getFloat(); if (!tz.checkToken(",")) return; sg = tz.getFloat(); if (!tz.checkToken(",")) return; sb = tz.getFloat(); if (!tz.checkToken("]")) return; if (!tz.checkToken(":")) return; if (!tz.checkToken("[")) return; // Read end colour er = tz.getFloat(); if (!tz.checkToken(",")) return; eg = tz.getFloat(); if (!tz.checkToken(",")) return; eb = tz.getFloat(); if (!tz.checkToken("]")) return; // Add translation TransRangeDesat* tr = new TransRangeDesat(); if (reverse) { tr->o_start = o_end; tr->o_end = o_start; tr->d_sr = er; tr->d_sg = eg; tr->d_sb = eb; tr->d_er = sr; tr->d_eg = sg; tr->d_eb = sb; } else { tr->o_start = o_start; tr->o_end = o_end; tr->d_sr = sr; tr->d_sg = sg; tr->d_sb = sb; tr->d_er = er; tr->d_eg = eg; tr->d_eb = eb; } translations.push_back(tr); //wxLogMessage("Added desat translation"); } else { // Palette range translation uint8_t d_start, d_end; // Read range values d_start = tz.getInteger(); if (!tz.checkToken(":")) d_end = d_start; else d_end = tz.getInteger(); // Add translation TransRangePalette* tr = new TransRangePalette(); if (reverse) { tr->o_start = o_end; tr->o_end = o_start; tr->d_start = d_end; tr->d_end = d_start; } else { tr->o_start = o_start; tr->o_end = o_end; tr->d_start = d_start; tr->d_end = d_end; } translations.push_back(tr); //wxLogMessage("Added range translation"); } }
/* ParseTreeNode::parse * Parses formatted text data. Current valid formatting is: * (type) child = value; * (type) child = value1, value2, ...; * (type) child = { value1, value2, ... } * (type) child { grandchild = value; etc... } * (type) child : inherited { ... } * All values are read as strings, but can be retrieved as string, * int, bool or float. *******************************************************************/ bool ParseTreeNode::parse(Tokenizer& tz) { // Get first token string token = tz.getToken(); // Keep parsing until final } is reached (or end of file) while (!(S_CMP(token, "}")) && !token.IsEmpty()) { // Check for preprocessor stuff if (parser) { // #define if (S_CMPNOCASE(token, "#define")) { parser->define(tz.getToken()); token = tz.getToken(); continue; } // #if(n)def if (S_CMPNOCASE(token, "#ifdef") || S_CMPNOCASE(token, "#ifndef")) { bool test = true; if (S_CMPNOCASE(token, "#ifndef")) test = false; string define = tz.getToken(); if (parser->defined(define) == test) { // Continue token = tz.getToken(); continue; } else { // Skip section int skip = 0; while (true) { token = tz.getToken(); if (S_CMPNOCASE(token, "#endif")) skip--; else if (S_CMPNOCASE(token, "#ifdef")) skip++; else if (S_CMPNOCASE(token, "#ifndef")) skip++; if (skip < 0) break; if (token.IsEmpty()) { wxLogMessage("Error: found end of file within #if(n)def block"); break; } } continue; } } // #include (ignore) if (S_CMPNOCASE(token, "#include")) { tz.skipToken(); // Skip include path token = tz.getToken(); continue; } // #endif (ignore) if (S_CMPNOCASE(token, "#endif")) { token = tz.getToken(); continue; } } // If it's a special character (ie not a valid name), parsing fails if (tz.isSpecialCharacter(token.at(0))) { wxLogMessage("Parsing error: Unexpected special character '%s' in %s (line %d)", CHR(token), CHR(tz.getName()), tz.lineNo()); return false; } // So we have either a node or property name string name = token; // Check next token to determine what we're doing string next = tz.peekToken(); // Check for type+name pair string type = ""; if (next != "=" && next != "{" && next != ";" && next != ":") { type = name; name = tz.getToken(); next = tz.peekToken(); } // Assignment if (S_CMP(next, "=")) { // Skip = tz.skipToken(); // Create item node ParseTreeNode* child = (ParseTreeNode*)addChild(name); child->type = type; // Check type of assignment list token = tz.getToken(); string list_end = ";"; if (token == "{") { list_end = "}"; token = tz.getToken(); } // Parse until ; or } while (1) { // Check for list end if (S_CMP(token, list_end) && !tz.quotedString()) break; // Setup value Property value; // Detect value type if (tz.quotedString()) // Quoted string value = token; else if (S_CMPNOCASE(token, "true")) // Boolean (true) value = true; else if (S_CMPNOCASE(token, "false")) // Boolean (false) value = false; else if (re_int1.Matches(token) || // Integer re_int2.Matches(token)) { long val; token.ToLong(&val); value = (int)val; } else if (re_int3.Matches(token)) // Hex (0xXXXXXX) { long val; token.ToLong(&val, 0); value = (int)val; //wxLogMessage("%s: %s is hex %d", CHR(name), CHR(token), value.getIntValue()); } else if (re_float.Matches(token)) // Floating point { double val; token.ToDouble(&val); value = (double)val; //LOG_MESSAGE(3, S_FMT("%s: %s is float %1.3f", CHR(name), CHR(token), val)); } else // Unknown, just treat as string value = token; // Add value child->values.push_back(value); // Check for , if (S_CMP(tz.peekToken(), ",")) tz.skipToken(); // Skip it else if (!(S_CMP(tz.peekToken(), list_end))) { string t = tz.getToken(); string n = tz.getName(); wxLogMessage("Parsing error: Expected \",\" or \"%s\", got \"%s\" in %s (line %d)", CHR(list_end), CHR(t), CHR(n), tz.lineNo()); return false; } token = tz.getToken(); } } // Child node else if (S_CMP(next, "{")) { // Add child node ParseTreeNode* child = (ParseTreeNode*)addChild(name); child->type = type; // Skip { tz.skipToken(); // Parse child node if (!child->parse(tz)) return false; } // Child node (with no values/children) else if (S_CMP(next, ";")) { // Add child node ParseTreeNode* child = (ParseTreeNode*)addChild(name); child->type = type; // Skip ; tz.skipToken(); } // Child node + inheritance else if (S_CMP(next, ":")) { // Skip : tz.skipToken(); // Read inherited name string inherit = tz.getToken(); // Check for opening brace if (tz.checkToken("{")) { // Add child node ParseTreeNode* child = (ParseTreeNode*)addChild(name); child->type = type; // Set its inheritance child->inherit = inherit; // Parse child node if (!child->parse(tz)) return false; } } // Unexpected token else { wxLogMessage("Parsing error: \"%s\" unexpected in %s (line %d)", CHR(next), CHR(tz.getName()), tz.lineNo()); return false; } // Continue parsing token = tz.getToken(); } return true; }
/* CTexture::parse * Parses a TEXTURES format texture definition *******************************************************************/ bool CTexture::parse(Tokenizer& tz, string type) { // Check if optional if (S_CMPNOCASE(tz.peekToken(), "optional")) { tz.getToken(); // Skip it optional = true; } // Read basic info this->type = type; this->extended = true; this->defined = false; name = tz.getToken().Upper(); tz.getToken(); // Skip , width = tz.getInteger(); tz.getToken(); // Skip , height = tz.getInteger(); // Check for extended info if (tz.peekToken() == "{") { tz.getToken(); // Skip { // Read properties string property = tz.getToken(); while (property != "}") { // Check if end of text is reached (error) if (property.IsEmpty()) { wxLogMessage("Error parsing texture %s: End of text found, missing } perhaps?", name); return false; } // XScale if (S_CMPNOCASE(property, "XScale")) scale_x = tz.getFloat(); // YScale if (S_CMPNOCASE(property, "YScale")) scale_y = tz.getFloat(); // Offset if (S_CMPNOCASE(property, "Offset")) { offset_x = tz.getInteger(); tz.getToken(); // Skip , offset_y = tz.getInteger(); } // WorldPanning if (S_CMPNOCASE(property, "WorldPanning")) world_panning = true; // NoDecals if (S_CMPNOCASE(property, "NoDecals")) no_decals = true; // NullTexture if (S_CMPNOCASE(property, "NullTexture")) null_texture = true; // Patch if (S_CMPNOCASE(property, "Patch")) { CTPatchEx* patch = new CTPatchEx(); patch->parse(tz); patches.push_back(patch); } // Graphic if (S_CMPNOCASE(property, "Graphic")) { CTPatchEx* patch = new CTPatchEx(); patch->parse(tz, PTYPE_GRAPHIC); patches.push_back(patch); } // Read next property property = tz.getToken(); } } return true; }
/* CTPatchEx::parse * Parses a ZDoom TEXTURES format patch definition *******************************************************************/ bool CTPatchEx::parse(Tokenizer& tz, uint8_t type) { // Read basic info this->type = type; name = tz.getToken().Upper(); tz.getToken(); // Skip , offset_x = tz.getInteger(); tz.getToken(); // Skip , offset_y = tz.getInteger(); // Check if there is any extended info if (tz.peekToken() == "{") { // Skip { tz.getToken(); // Parse extended info string property = tz.getToken(); while (property != "}") { // FlipX if (S_CMPNOCASE(property, "FlipX")) flip_x = true; // FlipY if (S_CMPNOCASE(property, "FlipY")) flip_y = true; // UseOffsets if (S_CMPNOCASE(property, "UseOffsets")) use_offsets = true; // Rotate if (S_CMPNOCASE(property, "Rotate")) rotation = tz.getInteger(); // Translation if (S_CMPNOCASE(property, "Translation")) { // Add first translation string translation.parse(tz.getToken()); // Add any subsequent translations (separated by commas) while (tz.peekToken() == ",") { tz.getToken(); // Skip , translation.parse(tz.getToken()); } blendtype = 1; } // Blend if (S_CMPNOCASE(property, "Blend")) { double val; wxColour col; blendtype = 2; // Read first value string first = tz.getToken(); // If no second value, it's just a colour string if (tz.peekToken() != ",") { col.Set(first); colour.set(col.Red(), col.Green(), col.Blue()); } else { // Second value could be alpha or green tz.getToken(); // Skip , double second = tz.getDouble(); // If no third value, it's an alpha value if (tz.peekToken() != ",") { col.Set(first); colour.set(col.Red(), col.Green(), col.Blue(), second*255); blendtype = 3; } else { // Third value exists, must be R,G,B,A format tz.getToken(); // Skip , first.ToDouble(&val); colour.r = val*255; colour.g = second*255; colour.b = tz.getDouble()*255; if (tz.peekToken() != ",") { wxLogMessage("Invalid TEXTURES definition, expected ',', got '%s'", tz.getToken()); return false; } tz.getToken(); // Skip , colour.a = tz.getDouble()*255; blendtype = 3; } } } // Alpha if (S_CMPNOCASE(property, "Alpha")) alpha = tz.getFloat(); // Style if (S_CMPNOCASE(property, "Style")) style = tz.getToken(); // Read next property name property = tz.getToken(); } } return true; }
// ----------------------------------------------------------------------------- // Initialises the start page // ----------------------------------------------------------------------------- void SStartPage::init() { // wxWebView #ifdef USE_WEBVIEW_STARTPAGE html_startpage_ = wxWebView::New( this, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxWebViewBackendDefault, wxBORDER_NONE); html_startpage_->SetZoomType(App::platform() == App::MacOS ? wxWEBVIEW_ZOOM_TYPE_TEXT : wxWEBVIEW_ZOOM_TYPE_LAYOUT); // wxHtmlWindow #else html_startpage_ = new wxHtmlWindow(this, -1, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_NEVER, "startpage"); #endif // Add to sizer GetSizer()->Add(html_startpage_, 1, wxEXPAND); // Bind events #ifdef USE_WEBVIEW_STARTPAGE html_startpage_->Bind(wxEVT_WEBVIEW_NAVIGATING, &SStartPage::onHTMLLinkClicked, this); html_startpage_->Bind( wxEVT_WEBVIEW_ERROR, [&](wxWebViewEvent& e) { Log::error(S_FMT("wxWebView Error: %s", CHR(e.GetString()))); }); if (App::platform() == App::Platform::Windows) { html_startpage_->Bind(wxEVT_WEBVIEW_LOADED, [&](wxWebViewEvent& e) { html_startpage_->Reload(); }); } Bind(wxEVT_THREAD_WEBGET_COMPLETED, [&](wxThreadEvent& e) { latest_news_ = e.GetString(); latest_news_.Trim(); if (latest_news_ == "connect_failed" || latest_news_.empty()) latest_news_ = "<center>Unable to load latest SLADE news</center>"; load(false); }); #else html_startpage_->Bind(wxEVT_COMMAND_HTML_LINK_CLICKED, &SStartPage::onHTMLLinkClicked, this); #endif // Get data used to build the page auto res_archive = App::archiveManager().programResourceArchive(); if (res_archive) { entry_base_html_ = res_archive->entryAtPath(App::useWebView() ? "html/startpage.htm" : "html/startpage_basic.htm"); entry_css_ = res_archive->entryAtPath(web_dark_theme ? "html/theme-dark.css" : "html/theme-light.css"); entry_export_.push_back(res_archive->entryAtPath("html/base.css")); entry_export_.push_back(res_archive->entryAtPath("fonts/FiraSans-Regular.woff")); entry_export_.push_back(res_archive->entryAtPath("fonts/FiraSans-Italic.woff")); entry_export_.push_back(res_archive->entryAtPath("fonts/FiraSans-Medium.woff")); entry_export_.push_back(res_archive->entryAtPath("fonts/FiraSans-Bold.woff")); entry_export_.push_back(res_archive->entryAtPath("fonts/FiraSans-Heavy.woff")); entry_export_.push_back(res_archive->entryAtPath("logo_icon.png")); entry_export_.push_back(res_archive->entryAtPath("icons/entry_list/Rounded/archive.png")); entry_export_.push_back(res_archive->entryAtPath("icons/entry_list/Rounded/wad.png")); entry_export_.push_back(res_archive->entryAtPath("icons/entry_list/Rounded/zip.png")); entry_export_.push_back(res_archive->entryAtPath("icons/entry_list/Rounded/folder.png")); entry_export_.push_back(res_archive->entryAtPath("icons/general/open.png")); entry_export_.push_back(res_archive->entryAtPath("icons/general/newarchive.png")); entry_export_.push_back(res_archive->entryAtPath("icons/general/newzip.png")); entry_export_.push_back(res_archive->entryAtPath("icons/general/mapeditor.png")); entry_export_.push_back(res_archive->entryAtPath("icons/general/wiki.png")); // Load tips auto entry_tips = res_archive->entryAtPath("tips.txt"); if (entry_tips) { Tokenizer tz; tz.openMem((const char*)entry_tips->getData(), entry_tips->getSize(), entry_tips->getName()); while (!tz.atEnd() && tz.peekToken() != "") tips_.push_back(tz.getToken()); } } }