yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
window_browser.cc
Go to the documentation of this file.
2
3#include <algorithm>
4#include <cctype>
5#include <string>
6#include <vector>
7
8#include "absl/strings/str_format.h"
10#include "app/gui/core/icons.h"
14#include "imgui/imgui.h"
15
16namespace yaze {
17namespace editor {
18
19namespace {
20
21std::string LowercaseCopy(std::string value) {
22 std::transform(value.begin(), value.end(), value.begin(),
23 [](unsigned char c) { return static_cast<char>(::tolower(c)); });
24 return value;
25}
26
27bool MatchesWindowSearch(const std::string& query,
28 const WindowDescriptor& window) {
29 if (query.empty()) {
30 return true;
31 }
32
33 const std::string search_str = LowercaseCopy(query);
34 return LowercaseCopy(window.display_name).find(search_str) !=
35 std::string::npos ||
36 LowercaseCopy(window.card_id).find(search_str) != std::string::npos ||
37 LowercaseCopy(window.shortcut_hint).find(search_str) !=
38 std::string::npos;
39}
40
41} // namespace
42
44 : window_manager_(window_manager) {}
45
46void WindowBrowser::Draw(size_t session_id, bool* p_open) {
47 const ImGuiViewport* viewport = ImGui::GetMainViewport();
48 ImVec2 max_window_size(1600.0f, 1000.0f);
49 ImVec2 default_window_size(1080.0f, 700.0f);
50 if (viewport) {
51 max_window_size = ImVec2(std::max(760.0f, viewport->WorkSize.x * 0.95f),
52 std::max(520.0f, viewport->WorkSize.y * 0.95f));
53 default_window_size = ImVec2(
54 std::clamp(viewport->WorkSize.x * 0.72f, 880.0f, max_window_size.x),
55 std::clamp(viewport->WorkSize.y * 0.76f, 600.0f, max_window_size.y));
56 const ImVec2 center(viewport->WorkPos.x + viewport->WorkSize.x * 0.5f,
57 viewport->WorkPos.y + viewport->WorkSize.y * 0.5f);
58 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
59 }
60
61 ImGui::SetNextWindowSize(default_window_size, ImGuiCond_Appearing);
62 ImGui::SetNextWindowSizeConstraints(ImVec2(780, 520), max_window_size);
63
64 if (ImGui::Begin(
65 absl::StrFormat("%s Window Browser", ICON_MD_DASHBOARD).c_str(),
66 p_open, ImGuiWindowFlags_NoDocking)) {
67 std::vector<std::string> categories =
69 std::sort(categories.begin(), categories.end());
70 if (category_filter_ != "All" &&
71 std::find(categories.begin(), categories.end(), category_filter_) ==
72 categories.end()) {
73 category_filter_ = "All";
74 }
75
76 const auto all_windows = window_manager_.GetWindowsInSession(session_id);
77 auto count_windows = [&](const std::string& category,
78 bool visible_only) -> int {
79 int count = 0;
80 for (const auto& window_id : all_windows) {
81 const auto* window =
82 window_manager_.GetWindowDescriptor(session_id, window_id);
83 if (!window) {
84 continue;
85 }
86 if (category != "All" && window->category != category) {
87 continue;
88 }
89 const bool visible =
90 window->visibility_flag && *window->visibility_flag;
91 if (!visible_only || visible) {
92 ++count;
93 }
94 }
95 return count;
96 };
97
98 ImGui::SetNextItemWidth(
99 std::max(280.0f, ImGui::GetContentRegionAvail().x * 0.45f));
100 ImGui::InputTextWithHint(
101 "##Search",
102 absl::StrFormat("%s Search windows...", ICON_MD_SEARCH).c_str(),
104 ImGui::SameLine();
105 if (ImGui::Button(ICON_MD_CLEAR " Clear")) {
106 search_filter_[0] = '\0';
107 }
108 ImGui::SameLine();
109 if (category_filter_ == "All") {
110 if (ImGui::Button(ICON_MD_VISIBILITY " Show All")) {
112 }
113 ImGui::SameLine();
114 if (ImGui::Button(ICON_MD_VISIBILITY_OFF " Hide All")) {
116 }
117 } else {
118 if (ImGui::Button(ICON_MD_VISIBILITY " Show Category")) {
120 }
121 ImGui::SameLine();
122 if (ImGui::Button(ICON_MD_VISIBILITY_OFF " Hide Category")) {
124 }
125 }
126
127 ImGui::Separator();
128
129 const float content_height = ImGui::GetContentRegionAvail().y;
130 const float max_sidebar_width =
131 std::max(220.0f, ImGui::GetContentRegionAvail().x * 0.50f);
132 float category_sidebar_width =
134 max_sidebar_width);
135
136 if (ImGui::BeginChild("##WindowBrowserCategories",
137 ImVec2(category_sidebar_width, content_height),
138 true)) {
139 const int visible_total = count_windows("All", true);
140 std::string all_label =
141 absl::StrFormat("%s All Windows (%d/%d)", ICON_MD_DASHBOARD,
142 visible_total, static_cast<int>(all_windows.size()));
143 if (ImGui::Selectable(all_label.c_str(), category_filter_ == "All")) {
144 category_filter_ = "All";
145 }
146 ImGui::Separator();
147
148 for (const auto& category : categories) {
149 const int category_total = count_windows(category, false);
150 if (category_total <= 0) {
151 continue;
152 }
153 const int visible_in_category = count_windows(category, true);
154 const std::string icon = WorkspaceWindowManager::GetCategoryIcon(category);
155 std::string label = absl::StrFormat(
156 "%s %s (%d/%d)", icon.c_str(), category.c_str(),
157 visible_in_category, category_total);
158 if (ImGui::Selectable(label.c_str(), category_filter_ == category)) {
159 category_filter_ = category;
160 }
161 }
162 }
163 ImGui::EndChild();
164
165 ImGui::SameLine(0.0f, 0.0f);
166
167 const float splitter_width = 6.0f;
168 const ImVec2 splitter_pos = ImGui::GetCursorScreenPos();
169 ImGui::InvisibleButton("##WindowBrowserSplitter",
170 ImVec2(splitter_width, content_height));
171 const bool splitter_hovered = ImGui::IsItemHovered();
172 const bool splitter_active = ImGui::IsItemActive();
173 if (splitter_hovered || splitter_active) {
174 ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeEW);
175 }
176 if (splitter_hovered &&
177 ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
180 category_sidebar_width =
182 max_sidebar_width);
183 }
184 if (splitter_active) {
185 category_sidebar_width =
186 std::clamp(category_sidebar_width + ImGui::GetIO().MouseDelta.x,
187 220.0f, max_sidebar_width);
188 window_manager_.SetWindowBrowserCategoryWidth(category_sidebar_width);
189 ImGui::SetTooltip("Width: %.0f px", category_sidebar_width);
190 }
191
192 ImVec4 splitter_color = gui::GetOutlineVec4();
193 splitter_color.w =
194 splitter_active ? 0.95f : (splitter_hovered ? 0.72f : 0.35f);
195 ImGui::GetWindowDrawList()->AddLine(
196 ImVec2(splitter_pos.x + splitter_width * 0.5f, splitter_pos.y),
197 ImVec2(splitter_pos.x + splitter_width * 0.5f,
198 splitter_pos.y + content_height),
199 ImGui::GetColorU32(splitter_color), splitter_active ? 2.0f : 1.0f);
200
201 ImGui::SameLine(0.0f, 0.0f);
202
203 if (ImGui::BeginChild("##WindowBrowserTable", ImVec2(0, content_height),
204 false)) {
205 if (ImGui::BeginTable("##WindowTable", 5,
206 ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg |
207 ImGuiTableFlags_Borders |
208 ImGuiTableFlags_Resizable)) {
209 ImGui::TableSetupColumn("Visible", ImGuiTableColumnFlags_WidthFixed,
210 60);
211 ImGui::TableSetupColumn("Pin", ImGuiTableColumnFlags_WidthFixed, 36);
212 ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch);
213 ImGui::TableSetupColumn("Category", ImGuiTableColumnFlags_WidthFixed,
214 130);
215 ImGui::TableSetupColumn("Shortcut", ImGuiTableColumnFlags_WidthFixed,
216 110);
217 ImGui::TableHeadersRow();
218
219 auto windows = (category_filter_ == "All")
220 ? all_windows
221 : std::vector<std::string>{};
222 if (category_filter_ != "All") {
223 auto category_windows =
225 windows.reserve(category_windows.size());
226 for (const auto& window : category_windows) {
227 windows.push_back(window.card_id);
228 }
229 }
230
231 for (const auto& window_id : windows) {
232 const auto* window =
233 window_manager_.GetWindowDescriptor(session_id, window_id);
234 if (!window) {
235 continue;
236 }
237
238 if (!MatchesWindowSearch(search_filter_, *window)) {
239 continue;
240 }
241
242 ImGui::TableNextRow();
243
244 ImGui::TableNextColumn();
245 if (window->visibility_flag) {
246 bool visible = *window->visibility_flag;
247 if (ImGui::Checkbox(absl::StrFormat("##vis_%s", window->card_id)
248 .c_str(),
249 &visible)) {
250 window_manager_.ToggleWindow(session_id, window->card_id);
251 }
252 }
253
254 ImGui::TableNextColumn();
255 const bool is_pinned = window_manager_.IsWindowPinned(window->card_id);
256 const ImVec4 pin_color =
258 const float pin_side =
260 ImGui::PushID(
261 absl::StrFormat("browser_pin_%s", window->card_id).c_str());
263 is_pinned ? ICON_MD_PUSH_PIN : ICON_MD_PIN,
264 ImVec2(pin_side, pin_side),
265 is_pinned ? "Unpin window" : "Pin window", is_pinned,
266 pin_color, "window_browser", window->card_id.c_str())) {
267 window_manager_.SetWindowPinned(session_id, window->card_id,
268 !is_pinned);
269 }
270 ImGui::PopID();
271
272 ImGui::TableNextColumn();
273 ImGui::Text("%s %s", window->icon.c_str(),
274 window->display_name.c_str());
275 if (ImGui::IsItemHovered() &&
276 ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
277 window_manager_.OpenWindow(session_id, window->card_id);
278 const std::string window_name =
280 if (!window_name.empty()) {
281 ImGui::SetWindowFocus(window_name.c_str());
282 }
283 }
284
285 ImGui::TableNextColumn();
286 ImGui::TextUnformatted(window->category.c_str());
287
288 ImGui::TableNextColumn();
289 if (window->shortcut_hint.empty()) {
290 ImGui::TextDisabled("-");
291 } else {
292 ImGui::TextDisabled("%s", window->shortcut_hint.c_str());
293 }
294 }
295
296 ImGui::EndTable();
297 }
298 }
299 ImGui::EndChild();
300 }
301 ImGui::End();
302}
303
304} // namespace editor
305} // namespace yaze
WindowBrowser(WorkspaceWindowManager &window_manager)
WorkspaceWindowManager & window_manager_
void Draw(size_t session_id, bool *p_open)
Central registry for all editor cards with session awareness and dependency injection.
void HideAllWindowsInCategory(size_t session_id, const std::string &category)
std::string GetWorkspaceWindowName(size_t session_id, const std::string &base_window_id) const
Resolve the exact ImGui window name for a panel by base ID.
std::vector< WindowDescriptor > GetWindowsInCategory(size_t session_id, const std::string &category) const
const WindowDescriptor * GetWindowDescriptor(size_t session_id, const std::string &base_window_id) const
std::vector< std::string > GetWindowsInSession(size_t session_id) const
void SetWindowPinned(size_t session_id, const std::string &base_window_id, bool pinned)
std::vector< std::string > GetAllWindowCategories(size_t session_id) const
static std::string GetCategoryIcon(const std::string &category)
bool OpenWindow(size_t session_id, const std::string &base_window_id)
static constexpr float GetDefaultWindowBrowserCategoryWidth()
bool IsWindowPinned(size_t session_id, const std::string &base_window_id) const
bool ToggleWindow(size_t session_id, const std::string &base_window_id)
void SetWindowBrowserCategoryWidth(float width, bool notify=true)
void ShowAllWindowsInCategory(size_t session_id, const std::string &category)
static float GetStandardWidgetHeight()
#define ICON_MD_SEARCH
Definition icons.h:1673
#define ICON_MD_VISIBILITY
Definition icons.h:2101
#define ICON_MD_VISIBILITY_OFF
Definition icons.h:2102
#define ICON_MD_PIN
Definition icons.h:1470
#define ICON_MD_CLEAR
Definition icons.h:416
#define ICON_MD_DASHBOARD
Definition icons.h:517
#define ICON_MD_PUSH_PIN
Definition icons.h:1529
bool MatchesWindowSearch(const std::string &query, const WindowDescriptor &window)
bool TransparentIconButton(const char *icon, const ImVec2 &size, const char *tooltip, bool is_active, const ImVec4 &active_color, const char *panel_id, const char *anim_id)
Draw a transparent icon button (hover effect only).
ImVec4 GetPrimaryVec4()
ImVec4 GetTextDisabledVec4()
ImVec4 GetOutlineVec4()
Metadata for a dockable editor window (formerly PanelInfo)