5#include <unordered_map>
8#include "absl/status/status.h"
9#include "absl/strings/str_cat.h"
10#include "absl/strings/str_format.h"
24#include "imgui/misc/cpp/imgui_stdlib.h"
36 std::string bankSTR = bank ?
"1st" :
"2nd";
38 bank ? absl::StrFormat(
"%X4", pos & 0xFFFF)
39 : absl::StrFormat(
"%X4", (pos -
kTextData2) & 0xFFFF);
40 std::string message = absl::StrFormat(
41 "There is too much text data in the %s block to save.\n"
42 "Available: %X4 | Used: %s",
43 bankSTR, space, posSTR);
48using ImGui::BeginChild;
49using ImGui::BeginTable;
53using ImGui::InputTextMultiline;
57using ImGui::Separator;
58using ImGui::TableHeadersRow;
59using ImGui::TableNextColumn;
60using ImGui::TableSetupColumn;
62using ImGui::TextWrapped;
65 ImGuiTableFlags_Borders |
66 ImGuiTableFlags_Resizable;
78 window_manager->RegisterWindowContent(
80 window_manager->RegisterWindowContent(
82 window_manager->RegisterWindowContent(
83 std::make_unique<FontAtlasPanel>([
this]() {
87 window_manager->RegisterWindowContent(
88 std::make_unique<DictionaryPanel>([
this]() {
95 window_manager->OpenWindow(session_id,
"message.message_list");
103 LOG_INFO(
"MessageEditor",
"Loaded %zu messages from ROM",
125 LOG_ERROR(
"MessageEditor",
"No messages found in ROM!");
130 const int vanilla_count =
static_cast<int>(
list_of_texts_.size());
135 expanded_base_id, expanded_count);
139 if (!resolved.has_value() && expanded_count == 0 &&
143 const size_t rom_size =
rom_->
size();
144 if (start >= 0 && end >= start &&
static_cast<size_t>(end) < rom_size) {
148 "OpenMessageById: expanded load skipped/failed: %s",
149 std::string(status.message()).c_str());
153 expanded_base_id, expanded_count);
156 "OpenMessageById: expanded region out of bounds (0x%X-0x%X, "
158 start, end, rom_size);
162 if (!resolved.has_value()) {
169 "message.message_list");
171 "message.message_editor");
174 if (!resolved->is_expanded) {
175 const int idx = resolved->index;
176 if (idx < 0 || idx >= vanilla_count) {
185 const int parsed_idx = resolved->display_id;
186 if (parsed_idx >= 0 &&
198 const int idx = resolved->index;
199 if (idx < 0 || idx >= expanded_count) {
208 const int parsed_idx = resolved->display_id;
209 if (parsed_idx >= 0 &&
224 if (layout.first_expanded_id != 0) {
225 base_id =
static_cast<int>(layout.first_expanded_id);
231 base_id = std::max(base_id,
static_cast<int>(
list_of_texts_.size()));
246 std::vector<gfx::SnesColor> colors;
248 for (
int i = 0; i < 16; ++i) {
249 const float value =
static_cast<float>(i) / 15.0f;
250 colors.emplace_back(ImVec4(value, value, value, 1.0f));
253 if (!colors.empty()) {
254 colors[0].set_transparent(
true);
262 if (!
rom() || !
rom()->is_loaded()) {
263 LOG_WARN(
"MessageEditor",
"ROM not loaded - skipping font graphics load");
269 const size_t rom_size =
rom()->
size();
270 if (rom_size >
static_cast<size_t>(
kGfxFont)) {
272 rom_size -
static_cast<size_t>(
kGfxFont));
277 "Font graphics truncated (ROM size %zu, read %zu bytes)",
278 rom_size, available);
282 "ROM size %zu too small for font graphics offset 0x%X", rom_size,
290 if (load_font.ok()) {
293 const std::string error_message(load_font.status().message());
294 LOG_WARN(
"MessageEditor",
"LoadFontGraphics failed: %s",
295 error_message.c_str());
306 const std::vector<uint8_t>& font_data) {
307 if (font_data.empty()) {
308 LOG_WARN(
"MessageEditor",
"Font graphics data missing - atlas stays empty");
313 const size_t row_count = (font_data.size() + atlas_width - 1) / atlas_width;
314 const int atlas_height =
static_cast<int>(std::max<size_t>(1, row_count));
316 const size_t expected_size =
static_cast<size_t>(atlas_width) * atlas_height;
317 std::vector<uint8_t> padded(font_data.begin(), font_data.end());
318 if (padded.size() < expected_size) {
319 padded.resize(expected_size, 0);
320 }
else if (padded.size() > expected_size) {
321 padded.resize(expected_size);
335 return absl::OkStatus();
342 return absl::OkStatus();
358 if (!bitmap.is_active()) {
361 const auto command = bitmap.texture()
397 if (BeginChild(
"##MessagesList", ImVec2(0, 0),
true,
398 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
400 if (ImGui::Button(
"Import Bundle")) {
407 if (ImGui::Button(
"Export Bundle")) {
414 absl::StrFormat(
"Export failed: %s", status.message());
429 TableSetupColumn(
"ID", ImGuiTableColumnFlags_WidthFixed, 50);
430 TableSetupColumn(
"Type", ImGuiTableColumnFlags_WidthFixed, 80);
431 TableSetupColumn(
"Contents", ImGuiTableColumnFlags_WidthStretch);
432 TableSetupColumn(
"Address", ImGuiTableColumnFlags_WidthFixed, 100);
437 const int vanilla_count =
static_cast<int>(
list_of_texts_.size());
439 const int total_rows = vanilla_count + expanded_count;
442 ImGuiListClipper clipper;
443 clipper.Begin(total_rows);
445 while (clipper.Step()) {
446 for (
int row = clipper.DisplayStart; row < clipper.DisplayEnd; ++row) {
447 if (row < vanilla_count) {
472 int expanded_idx = row - vanilla_count;
474 const int display_id =
476 const char* display_text =
"Missing text";
477 if (display_id >= 0 &&
497 TextWrapped(
"%s", display_text);
500 TextWrapped(
"%s",
util::HexLong(expanded_message.Address).c_str());
514 ImVec2(ImGui::GetContentRegionAvail().x, 0))) {
517 if (ImGui::IsItemDeactivatedAfterEdit()) {
521 if (!line_warnings.empty()) {
523 for (
const auto& warning : line_warnings) {
524 ImGui::BulletText(
"%s", warning.c_str());
530 ImGui::BeginChild(
"##MessagePreview", ImVec2(0, 0),
true);
532 Text(
"Message Preview");
533 if (Button(
"View Palette")) {
534 ImGui::OpenPopup(
"Palette");
536 if (ImGui::BeginPopup(
"Palette")) {
541 BeginChild(
"CurrentGfxFont", ImVec2(348, 0),
true,
542 ImGuiWindowFlags_NoScrollWithMouse);
548 if (ImGui::IsWindowHovered()) {
549 float wheel = ImGui::GetIO().MouseWheel;
552 }
else if (wheel < 0 &&
560 const float dest_width = std::max(0.0f, preview_canvas_size.x - 8.0f);
561 const float dest_height = std::max(0.0f, preview_canvas_size.y - 8.0f);
562 float src_height = 0.0f;
563 if (dest_width > 0.0f && dest_height > 0.0f) {
564 const float src_width =
570 ImVec2(dest_width, dest_height),
572 ImVec2(src_width, src_height)
578 ImDrawList* overlay_draw_list = ImGui::GetWindowDrawList();
581 float line_height = 16.0f;
584 float scale_y = 1.0f;
585 if (dest_height > 0.0f && src_height > 0.0f) {
586 scale_y = dest_height / src_height;
590 float y = canvas_p0.y + src_y * scale_y;
591 if (y >= canvas_p0.y && y <= canvas_p0.y + canvas_sz.y) {
592 overlay_draw_list->AddLine(ImVec2(canvas_p0.x, y),
593 ImVec2(canvas_p0.x + canvas_sz.x, y),
594 IM_COL32(100, 180, 255, 180), 1.5f);
595 overlay_draw_list->AddText(ImVec2(canvas_p0.x + canvas_sz.x + 4, y - 6),
596 IM_COL32(100, 180, 255, 200),
"[V]");
606 if (ImGui::CollapsingHeader(
"Message Structure",
607 ImGuiTreeNodeFlags_DefaultOpen)) {
610 int scroll_count = 0;
611 int current_line_chars = 0;
619 " [V] Scroll at byte %zu (line %d, %d chars)", i,
620 line_num, current_line_chars);
621 current_line_chars = 0;
623 }
else if (
byte ==
kLine1) {
624 ImGui::TextColored(ImVec4(0.7f, 0.85f, 0.5f, 1.0f),
625 " [1] Line 1 at byte %zu", i);
626 current_line_chars = 0;
628 }
else if (
byte ==
kLine2) {
629 ImGui::TextColored(ImVec4(0.7f, 0.85f, 0.5f, 1.0f),
630 " [2] Line 2 at byte %zu", i);
631 current_line_chars = 0;
633 }
else if (
byte ==
kLine3) {
634 ImGui::TextColored(ImVec4(0.7f, 0.85f, 0.5f, 1.0f),
635 " [3] Line 3 at byte %zu", i);
636 current_line_chars = 0;
638 }
else if (
byte < 100) {
639 current_line_chars++;
643 if (scroll_count == 0) {
644 ImGui::TextDisabled(
"No scroll breaks in this message");
646 ImGui::Text(
"Total scroll breaks: %d", scroll_count);
651 ImGui::TextDisabled(
"Line width budget (max ~170px):");
652 int estimated_line_width = current_line_chars * 8;
653 float width_ratio =
static_cast<float>(estimated_line_width) / 170.0f;
657 ImGui::TextColored(width_color,
"Last line: ~%dpx / 170px (%d chars)",
658 estimated_line_width, current_line_chars);
673 ImGui::BeginChild(
"##ExpandedMessageSettings", ImVec2(0, 130),
true,
674 ImGuiWindowFlags_AlwaysVerticalScrollbar);
675 ImGui::Text(
"Expanded Messages");
677 if (ImGui::Button(
"Load from ROM")) {
680 LOG_WARN(
"MessageEditor",
"Load from ROM: %s",
681 std::string(status.message()).c_str());
685 if (ImGui::Button(
"Load from File")) {
692 std::vector<std::string> parsed_expanded;
698 popup_manager->Show(
"Error");
702 parsed_expanded.end());
714 int remaining = capacity - used;
715 float usage_ratio =
static_cast<float>(used) /
static_cast<float>(capacity);
717 ImVec4 capacity_color;
718 if (usage_ratio < 0.75f) {
720 }
else if (usage_ratio < 0.90f) {
725 ImGui::TextColored(capacity_color,
"Bank: %d / %d bytes (%d free)", used,
726 capacity, remaining);
728 if (ImGui::Button(
"Add New Message")) {
735 if (display_id >= 0 &&
742 if (ImGui::Button(
"Export to JSON")) {
754 ImGui::BeginChild(
"##TextCommands",
755 ImVec2(0, ImGui::GetContentRegionAvail().y / 2),
true,
756 ImGuiWindowFlags_AlwaysVerticalScrollbar);
757 static uint8_t command_parameter = 0;
759 for (
const auto& text_element : TextCommands) {
760 if (Button(text_element.GenericToken.c_str())) {
762 text_element.GetParamToken(command_parameter));
766 TextWrapped(
"%s", text_element.Description.c_str());
773 ImGui::BeginChild(
"##SpecialChars",
774 ImVec2(0, ImGui::GetContentRegionAvail().y / 2),
true,
775 ImGuiWindowFlags_AlwaysVerticalScrollbar);
776 for (
const auto& text_element : SpecialChars) {
777 if (Button(text_element.GenericToken.c_str())) {
782 TextWrapped(
"%s", text_element.Description.c_str());
789 if (ImGui::BeginChild(
"##DictionaryChild",
790 ImVec2(0, ImGui::GetContentRegionAvail().y),
true,
791 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
793 TableSetupColumn(
"ID");
794 TableSetupColumn(
"Contents");
798 const int dict_count =
800 ImGuiListClipper clipper;
801 clipper.Begin(dict_count);
803 while (clipper.Step()) {
804 for (
int row = clipper.DisplayStart; row < clipper.DisplayEnd; ++row) {
809 Text(
"%s", dictionary.Contents.c_str());
822 std::string raw_text = text;
823 raw_text.erase(std::remove(raw_text.begin(), raw_text.end(),
'\n'),
835 if (parsed_index >= 0) {
862 if (!entries_or.ok()) {
864 absl::StrFormat(
"Import failed: %s", entries_or.status().message());
872 int duplicate_errors = 0;
873 int parse_error_entries = 0;
874 int vanilla_updated = 0;
875 int expanded_updated = 0;
876 int expanded_created = 0;
877 bool expanded_modified =
false;
878 std::vector<std::string> issue_samples;
880 auto add_issue_sample = [&issue_samples](
const std::string& issue) {
881 constexpr size_t kMaxIssueSamples = 4;
882 if (issue_samples.size() < kMaxIssueSamples) {
883 issue_samples.push_back(issue);
891 std::unordered_map<std::string, int> seen_entries;
893 auto entries = entries_or.value();
894 for (
const auto& entry : entries) {
895 const std::string entry_key = make_entry_key(entry);
896 if (seen_entries.find(entry_key) != seen_entries.end()) {
899 add_issue_sample(absl::StrFormat(
"Duplicate entry for %s", entry_key));
902 seen_entries.emplace(entry_key, 1);
906 warnings +=
static_cast<int>(parse_result.warnings.size());
907 warnings +=
static_cast<int>(line_warnings.size());
909 if (!parse_result.ok()) {
911 parse_error_entries++;
912 if (!parse_result.errors.empty()) {
913 add_issue_sample(absl::StrFormat(
"Parse error for %s: %s", entry_key,
914 parse_result.errors.front()));
916 add_issue_sample(absl::StrFormat(
"Parse error for %s", entry_key));
922 if (entry.id < 0 || entry.id >=
static_cast<int>(
list_of_texts_.size())) {
925 absl::StrFormat(
"Vanilla ID out of range: %d", entry.id));
929 message.RawString = entry.text;
930 message.ContentsParsed = entry.text;
931 message.Data = parse_result.bytes;
932 message.DataParsed = parse_result.bytes;
943 absl::StrFormat(
"Expanded ID out of range: %d", entry.id));
948 const int target_size = entry.id + 1;
950 for (
int i = old_size; i < target_size; ++i) {
953 expanded_created += target_size - old_size;
956 message.RawString = entry.text;
957 message.ContentsParsed = entry.text;
958 message.Data = parse_result.bytes;
959 message.DataParsed = parse_result.bytes;
961 if (parsed_index >= 0) {
967 expanded_modified =
true;
973 if (expanded_modified) {
976 message.Address = pos;
977 pos +=
static_cast<int>(message.Data.size()) + 1;
985 if (current_display_id >= 0) {
991 "Import finished with %d errors (%d applied: vanilla %d updated, "
992 "expanded %d updated/%d created; %d warnings, %d duplicates, %d "
994 errors, applied, vanilla_updated, expanded_updated, expanded_created,
995 warnings, duplicate_errors, parse_error_entries);
996 if (!issue_samples.empty()) {
1003 "Imported %d messages (vanilla %d updated, expanded %d updated/%d "
1004 "created, %d warnings).",
1005 applied, vanilla_updated, expanded_updated, expanded_created, warnings);
1015 LOG_WARN(
"MessageEditor",
"Preview data is empty, skipping bitmap update");
1031 LOG_ERROR(
"MessageEditor",
"Bitmap surface is null after set_data()");
1043 "Updated message preview bitmap (size: %zu) and queued texture update",
1055 "Created message preview bitmap (%dx%d) with 8-bit depth and "
1056 "queued texture creation",
1062 std::vector<uint8_t> backup =
rom()->
vector();
1070 bool in_second_bank =
false;
1073 for (
const auto value : message.Data) {
1080 return absl::InternalError(DisplayTextOverflowError(pos,
true));
1085 in_second_bank =
true;
1097 std::copy(backup.begin(), backup.end(),
rom()->mutable_data());
1098 return absl::InternalError(DisplayTextOverflowError(pos,
false));
1107 std::copy(backup.begin(), backup.end(),
rom()->mutable_data());
1112 return absl::OkStatus();
1117 return absl::OkStatus();
1121 return absl::FailedPreconditionError(
"ROM not loaded");
1125 std::vector<std::string> all_texts;
1128 all_texts.push_back(msg.RawString);
1141 pos +=
static_cast<int>(bytes.size()) + 1;
1144 return absl::OkStatus();
1149 return absl::FailedPreconditionError(
"ROM not loaded");
1160 return absl::NotFoundError(
1161 "No expanded messages found in ROM at expanded text region");
1165 auto parsed_expanded =
1168 if (msg.ID >= 0 && msg.ID <
static_cast<int>(parsed_expanded.size())) {
1174 return absl::OkStatus();
1182 total +=
static_cast<int>(msg.Data.size()) + 1;
1194 return absl::OkStatus();
1199 if (ImGui::GetClipboardText() !=
nullptr) {
1203 return absl::OkStatus();
1212 return absl::OkStatus();
1232 if (parsed_index >= 0 &&
1252 if (message_index < 0 ||
1259 if (message_index < 0 ||
1267 int parsed_index = message_index;
1272 if (parsed_index >= 0 &&
1277 message_index, is_expanded};
1295 if (parsed_index >= 0 &&
1344 if (ImGui::Begin(
"Find & Replace",
nullptr,
1345 ImGuiWindowFlags_AlwaysAutoResize)) {
1346 static char find_text[256] =
"";
1347 static char replace_text[256] =
"";
1348 ImGui::InputText(
"Search", find_text, IM_ARRAYSIZE(find_text));
1349 ImGui::InputText(
"Replace with", replace_text, IM_ARRAYSIZE(replace_text));
1351 if (ImGui::Button(
"Find Next")) {
1357 if (ImGui::Button(
"Find All")) {
1363 if (ImGui::Button(
"Replace")) {
1377 if (ImGui::Button(
"Replace All")) {
1382 count == 1 ?
"" :
"s");
1398 return absl::OkStatus();
1407 std::string source = text;
1410 std::transform(search.begin(), search.end(), search.begin(), ::tolower);
1411 std::transform(source.begin(), source.end(), source.begin(), ::tolower);
1414 size_t pos = source.find(search);
1415 if (pos == std::string::npos)
1420 bool start_ok = (pos == 0 || !std::isalnum(source[pos - 1]));
1421 bool end_ok = (pos + search.size() >= source.size() ||
1422 !std::isalnum(source[pos + search.size()]));
1423 if (!start_ok || !end_ok) {
1425 while (pos != std::string::npos) {
1426 start_ok = (pos == 0 || !std::isalnum(source[pos - 1]));
1427 end_ok = (pos + search.size() >= source.size() ||
1428 !std::isalnum(source[pos + search.size()]));
1429 if (start_ok && end_ok)
1431 pos = source.find(search, pos + 1);
1433 if (pos == std::string::npos)
1449 int total_replacements = 0;
1451 auto replace_in_text = [&](std::string& text) ->
int {
1456 std::transform(search.begin(), search.end(), search.begin(), ::tolower);
1460 while (pos < text.size()) {
1461 std::string source = text;
1463 std::transform(source.begin(), source.end(), source.begin(), ::tolower);
1466 size_t found = source.find(search, pos);
1467 if (found == std::string::npos)
1471 bool start_ok = (found == 0 || !std::isalnum(source[found - 1]));
1472 bool end_ok = (found + search.size() >= source.size() ||
1473 !std::isalnum(source[found + search.size()]));
1474 if (!start_ok || !end_ok) {
1489 int parsed_idx =
static_cast<int>(i);
1490 if (parsed_idx < 0 ||
1496 int count = replace_in_text(text);
1511 total_replacements += count;
1524 if (parsed_idx < 0 ||
1530 int count = replace_in_text(text);
1544 total_replacements += count;
1559 if (current_parsed_idx >= 0 &&
1577 return total_replacements;
const auto & vector() const
const MessageLayout & message_layout() const
bool loaded() const
Check if the manifest has been loaded.
virtual void SetGameData(zelda3::GameData *game_data)
UndoManager undo_manager_
zelda3::GameData * game_data() const
EditorDependencies dependencies_
std::vector< std::string > parsed_messages_
absl::Status Copy() override
bool current_message_is_expanded_
bool replace_status_error_
std::vector< MessageData > expanded_messages_
int CalculateExpandedBankUsage() const
absl::Status Find() override
void ResolveFontPalette()
void EnsureFontTexturesReady()
absl::Status SaveExpandedMessages()
bool font_graphics_loaded_
absl::Status Update() override
void FinalizePendingUndo()
absl::Status LoadExpandedMessagesFromRom()
void DrawExpandedMessageSettings()
void UpdateCurrentMessageFromText(const std::string &text)
absl::Status Paste() override
void ApplySnapshot(const MessageSnapshot &snapshot)
gui::Canvas current_font_gfx16_canvas_
gui::Canvas font_gfx_canvas_
void RefreshFontAtlasBitmap(const std::vector< uint8_t > &font_data)
absl::Status Undo() override
absl::Status Load() override
std::string replace_status_
std::string message_bundle_status_
std::array< uint8_t, 0x4000 > raw_font_gfx_data_
gfx::SnesPalette BuildFallbackFontPalette() const
void Initialize() override
std::string replace_text_
absl::Status Cut() override
void DrawMessagePreview()
int expanded_message_base_id_
bool message_bundle_status_error_
std::optional< MessageSnapshot > pending_undo_before_
std::vector< MessageData > list_of_texts_
bool OpenMessageById(int display_id)
gfx::SnesPalette font_preview_colors_
MessageData current_message_
MessagePreview message_preview_
gui::TextBox message_text_box_
void DrawCurrentMessage()
void DrawSpecialCharacters()
absl::Status Redo() override
int ResolveExpandedMessageBaseId() const
void ImportMessageBundleFromFile(const std::string &path)
gfx::Bitmap current_font_gfx16_bitmap_
int ReplaceCurrentMatch()
int current_message_index_
gfx::Bitmap font_gfx_bitmap_
std::string expanded_message_path_
absl::Status Save() override
void SetGameData(zelda3::GameData *game_data) override
void Push(std::unique_ptr< UndoAction > action)
absl::Status Redo()
Redo the top action. Returns error if stack is empty.
absl::Status Undo()
Undo the top action. Returns error if stack is empty.
bool OpenWindow(size_t session_id, const std::string &base_window_id)
void QueueTextureCommand(TextureCommandType type, Bitmap *bitmap)
Represents a bitmap image optimized for SNES ROM hacking.
const SnesPalette & palette() const
void Create(int width, int height, int depth, std::span< uint8_t > data)
Create a bitmap with the given dimensions and data.
TextureHandle texture() const
SnesPalette * mutable_palette()
void set_data(const std::vector< uint8_t > &data)
void SetPalette(const SnesPalette &palette)
Set the palette for the bitmap using SNES palette format.
SDL_Surface * surface() const
RAII timer for automatic timing management.
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
void DrawBitmap(Bitmap &bitmap, int border_offset, float scale)
bool DrawTileSelector(int size, int size_y=0)
void DrawBackground(ImVec2 canvas_size=ImVec2(0, 0))
void DrawGrid(float grid_step=64.0f, int tile_id_offset=8)
static std::string ShowSaveFileDialog(const std::string &default_name="", const std::string &default_extension="")
ShowSaveFileDialog opens a save file dialog and returns the selected filepath. Uses global feature fl...
static std::string ShowOpenFileDialog()
ShowOpenFileDialog opens a file dialog and returns the selected filepath. Uses global feature flag to...
#define LOG_DEBUG(category, format,...)
#define LOG_ERROR(category, format,...)
#define LOG_WARN(category, format,...)
#define LOG_INFO(category, format,...)
#define PRINT_IF_ERROR(expression)
std::string DisplayTextOverflowError(int pos, bool bank)
constexpr int kCharactersWidth
int GetExpandedTextDataStart()
constexpr uint8_t kScrollVertical
std::optional< ResolvedMessageId > ResolveMessageDisplayId(int display_id, int vanilla_count, int expanded_base_id, int expanded_count)
absl::Status LoadExpandedMessages(std::string &expanded_message_path, std::vector< std::string > &parsed_messages, std::vector< MessageData > &expanded_messages, std::vector< DictionaryEntry > &dictionary)
std::string MessageBankToString(MessageBank bank)
constexpr int kCurrentMessageWidth
constexpr int kCurrentMessageHeight
absl::Status WriteExpandedTextData(Rom *rom, int start, int end, const std::vector< std::string > &messages)
constexpr uint8_t kBlockTerminator
absl::StatusOr< std::vector< MessageBundleEntry > > LoadMessageBundleFromJson(const std::string &path)
constexpr int kFontGfxMessageSize
std::vector< std::string > ParseMessageData(std::vector< MessageData > &message_data, const std::vector< DictionaryEntry > &dictionary_entries)
constexpr uint8_t kMessageTerminator
constexpr int kFontGfxMessageDepth
std::vector< MessageData > ReadAllTextData(uint8_t *rom, int pos, int max_pos)
constexpr int kTextData2End
std::vector< DictionaryEntry > BuildDictionaryEntries(Rom *rom)
std::vector< uint8_t > ParseMessageToData(std::string str)
absl::Status ExportMessagesToJson(const std::string &path, const std::vector< MessageData > &messages)
constexpr uint8_t kWidthArraySize
absl::Status ExportMessageBundleToJson(const std::string &path, const std::vector< MessageData > &vanilla, const std::vector< MessageData > &expanded)
constexpr ImGuiTableFlags kMessageTableFlags
std::vector< MessageData > ReadExpandedTextData(uint8_t *rom, int pos)
MessageParseResult ParseMessageToDataWithDiagnostics(std::string_view str)
int GetExpandedTextDataEnd()
std::vector< std::string > ValidateMessageLineWidths(const std::string &message)
constexpr int kTextDataEnd
std::vector< uint8_t > SnesTo8bppSheet(std::span< const uint8_t > sheet, int bpp, int num_sheets)
void EndCanvas(Canvas &canvas)
void BeginCanvas(Canvas &canvas, ImVec2 child_size)
void MemoryEditorPopup(const std::string &label, std::span< uint8_t > memory)
IMGUI_API bool DisplayPalette(gfx::SnesPalette &palette, bool loaded)
bool InputHexByte(const char *label, uint8_t *data, float input_width, bool no_step)
std::string HexWord(uint16_t word, HexStringParams params)
std::string HexLong(uint32_t dword, HexStringParams params)
absl::StatusOr< gfx::Bitmap > LoadFontGraphics(const Rom &rom)
Loads font graphics from ROM.
#define RETURN_IF_ERROR(expr)
project::YazeProject * project
WorkspaceWindowManager * window_manager
PopupManager * popup_manager
std::vector< uint8_t > Data
std::string ContentsParsed
std::vector< uint8_t > current_preview_data_
void DrawMessagePreview(const MessageData &message)
std::array< uint8_t, kWidthArraySize > width_array
std::vector< uint8_t > font_gfx16_data_2_
std::vector< uint8_t > font_gfx16_data_
std::vector< int > scroll_marker_lines
std::vector< DictionaryEntry > all_dictionaries_
auto palette(int i) const
core::HackManifest hack_manifest
gfx::PaletteGroupMap palette_groups