tools: Some subtitle editor cleanup and add hint support (#1450)

* nrepl: detect a disconnected client better

* tools: remove some duplicate code

* tools: add hint playing support

* lint: formatting
This commit is contained in:
Tyler Wilding
2022-06-12 21:07:03 -04:00
committed by GitHub
parent b053da7e33
commit ad959e6291
5 changed files with 283 additions and 256 deletions
+18 -14
View File
@@ -39,25 +39,29 @@ bool write_subtitle_db_to_files(const GameSubtitleDB& db) {
}
file_contents += fmt::format("\n(\"{}\"", scene_name);
if (scene_info.m_kind == SubtitleSceneKind::Hint) {
file_contents += " :hint 0";
file_contents += " :hint #x0";
} else if (scene_info.m_kind == SubtitleSceneKind::HintNamed) {
file_contents += fmt::format(" :hint #x{0:x}", scene_info.m_id);
}
file_contents += "\n";
for (const auto& line : scene_info.m_lines) {
// Clear screen entries
if (line.line_utf8.empty()) {
file_contents += fmt::format(" ({})\n", line.frame);
} else {
file_contents += fmt::format(" ({}", line.frame);
if (line.offscreen && scene_info.m_kind == SubtitleSceneKind::Movie) {
file_contents += " :offscreen";
if (scene_info.m_lines.empty()) {
file_contents += fmt::format(" ()\n");
} else {
for (const auto& line : scene_info.m_lines) {
// Clear screen entries
if (line.line_utf8.empty()) {
file_contents += fmt::format(" ({})\n", line.frame);
} else {
file_contents += fmt::format(" ({}", line.frame);
if (line.offscreen && scene_info.m_kind == SubtitleSceneKind::Movie) {
file_contents += " :offscreen";
}
file_contents += fmt::format(" \"{}\"", line.speaker_utf8);
// escape quotes
std::string temp = line.line_utf8;
temp = std::regex_replace(temp, std::regex("\""), "\\\"");
file_contents += fmt::format(" \"{}\")\n", temp);
}
file_contents += fmt::format(" \"{}\"", line.speaker_utf8);
// escape quotes
std::string temp = line.line_utf8;
temp = std::regex_replace(temp, std::regex("\""), "\\\"");
file_contents += fmt::format(" \"{}\")\n", temp);
}
}
file_contents += " )\n";
+7 -1
View File
@@ -34,7 +34,13 @@ void ReplServer::post_init() {
void ReplServer::ping_response(int socket) {
std::string ping = fmt::format("Connected to OpenGOAL v{}.{} nREPL!",
versions::GOAL_VERSION_MAJOR, versions::GOAL_VERSION_MINOR);
write_to_socket(socket, ping.c_str(), ping.size());
auto resp = write_to_socket(socket, ping.c_str(), ping.size());
if (resp == -1) {
fmt::print("[nREPL:{}] Client Disconnected: {}\n", tcp_port, inet_ntoa(addr.sin_addr),
ntohs(addr.sin_port), socket);
close_socket(socket);
client_sockets.erase(socket);
}
}
std::optional<std::string> ReplServer::get_msg() {
@@ -824,51 +824,21 @@
[[157, 162], "a1", "dma-packet"]
],
"(top-level-login task-control)": [[165, "v1", "symbol"]],
"(anon-function 227 task-control)": [
[17, "v1", "float"]
],
"(anon-function 286 task-control)": [
[17, "v1", "float"]
],
"(anon-function 366 task-control)": [
[17, "v1", "float"]
],
"(anon-function 367 task-control)": [
[17, "v1", "float"]
],
"(anon-function 368 task-control)": [
[17, "v1", "float"]
],
"(anon-function 369 task-control)": [
[17, "v1", "float"]
],
"(anon-function 380 task-control)": [
[17, "v1", "float"]
],
"(anon-function 383 task-control)": [
[17, "v1", "float"]
],
"(anon-function 390 task-control)": [
[17, "v1", "float"]
],
"(anon-function 393 task-control)": [
[17, "v1", "float"]
],
"(anon-function 400 task-control)": [
[17, "v1", "float"]
],
"(anon-function 403 task-control)": [
[17, "v1", "float"]
],
"(anon-function 435 task-control)": [
[17, "v1", "float"]
],
"(anon-function 445 task-control)": [
[17, "v1", "float"]
],
"(anon-function 455 task-control)": [
[17, "v1", "float"]
],
"(anon-function 227 task-control)": [[17, "v1", "float"]],
"(anon-function 286 task-control)": [[17, "v1", "float"]],
"(anon-function 366 task-control)": [[17, "v1", "float"]],
"(anon-function 367 task-control)": [[17, "v1", "float"]],
"(anon-function 368 task-control)": [[17, "v1", "float"]],
"(anon-function 369 task-control)": [[17, "v1", "float"]],
"(anon-function 380 task-control)": [[17, "v1", "float"]],
"(anon-function 383 task-control)": [[17, "v1", "float"]],
"(anon-function 390 task-control)": [[17, "v1", "float"]],
"(anon-function 393 task-control)": [[17, "v1", "float"]],
"(anon-function 400 task-control)": [[17, "v1", "float"]],
"(anon-function 403 task-control)": [[17, "v1", "float"]],
"(anon-function 435 task-control)": [[17, "v1", "float"]],
"(anon-function 445 task-control)": [[17, "v1", "float"]],
"(anon-function 455 task-control)": [[17, "v1", "float"]],
"(method 18 game-info)": [
[4, "v1", "symbol"],
[5, "v1", "level-load-info"],
@@ -5946,18 +5916,14 @@
[67, "v1", "art-joint-anim"]
],
"(method 56 ram-boss)": [
[58, "v1", "(pointer ram-boss-proj)"]
],
"(method 56 ram-boss)": [[58, "v1", "(pointer ram-boss-proj)"]],
"(code ram-idle)": [
[28, "v1", "art-joint-anim"],
[98, "v1", "art-joint-anim"]
],
"(code ram-give-fuel-cell)": [
[69, "v1", "(pointer snowcam)"]
],
"(code ram-give-fuel-cell)": [[69, "v1", "(pointer snowcam)"]],
"(code snow-bumper-deactivate)": [
[29, "v1", "art-joint-anim"],
+235 -189
View File
@@ -43,7 +43,6 @@ SubtitleEditor::SubtitleEditor() : m_repl(8181) {
m_subtitle_db = load_subtitle_project();
m_filter = m_filter_placeholder;
m_filter_hints = m_filter_placeholder;
m_repl.connect();
}
void SubtitleEditor::repl_set_continue_point(const std::string_view& continue_point) {
@@ -70,6 +69,16 @@ std::string SubtitleEditor::repl_get_process_string(const std::string_view& enti
process_name);
}
void SubtitleEditor::repl_play_hint(const std::string_view& hint_name) {
repl_reset_game();
repl_set_continue_point("village1-hut");
// TODO - move into water fountain
m_repl.eval(
fmt::format("(level-hint-spawn (game-text-id zero) \"{}\" (the-as entity #f) *entity-pool* "
"(game-task none))",
hint_name));
}
void SubtitleEditor::repl_execute_cutscene_code(const SubtitleEditorDB::Entry& entry) {
// Reset the game first to get to a known state
repl_reset_game();
@@ -150,7 +159,24 @@ void SubtitleEditor::draw_window() {
draw_edit_options();
draw_repl_options();
draw_current_cutscene();
if (!m_current_scene) {
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
} else {
ImGui::PushStyleColor(ImGuiCol_Text, m_selected_text_color);
}
if (ImGui::TreeNode("Currently Selected Cutscene")) {
ImGui::PopStyleColor();
if (m_current_scene) {
draw_subtitle_options(*m_current_scene, true);
} else {
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255));
ImGui::Text("Select a Scene from Below!");
ImGui::PopStyleColor();
}
ImGui::TreePop();
} else {
ImGui::PopStyleColor();
}
if (ImGui::TreeNode("All Cutscenes")) {
ImGui::InputText("New Scene Name", &m_new_scene_name);
@@ -183,13 +209,50 @@ void SubtitleEditor::draw_window() {
ImGui::TreePop();
}
// TODO - hints
if (ImGui::TreeNode("All Hints")) {
ImGui::InputText("New Scene Name", &m_new_scene_name);
// TODO - make this a dropdown
ImGui::InputText("New Scene ID (hex)", &m_new_scene_id);
ImGui::InputText("New Scene Group", &m_new_scene_group);
ImGui::InputText("Filter", &m_filter, ImGuiInputTextFlags_::ImGuiInputTextFlags_AutoSelectAll);
if (is_scene_in_current_lang(m_new_scene_name)) {
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
ImGui::Text("Scene already exists with that name, no!");
ImGui::PopStyleColor();
}
if (m_new_scene_group.empty()) {
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
ImGui::Text("You must provide a group to sort the scene into!");
ImGui::PopStyleColor();
}
if (!is_scene_in_current_lang(m_new_scene_name) && !m_new_scene_group.empty()) {
if (ImGui::Button("Add Scene")) {
GameSubtitleSceneInfo newScene;
newScene.m_name = m_new_scene_name;
if (m_new_scene_id == "0") {
newScene.m_kind = SubtitleSceneKind::Hint;
newScene.m_id = strtoul(m_new_scene_id.c_str(), nullptr, 16);
} else {
newScene.m_kind = SubtitleSceneKind::HintNamed;
newScene.m_id = strtoul(m_new_scene_id.c_str(), nullptr, 16);
}
newScene.m_sorting_group = m_new_scene_group;
m_subtitle_db.m_banks.at(m_current_language)->add_scene(newScene);
m_new_scene_name = "";
}
}
draw_all_hint_groups();
ImGui::TreePop();
}
ImGui::End();
}
void SubtitleEditor::draw_edit_options() {
if (ImGui::TreeNode("Editing Options")) {
// TODO - validate these / make it a dropdown
// - source of truth is the files
ImGui::InputInt("Editing language ID", &m_current_language);
ImGui::InputInt("Base language ID", &m_base_language);
ImGui::Checkbox("Show missing cutscenes from base", &m_base_show_missing_cutscenes);
@@ -252,6 +315,17 @@ void SubtitleEditor::draw_all_cutscene_groups() {
}
}
void SubtitleEditor::draw_all_hint_groups() {
for (auto& group_name : m_subtitle_db.m_subtitle_groups->m_group_order) {
ImGui::SetNextItemOpen(true);
if (ImGui::TreeNode(group_name.c_str())) {
draw_all_hints(group_name, false);
draw_all_hints(group_name, true);
ImGui::TreePop();
}
}
}
void SubtitleEditor::draw_all_scenes(std::string group_name, bool base_cutscenes) {
auto& scenes =
m_subtitle_db.m_banks.at(base_cutscenes ? m_base_language : m_current_language)->m_scenes;
@@ -279,6 +353,7 @@ void SubtitleEditor::draw_all_scenes(std::string group_name, bool base_cutscenes
if (base_cutscenes) {
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
}
if (ImGui::TreeNode(
fmt::format("{}-{}", scene_name, base_cutscenes ? m_base_language : m_current_language)
.c_str(),
@@ -296,77 +371,7 @@ void SubtitleEditor::draw_all_scenes(std::string group_name, bool base_cutscenes
m_subtitle_db.m_banks.at(m_current_language)->add_scene(scene_info);
}
}
if (!m_repl.is_connected()) {
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
ImGui::Text("REPL not connected, can't play!");
ImGui::PopStyleColor();
} else if (m_db.count(scene_info.m_name) > 0) {
if (ImGui::Button("Play Scene")) {
if (m_db.count(scene_info.m_name) == 1) {
repl_execute_cutscene_code(m_db[scene_info.m_name]);
}
}
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
ImGui::TextWrapped("You may have to click twice, load times cause issues");
ImGui::PopStyleColor();
ImGui::NewLine();
}
if (ImGui::BeginCombo("Sorting Group", scene_info.m_sorting_group.c_str())) {
for (size_t i = 0; i < m_subtitle_db.m_subtitle_groups->m_group_order.size(); ++i) {
const bool isSelected = (scene_info.m_sorting_group_idx == (int)i);
if (ImGui::Selectable(m_subtitle_db.m_subtitle_groups->m_group_order[i].c_str(),
isSelected)) {
// Remove from current group
m_subtitle_db.m_subtitle_groups->remove_scene(scene_info.m_sorting_group,
scene_info.m_name);
// Add to new group
scene_info.m_sorting_group_idx = i;
scene_info.m_sorting_group = m_subtitle_db.m_subtitle_groups->m_group_order.at(i);
m_subtitle_db.m_subtitle_groups->add_scene(scene_info.m_sorting_group,
scene_info.m_name);
}
if (isSelected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
for (size_t i = 0; i < scene_info.m_lines.size(); i++) {
auto& subtitleLine = scene_info.m_lines.at(i);
std::string summary;
if (subtitleLine.line_utf8.empty()) {
summary = fmt::format("[{}] Clear Screen", subtitleLine.frame);
} else {
summary = fmt::format("[{}] {} - '{}...'", subtitleLine.frame, subtitleLine.speaker_utf8,
subtitleLine.line_utf8.substr(0, 30));
}
if (subtitleLine.line_utf8.empty()) {
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
} else if (subtitleLine.offscreen) {
ImGui::PushStyleColor(ImGuiCol_Text, m_offscreen_text_color);
}
if (ImGui::TreeNode(fmt::format("{}", i).c_str(), "%s", summary.c_str())) {
if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
ImGui::PopStyleColor();
}
ImGui::InputInt("Starting Frame", &subtitleLine.frame,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
ImGui::InputText("Speaker", &subtitleLine.speaker_utf8,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
ImGui::InputText("Text", &subtitleLine.line_utf8,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
ImGui::Checkbox("Offscreen?", &subtitleLine.offscreen);
ImGui::PushStyleColor(ImGuiCol_Button, m_warning_color);
if (ImGui::Button("Remove Line")) {
scene_info.m_lines.erase(scene_info.m_lines.begin() + i);
}
ImGui::PopStyleColor();
ImGui::TreePop();
} else if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
ImGui::PopStyleColor();
}
}
draw_subtitle_options(scene_info);
ImGui::TreePop();
} else if (base_cutscenes || is_current_scene) {
ImGui::PopStyleColor();
@@ -374,126 +379,167 @@ void SubtitleEditor::draw_all_scenes(std::string group_name, bool base_cutscenes
}
}
void SubtitleEditor::draw_current_cutscene() {
if (!m_current_scene) {
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
} else {
ImGui::PushStyleColor(ImGuiCol_Text, m_selected_text_color);
}
if (ImGui::TreeNode("Currently Selected Movie")) {
ImGui::PopStyleColor();
if (m_current_scene) {
if (!m_repl.is_connected()) {
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
ImGui::Text("REPL not connected, can't play!");
void SubtitleEditor::draw_all_hints(std::string group_name, bool base_cutscenes) {
auto& scenes =
m_subtitle_db.m_banks.at(base_cutscenes ? m_base_language : m_current_language)->m_scenes;
auto scenes_in_group = m_subtitle_db.m_subtitle_groups->m_groups[group_name];
for (auto& scene_name : scenes_in_group) {
if (scenes.count(scene_name) == 0) {
continue;
}
auto& scene_info = scenes[scene_name];
// Don't duplicate entries
if (base_cutscenes && is_scene_in_current_lang(scene_name)) {
continue;
}
if (scene_info.m_kind != SubtitleSceneKind::Hint &&
scene_info.m_kind != SubtitleSceneKind::HintNamed) {
continue;
}
if ((!m_filter.empty() && m_filter != m_filter_placeholder) &&
scene_name.find(m_filter) == std::string::npos) {
continue;
}
if (base_cutscenes) {
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
}
if (ImGui::TreeNode(
fmt::format("{}-{}", scene_name, base_cutscenes ? m_base_language : m_current_language)
.c_str(),
"%s", scene_name.c_str())) {
if (base_cutscenes) {
ImGui::PopStyleColor();
} else if (m_db.count(m_current_scene->m_name) > 0) {
if (ImGui::Button("Play Scene")) {
if (m_db.count(m_current_scene->m_name) == 1) {
repl_execute_cutscene_code(m_db[m_current_scene->m_name]);
}
}
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
ImGui::TextWrapped("You may have to click twice, load times cause issues");
ImGui::PopStyleColor();
ImGui::NewLine();
}
if (ImGui::BeginCombo("Sorting Group", m_current_scene->m_sorting_group.c_str())) {
for (size_t i = 0; i < m_subtitle_db.m_subtitle_groups->m_group_order.size(); ++i) {
const bool isSelected = (m_current_scene->m_sorting_group_idx == (int)i);
if (ImGui::Selectable(m_subtitle_db.m_subtitle_groups->m_group_order[i].c_str(),
isSelected)) {
// Remove from current group
m_subtitle_db.m_subtitle_groups->remove_scene(m_current_scene->m_sorting_group,
m_current_scene->m_name);
// Add to new group
m_current_scene->m_sorting_group_idx = i;
m_current_scene->m_sorting_group = m_subtitle_db.m_subtitle_groups->m_group_order.at(i);
m_subtitle_db.m_subtitle_groups->add_scene(m_current_scene->m_sorting_group,
m_current_scene->m_name);
}
if (isSelected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::InputInt("Frame Number", &m_current_scene_frame,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
ImGui::InputText("Text", &m_current_scene_text,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
ImGui::InputText("Speaker", &m_current_scene_speaker,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
ImGui::Checkbox("Offscreen", &m_current_scene_offscreen);
bool rendered_text_entry_btn = false;
if (m_current_scene_frame < 0 || m_current_scene_text.empty() ||
m_current_scene_speaker.empty()) {
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
ImGui::Text("Can't add a new text entry with the current fields!");
ImGui::PopStyleColor();
} else {
rendered_text_entry_btn = true;
if (ImGui::Button("Add Text Entry")) {
m_current_scene->add_line(m_current_scene_frame, "", m_current_scene_text, "",
m_current_scene_speaker, m_current_scene_offscreen);
if (base_cutscenes) {
if (ImGui::Button("Copy from Base Language")) {
m_subtitle_db.m_banks.at(m_current_language)->add_scene(scene_info);
}
}
if (m_current_scene_frame < 0) {
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
ImGui::Text("Can't add a clear screen entry with the current fields!");
ImGui::PopStyleColor();
} else {
if (rendered_text_entry_btn) {
ImGui::SameLine();
if (ImGui::Button("Add Clear Screen Entry")) {
m_current_scene->add_line(m_current_scene_frame, "", "", "", "", false);
}
}
}
ImGui::NewLine();
for (size_t i = 0; i < m_current_scene->m_lines.size(); i++) {
auto& subtitleLine = m_current_scene->m_lines.at(i);
std::string summary;
if (subtitleLine.line_utf8.empty()) {
summary = fmt::format("[{}] Clear Screen", subtitleLine.frame);
} else {
summary = fmt::format("[{}] {} - '{}...'", subtitleLine.frame, subtitleLine.speaker_utf8,
subtitleLine.line_utf8.substr(0, 30));
}
if (subtitleLine.line_utf8.empty()) {
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
} else if (subtitleLine.offscreen) {
ImGui::PushStyleColor(ImGuiCol_Text, m_offscreen_text_color);
}
if (ImGui::TreeNode(fmt::format("{}", i).c_str(), "%s", summary.c_str())) {
if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
ImGui::PopStyleColor();
}
ImGui::InputInt("Starting Frame", &subtitleLine.frame,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
ImGui::InputText("Speaker", &subtitleLine.speaker_utf8,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
ImGui::InputText("Text", &subtitleLine.line_utf8,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsUppercase);
ImGui::Checkbox("Offscreen?", &subtitleLine.offscreen);
ImGui::PushStyleColor(ImGuiCol_Button, m_warning_color);
if (ImGui::Button("Remove Line")) {
m_current_scene->m_lines.erase(m_current_scene->m_lines.begin() + i);
}
ImGui::PopStyleColor();
ImGui::TreePop();
} else if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
ImGui::PopStyleColor();
}
}
} else {
ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 0, 0, 255));
ImGui::Text("Select a Scene from Below!");
draw_subtitle_options(scene_info);
ImGui::TreePop();
} else if (base_cutscenes) {
ImGui::PopStyleColor();
}
ImGui::TreePop();
} else {
ImGui::PopStyleColor();
}
}
void SubtitleEditor::draw_subtitle_options(GameSubtitleSceneInfo& scene, bool current_scene) {
if (!m_repl.is_connected()) {
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
ImGui::Text("REPL not connected, can't play!");
ImGui::PopStyleColor();
} else {
// Cutscenes
if (scene.m_kind == SubtitleSceneKind::Movie && m_db.count(scene.m_name) > 0) {
if (ImGui::Button("Play Scene")) {
repl_execute_cutscene_code(m_db[scene.m_name]);
}
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
ImGui::TextWrapped("You may have to click twice, load times cause issues");
ImGui::PopStyleColor();
ImGui::NewLine();
}
// Hints
else if (scene.m_kind == SubtitleSceneKind::Hint ||
scene.m_kind == SubtitleSceneKind::HintNamed) {
if (ImGui::Button("Play Hint")) {
repl_play_hint(scene.m_name);
}
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
ImGui::TextWrapped("You may have to click twice, load times cause issues");
ImGui::PopStyleColor();
ImGui::NewLine();
}
}
if (ImGui::BeginCombo("Sorting Group", scene.m_sorting_group.c_str())) {
for (size_t i = 0; i < m_subtitle_db.m_subtitle_groups->m_group_order.size(); ++i) {
const bool isSelected = (scene.m_sorting_group_idx == (int)i);
if (ImGui::Selectable(m_subtitle_db.m_subtitle_groups->m_group_order[i].c_str(),
isSelected)) {
// Remove from current group
m_subtitle_db.m_subtitle_groups->remove_scene(scene.m_sorting_group, scene.m_name);
// Add to new group
scene.m_sorting_group_idx = i;
scene.m_sorting_group = m_subtitle_db.m_subtitle_groups->m_group_order.at(i);
m_subtitle_db.m_subtitle_groups->add_scene(scene.m_sorting_group, scene.m_name);
}
if (isSelected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
if (current_scene) {
draw_new_cutscene_line_form();
}
for (size_t i = 0; i < scene.m_lines.size(); i++) {
auto& subtitleLine = scene.m_lines.at(i);
std::string summary;
if (subtitleLine.line_utf8.empty()) {
summary = fmt::format("[{}] Clear Screen", subtitleLine.frame);
} else {
summary = fmt::format("[{}] {} - '{}...'", subtitleLine.frame, subtitleLine.speaker_utf8,
subtitleLine.line_utf8.substr(0, 30));
}
if (subtitleLine.line_utf8.empty()) {
ImGui::PushStyleColor(ImGuiCol_Text, m_disabled_text_color);
} else if (subtitleLine.offscreen) {
ImGui::PushStyleColor(ImGuiCol_Text, m_offscreen_text_color);
}
if (ImGui::TreeNode(fmt::format("{}", i).c_str(), "%s", summary.c_str())) {
if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
ImGui::PopStyleColor();
}
ImGui::InputInt("Starting Frame", &subtitleLine.frame,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
ImGui::InputText("Speaker", &subtitleLine.speaker_utf8);
ImGui::InputText("Text", &subtitleLine.line_utf8);
ImGui::Checkbox("Offscreen?", &subtitleLine.offscreen);
ImGui::PushStyleColor(ImGuiCol_Button, m_warning_color);
if (ImGui::Button("Remove Line")) {
scene.m_lines.erase(scene.m_lines.begin() + i);
}
ImGui::PopStyleColor();
ImGui::TreePop();
} else if (subtitleLine.line_utf8.empty() || subtitleLine.offscreen) {
ImGui::PopStyleColor();
}
}
}
void SubtitleEditor::draw_new_cutscene_line_form() {
ImGui::InputInt("Frame Number", &m_current_scene_frame,
ImGuiInputTextFlags_::ImGuiInputTextFlags_CharsDecimal);
ImGui::InputText("Text", &m_current_scene_text);
ImGui::InputText("Speaker", &m_current_scene_speaker);
ImGui::Checkbox("Offscreen", &m_current_scene_offscreen);
bool rendered_text_entry_btn = false;
if (m_current_scene_frame < 0 || m_current_scene_text.empty() ||
m_current_scene_speaker.empty()) {
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
ImGui::Text("Can't add a new text entry with the current fields!");
ImGui::PopStyleColor();
} else {
rendered_text_entry_btn = true;
if (ImGui::Button("Add Text Entry")) {
m_current_scene->add_line(m_current_scene_frame, "", m_current_scene_text, "",
m_current_scene_speaker, m_current_scene_offscreen);
}
}
if (m_current_scene_frame < 0) {
ImGui::PushStyleColor(ImGuiCol_Text, m_error_text_color);
ImGui::Text("Can't add a clear screen entry with the current fields!");
ImGui::PopStyleColor();
} else {
if (rendered_text_entry_btn) {
ImGui::SameLine();
if (ImGui::Button("Add Clear Screen Entry")) {
m_current_scene->add_line(m_current_scene_frame, "", "", "", "", false);
}
}
}
ImGui::NewLine();
}
+6 -1
View File
@@ -33,7 +33,10 @@ class SubtitleEditor {
void draw_all_cutscene_groups();
void draw_all_scenes(std::string group_name, bool base_cutscenes = false);
void draw_current_cutscene();
void draw_subtitle_options(GameSubtitleSceneInfo& scene, bool current_scene = false);
void draw_new_cutscene_line_form();
void draw_all_hint_groups();
void draw_all_hints(std::string group_name, bool base_cutscenes);
GameSubtitleDB m_subtitle_db;
std::map<std::string, SubtitleEditorDB::Entry> m_db = {};
@@ -50,6 +53,7 @@ class SubtitleEditor {
std::string m_new_scene_name = "";
std::string m_new_scene_group = "";
std::string m_new_scene_id = "0";
std::string m_new_scene_group_name = "";
@@ -79,6 +83,7 @@ class SubtitleEditor {
const std::string_view& process_name);
void repl_execute_cutscene_code(const SubtitleEditorDB::Entry& entry);
void repl_rebuild_text();
void repl_play_hint(const std::string_view& hint_name);
bool is_scene_in_current_lang(const std::string& scene_name);
};