feat(toolbar): Layout dropdown + Physics toggle, default fixed/paused

Cambios de UX en la toolbar y arranque:

- Boton 'Layout: <name>' que abre popup con la lista de layouts (force,
  grid, circular, radial, hierarchical, fixed) + 'Reset positions
  (unpin + restart)' + 'Save current layout'. Reemplaza el combo
  pequeno + los botones Save/Reset que estaban dispersos.

- Boton 'Physics: ON/OFF' (Player Play/Pause) toggle visible que
  reemplaza el checkbox 'Run layout'. Variant Primary cuando ON,
  Subtle cuando OFF.

- Default: layout_mode = 5 (fixed) y layout_running = false. Asi al
  abrir un proyecto los nodos respetan posiciones guardadas y no se
  mueven solos. El usuario activa fisicas con el boton Physics y/o
  cambia el layout desde el dropdown si quiere.

Reset layout (boton dentro del popup Layout) sigue activando physics
para que el grafo se reasiente; es el flujo natural del 'Reset'.
This commit is contained in:
2026-05-01 16:54:27 +02:00
parent 4e0c759b75
commit 87a554da84
3 changed files with 47 additions and 21 deletions
+39 -18
View File
@@ -458,14 +458,46 @@ void views_toolbar(AppState& app) {
}
toolbar_separator();
ImGui::TextUnformatted("Layout:");
// Layout: <name> ▾ — dropdown con todos los layouts + acciones.
{
char btn[96];
std::snprintf(btn, sizeof(btn), TI_LAYOUT_GRID " Layout: %s",
k_layout_names[app.layout_mode % k_layout_count]);
if (button(btn, ButtonVariant::Secondary)) {
ImGui::OpenPopup("##layout_menu");
}
if (ImGui::BeginPopup("##layout_menu")) {
ImGui::TextDisabled("Apply layout");
ImGui::Separator();
for (int i = 0; i < k_layout_count; ++i) {
bool is_cur = (i == app.layout_mode);
if (ImGui::MenuItem(k_layout_names[i], nullptr, is_cur)) {
app.layout_mode = i;
++app.apply_layout_tick;
}
}
ImGui::Separator();
if (ImGui::MenuItem(TI_LAYOUT_GRID " Reset positions (unpin + restart)")) {
app.want_unpin_all = true;
++app.apply_layout_tick;
}
if (ImGui::MenuItem(TI_DEVICE_FLOPPY " Save current layout")) {
app.want_save_layout = true;
}
ImGui::EndPopup();
}
}
ImGui::SameLine();
ImGui::SetNextItemWidth(140);
int idx = app.layout_mode;
if (ImGui::Combo("##layout", &idx, k_layout_names, k_layout_count)) {
if (idx != app.layout_mode) {
app.layout_mode = idx;
++app.apply_layout_tick;
// Physics ▶ / ⏸ — toggle visible. Solo afecta a layout 'force'.
if (app.viewport) {
const bool running = app.viewport->layout_running;
const char* lbl = running ? TI_PLAYER_PAUSE " Physics: ON"
: TI_PLAYER_PLAY " Physics: OFF";
ButtonVariant var = running ? ButtonVariant::Primary
: ButtonVariant::Subtle;
if (button(lbl, var)) {
app.viewport->layout_running = !running;
}
}
toolbar_separator();
@@ -476,25 +508,14 @@ void views_toolbar(AppState& app) {
if (button(TI_ARROWS_MAXIMIZE " Fit view", ButtonVariant::Subtle)) {
app.want_fit = true;
}
if (button(TI_DEVICE_FLOPPY " Save layout", ButtonVariant::Subtle)) {
app.want_save_layout = true;
}
if (button(TI_REFRESH " Reload", ButtonVariant::Subtle)) {
app.want_reload = true;
}
if (button(TI_LAYOUT_GRID " Reset layout", ButtonVariant::Subtle)) {
app.want_unpin_all = true;
++app.apply_layout_tick;
}
toolbar_separator();
ImGui::Checkbox("GPU layout", &app.use_gpu);
ImGui::SameLine();
ImGui::Checkbox("Labels", &app.labels_enabled);
if (app.viewport) {
ImGui::SameLine();
ImGui::Checkbox("Run layout", &app.viewport->layout_running);
}
toolbar_end();
}