/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program 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. * * This program 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 this program. If not, see . * */ #include "director/director.h" #include "director/movie.h" #include "director/cast.h" #include "director/debugger/dt-internal.h" #include "director/debugger.h" #include "director/lingo/lingo-ast.h" #include "director/lingo/lingo-code.h" #include "director/lingo/lingo-object.h" #include "director/lingo/lingo-the.h" namespace Director { namespace DT { class RenderOldScriptVisitor : public NodeVisitor { private: ImGuiScript &_script; int _indent = 0; bool _isScriptInDebug = false; bool _currentStatementDisplayed = false; bool _scrollTo = false; bool _scrollDone = true; public: explicit RenderOldScriptVisitor(ImGuiScript &script, bool scrollTo) : _script(script), _scrollTo(scrollTo) { Common::Array &callstack = g_lingo->_state->callstack; if (!callstack.empty()) { CFrame *head = callstack[callstack.size() - 1]; _isScriptInDebug = (head->sp.ctx->_id == script.id.member) && (*head->sp.name == script.handlerId); } _script.startOffsets.clear(); } virtual bool visitHandlerNode(HandlerNode *node) { ImGui::Text("on "); ImGui::SameLine(); ImGui::TextColored(_state->_colors._call_color, "%s", node->name->c_str()); if (!node->args->empty()) { ImGui::SameLine(); ImGui::Text(" "); ImGui::SameLine(); for (uint i = 0; i < node->args->size(); i++) { Common::String *arg = (*node->args)[i]; ImGui::Text("%s", arg->c_str()); ImGui::SameLine(); if (i != (node->args->size() - 1)) { ImGui::Text(", "); ImGui::SameLine(); } } ImGui::NewLine(); } if (_state->_dbg._goToDefinition && _scrollTo) { ImGui::SetScrollHereY(0.5f); _state->_dbg._goToDefinition = false; } indent(); for (uint i = 0; i < node->stmts->size(); i++) { Node *stmt = (*node->stmts)[i]; renderLine(stmt->startOffset); stmt->accept(this); ImGui::NewLine(); } unindent(); renderLine(node->endOffset); ImGui::TextColored(_state->_colors._keyword_color, "end"); return true; } virtual bool visitScriptNode(ScriptNode *node) { ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2()); for (Node *child : *node->children) { if (child->type == kHandlerNode && *((HandlerNode *)child)->name != _script.handlerId) continue; renderLine(child->startOffset); child->accept(this); } ImGui::PopStyleVar(); return true; } virtual bool visitFactoryNode(FactoryNode *node) { ImGui::Text("factory %s", node->name->c_str()); ImGui::NewLine(); indent(); for (uint i = 0; i < node->methods->size(); i++) { Node *method = (*node->methods)[i]; renderLine(method->startOffset); method->accept(this); ImGui::NewLine(); } unindent(); return true; } virtual bool visitCmdNode(CmdNode *node) { ImGui::Text("%s ", node->name->c_str()); ImGui::SameLine(); if (*node->name == "go") { ImGui::TextColored(_state->_colors._keyword_color, "to "); ImGui::SameLine(); } for (uint i = 0; i < node->args->size(); i++) { Node *arg = (*node->args)[i]; if ((i != 0) || (node->args->size() < 2) || ((*node->args)[1]->type != kMovieNode)) { arg->accept(this); ImGui::SameLine(); if (i != (node->args->size() - 1)) { ImGui::Text(", "); ImGui::SameLine(); } } } return true; } virtual bool visitPutIntoNode(PutIntoNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "put "); ImGui::SameLine(); node->val->accept(this); ImGui::TextColored(_state->_colors._keyword_color, " into "); ImGui::SameLine(); node->var->accept(this); return true; } virtual bool visitPutAfterNode(PutAfterNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "put "); ImGui::SameLine(); node->val->accept(this); ImGui::TextColored(_state->_colors._keyword_color, " after "); ImGui::SameLine(); node->var->accept(this); return true; } virtual bool visitPutBeforeNode(PutBeforeNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "put "); ImGui::SameLine(); node->val->accept(this); ImGui::TextColored(_state->_colors._keyword_color, " before "); ImGui::SameLine(); node->var->accept(this); return true; } virtual bool visitSetNode(SetNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "set "); ImGui::SameLine(); node->val->accept(this); ImGui::TextColored(_state->_colors._keyword_color, " to "); ImGui::SameLine(); node->var->accept(this); return true; } void displayDefineVar(const char *name, IDList *names) { ImGui::Text("%s ", name); ImGui::SameLine(); for (uint i = 0; i < names->size(); i++) { Common::String *arg = (*names)[i]; ImGui::Text("%s", arg->c_str()); ImGui::SameLine(); if (i != (names->size() - 1)) { ImGui::Text(" "); ImGui::SameLine(); } } } virtual bool visitGlobalNode(GlobalNode *node) { displayDefineVar("global", node->names); return true; } virtual bool visitPropertyNode(PropertyNode *node) { displayDefineVar("property", node->names); return true; } virtual bool visitInstanceNode(InstanceNode *node) { displayDefineVar("instance", node->names); return true; } virtual bool visitIfStmtNode(IfStmtNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "if "); ImGui::SameLine(); node->cond->accept(this); ImGui::TextColored(_state->_colors._keyword_color, " then "); if (node->stmts->size() == 1) { ImGui::SameLine(); (*node->stmts)[0]->accept(this); } else { indent(); for (uint i = 0; i < node->stmts->size(); i++) { Node *stmt = (*node->stmts)[i]; renderLine(stmt->startOffset); stmt->accept(this); ImGui::NewLine(); } unindent(); renderLine(node->endOffset); ImGui::TextColored(_state->_colors._keyword_color, "endif"); ImGui::SameLine(); } return true; } virtual bool visitIfElseStmtNode(IfElseStmtNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "if "); ImGui::SameLine(); node->cond->accept(this); ImGui::TextColored(_state->_colors._keyword_color, " then "); if (node->stmts1->size() == 1) { ImGui::SameLine(); (*node->stmts1)[0]->accept(this); ImGui::Text(" "); ImGui::SameLine(); } else { uint offset = node->cond->endOffset; indent(); for (uint i = 0; i < node->stmts1->size(); i++) { Node *stmt = (*node->stmts1)[i]; renderLine(stmt->startOffset); stmt->accept(this); ImGui::NewLine(); offset = stmt->endOffset; } unindent(); renderLine(offset); } ImGui::TextColored(_state->_colors._keyword_color, "else "); if (node->stmts2->size() == 1) { ImGui::SameLine(); (*node->stmts2)[0]->accept(this); } else { uint offset = node->cond->endOffset; indent(); for (uint i = 0; i < node->stmts2->size(); i++) { Node *stmt = (*node->stmts2)[i]; renderLine(stmt->startOffset); stmt->accept(this); ImGui::NewLine(); offset = stmt->endOffset; } unindent(); renderLine(offset); ImGui::TextColored(_state->_colors._keyword_color, "endif"); ImGui::SameLine(); } return true; } virtual bool visitRepeatWhileNode(RepeatWhileNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "repeat while "); ImGui::SameLine(); node->cond->accept(this); ImGui::NewLine(); indent(); uint offset = node->cond->endOffset; for (uint i = 0; i < node->stmts->size(); i++) { Node *stmt = (*node->stmts)[i]; renderLine(stmt->startOffset); stmt->accept(this); ImGui::NewLine(); offset = stmt->endOffset; } unindent(); renderLine(offset); ImGui::TextColored(_state->_colors._keyword_color, "endrepeat"); return true; } virtual bool visitRepeatWithToNode(RepeatWithToNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "repeat with "); ImGui::SameLine(); ImGui::Text("%s = ", node->var->c_str()); ImGui::SameLine(); node->start->accept(this); ImGui::TextColored(_state->_colors._keyword_color, " %s ", node->down ? "down to" : "to"); node->end->accept(this); ImGui::NewLine(); indent(); for (uint i = 0; i < node->stmts->size(); i++) { Node *stmt = (*node->stmts)[i]; renderLine(stmt->startOffset); stmt->accept(this); ImGui::NewLine(); } unindent(); renderLine(node->endOffset); ImGui::TextColored(_state->_colors._keyword_color, "endrepeat"); return true; } virtual bool visitRepeatWithInNode(RepeatWithInNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "repeat with "); ImGui::SameLine(); ImGui::Text("%s in ", node->var->c_str()); ImGui::SameLine(); node->list->accept(this); ImGui::NewLine(); indent(); for (uint i = 0; i < node->stmts->size(); i++) { Node *stmt = (*node->stmts)[i]; renderLine(stmt->startOffset); stmt->accept(this); ImGui::NewLine(); } unindent(); renderLine(node->endOffset); ImGui::TextColored(_state->_colors._keyword_color, "endrepeat"); return true; } virtual bool visitNextRepeatNode(NextRepeatNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "next repeat"); return true; } virtual bool visitExitRepeatNode(ExitRepeatNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "exit repeat"); return true; } virtual bool visitExitNode(ExitNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "exit"); return true; } virtual bool visitReturnNode(ReturnNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "return"); if (node->expr) { ImGui::Text(" "); ImGui::SameLine(); node->expr->accept(this); ImGui::NewLine(); } return true; } virtual bool visitTellNode(TellNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "tell "); node->target->accept(this); if (node->stmts->size() == 1) { ImGui::SameLine(); ImGui::TextColored(_state->_colors._keyword_color, " to "); ImGui::SameLine(); (*node->stmts)[0]->accept(this); } else { indent(); for (uint i = 0; i < node->stmts->size(); i++) { Node *stmt = (*node->stmts)[i]; renderLine(stmt->startOffset); stmt->accept(this); ImGui::NewLine(); } unindent(); renderLine(node->endOffset); ImGui::TextColored(_state->_colors._keyword_color, "endtell"); } return true; } virtual bool visitWhenNode(WhenNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "when "); ImGui::SameLine(); ImGui::Text("%s", node->event->c_str()); ImGui::SameLine(); ImGui::TextColored(_state->_colors._keyword_color, " then "); ImGui::SameLine(); ImGui::Text("%s", node->code->c_str()); ImGui::SameLine(); return true; } virtual bool visitDeleteNode(DeleteNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "delete "); ImGui::SameLine(); node->chunk->accept(this); return true; } virtual bool visitHiliteNode(HiliteNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "hilite "); ImGui::SameLine(); node->chunk->accept(this); return true; } virtual bool visitAssertErrorNode(AssertErrorNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "scummvmAssertError "); ImGui::SameLine(); node->stmt->accept(this); return true; } virtual bool visitIntNode(IntNode *node) { ImGui::TextColored(_state->_colors._literal_color, "%d", node->val); ImGui::SameLine(); return true; } virtual bool visitFloatNode(FloatNode *node) { ImGui::TextColored(_state->_colors._literal_color, "%g", node->val); ImGui::SameLine(); return true; } virtual bool visitSymbolNode(SymbolNode *node) { ImGui::TextColored(_state->_colors._literal_color, "%s", node->val->c_str()); ImGui::SameLine(); return true; } virtual bool visitStringNode(StringNode *node) { ImGui::TextColored(_state->_colors._literal_color, "\"%s\"", node->val->c_str()); ImGui::SameLine(); return true; } virtual bool visitListNode(ListNode *node) { ImGui::Text("["); ImGui::SameLine(); for (uint i = 0; i < node->items->size(); i++) { Node *prop = (*node->items)[i]; prop->accept(this); if (i != (node->items->size() - 1)) { ImGui::Text(","); ImGui::SameLine(); } } ImGui::Text("]"); ImGui::SameLine(); return true; } virtual bool visitPropListNode(PropListNode *node) { ImGui::Text("["); ImGui::SameLine(); if (node->items->empty()) { ImGui::Text(":"); ImGui::SameLine(); } else { for (uint i = 0; i < node->items->size(); i++) { Node *prop = (*node->items)[i]; prop->accept(this); if (i != (node->items->size() - 1)) { ImGui::Text(","); ImGui::SameLine(); } } } ImGui::Text("]"); ImGui::SameLine(); return true; } virtual bool visitPropPairNode(PropPairNode *node) { node->key->accept(this); ImGui::Text(":"); ImGui::SameLine(); node->val->accept(this); return true; } virtual bool visitFuncNode(FuncNode *node) { const bool isBuiltin = g_lingo->_builtinCmds.contains(*node->name); const ImVec4 color = (ImVec4)ImColor(isBuiltin ? _state->_colors._builtin_color : _state->_colors._call_color); ImGui::TextColored(color, "%s(", node->name->c_str()); if (!isBuiltin && ImGui::IsItemHovered() && ImGui::BeginTooltip()) { ImGui::Text("Go to definition"); ImGui::EndTooltip(); } if (!isBuiltin && ImGui::IsItemClicked()) { int obj = 0; for (uint i = 0; i < _script.bytecodeArray.size(); i++) { if (node->startOffset == _script.bytecodeArray[i].pos) { obj = _script.bytecodeArray[i].obj; break; } } ScriptContext *context = getScriptContext(obj, _script.id, *node->name); if (context) { ImGuiScript script = toImGuiScript(_script.type, CastMemberID(context->_id, _script.id.castLib), *node->name); const Director::Movie *movie = g_director->getCurrentMovie(); int castId = context->_id; bool childScript = false; if (castId == -1) { castId = movie->getCast()->getCastIdByScriptId(context->_parentNumber); childScript = true; } script.byteOffsets = context->_functionByteOffsets[script.handlerId]; script.moviePath = _script.moviePath; script.handlerName = formatHandlerName(context->_scriptId, castId, script.handlerId, context->_scriptType, childScript); setScriptToDisplay(script); _state->_dbg._goToDefinition = true; } } ImGui::SameLine(); for (uint i = 0; i < node->args->size(); i++) { Node *arg = (*node->args)[i]; arg->accept(this); if (i != (node->args->size() - 1)) { ImGui::Text(","); ImGui::SameLine(); } } ImGui::Text(")"); ImGui::SameLine(); return true; } virtual bool visitVarNode(VarNode *node) { ImGui::TextColored(_state->_colors._var_color, "%s", node->name->c_str()); if (ImGui::IsItemHovered() && g_lingo->_globalvars.contains(*node->name)) { const Datum &val = g_lingo->_globalvars.getVal(*node->name); ImGui::BeginTooltip(); ImGui::Text("Click to add to watches."); Common::String s = val.asString(true); s.wordWrap(150); if (s.size() > 4000) { uint chop = s.size() - 4000; s.chop(s.size() - 4000); s += Common::String::format("... [chopped %d chars]", chop); } ImGui::Text("= %s", s.c_str()); ImGui::EndTooltip(); } if (ImGui::IsItemClicked()) { _state->_variables[*node->name] = true; } ImGui::SameLine(); return true; } virtual bool visitParensNode(ParensNode *node) { ImGui::Text("("); ImGui::SameLine(); node->expr->accept(this); ImGui::Text(")"); ImGui::SameLine(); return true; } virtual bool visitUnaryOpNode(UnaryOpNode *node) { char op = '?'; if (node->op == LC::c_negate) { op = '-'; } else if (node->op == LC::c_not) { op = '!'; } ImGui::Text("%c", op); ImGui::SameLine(); node->arg->accept(this); return true; } virtual bool visitBinaryOpNode(BinaryOpNode *node) { node->a->accept(this); static struct { inst op; const char *name; } ops[] = { {LC::c_add, "+"}, {LC::c_sub, "-"}, {LC::c_mul, "*"}, {LC::c_div, "/"}, {LC::c_mod, "mod"}, {LC::c_gt, ">"}, {LC::c_lt, "<"}, {LC::c_eq, "="}, {LC::c_neq, "<>"}, {LC::c_ge, ">="}, {LC::c_le, "<="}, {LC::c_and, "and"}, {LC::c_or, "or"}, {LC::c_ampersand, "&"}, {LC::c_concat, "&&"}, {LC::c_contains, "contains"}, {LC::c_starts, "starts"}, }; for (auto &op : ops) { if (op.op == node->op) { ImGui::Text(" %s ", op.name); ImGui::SameLine(); break; } } node->b->accept(this); return true; } virtual bool visitFrameNode(FrameNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "frame "); ImGui::SameLine(); node->arg->accept(this); return true; } virtual bool visitMovieNode(MovieNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "movie "); ImGui::SameLine(); node->arg->accept(this); return true; } virtual bool visitIntersectsNode(IntersectsNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "sprite "); ImGui::SameLine(); node->sprite1->accept(this); ImGui::TextColored(_state->_colors._keyword_color, "intersects "); node->sprite2->accept(this); return true; } virtual bool visitWithinNode(WithinNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "sprite "); ImGui::SameLine(); node->sprite1->accept(this); ImGui::TextColored(_state->_colors._keyword_color, "within "); node->sprite2->accept(this); return true; } virtual bool visitTheNode(TheNode *node) { ImGui::TextColored(_state->_colors._the_color, "the %s", node->prop->c_str()); ImGui::SameLine(); return true; } virtual bool visitTheOfNode(TheOfNode *node) { ImGui::TextColored(_state->_colors._the_color, "the %s of ", node->prop->c_str()); ImGui::SameLine(); node->obj->accept(this); return true; } virtual bool visitTheNumberOfNode(TheNumberOfNode *node) { ImGui::TextColored(_state->_colors._the_color, "the number of "); ImGui::SameLine(); node->arg->accept(this); return true; } virtual bool visitTheLastNode(TheLastNode *node) { // TODO: change the node to know if it's 'in' or 'of' ImGui::TextColored(_state->_colors._the_color, "the last %s in/of ", toString(node->type).c_str()); ImGui::SameLine(); node->arg->accept(this); return true; } virtual bool visitTheDateTimeNode(TheDateTimeNode *node) { const char *key1 = ""; switch (node->field) { case kTheAbbr: key1 = "abbreviated"; break; case kTheLong: key1 = "long"; break; case kTheShort: key1 = "short"; break; } const char *key2 = node->entity == kTheDate ? "date" : "time"; ImGui::TextColored(_state->_colors._the_color, "the %s %s", key1, key2); ImGui::SameLine(); return true; } virtual bool visitMenuNode(MenuNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "menu "); ImGui::SameLine(); node->arg->accept(this); return true; } virtual bool visitMenuItemNode(MenuItemNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "menuitem "); ImGui::SameLine(); node->arg1->accept(this); ImGui::TextColored(_state->_colors._keyword_color, "of menu "); ImGui::SameLine(); node->arg2->accept(this); return true; } virtual bool visitSoundNode(SoundNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "sound "); ImGui::SameLine(); node->arg->accept(this); return true; } virtual bool visitSpriteNode(SpriteNode *node) { ImGui::TextColored(_state->_colors._keyword_color, "sprite "); ImGui::SameLine(); node->arg->accept(this); return true; } virtual bool visitChunkExprNode(ChunkExprNode *node) { const char *key1 = ""; switch (node->type) { case kChunkChar: key1 = "char"; break; case kChunkWord: key1 = "word"; break; case kChunkItem: key1 = "item"; break; case kChunkLine: key1 = "line"; break; } ImGui::Text("%s", key1); ImGui::SameLine(); node->start->accept(this); if (node->end) { ImGui::TextColored(_state->_colors._keyword_color, " to "); ImGui::SameLine(); node->end->accept(this); } ImGui::TextColored(_state->_colors._keyword_color, " of "); ImGui::SameLine(); node->src->accept(this); return true; } private: static Common::String toString(ChunkType chunkType) { // TODO: this method could be used in ChunkExprNode switch (chunkType) { case kChunkChar: return "char"; case kChunkWord: return "word"; case kChunkItem: return "item"; case kChunkLine: return "line"; } return ""; } void indent() { _indent++; } void unindent() { if (_indent > 0) _indent--; } void renderIndentation() const { for (int i = 0; i < _indent; i++) { ImGui::Text(" "); ImGui::SameLine(); } } void renderLine(uint32 pc) { bool showCurrentStatement = false; _script.startOffsets.push_back(pc); if (_script.pc != 0 && pc >= _script.pc) { if (!_currentStatementDisplayed) { showCurrentStatement = true; _currentStatementDisplayed = true; } } else if (_isScriptInDebug && g_lingo->_exec._state == kPause) { // check current statement if (!_currentStatementDisplayed) { if (g_lingo->_state->pc <= pc) { showCurrentStatement = true; _currentStatementDisplayed = true; } } } ImDrawList *dl = ImGui::GetWindowDrawList(); const ImVec2 pos = ImGui::GetCursorScreenPos(); const float width = ImGui::GetContentRegionAvail().x; const ImVec2 mid(pos.x + 7, pos.y + 7); ImVec4 color = _state->_colors._bp_color_disabled; const Director::Breakpoint *bp = getBreakpoint(_script.handlerId, _script.id.member, pc); if (bp) color = _state->_colors._bp_color_enabled; ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize())); // click on breakpoint column? if (ImGui::IsItemClicked(0)) { if (color == _state->_colors._bp_color_enabled) { g_lingo->delBreakpoint(bp->id); color = _state->_colors._bp_color_disabled; } else { Director::Breakpoint newBp; newBp.type = kBreakpointFunction; newBp.scriptId = _script.id.member; newBp.funcName = _script.handlerId; newBp.funcOffset = pc; g_lingo->addBreakpoint(newBp); color = _state->_colors._bp_color_enabled; } } if (color == _state->_colors._bp_color_disabled && ImGui::IsItemHovered()) { color = _state->_colors._bp_color_hover; } // draw breakpoint if (!bp || bp->enabled) dl->AddCircleFilled(mid, 4.0f, ImColor(color)); else dl->AddCircle(mid, 4.0f, ImColor(_state->_colors._line_color)); // draw current statement if (showCurrentStatement) { dl->AddQuadFilled(ImVec2(pos.x, pos.y + 4.f), ImVec2(pos.x + 9.f, pos.y + 4.f), ImVec2(pos.x + 9.f, pos.y + 10.f), ImVec2(pos.x, pos.y + 10.f), ImColor(_state->_colors._current_statement)); dl->AddTriangleFilled(ImVec2(pos.x + 8.f, pos.y), ImVec2(pos.x + 14.f, pos.y + 7.f), ImVec2(pos.x + 8.f, pos.y + 14.f), ImColor(_state->_colors._current_statement)); if (!_scrollDone && _scrollTo && g_lingo->_state->callstack.size() != _state->_dbg._callstackSize) { ImGui::SetScrollHereY(0.5f); _scrollDone = true; } dl->AddRectFilled(ImVec2(pos.x + 16.f, pos.y), ImVec2(pos.x + width, pos.y + 16.f), ImColor(IM_COL32(0xFF, 0xFF, 0x00, 0x20)), 0.4f); } // draw separator dl->AddLine(ImVec2(pos.x + 16.0f, pos.y), ImVec2(pos.x + 16.0f, pos.y + 17), ImColor(_state->_colors._line_color)); ImGui::SetItemTooltip("Click to add a breakpoint"); ImGui::SameLine(); // draw offset ImGui::Text("[%5d] ", pc == 0xFFFFFFFF ? -1 : pc); ImGui::SameLine(); renderIndentation(); } }; void renderOldScriptAST(ImGuiScript &script, bool showByteCode, bool scrollTo) { RenderOldScriptVisitor oldVisitor(script, scrollTo); script.oldAst->accept(&oldVisitor); } } // namespace DT } // namespace Director