yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
editor_selection_dialog.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cfloat>
5#include <fstream>
6#include <sstream>
7
8#include "absl/strings/str_cat.h"
9#include "absl/strings/str_format.h"
10#include "app/gui/core/color.h"
11#include "app/gui/core/icons.h"
13#include "app/gui/core/style.h"
15#include "imgui/imgui.h"
16#include "util/file_util.h"
17
18namespace yaze {
19namespace editor {
20
21namespace {
22
23constexpr float kEditorSelectBaseFontSize = 16.0f;
24constexpr float kEditorSelectCardBaseWidth = 180.0f;
25constexpr float kEditorSelectCardBaseHeight = 120.0f;
26constexpr float kEditorSelectCardWidthMaxFactor = 1.35f;
27constexpr float kEditorSelectCardHeightMaxFactor = 1.35f;
28constexpr float kEditorSelectRecentBaseWidth = 150.0f;
29constexpr float kEditorSelectRecentBaseHeight = 35.0f;
30constexpr float kEditorSelectRecentWidthMaxFactor = 1.3f;
31
32struct GridLayout {
33 int columns = 1;
34 float item_width = 0.0f;
35 float item_height = 0.0f;
36 float spacing = 0.0f;
37 float row_start_x = 0.0f;
38};
39
41 const float font_size = ImGui::GetFontSize();
42 if (font_size <= 0.0f) {
43 return 1.0f;
44 }
45 return font_size / kEditorSelectBaseFontSize;
46}
47
48GridLayout ComputeGridLayout(float avail_width, float min_width,
49 float max_width, float min_height,
50 float max_height, float preferred_width,
51 float aspect_ratio, float spacing) {
52 GridLayout layout;
53 layout.spacing = spacing;
54 const auto width_for_columns = [avail_width, spacing](int columns) {
55 return (avail_width - spacing * static_cast<float>(columns - 1)) /
56 static_cast<float>(columns);
57 };
58
59 layout.columns = std::max(1, static_cast<int>((avail_width + spacing) /
60 (preferred_width + spacing)));
61
62 layout.item_width = width_for_columns(layout.columns);
63 while (layout.columns > 1 && layout.item_width < min_width) {
64 layout.columns -= 1;
65 layout.item_width = width_for_columns(layout.columns);
66 }
67
68 layout.item_width = std::min(layout.item_width, max_width);
69 layout.item_width = std::min(layout.item_width, avail_width);
70 layout.item_height =
71 std::clamp(layout.item_width * aspect_ratio, min_height, max_height);
72
73 const float row_width =
74 layout.item_width * static_cast<float>(layout.columns) +
75 spacing * static_cast<float>(layout.columns - 1);
76 layout.row_start_x = ImGui::GetCursorPosX();
77 if (row_width < avail_width) {
78 layout.row_start_x += (avail_width - row_width) * 0.5f;
79 }
80
81 return layout;
82}
83
84ImVec4 ScaleColor(const ImVec4& color, float scale, float alpha) {
85 return ImVec4(color.x * scale, color.y * scale, color.z * scale, alpha);
86}
87
88ImVec4 ScaleColor(const ImVec4& color, float scale) {
89 return ScaleColor(color, scale, color.w);
90}
91
92ImVec4 WithAlpha(ImVec4 color, float alpha) {
93 color.w = alpha;
94 return color;
95}
96
97ImVec4 GetEditorAccentColor(EditorType type, const gui::Theme& theme) {
98 switch (type) {
106 return gui::ConvertColorToImVec4(theme.info);
110 return gui::ConvertColorToImVec4(theme.accent);
112 return gui::ConvertColorToImVec4(theme.error);
114 return gui::ConvertColorToImVec4(theme.info);
117 case EditorType::kHex:
120 return gui::ConvertColorToImVec4(theme.info);
122 return gui::ConvertColorToImVec4(theme.accent);
125 default:
127 }
128}
129
130} // namespace
131
133 // Use platform-aware shortcut strings (Cmd on macOS, Ctrl elsewhere)
134 const char* ctrl = gui::GetCtrlDisplayName();
135 editors_ = {
136 {EditorType::kOverworld, "Overworld", ICON_MD_MAP,
137 "Edit overworld maps, entrances, and properties",
138 absl::StrFormat("%s+1", ctrl), false, true},
139
141 "Design dungeon rooms, layouts, and mechanics",
142 absl::StrFormat("%s+2", ctrl), false, true},
143
145 "Modify tiles, palettes, and graphics sets",
146 absl::StrFormat("%s+3", ctrl), false, true},
147
149 "Edit sprite graphics and properties", absl::StrFormat("%s+4", ctrl),
150 false, true},
151
153 "Edit dialogue, signs, and text", absl::StrFormat("%s+5", ctrl), false,
154 true},
155
157 "Configure music and sound effects", absl::StrFormat("%s+6", ctrl),
158 false, true},
159
161 "Edit color palettes and animations", absl::StrFormat("%s+7", ctrl),
162 false, true},
163
164 {EditorType::kScreen, "Screens", ICON_MD_TV,
165 "Edit title screen and ending screens", absl::StrFormat("%s+8", ctrl),
166 false, true},
167
169 "Write and edit assembly code", absl::StrFormat("%s+9", ctrl), false,
170 false},
171
172 {EditorType::kHex, "Hex Editor", ICON_MD_DATA_ARRAY,
173 "Direct ROM memory editing and comparison",
174 absl::StrFormat("%s+0", ctrl), false, true},
175
177 "Test and debug your ROM in real-time with live debugging",
178 absl::StrFormat("%s+Shift+E", ctrl), false, true},
179
181 "Configure AI agent, collaboration, and automation",
182 absl::StrFormat("%s+Shift+A", ctrl), false, false},
183 };
184
186}
187
188bool EditorSelectionDialog::Show(bool* p_open) {
189 // Sync internal state with external flag
190 if (p_open && *p_open && !is_open_) {
191 is_open_ = true;
192 }
193
194 if (!is_open_) {
195 if (p_open)
196 *p_open = false;
197 return false;
198 }
199
200 bool editor_selected = false;
201 bool* window_open = p_open ? p_open : &is_open_;
202
203 // Set window properties immediately before Begin to prevent them from
204 // affecting tooltips
205 ImVec2 center = ImGui::GetMainViewport()->GetCenter();
206 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
207 ImGui::SetNextWindowSize(
208 ImVec2(950, 650),
209 ImGuiCond_Appearing); // Slightly larger for better layout
210
211 if (ImGui::Begin("Editor Selection", window_open,
212 ImGuiWindowFlags_NoCollapse)) {
214
215 ImGui::Separator();
216 ImGui::Spacing();
217
218 // Quick access buttons for recently used
219 if (!recent_editors_.empty()) {
221 ImGui::Separator();
222 ImGui::Spacing();
223 }
224
225 // Main editor grid
226 ImGui::Text(ICON_MD_APPS " All Editors");
227 ImGui::Spacing();
228
229 const float scale = GetEditorSelectScale();
230 const float min_width = kEditorSelectCardBaseWidth * scale;
231 const float max_width =
232 kEditorSelectCardBaseWidth * kEditorSelectCardWidthMaxFactor * scale;
233 const float min_height = kEditorSelectCardBaseHeight * scale;
234 const float max_height =
235 kEditorSelectCardBaseHeight * kEditorSelectCardHeightMaxFactor * scale;
236 const float spacing = ImGui::GetStyle().ItemSpacing.x;
237 const float aspect_ratio = min_height / std::max(min_width, 1.0f);
238 GridLayout layout = ComputeGridLayout(
239 ImGui::GetContentRegionAvail().x, min_width, max_width, min_height,
240 max_height, min_width, aspect_ratio, spacing);
241
242 int column = 0;
243 for (size_t i = 0; i < editors_.size(); ++i) {
244 if (column == 0) {
245 ImGui::SetCursorPosX(layout.row_start_x);
246 }
247
248 EditorType prev_selection = selected_editor_;
249 DrawEditorPanel(editors_[i], static_cast<int>(i),
250 ImVec2(layout.item_width, layout.item_height));
251
252 // Check if an editor was just selected
253 if (selected_editor_ != prev_selection) {
254 editor_selected = true;
258 }
259 // Auto-dismiss after selection
260 is_open_ = false;
261 if (p_open) {
262 *p_open = false;
263 }
264 }
265
266 column += 1;
267 if (column < layout.columns) {
268 ImGui::SameLine(0.0f, layout.spacing);
269 } else {
270 column = 0;
271 ImGui::Spacing();
272 }
273 }
274
275 if (column != 0) {
276 ImGui::NewLine();
277 }
278 }
279 ImGui::End();
280
281 // Sync state back
282 if (p_open && !(*p_open)) {
283 is_open_ = false;
284 }
285
286 // DO NOT auto-dismiss here. Let the callback/EditorManager handle it.
287 // This allows the dialog to be used as a persistent switcher if desired.
288
289 return editor_selected;
290}
291
293 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
294 const ImVec4 accent = gui::ConvertColorToImVec4(theme.accent);
295 const ImVec4 text_secondary = gui::ConvertColorToImVec4(theme.text_secondary);
296
297 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[2]); // Large font
298
299 ImGui::TextColored(accent, ICON_MD_EDIT " Select an Editor");
300
301 ImGui::PopFont();
302
303 ImGui::TextColored(text_secondary,
304 "Choose an editor to begin working on your ROM. "
305 "You can open multiple editors simultaneously.");
306}
307
309 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
310 const ImVec4 accent = gui::ConvertColorToImVec4(theme.accent);
311 ImGui::TextColored(accent, ICON_MD_HISTORY " Recently Used");
312 ImGui::Spacing();
313
314 const float scale = GetEditorSelectScale();
315 const float min_width = kEditorSelectRecentBaseWidth * scale;
316 const float max_width =
317 kEditorSelectRecentBaseWidth * kEditorSelectRecentWidthMaxFactor * scale;
318 const float height = kEditorSelectRecentBaseHeight * scale;
319 const float spacing = ImGui::GetStyle().ItemSpacing.x;
320 GridLayout layout = ComputeGridLayout(
321 ImGui::GetContentRegionAvail().x, min_width, max_width, height, height,
322 min_width, height / std::max(min_width, 1.0f), spacing);
323
324 int column = 0;
325 for (EditorType type : recent_editors_) {
326 // Find editor info
327 auto it = std::find_if(
328 editors_.begin(), editors_.end(),
329 [type](const EditorInfo& info) { return info.type == type; });
330
331 if (it != editors_.end()) {
332 if (column == 0) {
333 ImGui::SetCursorPosX(layout.row_start_x);
334 }
335
336 const ImVec4 base_color = GetEditorAccentColor(it->type, theme);
337 ImGui::PushStyleColor(ImGuiCol_Button,
338 ScaleColor(base_color, 0.5f, 0.7f));
339 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
340 ScaleColor(base_color, 0.7f, 0.9f));
341 ImGui::PushStyleColor(ImGuiCol_ButtonActive, WithAlpha(base_color, 1.0f));
342
343 if (ImGui::Button(absl::StrCat(it->icon, " ", it->name).c_str(),
344 ImVec2(layout.item_width, layout.item_height))) {
345 selected_editor_ = type;
346 }
347
348 ImGui::PopStyleColor(3);
349
350 if (ImGui::IsItemHovered()) {
351 ImGui::SetTooltip("%s", it->description);
352 }
353
354 column += 1;
355 if (column < layout.columns) {
356 ImGui::SameLine(0.0f, layout.spacing);
357 } else {
358 column = 0;
359 ImGui::Spacing();
360 }
361 }
362 }
363
364 if (column != 0) {
365 ImGui::NewLine();
366 }
367}
368
370 const ImVec2& card_size) {
371 ImGui::PushID(index);
372
373 const auto& theme = gui::ThemeManager::Get().GetCurrentTheme();
374 const ImVec4 base_color = GetEditorAccentColor(info.type, theme);
375 const ImVec4 text_primary = gui::ConvertColorToImVec4(theme.text_primary);
376 const ImVec4 text_secondary = gui::ConvertColorToImVec4(theme.text_secondary);
377 const ImVec4 accent = gui::ConvertColorToImVec4(theme.accent);
378 ImFont* text_font = ImGui::GetFont();
379 const float text_font_size = ImGui::GetFontSize();
380
381 const ImGuiStyle& style = ImGui::GetStyle();
382 const float line_height = ImGui::GetTextLineHeight();
383 const float padding_x = std::max(style.FramePadding.x, card_size.x * 0.06f);
384 const float padding_y = std::max(style.FramePadding.y, card_size.y * 0.08f);
385
386 const float footer_height = info.shortcut.empty() ? 0.0f : line_height;
387 const float footer_spacing =
388 info.shortcut.empty() ? 0.0f : style.ItemSpacing.y;
389 const float available_icon_height = card_size.y - padding_y * 2.0f -
390 line_height - footer_height -
391 footer_spacing;
392 const float min_icon_radius = line_height * 0.9f;
393 float max_icon_radius = card_size.y * 0.24f;
394 max_icon_radius = std::max(max_icon_radius, min_icon_radius);
395 const float icon_radius = std::clamp(available_icon_height * 0.5f,
396 min_icon_radius, max_icon_radius);
397
398 const ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
399 ImDrawList* draw_list = ImGui::GetWindowDrawList();
400 const ImVec2 icon_center(cursor_pos.x + card_size.x * 0.5f,
401 cursor_pos.y + padding_y + icon_radius);
402 float title_y = icon_center.y + icon_radius + style.ItemSpacing.y;
403 const float footer_y = cursor_pos.y + card_size.y - padding_y - footer_height;
404 if (title_y + line_height > footer_y - style.ItemSpacing.y) {
405 title_y = footer_y - line_height - style.ItemSpacing.y;
406 }
407
408 // Panel styling with gradients
409 bool is_recent = std::find(recent_editors_.begin(), recent_editors_.end(),
410 info.type) != recent_editors_.end();
411
412 // Create gradient background
413 ImU32 color_top = ImGui::GetColorU32(ScaleColor(base_color, 0.4f, 0.85f));
414 ImU32 color_bottom = ImGui::GetColorU32(ScaleColor(base_color, 0.2f, 0.9f));
415
416 // Draw gradient card background
417 draw_list->AddRectFilledMultiColor(
418 cursor_pos,
419 ImVec2(cursor_pos.x + card_size.x, cursor_pos.y + card_size.y), color_top,
420 color_top, color_bottom, color_bottom);
421
422 // Colored border
423 ImU32 border_color =
424 is_recent ? ImGui::GetColorU32(WithAlpha(base_color, 1.0f))
425 : ImGui::GetColorU32(ScaleColor(base_color, 0.6f, 0.7f));
426 const float rounding = std::max(style.FrameRounding, card_size.y * 0.05f);
427 const float border_thickness =
428 is_recent ? std::max(2.0f, style.FrameBorderSize + 1.0f)
429 : std::max(1.0f, style.FrameBorderSize);
430 draw_list->AddRect(
431 cursor_pos,
432 ImVec2(cursor_pos.x + card_size.x, cursor_pos.y + card_size.y),
433 border_color, rounding, 0, border_thickness);
434
435 // Recent indicator badge
436 if (is_recent) {
437 const float badge_radius =
438 std::clamp(line_height * 0.6f, line_height * 0.4f, line_height);
439 ImVec2 badge_pos(cursor_pos.x + card_size.x - padding_x - badge_radius,
440 cursor_pos.y + padding_y + badge_radius);
441 draw_list->AddCircleFilled(badge_pos, badge_radius,
442 ImGui::GetColorU32(base_color), 16);
443 const ImU32 star_color = ImGui::GetColorU32(text_primary);
444 const ImVec2 star_size =
445 text_font->CalcTextSizeA(text_font_size, FLT_MAX, 0.0f, ICON_MD_STAR);
446 const ImVec2 star_pos(badge_pos.x - star_size.x * 0.5f,
447 badge_pos.y - star_size.y * 0.5f);
448 draw_list->AddText(text_font, text_font_size, star_pos, star_color,
450 }
451
452 // Make button transparent (we draw our own background)
453 ImVec4 button_bg = ImGui::GetStyleColorVec4(ImGuiCol_Button);
454 button_bg.w = 0.0f;
455 ImGui::PushStyleColor(ImGuiCol_Button, button_bg);
456 ImGui::PushStyleColor(ImGuiCol_ButtonHovered,
457 ScaleColor(base_color, 0.3f, 0.5f));
458 ImGui::PushStyleColor(ImGuiCol_ButtonActive,
459 ScaleColor(base_color, 0.5f, 0.7f));
460
461 bool clicked =
462 ImGui::Button(absl::StrCat("##", info.name).c_str(), card_size);
463 bool is_hovered = ImGui::IsItemHovered();
464
465 ImGui::PopStyleColor(3);
466
467 // Draw icon with colored background circle
468 ImU32 icon_bg = ImGui::GetColorU32(base_color);
469 draw_list->AddCircleFilled(icon_center, icon_radius, icon_bg, 32);
470
471 // Draw icon
472 ImFont* icon_font = ImGui::GetFont();
473 if (ImGui::GetIO().Fonts->Fonts.size() > 2) {
474 icon_font = ImGui::GetIO().Fonts->Fonts[2];
475 } else if (ImGui::GetIO().Fonts->Fonts.size() > 1) {
476 icon_font = ImGui::GetIO().Fonts->Fonts[1];
477 }
478 ImGui::PushFont(icon_font);
479 const float icon_font_size = ImGui::GetFontSize();
480 const ImVec2 icon_size =
481 icon_font->CalcTextSizeA(icon_font_size, FLT_MAX, 0.0f, info.icon);
482 ImGui::PopFont();
483 const ImVec2 icon_text_pos(icon_center.x - icon_size.x * 0.5f,
484 icon_center.y - icon_size.y * 0.5f);
485 draw_list->AddText(icon_font, icon_font_size, icon_text_pos,
486 ImGui::GetColorU32(text_primary), info.icon);
487
488 // Draw name
489 const ImVec2 name_size =
490 text_font->CalcTextSizeA(text_font_size, FLT_MAX, 0.0f, info.name);
491 float name_x = cursor_pos.x + (card_size.x - name_size.x) * 0.5f;
492 const float name_min_x = cursor_pos.x + padding_x;
493 const float name_max_x = cursor_pos.x + card_size.x - padding_x;
494 name_x = std::clamp(name_x, name_min_x, name_max_x);
495 const ImVec2 name_pos(name_x, title_y);
496 const ImVec4 name_clip(name_min_x, cursor_pos.y + padding_y, name_max_x,
497 footer_y);
498 draw_list->AddText(text_font, text_font_size, name_pos,
499 ImGui::GetColorU32(base_color), info.name, nullptr, 0.0f,
500 &name_clip);
501
502 // Draw shortcut hint if available
503 if (!info.shortcut.empty()) {
504 const ImVec2 shortcut_pos(cursor_pos.x + padding_x, footer_y);
505 const ImVec4 shortcut_clip(cursor_pos.x + padding_x, footer_y,
506 cursor_pos.x + card_size.x - padding_x,
507 cursor_pos.y + card_size.y - padding_y);
508 draw_list->AddText(text_font, text_font_size, shortcut_pos,
509 ImGui::GetColorU32(text_secondary),
510 info.shortcut.c_str(), nullptr, 0.0f, &shortcut_clip);
511 }
512
513 // Hover glow effect
514 if (is_hovered) {
515 ImU32 glow_color = ImGui::GetColorU32(ScaleColor(base_color, 1.0f, 0.18f));
516 draw_list->AddRectFilled(
517 cursor_pos,
518 ImVec2(cursor_pos.x + card_size.x, cursor_pos.y + card_size.y),
519 glow_color, rounding);
520 }
521
522 // Enhanced tooltip with fixed sizing
523 if (is_hovered) {
524 const float tooltip_width = std::clamp(card_size.x * 1.4f, 240.0f, 340.0f);
525 ImGui::SetNextWindowSize(ImVec2(tooltip_width, 0), ImGuiCond_Always);
526 ImGui::BeginTooltip();
527 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]); // Medium font
528 ImGui::TextColored(base_color, "%s %s", info.icon, info.name);
529 ImGui::PopFont();
530 ImGui::Separator();
531 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + tooltip_width - 20.0f);
532 ImGui::TextWrapped("%s", info.description);
533 ImGui::PopTextWrapPos();
534 if (!info.shortcut.empty()) {
535 ImGui::Spacing();
536 ImGui::TextColored(base_color, ICON_MD_KEYBOARD " %s",
537 info.shortcut.c_str());
538 }
539 if (is_recent) {
540 ImGui::Spacing();
541 ImGui::TextColored(accent, ICON_MD_STAR " Recently used");
542 }
543 ImGui::EndTooltip();
544 }
545
546 if (clicked) {
547 selected_editor_ = info.type;
548 }
549
550 ImGui::PopID();
551}
552
554 // Remove if already in list
555 auto it = std::find(recent_editors_.begin(), recent_editors_.end(), type);
556 if (it != recent_editors_.end()) {
557 recent_editors_.erase(it);
558 }
559
560 // Add to front
561 recent_editors_.insert(recent_editors_.begin(), type);
562
563 // Limit size
564 if (recent_editors_.size() > kMaxRecentEditors) {
566 }
567
569}
570
572 try {
573 auto data = util::LoadFileFromConfigDir("recent_editors.txt");
574 if (!data.empty()) {
575 std::istringstream ss(data);
576 std::string line;
577 while (std::getline(ss, line) &&
579 int type_int = std::stoi(line);
580 if (type_int >= 0 &&
581 type_int < static_cast<int>(EditorType::kSettings)) {
582 recent_editors_.push_back(static_cast<EditorType>(type_int));
583 }
584 }
585 }
586 } catch (...) {
587 // Ignore errors, just start with empty recent list
588 }
589}
590
592 try {
593 std::ostringstream ss;
594 for (EditorType type : recent_editors_) {
595 ss << static_cast<int>(type) << "\n";
596 }
597 util::SaveFile("recent_editors.txt", ss.str());
598 } catch (...) {
599 // Ignore save errors
600 }
601}
602
603} // namespace editor
604} // namespace yaze
void DrawEditorPanel(const EditorInfo &info, int index, const ImVec2 &card_size)
void SaveRecentEditors()
Save recently used editors to settings.
void LoadRecentEditors()
Load recently used editors from settings.
std::function< void(EditorType)> selection_callback_
void MarkRecentlyUsed(EditorType type)
Mark an editor as recently used.
bool Show(bool *p_open=nullptr)
Show the dialog.
const Theme & GetCurrentTheme() const
static ThemeManager & Get()
#define ICON_MD_APPS
Definition icons.h:168
#define ICON_MD_EMOJI_EMOTIONS
Definition icons.h:672
#define ICON_MD_DATA_ARRAY
Definition icons.h:519
#define ICON_MD_STAR
Definition icons.h:1848
#define ICON_MD_MAP
Definition icons.h:1173
#define ICON_MD_CODE
Definition icons.h:434
#define ICON_MD_VIDEOGAME_ASSET
Definition icons.h:2076
#define ICON_MD_CHAT_BUBBLE
Definition icons.h:395
#define ICON_MD_EDIT
Definition icons.h:645
#define ICON_MD_CASTLE
Definition icons.h:380
#define ICON_MD_MUSIC_NOTE
Definition icons.h:1264
#define ICON_MD_KEYBOARD
Definition icons.h:1028
#define ICON_MD_PALETTE
Definition icons.h:1370
#define ICON_MD_TV
Definition icons.h:2032
#define ICON_MD_COLOR_LENS
Definition icons.h:440
#define ICON_MD_SMART_TOY
Definition icons.h:1781
#define ICON_MD_HISTORY
Definition icons.h:946
GridLayout ComputeGridLayout(float avail_width, float min_width, float max_width, float min_height, float max_height, float preferred_width, float aspect_ratio, float spacing)
const char * GetCtrlDisplayName()
Get the display name for the primary modifier key.
ImVec4 ConvertColorToImVec4(const Color &color)
Definition color.h:23
void SaveFile(const std::string &filename, const std::string &contents)
Definition file_util.cc:56
std::string LoadFileFromConfigDir(const std::string &filename)
Loads a file from the user's config directory.
Definition file_util.cc:38
Metadata about an available editor.
Comprehensive theme structure for YAZE.