191 if (p_open && *p_open && !
is_open_) {
201 bool editor_selected =
false;
202 bool* window_open = p_open ? p_open : &
is_open_;
206 ImGuiViewport* viewport = ImGui::GetMainViewport();
207 ImVec2 center = viewport->GetCenter();
208 ImVec2 view_size = viewport->WorkSize;
209 float target_width = std::clamp(view_size.x * 0.9f, 520.0f, 980.0f);
210 float target_height = std::clamp(view_size.y * 0.88f, 420.0f, 760.0f);
211 ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
212 ImGui::SetNextWindowSize(ImVec2(target_width, target_height),
213 ImGuiCond_Appearing);
214 ImGui::SetNextWindowSizeConstraints(
215 ImVec2(420.0f, 360.0f),
216 ImVec2(view_size.x * 0.98f, view_size.y * 0.95f));
218 if (ImGui::Begin(
"Editor Selection", window_open,
219 ImGuiWindowFlags_NoCollapse)) {
236 const float scale = GetEditorSelectScale();
237 const float compact_scale =
238 ImGui::GetContentRegionAvail().x < 620.0f ? 0.85f : 1.0f;
239 const float min_width =
240 kEditorSelectCardBaseWidth * scale * compact_scale;
241 const float max_width = kEditorSelectCardBaseWidth *
242 kEditorSelectCardWidthMaxFactor * scale *
244 const float min_height =
245 kEditorSelectCardBaseHeight * scale * compact_scale;
246 const float max_height = kEditorSelectCardBaseHeight *
247 kEditorSelectCardHeightMaxFactor * scale *
249 const float spacing = ImGui::GetStyle().ItemSpacing.x;
250 const float aspect_ratio = min_height / std::max(min_width, 1.0f);
251 GridLayout layout = ComputeGridLayout(
252 ImGui::GetContentRegionAvail().x, min_width, max_width, min_height,
253 max_height, min_width, aspect_ratio, spacing);
256 for (
size_t i = 0; i <
editors_.size(); ++i) {
258 ImGui::SetCursorPosX(layout.row_start_x);
263 ImVec2(layout.item_width, layout.item_height));
267 editor_selected =
true;
280 if (column < layout.columns) {
281 ImGui::SameLine(0.0f, layout.spacing);
295 if (p_open && !(*p_open)) {
302 return editor_selected;
327 const float scale = GetEditorSelectScale();
328 const float min_width = kEditorSelectRecentBaseWidth * scale;
329 const float max_width =
330 kEditorSelectRecentBaseWidth * kEditorSelectRecentWidthMaxFactor * scale;
331 const float height = kEditorSelectRecentBaseHeight * scale;
332 const float spacing = ImGui::GetStyle().ItemSpacing.x;
333 const float avail_width = ImGui::GetContentRegionAvail().x;
334 const bool stack_items = avail_width < min_width * 1.6f;
338 layout.item_width = avail_width;
339 layout.item_height = height;
340 layout.spacing = spacing;
342 layout = ComputeGridLayout(
343 avail_width, min_width, max_width, height, height, min_width,
344 height / std::max(min_width, 1.0f), spacing);
350 auto it = std::find_if(
352 [type](
const EditorInfo& info) { return info.type == type; });
356 ImGui::SetCursorPosX(layout.row_start_x);
359 const ImVec4 base_color = GetEditorAccentColor(it->type, theme);
361 {{ImGuiCol_Button, ScaleColor(base_color, 0.5f, 0.7f)},
362 {ImGuiCol_ButtonHovered, ScaleColor(base_color, 0.7f, 0.9f)},
363 {ImGuiCol_ButtonActive, WithAlpha(base_color, 1.0f)}});
365 if (ImGui::Button(absl::StrCat(it->icon,
" ", it->name).c_str(),
366 ImVec2(layout.item_width, layout.item_height))) {
370 if (ImGui::IsItemHovered()) {
371 ImGui::SetTooltip(
"%s", it->description);
375 if (column < layout.columns) {
376 ImGui::SameLine(0.0f, layout.spacing);
390 const ImVec2& card_size) {
391 ImGui::PushID(index);
394 const ImVec4 base_color = GetEditorAccentColor(info.
type, theme);
398 ImFont* text_font = ImGui::GetFont();
399 const float text_font_size = ImGui::GetFontSize();
401 const ImGuiStyle& style = ImGui::GetStyle();
402 const float line_height = ImGui::GetTextLineHeight();
403 const float padding_x = std::max(style.FramePadding.x, card_size.x * 0.06f);
404 const float padding_y = std::max(style.FramePadding.y, card_size.y * 0.08f);
406 const float footer_height = info.
shortcut.empty() ? 0.0f : line_height;
407 const float footer_spacing =
408 info.
shortcut.empty() ? 0.0f : style.ItemSpacing.y;
409 const float available_icon_height = card_size.y - padding_y * 2.0f -
410 line_height - footer_height -
412 const float min_icon_radius = line_height * 0.9f;
413 float max_icon_radius = card_size.y * 0.24f;
414 max_icon_radius = std::max(max_icon_radius, min_icon_radius);
415 const float icon_radius = std::clamp(available_icon_height * 0.5f,
416 min_icon_radius, max_icon_radius);
418 const ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
419 ImDrawList* draw_list = ImGui::GetWindowDrawList();
420 const ImVec2 icon_center(cursor_pos.x + card_size.x * 0.5f,
421 cursor_pos.y + padding_y + icon_radius);
422 float title_y = icon_center.y + icon_radius + style.ItemSpacing.y;
423 const float footer_y = cursor_pos.y + card_size.y - padding_y - footer_height;
424 if (title_y + line_height > footer_y - style.ItemSpacing.y) {
425 title_y = footer_y - line_height - style.ItemSpacing.y;
433 ImU32 color_top = ImGui::GetColorU32(ScaleColor(base_color, 0.4f, 0.85f));
434 ImU32 color_bottom = ImGui::GetColorU32(ScaleColor(base_color, 0.2f, 0.9f));
437 draw_list->AddRectFilledMultiColor(
439 ImVec2(cursor_pos.x + card_size.x, cursor_pos.y + card_size.y), color_top,
440 color_top, color_bottom, color_bottom);
444 is_recent ? ImGui::GetColorU32(WithAlpha(base_color, 1.0f))
445 : ImGui::GetColorU32(ScaleColor(base_color, 0.6f, 0.7f));
446 const float rounding = std::max(style.FrameRounding, card_size.y * 0.05f);
447 const float border_thickness =
448 is_recent ? std::max(2.0f, style.FrameBorderSize + 1.0f)
449 : std::max(1.0f, style.FrameBorderSize);
452 ImVec2(cursor_pos.x + card_size.x, cursor_pos.y + card_size.y),
453 border_color, rounding, 0, border_thickness);
457 const float badge_radius =
458 std::clamp(line_height * 0.6f, line_height * 0.4f, line_height);
459 ImVec2 badge_pos(cursor_pos.x + card_size.x - padding_x - badge_radius,
460 cursor_pos.y + padding_y + badge_radius);
461 draw_list->AddCircleFilled(badge_pos, badge_radius,
462 ImGui::GetColorU32(base_color), 16);
463 const ImU32 star_color = ImGui::GetColorU32(text_primary);
464 const ImVec2 star_size =
465 text_font->CalcTextSizeA(text_font_size, FLT_MAX, 0.0f,
ICON_MD_STAR);
466 const ImVec2 star_pos(badge_pos.x - star_size.x * 0.5f,
467 badge_pos.y - star_size.y * 0.5f);
468 draw_list->AddText(text_font, text_font_size, star_pos, star_color,
473 ImVec4 button_bg = ImGui::GetStyleColorVec4(ImGuiCol_Button);
476 {{ImGuiCol_Button, button_bg},
477 {ImGuiCol_ButtonHovered, ScaleColor(base_color, 0.3f, 0.5f)},
478 {ImGuiCol_ButtonActive, ScaleColor(base_color, 0.5f, 0.7f)}});
481 ImGui::Button(absl::StrCat(
"##", info.
name).c_str(), card_size);
482 bool is_hovered = ImGui::IsItemHovered();
485 ImU32 icon_bg = ImGui::GetColorU32(base_color);
486 draw_list->AddCircleFilled(icon_center, icon_radius, icon_bg, 32);
489 ImFont* icon_font = ImGui::GetFont();
490 if (ImGui::GetIO().Fonts->Fonts.size() > 2) {
491 icon_font = ImGui::GetIO().Fonts->Fonts[2];
492 }
else if (ImGui::GetIO().Fonts->Fonts.size() > 1) {
493 icon_font = ImGui::GetIO().Fonts->Fonts[1];
495 ImGui::PushFont(icon_font);
496 const float icon_font_size = ImGui::GetFontSize();
497 const ImVec2 icon_size =
498 icon_font->CalcTextSizeA(icon_font_size, FLT_MAX, 0.0f, info.
icon);
500 const ImVec2 icon_text_pos(icon_center.x - icon_size.x * 0.5f,
501 icon_center.y - icon_size.y * 0.5f);
502 draw_list->AddText(icon_font, icon_font_size, icon_text_pos,
503 ImGui::GetColorU32(text_primary), info.
icon);
506 const ImVec2 name_size =
507 text_font->CalcTextSizeA(text_font_size, FLT_MAX, 0.0f, info.
name);
508 float name_x = cursor_pos.x + (card_size.x - name_size.x) * 0.5f;
509 const float name_min_x = cursor_pos.x + padding_x;
510 const float name_max_x = cursor_pos.x + card_size.x - padding_x;
511 name_x = std::clamp(name_x, name_min_x, name_max_x);
512 const ImVec2 name_pos(name_x, title_y);
513 const ImVec4 name_clip(name_min_x, cursor_pos.y + padding_y, name_max_x,
515 draw_list->AddText(text_font, text_font_size, name_pos,
516 ImGui::GetColorU32(base_color), info.
name,
nullptr, 0.0f,
521 const ImVec2 shortcut_pos(cursor_pos.x + padding_x, footer_y);
522 const ImVec4 shortcut_clip(cursor_pos.x + padding_x, footer_y,
523 cursor_pos.x + card_size.x - padding_x,
524 cursor_pos.y + card_size.y - padding_y);
525 draw_list->AddText(text_font, text_font_size, shortcut_pos,
526 ImGui::GetColorU32(text_secondary),
527 info.
shortcut.c_str(),
nullptr, 0.0f, &shortcut_clip);
532 ImU32 glow_color = ImGui::GetColorU32(ScaleColor(base_color, 1.0f, 0.18f));
533 draw_list->AddRectFilled(
535 ImVec2(cursor_pos.x + card_size.x, cursor_pos.y + card_size.y),
536 glow_color, rounding);
541 const float tooltip_width = std::clamp(card_size.x * 1.4f, 240.0f, 340.0f);
542 ImGui::SetNextWindowSize(ImVec2(tooltip_width, 0), ImGuiCond_Always);
543 ImGui::BeginTooltip();
544 ImGui::PushFont(ImGui::GetIO().Fonts->Fonts[1]);
545 ImGui::TextColored(base_color,
"%s %s", info.
icon, info.
name);
548 ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + tooltip_width - 20.0f);
550 ImGui::PopTextWrapPos();
558 ImGui::TextColored(accent,
ICON_MD_STAR " Recently used");