5#include <unordered_map>
8#include "absl/status/status.h"
9#include "absl/strings/str_cat.h"
10#include "absl/strings/str_format.h"
23#include "imgui/misc/cpp/imgui_stdlib.h"
35 std::string bankSTR = bank ?
"1st" :
"2nd";
37 bank ? absl::StrFormat(
"%X4", pos & 0xFFFF)
38 : absl::StrFormat(
"%X4", (pos -
kTextData2) & 0xFFFF);
39 std::string message = absl::StrFormat(
40 "There is too much text data in the %s block to save.\n"
41 "Available: %X4 | Used: %s",
42 bankSTR, space, posSTR);
47using ImGui::BeginChild;
48using ImGui::BeginTable;
52using ImGui::InputTextMultiline;
56using ImGui::Separator;
57using ImGui::TableHeadersRow;
58using ImGui::TableNextColumn;
59using ImGui::TableSetupColumn;
61using ImGui::TextWrapped;
64 ImGuiTableFlags_Borders |
65 ImGuiTableFlags_Resizable;
77 panel_manager->RegisterEditorPanel(
79 panel_manager->RegisterEditorPanel(
81 panel_manager->RegisterEditorPanel(std::make_unique<FontAtlasPanel>([
this]() {
85 panel_manager->RegisterEditorPanel(
86 std::make_unique<DictionaryPanel>([
this]() {
93 panel_manager->ShowPanel(session_id,
"message.message_list");
101 LOG_INFO(
"MessageEditor",
"Loaded %zu messages from ROM",
123 LOG_ERROR(
"MessageEditor",
"No messages found in ROM!");
128 const int vanilla_count =
static_cast<int>(
list_of_texts_.size());
138 if (!resolved.has_value() && expanded_count == 0 &&
142 const size_t rom_size =
rom_->
size();
143 if (start >= 0 && end >= start &&
144 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, rom=0x%zX)",
157 start, end, rom_size);
161 if (!resolved.has_value()) {
171 if (!resolved->is_expanded) {
172 const int idx = resolved->index;
173 if (idx < 0 || idx >= vanilla_count) {
182 const int parsed_idx = resolved->display_id;
183 if (parsed_idx >= 0 &&
195 const int idx = resolved->index;
196 if (idx < 0 || idx >= expanded_count) {
205 const int parsed_idx = resolved->display_id;
206 if (parsed_idx >= 0 && parsed_idx <
static_cast<int>(
parsed_messages_.size())) {
220 if (layout.first_expanded_id != 0) {
221 base_id =
static_cast<int>(layout.first_expanded_id);
227 base_id = std::max(base_id,
static_cast<int>(
list_of_texts_.size()));
242 std::vector<gfx::SnesColor> colors;
244 for (
int i = 0; i < 16; ++i) {
245 const float value =
static_cast<float>(i) / 15.0f;
246 colors.emplace_back(ImVec4(value, value, value, 1.0f));
249 if (!colors.empty()) {
250 colors[0].set_transparent(
true);
258 if (!
rom() || !
rom()->is_loaded()) {
259 LOG_WARN(
"MessageEditor",
"ROM not loaded - skipping font graphics load");
265 const size_t rom_size =
rom()->
size();
266 if (rom_size >
static_cast<size_t>(
kGfxFont)) {
267 const size_t available =
269 rom_size -
static_cast<size_t>(
kGfxFont));
273 "Font graphics truncated (ROM size %zu, read %zu bytes)",
274 rom_size, available);
278 "ROM size %zu too small for font graphics offset 0x%X", rom_size,
286 if (load_font.ok()) {
289 const std::string error_message(load_font.status().message());
290 LOG_WARN(
"MessageEditor",
"LoadFontGraphics failed: %s",
291 error_message.c_str());
302 const std::vector<uint8_t>& font_data) {
303 if (font_data.empty()) {
304 LOG_WARN(
"MessageEditor",
"Font graphics data missing - atlas stays empty");
309 const size_t row_count =
310 (font_data.size() + atlas_width - 1) / atlas_width;
311 const int atlas_height =
312 static_cast<int>(std::max<size_t>(1, row_count));
314 const size_t expected_size =
315 static_cast<size_t>(atlas_width) * atlas_height;
316 std::vector<uint8_t> padded(font_data.begin(), font_data.end());
317 if (padded.size() < expected_size) {
318 padded.resize(expected_size, 0);
319 }
else if (padded.size() > expected_size) {
320 padded.resize(expected_size);
334 return absl::OkStatus();
341 return absl::OkStatus();
357 if (!bitmap.is_active()) {
360 const auto command = bitmap.texture()
395 if (BeginChild(
"##MessagesList", ImVec2(0, 0),
true,
396 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
398 if (ImGui::Button(
"Import Bundle")) {
405 if (ImGui::Button(
"Export Bundle")) {
412 absl::StrFormat(
"Export failed: %s", status.message());
416 absl::StrFormat(
"Exported bundle: %s", path);
423 ? ImVec4(1.0f, 0.4f, 0.4f, 1.0f)
424 : ImVec4(0.6f, 0.9f, 0.6f, 1.0f);
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) {
463 ImGui::TextColored(ImVec4(0.6f, 0.6f, 1.0f, 1.0f),
"Vanilla");
472 int expanded_idx = row - vanilla_count;
474 const int display_id =
476 const char* display_text =
"Missing text";
477 if (display_id >= 0 &&
494 ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.4f, 1.0f),
"Expanded");
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()) {
522 ImGui::TextColored(ImVec4(1.0f, 0.75f, 0.3f, 1.0f),
523 "Line width warnings");
524 for (
const auto& warning : line_warnings) {
525 ImGui::BulletText(
"%s", warning.c_str());
531 ImGui::BeginChild(
"##MessagePreview", ImVec2(0, 0),
true);
533 Text(
"Message Preview");
534 if (Button(
"View Palette")) {
535 ImGui::OpenPopup(
"Palette");
537 if (ImGui::BeginPopup(
"Palette")) {
542 BeginChild(
"CurrentGfxFont", ImVec2(348, 0),
true,
543 ImGuiWindowFlags_NoScrollWithMouse);
549 if (ImGui::IsWindowHovered()) {
550 float wheel = ImGui::GetIO().MouseWheel;
553 }
else if (wheel < 0 &&
561 const float dest_width = std::max(0.0f, preview_canvas_size.x - 8.0f);
562 const float dest_height = std::max(0.0f, preview_canvas_size.y - 8.0f);
563 float src_height = 0.0f;
564 if (dest_width > 0.0f && dest_height > 0.0f) {
565 const float src_width = std::min(dest_width * 0.5f,
567 src_height = std::min(dest_height * 0.5f,
571 ImVec2(dest_width, dest_height),
573 ImVec2(src_width, src_height)
579 ImDrawList* overlay_draw_list = ImGui::GetWindowDrawList();
582 float line_height = 16.0f;
585 float scale_y = 1.0f;
586 if (dest_height > 0.0f && src_height > 0.0f) {
587 scale_y = dest_height / src_height;
591 float y = canvas_p0.y + src_y * scale_y;
592 if (y >= canvas_p0.y && y <= canvas_p0.y + canvas_sz.y) {
593 overlay_draw_list->AddLine(
594 ImVec2(canvas_p0.x, y),
595 ImVec2(canvas_p0.x + canvas_sz.x, y),
596 IM_COL32(100, 180, 255, 180), 1.5f);
597 overlay_draw_list->AddText(
598 ImVec2(canvas_p0.x + canvas_sz.x + 4, y - 6),
599 IM_COL32(100, 180, 255, 200),
"[V]");
609 if (ImGui::CollapsingHeader(
"Message Structure",
610 ImGuiTreeNodeFlags_DefaultOpen)) {
613 int scroll_count = 0;
614 int current_line_chars = 0;
622 ImVec4(0.4f, 0.7f, 1.0f, 1.0f),
623 " [V] Scroll at byte %zu (line %d, %d chars)",
624 i, line_num, current_line_chars);
625 current_line_chars = 0;
627 }
else if (
byte ==
kLine1) {
628 ImGui::TextColored(ImVec4(0.7f, 0.85f, 0.5f, 1.0f),
629 " [1] Line 1 at byte %zu", i);
630 current_line_chars = 0;
632 }
else if (
byte ==
kLine2) {
633 ImGui::TextColored(ImVec4(0.7f, 0.85f, 0.5f, 1.0f),
634 " [2] Line 2 at byte %zu", i);
635 current_line_chars = 0;
637 }
else if (
byte ==
kLine3) {
638 ImGui::TextColored(ImVec4(0.7f, 0.85f, 0.5f, 1.0f),
639 " [3] Line 3 at byte %zu", i);
640 current_line_chars = 0;
642 }
else if (
byte < 100) {
643 current_line_chars++;
647 if (scroll_count == 0) {
648 ImGui::TextDisabled(
"No scroll breaks in this message");
650 ImGui::Text(
"Total scroll breaks: %d", scroll_count);
655 ImGui::TextDisabled(
"Line width budget (max ~170px):");
656 int estimated_line_width = current_line_chars * 8;
657 float width_ratio =
static_cast<float>(estimated_line_width) / 170.0f;
660 ? ImVec4(0.9f, 0.2f, 0.2f, 1.0f)
661 : (width_ratio > 0.85f)
662 ? ImVec4(0.9f, 0.7f, 0.1f, 1.0f)
663 : ImVec4(0.2f, 0.8f, 0.2f, 1.0f);
664 ImGui::TextColored(width_color,
"Last line: ~%dpx / 170px (%d chars)",
665 estimated_line_width, current_line_chars);
680 ImGui::BeginChild(
"##ExpandedMessageSettings", ImVec2(0, 130),
true,
681 ImGuiWindowFlags_AlwaysVerticalScrollbar);
682 ImGui::Text(
"Expanded Messages");
684 if (ImGui::Button(
"Load from ROM")) {
687 LOG_WARN(
"MessageEditor",
"Load from ROM: %s",
688 std::string(status.message()).c_str());
692 if (ImGui::Button(
"Load from File")) {
699 std::vector<std::string> parsed_expanded;
705 popup_manager->Show(
"Error");
709 parsed_expanded.end());
721 int remaining = capacity - used;
722 float usage_ratio =
static_cast<float>(used) /
static_cast<float>(capacity);
724 ImVec4 capacity_color;
725 if (usage_ratio < 0.75f) {
726 capacity_color = ImVec4(0.2f, 0.8f, 0.2f, 1.0f);
727 }
else if (usage_ratio < 0.90f) {
728 capacity_color = ImVec4(0.9f, 0.7f, 0.1f, 1.0f);
730 capacity_color = ImVec4(0.9f, 0.2f, 0.2f, 1.0f);
732 ImGui::TextColored(capacity_color,
"Bank: %d / %d bytes (%d free)",
733 used, capacity, remaining);
735 if (ImGui::Button(
"Add New Message")) {
742 if (display_id >= 0 &&
749 if (ImGui::Button(
"Export to JSON")) {
761 ImGui::BeginChild(
"##TextCommands",
762 ImVec2(0, ImGui::GetContentRegionAvail().y / 2),
true,
763 ImGuiWindowFlags_AlwaysVerticalScrollbar);
764 static uint8_t command_parameter = 0;
766 for (
const auto& text_element : TextCommands) {
767 if (Button(text_element.GenericToken.c_str())) {
769 text_element.GetParamToken(command_parameter));
773 TextWrapped(
"%s", text_element.Description.c_str());
780 ImGui::BeginChild(
"##SpecialChars",
781 ImVec2(0, ImGui::GetContentRegionAvail().y / 2),
true,
782 ImGuiWindowFlags_AlwaysVerticalScrollbar);
783 for (
const auto& text_element : SpecialChars) {
784 if (Button(text_element.GenericToken.c_str())) {
789 TextWrapped(
"%s", text_element.Description.c_str());
796 if (ImGui::BeginChild(
"##DictionaryChild",
797 ImVec2(0, ImGui::GetContentRegionAvail().y),
true,
798 ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
800 TableSetupColumn(
"ID");
801 TableSetupColumn(
"Contents");
805 const int dict_count =
807 ImGuiListClipper clipper;
808 clipper.Begin(dict_count);
810 while (clipper.Step()) {
811 for (
int row = clipper.DisplayStart; row < clipper.DisplayEnd; ++row) {
816 Text(
"%s", dictionary.Contents.c_str());
829 std::string raw_text = text;
830 raw_text.erase(std::remove(raw_text.begin(), raw_text.end(),
'\n'),
842 if (parsed_index >= 0) {
870 if (!entries_or.ok()) {
872 absl::StrFormat(
"Import failed: %s", entries_or.status().message());
880 int duplicate_errors = 0;
881 int parse_error_entries = 0;
882 int vanilla_updated = 0;
883 int expanded_updated = 0;
884 int expanded_created = 0;
885 bool expanded_modified =
false;
886 std::vector<std::string> issue_samples;
888 auto add_issue_sample = [&issue_samples](
const std::string& issue) {
889 constexpr size_t kMaxIssueSamples = 4;
890 if (issue_samples.size() < kMaxIssueSamples) {
891 issue_samples.push_back(issue);
899 std::unordered_map<std::string, int> seen_entries;
901 auto entries = entries_or.value();
902 for (
const auto& entry : entries) {
903 const std::string entry_key = make_entry_key(entry);
904 if (seen_entries.find(entry_key) != seen_entries.end()) {
908 absl::StrFormat(
"Duplicate entry for %s", entry_key));
911 seen_entries.emplace(entry_key, 1);
915 warnings +=
static_cast<int>(parse_result.warnings.size());
916 warnings +=
static_cast<int>(line_warnings.size());
918 if (!parse_result.ok()) {
920 parse_error_entries++;
921 if (!parse_result.errors.empty()) {
922 add_issue_sample(absl::StrFormat(
923 "Parse error for %s: %s", entry_key,
924 parse_result.errors.front()));
927 absl::StrFormat(
"Parse error for %s", entry_key));
933 if (entry.id < 0 || entry.id >=
static_cast<int>(
list_of_texts_.size())) {
935 add_issue_sample(absl::StrFormat(
936 "Vanilla ID out of range: %d", entry.id));
940 message.RawString = entry.text;
941 message.ContentsParsed = entry.text;
942 message.Data = parse_result.bytes;
943 message.DataParsed = parse_result.bytes;
944 if (entry.id >= 0 && entry.id <
static_cast<int>(
parsed_messages_.size())) {
953 absl::StrFormat(
"Expanded ID out of range: %d", entry.id));
958 const int target_size = entry.id + 1;
960 for (
int i = old_size; i < target_size; ++i) {
963 expanded_created += target_size - old_size;
966 message.RawString = entry.text;
967 message.ContentsParsed = entry.text;
968 message.Data = parse_result.bytes;
969 message.DataParsed = parse_result.bytes;
971 if (parsed_index >= 0) {
977 expanded_modified =
true;
983 if (expanded_modified) {
986 message.Address = pos;
987 pos +=
static_cast<int>(message.Data.size()) + 1;
995 if (current_display_id >= 0) {
1001 "Import finished with %d errors (%d applied: vanilla %d updated, "
1002 "expanded %d updated/%d created; %d warnings, %d duplicates, %d "
1004 errors, applied, vanilla_updated, expanded_updated, expanded_created,
1005 warnings, duplicate_errors, parse_error_entries);
1006 if (!issue_samples.empty()) {
1013 "Imported %d messages (vanilla %d updated, expanded %d updated/%d "
1014 "created, %d warnings).",
1015 applied, vanilla_updated, expanded_updated, expanded_created, warnings);
1025 LOG_WARN(
"MessageEditor",
"Preview data is empty, skipping bitmap update");
1041 LOG_ERROR(
"MessageEditor",
"Bitmap surface is null after set_data()");
1053 "Updated message preview bitmap (size: %zu) and queued texture update",
1065 "Created message preview bitmap (%dx%d) with 8-bit depth and "
1066 "queued texture creation",
1072 std::vector<uint8_t> backup =
rom()->
vector();
1080 bool in_second_bank =
false;
1083 for (
const auto value : message.Data) {
1090 return absl::InternalError(DisplayTextOverflowError(pos,
true));
1095 in_second_bank =
true;
1107 std::copy(backup.begin(), backup.end(),
rom()->mutable_data());
1108 return absl::InternalError(DisplayTextOverflowError(pos,
false));
1117 std::copy(backup.begin(), backup.end(),
rom()->mutable_data());
1122 return absl::OkStatus();
1127 return absl::OkStatus();
1131 return absl::FailedPreconditionError(
"ROM not loaded");
1135 std::vector<std::string> all_texts;
1138 all_texts.push_back(msg.RawString);
1153 pos +=
static_cast<int>(bytes.size()) + 1;
1156 return absl::OkStatus();
1161 return absl::FailedPreconditionError(
"ROM not loaded");
1172 return absl::NotFoundError(
1173 "No expanded messages found in ROM at expanded text region");
1177 auto parsed_expanded =
1181 msg.ID <
static_cast<int>(parsed_expanded.size())) {
1187 return absl::OkStatus();
1194 total +=
static_cast<int>(msg.Data.size()) + 1;
1206 return absl::OkStatus();
1211 if (ImGui::GetClipboardText() !=
nullptr) {
1215 return absl::OkStatus();
1224 return absl::OkStatus();
1244 if (parsed_index >= 0 &&
1263 if (message_index < 0 ||
1270 if (message_index < 0 ||
1278 int parsed_index = message_index;
1283 if (parsed_index >= 0 &&
1287 MessageSnapshot after{std::move(after_message), std::move(text), message_index,
1306 if (parsed_index >= 0 &&
1356 if (ImGui::Begin(
"Find Text",
nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
1357 static char find_text[256] =
"";
1358 ImGui::InputText(
"Search", find_text, IM_ARRAYSIZE(find_text));
1360 if (ImGui::Button(
"Find Next")) {
1365 if (ImGui::Button(
"Find All")) {
1370 if (ImGui::Button(
"Replace")) {
1380 return absl::OkStatus();
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_
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 message_bundle_status_
std::array< uint8_t, 0x4000 > raw_font_gfx_data_
gfx::SnesPalette BuildFallbackFontPalette() const
void Initialize() override
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 current_message_index_
gfx::Bitmap font_gfx_bitmap_
std::string expanded_message_path_
absl::Status Save() override
void SetGameData(zelda3::GameData *game_data) override
bool ShowPanel(size_t session_id, const std::string &base_card_id)
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.
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
PanelManager * panel_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