diff --git a/src/graphics/RasterDrawMethods.inl b/src/graphics/RasterDrawMethods.inl index 1c9a31614..4d7b0be40 100644 --- a/src/graphics/RasterDrawMethods.inl +++ b/src/graphics/RasterDrawMethods.inl @@ -58,34 +58,14 @@ int PIXELMETHODS_CLASS::drawtext(int x, int y, String str, int r, int g, int b, if(!s[1]) break; switch (s[1]) { - case 'w': - r = g = b = 255; - break; - case 'g': - r = g = b = 192; - break; - case 'o': - r = 255; - g = 216; - b = 32; - break; - case 'r': - r = 255; - g = b = 0; - break; - case 'l': - r = 255; - g = b = 75; - break; - case 'b': - r = g = 0; - b = 255; - break; - case 't': - b = 255; - g = 170; - r = 32; - break; + case 'w': r = 255; g = 255; b = 255; break; + case 'g': r = 192; g = 192; b = 192; break; + case 'o': r = 255; g = 216; b = 32; break; + case 'r': r = 255; g = 0; b = 0; break; + case 'l': r = 255; g = 75; b = 75; break; + case 'b': r = 0; g = 0; b = 255; break; + case 't': b = 255; g = 170; r = 32; break; + case 'u': r = 147; g = 83; b = 211; break; } if(invert) { diff --git a/src/graphics/Renderer.cpp b/src/graphics/Renderer.cpp index 7b495838a..905fd473e 100644 --- a/src/graphics/Renderer.cpp +++ b/src/graphics/Renderer.cpp @@ -981,28 +981,21 @@ void Renderer::DrawSigns() glBindFramebuffer(GL_DRAW_FRAMEBUFFER, partsFbo); glTranslated(0, MENUSIZE, 0); #endif - for (size_t i = 0; i < signs.size(); i++) - if (signs[i].text.length()) + for (auto ¤tSign : signs) + { + if (currentSign.text.length()) { - String::value_type type = 0; - String text = signs[i].getText(sim); - sign::splitsign(signs[i].text, &type); - signs[i].pos(text, x, y, w, h); + String text = currentSign.getDisplayText(sim, x, y, w, h); clearrect(x, y, w+1, h); drawrect(x, y, w+1, h, 192, 192, 192, 255); - if (!type) - drawtext(x+3, y+3, text, 255, 255, 255, 255); - else if(type == 'b') - drawtext(x+3, y+3, text, 211, 211, 40, 255); - else - drawtext(x+3, y+3, text, 0, 191, 255, 255); + drawtext(x+3, y+3, text, 255, 255, 255, 255); - if (signs[i].ju != sign::None) + if (currentSign.ju != sign::None) { - int x = signs[i].x; - int y = signs[i].y; - int dx = 1 - signs[i].ju; - int dy = (signs[i].y > 18) ? -1 : 1; + int x = currentSign.x; + int y = currentSign.y; + int dx = 1 - currentSign.ju; + int dy = (currentSign.y > 18) ? -1 : 1; #ifdef OGLR glBegin(GL_LINES); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); @@ -1019,6 +1012,7 @@ void Renderer::DrawSigns() #endif } } + } #ifdef OGLR glTranslated(0, -MENUSIZE, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFbo); diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index 5b558bf69..4366e8dcd 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -311,7 +311,7 @@ int GameController::GetSignAt(int x, int y) for (int i = sim->signs.size()-1; i >= 0; i--) { int signx, signy, signw, signh; - sim->signs[i].pos(sim->signs[i].getText(sim), signx, signy, signw, signh); + sim->signs[i].getDisplayText(sim, signx, signy, signw, signh); if (x>=signx && x<=signx+signw && y>=signy && y<=signy+signh) return i; } @@ -324,6 +324,11 @@ String GameController::GetSignText(int signID) return gameModel->GetSimulation()->signs[signID].text; } +std::pair GameController::GetSignSplit(int signID) +{ + return gameModel->GetSimulation()->signs[signID].split(); +} + void GameController::PlaceSave(ui::Point position, bool includePressure) { bool incPressure = Client::Ref().GetPrefBool("Simulation.LoadPressure", true); @@ -640,9 +645,10 @@ bool GameController::MouseDown(int x, int y, unsigned button) foundSignID = GetSignAt(x, y); if (foundSignID != -1) { - sign foundSign = gameModel->GetSimulation()->signs[foundSignID]; - if (sign::splitsign(foundSign.text)) + if (gameModel->GetSimulation()->signs[foundSignID].split().first) + { return false; + } } } } @@ -665,40 +671,31 @@ bool GameController::MouseUp(int x, int y, unsigned button, char type) int foundSignID = GetSignAt(x, y); if (foundSignID != -1) { - sign foundSign = gameModel->GetSimulation()->signs[foundSignID]; + sign &foundSign = gameModel->GetSimulation()->signs[foundSignID]; String str = foundSign.text; - String::value_type type; - int pos = sign::splitsign(str, &type); - if (pos) + auto si = gameModel->GetSimulation()->signs[foundSignID].split(); + if (si.first) { ret = false; - if (type == 'c' || type == 't' || type == 's') + switch (si.second) { - String link = str.Substr(3, pos-3); - switch (type) + case sign::Type::Save: { - case 'c': - { - int saveID = link.ToNumber(true); + int saveID = str.Substr(3, si.first - 3).ToNumber(true); if (saveID) OpenSavePreview(saveID, 0, false); - break; } - case 't': - { - // buff is already confirmed to be a number by sign::splitsign - Platform::OpenURI(ByteString::Build(SCHEME "powdertoy.co.uk/Discussions/Thread/View.html?Thread=", link.ToUtf8())); - break; - } - case 's': - OpenSearch(link); - break; - } - } - else if (type == 'b') - { - Simulation * sim = gameModel->GetSimulation(); - sim->create_part(-1, foundSign.x, foundSign.y, PT_SPRK); + break; + case sign::Type::Thread: + Platform::OpenURI(ByteString::Build(SCHEME "powdertoy.co.uk/Discussions/Thread/View.html?Thread=", str.Substr(3, si.first - 3).ToUtf8())); + break; + case sign::Type::Search: + OpenSearch(str.Substr(3, si.first - 3)); + break; + case sign::Type::Button: + gameModel->GetSimulation()->create_part(-1, foundSign.x, foundSign.y, PT_SPRK); + break; + default: break; } } } diff --git a/src/gui/game/GameController.h b/src/gui/game/GameController.h index 50a7bb550..cbecda932 100644 --- a/src/gui/game/GameController.h +++ b/src/gui/game/GameController.h @@ -59,6 +59,7 @@ public: GameView * GetView(); int GetSignAt(int x, int y); String GetSignText(int signID); + std::pair GetSignSplit(int signID); bool MouseMove(int x, int y, int dx, int dy); bool MouseDown(int x, int y, unsigned button); diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index 039442649..9162828cc 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -1726,24 +1726,25 @@ void GameView::OnTick(float dt) if (foundSignID != -1) { String str = c->GetSignText(foundSignID); - String::value_type type = '\0'; - int pos = sign::splitsign(str, &type); - if (type == 'c' || type == 't' || type == 's') + auto si = c->GetSignSplit(foundSignID); + + StringBuilder tooltip; + switch (si.second) + { + case sign::Type::Save: + tooltip << "Go to save ID:" << str.Substr(3, si.first - 3); + break; + case sign::Type::Thread: + tooltip << "Open forum thread " << str.Substr(3, si.first - 3) << " in browser"; + break; + case sign::Type::Search: + tooltip << "Search for " << str.Substr(3, si.first - 3); + break; + default: break; + } + + if (tooltip.Size()) { - String linkSign = str.Substr(3, pos-3); - StringBuilder tooltip; - switch (type) - { - case 'c': - tooltip << "Go to save ID:" << linkSign; - break; - case 't': - tooltip << "Open forum thread " << linkSign << " in browser"; - break; - case 's': - tooltip << "Search for " << linkSign; - break; - } ToolTip(ui::Point(0, Size.Y), tooltip.Build()); } } diff --git a/src/gui/game/SignTool.cpp b/src/gui/game/SignTool.cpp index db9688981..1a8cad401 100644 --- a/src/gui/game/SignTool.cpp +++ b/src/gui/game/SignTool.cpp @@ -193,23 +193,15 @@ void SignWindow::OnTryExit(ui::Window::ExitMethod method) void SignWindow::DoDraw() { - for(std::vector::iterator iter = sim->signs.begin(), end = sim->signs.end(); iter != end; ++iter) + for (auto ¤tSign : sim->signs) { - sign & currentSign = *iter; int x, y, w, h, dx, dy; - String::value_type type = 0; Graphics * g = GetGraphics(); - String text = currentSign.getText(sim); - sign::splitsign(currentSign.text, &type); - currentSign.pos(text, x, y, w, h); + + String text = currentSign.getDisplayText(sim, x, y, w, h); g->clearrect(x, y, w+1, h); g->drawrect(x, y, w+1, h, 192, 192, 192, 255); - if (!type) - g->drawtext(x+3, y+3, text, 255, 255, 255, 255); - else if(type == 'b') - g->drawtext(x+3, y+3, text, 211, 211, 40, 255); - else - g->drawtext(x+3, y+3, text, 0, 191, 255, 255); + g->drawtext(x+3, y+3, text, 255, 255, 255, 255); if (currentSign.ju != sign::None) { @@ -294,7 +286,7 @@ void SignTool::Click(Simulation * sim, Brush * brush, ui::Point position) int signX, signY, signW, signH, signIndex = -1; for (size_t i = 0; i < sim->signs.size(); i++) { - sim->signs[i].pos(sim->signs[i].getText(sim), signX, signY, signW, signH); + sim->signs[i].getDisplayText(sim, signX, signY, signW, signH); if (position.X > signX && position.X < signX+signW && position.Y > signY && position.Y < signY+signH) { signIndex = i; diff --git a/src/lua/LuaScriptInterface.cpp b/src/lua/LuaScriptInterface.cpp index 393506186..02cf8cdd9 100644 --- a/src/lua/LuaScriptInterface.cpp +++ b/src/lua/LuaScriptInterface.cpp @@ -564,10 +564,11 @@ int LuaScriptInterface::simulation_signIndex(lua_State *l) return lua_pushnil(l), 1; } + int x, y, w, h; if (!key.compare("text")) return lua_pushstring(l, luacon_sim->signs[id].text.ToUtf8().c_str()), 1; else if (!key.compare("displayText")) - return lua_pushstring(l, luacon_sim->signs[id].getText(luacon_sim).ToUtf8().c_str()), 1; + return lua_pushstring(l, luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h, false).ToUtf8().c_str()), 1; else if (!key.compare("justification")) return lua_pushnumber(l, (int)luacon_sim->signs[id].ju), 1; else if (!key.compare("x")) @@ -576,29 +577,25 @@ int LuaScriptInterface::simulation_signIndex(lua_State *l) return lua_pushnumber(l, luacon_sim->signs[id].y), 1; else if (!key.compare("screenX")) { - int x, y, w, h; - luacon_sim->signs[id].pos(luacon_sim->signs[id].getText(luacon_sim), x, y, w, h); + luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h); lua_pushnumber(l, x); return 1; } else if (!key.compare("screenY")) { - int x, y, w, h; - luacon_sim->signs[id].pos(luacon_sim->signs[id].getText(luacon_sim), x, y, w, h); + luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h); lua_pushnumber(l, y); return 1; } else if (!key.compare("width")) { - int x, y, w, h; - luacon_sim->signs[id].pos(luacon_sim->signs[id].getText(luacon_sim), x, y, w, h); + luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h); lua_pushnumber(l, w); return 1; } else if (!key.compare("height")) { - int x, y, w, h; - luacon_sim->signs[id].pos(luacon_sim->signs[id].getText(luacon_sim), x, y, w, h); + luacon_sim->signs[id].getDisplayText(luacon_sim, x, y, w, h); lua_pushnumber(l, h); return 1; } diff --git a/src/simulation/Sign.cpp b/src/simulation/Sign.cpp index 7e5805fba..7ae3f13a5 100644 --- a/src/simulation/Sign.cpp +++ b/src/simulation/Sign.cpp @@ -11,139 +11,153 @@ sign::sign(String text_, int x_, int y_, Justification justification_): { } -void sign::pos(String signText, int & x0, int & y0, int & w, int & h) -{ - w = Graphics::textwidth(signText.c_str()) + 5; - h = 15; - x0 = (ju == Right) ? x - w : - (ju == Left) ? x : x - w/2; - y0 = (y > 18) ? y - 18 : y + 4; -} - -int sign::splitsign(String str, String::value_type *type) -{ - if (str[0] == '{' && (str[1] == 'c' || str[1] == 't' || str[1] == 'b' || str[1] == 's')) - { - size_t strIndex = 2; - // Signs with text arguments - if (str[1] == 's') - { - if (str[2] == ':') - { - strIndex = 3; - while (strIndex < str.length() && str[strIndex] != '|') - strIndex++; - } - else - return 0; - } - // Signs with number arguments - if (str[1] == 'c' || str[1] == 't') - { - if (str[2] == ':' && str[3] >= '0' && str[3] <= '9') - { - strIndex = 4; - while (str[strIndex] >= '0' && str[strIndex] <= '9') - strIndex++; - } - else - return 0; - } - - if (str[strIndex] == '|') - { - if (str[str.length() - 1] == '}') - { - if (type) - *type = str[1]; - return strIndex; - } - } - } - return 0; -} - -String sign::getText(Simulation *sim) +String sign::getDisplayText(Simulation *sim, int &x0, int &y0, int &w, int &h, bool colorize) { + String drawable_text; + auto si = std::make_pair(0, Type::Normal); if (text.find('{') == text.npos) { - return text; + drawable_text = text; } - - if (int pos = splitsign(text)) + else { - return text.Between(pos + 1, text.size() - 1); - } - - Particle const *part = nullptr; - float pressure = 0.0f; - float aheat = 0.0f; - if (x >= 0 && x < XRES && y >= 0 && y < YRES) - { - if (sim->photons[y][x]) + si = split(); + if (si.first) { - part = &(sim->parts[ID(sim->photons[y][x])]); - } - else if (sim->pmap[y][x]) - { - part = &(sim->parts[ID(sim->pmap[y][x])]); - } - pressure = sim->pv[y/CELL][x/CELL]; - aheat = sim->hv[y/CELL][x/CELL] - 273.15f; - } - - String remaining_text = text; - StringBuilder formatted_text; - while (auto split_left_curly = remaining_text.SplitBy('{')) - { - String after_left_curly = split_left_curly.After(); - if (auto split_right_curly = after_left_curly.SplitBy('}')) - { - formatted_text << split_left_curly.Before(); - remaining_text = split_right_curly.After(); - String between_curlies = split_right_curly.Before(); - if (between_curlies == "t" || between_curlies == "temp") - { - formatted_text << Format::Precision(Format::ShowPoint(part ? part->temp - 273.15f : 0.0f), 2); - } - else if (between_curlies == "p" || between_curlies == "pres") - { - formatted_text << Format::Precision(Format::ShowPoint(pressure), 2); - } - else if (between_curlies == "a" || between_curlies == "aheat") - { - formatted_text << Format::Precision(Format::ShowPoint(aheat), 2); - } - else if (between_curlies == "type") - { - formatted_text << (part ? sim->BasicParticleInfo(*part) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty"))); - } - else if (between_curlies == "ctype") - { - formatted_text << (part ? ((part->ctype && sim->IsValidElement(part->ctype)) ? sim->ElementResolve(part->ctype, -1) : String::Build(part->ctype)) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty"))); - } - else if (between_curlies == "life") - { - formatted_text << (part ? part->life : 0); - } - else if (between_curlies == "tmp") - { - formatted_text << (part ? part->tmp : 0); - } - else if (between_curlies == "tmp2") - { - formatted_text << (part ? part->tmp2 : 0); - } - else - { - formatted_text << '{' << between_curlies << '}'; - } + drawable_text = text.Between(si.first + 1, text.size() - 1); } else { + Particle const *part = nullptr; + float pressure = 0.0f; + float aheat = 0.0f; + if (x >= 0 && x < XRES && y >= 0 && y < YRES) + { + if (sim->photons[y][x]) + { + part = &(sim->parts[ID(sim->photons[y][x])]); + } + else if (sim->pmap[y][x]) + { + part = &(sim->parts[ID(sim->pmap[y][x])]); + } + pressure = sim->pv[y/CELL][x/CELL]; + aheat = sim->hv[y/CELL][x/CELL] - 273.15f; + } + + String remaining_text = text; + StringBuilder formatted_text; + while (auto split_left_curly = remaining_text.SplitBy('{')) + { + String after_left_curly = split_left_curly.After(); + if (auto split_right_curly = after_left_curly.SplitBy('}')) + { + formatted_text << split_left_curly.Before(); + remaining_text = split_right_curly.After(); + String between_curlies = split_right_curly.Before(); + if (between_curlies == "t" || between_curlies == "temp") + { + formatted_text << Format::Precision(Format::ShowPoint(part ? part->temp - 273.15f : 0.0f), 2); + } + else if (between_curlies == "p" || between_curlies == "pres") + { + formatted_text << Format::Precision(Format::ShowPoint(pressure), 2); + } + else if (between_curlies == "a" || between_curlies == "aheat") + { + formatted_text << Format::Precision(Format::ShowPoint(aheat), 2); + } + else if (between_curlies == "type") + { + formatted_text << (part ? sim->BasicParticleInfo(*part) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty"))); + } + else if (between_curlies == "ctype") + { + formatted_text << (part ? ((part->ctype && sim->IsValidElement(part->ctype)) ? sim->ElementResolve(part->ctype, -1) : String::Build(part->ctype)) : (formatted_text.Size() ? String::Build("empty") : String::Build("Empty"))); + } + else if (between_curlies == "life") + { + formatted_text << (part ? part->life : 0); + } + else if (between_curlies == "tmp") + { + formatted_text << (part ? part->tmp : 0); + } + else if (between_curlies == "tmp2") + { + formatted_text << (part ? part->tmp2 : 0); + } + else + { + formatted_text << '{' << between_curlies << '}'; + } + } + else + { + break; + } + } + formatted_text << remaining_text; + drawable_text = formatted_text.Build(); + } + } + + if (colorize) + { + switch (si.second) + { + case Normal: break; + case Save: drawable_text = "\bt" + drawable_text; break; + case Thread: drawable_text = "\bl" + drawable_text; break; + case Button: drawable_text = "\bo" + drawable_text; break; + case Search: drawable_text = "\bu" + drawable_text; break; + } + } + + w = Graphics::textwidth(drawable_text.c_str()) + 5; + h = 15; + x0 = (ju == Right) ? x - w : (ju == Left) ? x : x - w/2; + y0 = (y > 18) ? y - 18 : y + 4; + + return drawable_text; +} + +std::pair sign::split() +{ + String::size_type pipe = 0; + if (text.size() >= 4 && text.front() == '{' && text.back() == '}') + { + switch (text[1]) + { + case 'c': + case 't': + if (text[2] == ':' && (pipe = text.find('|', 4)) != text.npos) + { + for (String::size_type i = 3; i < pipe; ++i) + { + if (text[i] < '0' || text[i] > '9') + { + return std::make_pair(0, Type::Normal); + } + } + return std::make_pair(pipe, text[1] == 'c' ? Type::Save : Type::Thread); + } + break; + + case 'b': + if (text[2] == '|') + { + return std::make_pair(2, Type::Button); + } + break; + + case 's': + if (text[2] == ':' && (pipe = text.find('|', 3)) != text.npos) + { + return std::make_pair(pipe, Type::Search); + } break; } } - formatted_text << remaining_text; - return formatted_text.Build(); + return std::make_pair(0, Type::Normal); } diff --git a/src/simulation/Sign.h b/src/simulation/Sign.h index 6eb83db46..66dc052aa 100644 --- a/src/simulation/Sign.h +++ b/src/simulation/Sign.h @@ -3,21 +3,36 @@ #include "common/String.h" +#include + class Simulation; -class sign +struct sign { -public: - enum Justification { Left = 0, Middle = 1, Right = 2, None = 3 }; - sign(String text_, int x_, int y_, Justification justification_); + enum Justification + { + Left = 0, + Middle = 1, + Right = 2, + None = 3 + }; + + enum Type + { + Normal, + Save, + Thread, + Button, + Search + }; + int x, y; Justification ju; String text; - String getText(Simulation *sim); - void pos(String signText, int & x0, int & y0, int & w, int & h); - - static int splitsign(String str, String::value_type *type = NULL); + sign(String text_, int x_, int y_, Justification justification_); + String getDisplayText(Simulation *sim, int &x, int &y, int &w, int &h, bool colorize = true); + std::pair split(); }; #endif