From 544f711adc7fb57631de77299187d42c6c90e48c Mon Sep 17 00:00:00 2001 From: David Capello Date: Thu, 25 Aug 2022 10:14:09 -0300 Subject: [PATCH] Improve the layout selector UI Changes: * Now we use the "user data" icon as the button to expand the layouts combobox * Added a tooltip to this icon * Added buttons to configure the Timeline position in the same combobox * Fixed some bugs in Dock using space for hidden widgets --- data/strings/en.ini | 3 ++ src/app/ui/configure_timeline_popup.cpp | 9 ++-- src/app/ui/configure_timeline_popup.h | 5 +- src/app/ui/dock.cpp | 11 ++--- src/app/ui/dock.h | 2 + src/app/ui/layout_selector.cpp | 65 +++++++++++++++++++++++-- src/app/ui/layout_selector.h | 11 +++-- src/app/ui/main_window.cpp | 3 +- 8 files changed, 88 insertions(+), 21 deletions(-) diff --git a/data/strings/en.ini b/data/strings/en.ini index 7f1a29a4d..991335f44 100644 --- a/data/strings/en.ini +++ b/data/strings/en.ini @@ -1205,6 +1205,9 @@ help_twitter = Twitter help_enter_license = Enter &License help_about = &About +[main_window] +layout = User Interface Layout + [mask_by_color] title = Select Color label_color = Color: diff --git a/src/app/ui/configure_timeline_popup.cpp b/src/app/ui/configure_timeline_popup.cpp index 1800af24c..d6df3ced3 100644 --- a/src/app/ui/configure_timeline_popup.cpp +++ b/src/app/ui/configure_timeline_popup.cpp @@ -53,7 +53,8 @@ ConfigureTimelinePopup::ConfigureTimelinePopup() m_box = new app::gen::TimelineConf(); addChild(m_box); - m_box->position()->ItemChange.connect([this] { onChangePosition(); }); + m_box->position()->ItemChange.connect( + [this] { onChangeTimelinePosition(m_box->position()->selectedItem()); }); m_box->firstFrame()->Change.connect([this] { onChangeFirstFrame(); }); m_box->merge()->Click.connect([this] { onChangeType(); }); m_box->tint()->Click.connect([this] { onChangeType(); }); @@ -147,12 +148,12 @@ bool ConfigureTimelinePopup::onProcessMessage(ui::Message* msg) return PopupWindow::onProcessMessage(msg); } -void ConfigureTimelinePopup::onChangePosition() +void ConfigureTimelinePopup::onChangeTimelinePosition(int option) { gen::TimelinePosition newTimelinePos = gen::TimelinePosition::BOTTOM; - int selITem = m_box->position()->selectedItem(); - switch (selITem) { + int selItem = option; + switch (selItem) { case 0: newTimelinePos = gen::TimelinePosition::LEFT; break; case 1: newTimelinePos = gen::TimelinePosition::RIGHT; break; case 2: newTimelinePos = gen::TimelinePosition::BOTTOM; break; diff --git a/src/app/ui/configure_timeline_popup.h b/src/app/ui/configure_timeline_popup.h index 27671dff2..7e4c00709 100644 --- a/src/app/ui/configure_timeline_popup.h +++ b/src/app/ui/configure_timeline_popup.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2025 Igara Studio S.A. +// Copyright (C) 2022-2025 Igara Studio S.A. // Copyright (C) 2001-2017 David Capello // // This program is distributed under the terms of @@ -31,9 +31,10 @@ class ConfigureTimelinePopup : public ui::PopupWindow { public: ConfigureTimelinePopup(); + static void onChangeTimelinePosition(int option); + protected: bool onProcessMessage(ui::Message* msg) override; - void onChangePosition(); void onChangeFirstFrame(); void onChangeType(); void onOpacity(); diff --git a/src/app/ui/dock.cpp b/src/app/ui/dock.cpp index 6614bb8dd..be86a4e4b 100644 --- a/src/app/ui/dock.cpp +++ b/src/app/ui/dock.cpp @@ -227,17 +227,16 @@ void Dock::onSizeHint(ui::SizeHintEvent& ev) { gfx::Size sz = border().size(); - if (m_sides[kLeftIndex]) + if (hasVisibleSide(kLeftIndex)) sz.w += m_sides[kLeftIndex]->sizeHint().w + childSpacing(); - if (m_sides[kRightIndex]) + if (hasVisibleSide(kRightIndex)) sz.w += m_sides[kRightIndex]->sizeHint().w + childSpacing(); - if (m_sides[kTopIndex]) + if (hasVisibleSide(kTopIndex)) sz.h += m_sides[kTopIndex]->sizeHint().h + childSpacing(); - if (m_sides[kBottomIndex]) + if (hasVisibleSide(kBottomIndex)) sz.h += m_sides[kBottomIndex]->sizeHint().h + childSpacing(); - if (m_sides[kCenterIndex]) { + if (hasVisibleSide(kCenterIndex)) sz += m_sides[kCenterIndex]->sizeHint(); - } ev.setSizeHint(sz); } diff --git a/src/app/ui/dock.h b/src/app/ui/dock.h index 0d97d7064..d4dbd4920 100644 --- a/src/app/ui/dock.h +++ b/src/app/ui/dock.h @@ -72,6 +72,8 @@ private: const gfx::Rect& separator, const int index)> f); + bool hasVisibleSide(const int i) const { return (m_sides[i] && m_sides[i]->isVisible()); } + std::array m_sides; std::array m_aligns; std::array m_sizes; diff --git a/src/app/ui/layout_selector.cpp b/src/app/ui/layout_selector.cpp index 16e8ed0e7..ab58f2c71 100644 --- a/src/app/ui/layout_selector.cpp +++ b/src/app/ui/layout_selector.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2021 Igara Studio S.A. +// Copyright (C) 2021-2022 Igara Studio S.A. // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. @@ -11,10 +11,14 @@ #include "app/ui/layout_selector.h" #include "app/app.h" +#include "app/i18n/strings.h" +#include "app/ui/button_set.h" +#include "app/ui/configure_timeline_popup.h" #include "app/ui/main_window.h" #include "app/ui/separator_in_view.h" #include "app/ui/skin/skin_theme.h" #include "ui/listitem.h" +#include "ui/tooltips.h" #include "ui/window.h" #define ANI_TICKS 5 @@ -49,6 +53,41 @@ private: LayoutId m_id; }; +// TODO Similar ButtonSet to the one in timeline_conf.xml +class TimelineButtons : public ButtonSet { +public: + TimelineButtons() : ButtonSet(2) + { + addItem(Strings::timeline_conf_left())->processMnemonicFromText(); + addItem(Strings::timeline_conf_right())->processMnemonicFromText(); + addItem(Strings::timeline_conf_bottom(), 2)->processMnemonicFromText(); + + Preferences::instance().general.timelinePosition.AfterChange.connect( + [this](gen::TimelinePosition position) { + int selItem = 0; + switch (position) { + case gen::TimelinePosition::LEFT: selItem = 0; break; + case gen::TimelinePosition::RIGHT: selItem = 1; break; + case gen::TimelinePosition::BOTTOM: selItem = 2; break; + } + setSelectedItem(selItem, false); + }); + + InitTheme.connect([this] { + auto theme = skin::SkinTheme::get(this); + setStyle(theme->styles.separatorInView()); + }); + initTheme(); + } + +private: + void onItemChange(Item* item) override + { + ButtonSet::onItemChange(item); + ConfigureTimelinePopup::onChangeTimelinePosition(selectedItem()); + } +}; + }; // namespace void LayoutSelector::LayoutComboBox::onChange() @@ -58,7 +97,8 @@ void LayoutSelector::LayoutComboBox::onChange() } } -LayoutSelector::LayoutSelector() : m_button("", "\xc3\xb7") +LayoutSelector::LayoutSelector(TooltipManager* tooltipManager) + : m_button(SkinTheme::instance()->parts.iconUserData()) { m_button.Click.connect([this]() { switchSelector(); }); @@ -66,6 +106,15 @@ LayoutSelector::LayoutSelector() : m_button("", "\xc3\xb7") addChild(&m_comboBox); addChild(&m_button); + + setupTooltips(tooltipManager); + + InitTheme.connect([this] { + noBorderNoChildSpacing(); + m_comboBox.noBorderNoChildSpacing(); + m_button.noBorderNoChildSpacing(); + }); + initTheme(); } LayoutSelector::~LayoutSelector() @@ -80,8 +129,8 @@ void LayoutSelector::onAnimationFrame() case ANI_EXPANDING: case ANI_COLLAPSING: { const double t = animationTime(); - m_comboBox.setSizeHint(gfx::Size((1.0 - t) * m_startSize.w + t * m_endSize.w, - (1.0 - t) * m_startSize.h + t * m_endSize.h)); + m_comboBox.setSizeHint(gfx::Size(int(inbetween(m_startSize.w, m_endSize.w, t)), + int(inbetween(m_startSize.h, m_endSize.h, t)))); break; } } @@ -112,8 +161,11 @@ void LayoutSelector::switchSelector() // Create the combobox for first time if (m_comboBox.getItemCount() == 0) { + m_comboBox.addItem(new SeparatorInView("Layout", HORIZONTAL)); m_comboBox.addItem(new LayoutItem(LayoutId::DEFAULT, "Default")); m_comboBox.addItem(new LayoutItem(LayoutId::DEFAULT_MIRROR, "Default / Mirror")); + m_comboBox.addItem(new SeparatorInView("Timeline", HORIZONTAL)); + m_comboBox.addItem(new TimelineButtons()); } m_comboBox.setVisible(true); @@ -131,4 +183,9 @@ void LayoutSelector::switchSelector() startAnimation((expand ? ANI_EXPANDING : ANI_COLLAPSING), ANI_TICKS); } +void LayoutSelector::setupTooltips(TooltipManager* tooltipManager) +{ + tooltipManager->addTooltipFor(&m_button, Strings::main_window_layout(), TOP); +} + } // namespace app diff --git a/src/app/ui/layout_selector.h b/src/app/ui/layout_selector.h index cedbf8821..808ae1eb2 100644 --- a/src/app/ui/layout_selector.h +++ b/src/app/ui/layout_selector.h @@ -9,13 +9,17 @@ #pragma once #include "app/ui/dockable.h" +#include "app/ui/icon_button.h" #include "ui/animated_widget.h" #include "ui/box.h" #include "ui/combobox.h" -#include "ui/link_label.h" #include +namespace ui { +class TooltipManager; +} + namespace app { class LayoutSelector : public ui::HBox, @@ -32,19 +36,20 @@ class LayoutSelector : public ui::HBox, }; public: - LayoutSelector(); + LayoutSelector(ui::TooltipManager* tooltipManager); ~LayoutSelector(); // Dockable impl int dockableAt() const override { return ui::TOP | ui::BOTTOM; } private: + void setupTooltips(ui::TooltipManager* tooltipManager); void onAnimationFrame() override; void onAnimationStop(int animation) override; void switchSelector(); LayoutComboBox m_comboBox; - ui::LinkLabel m_button; + IconButton m_button; gfx::Size m_startSize; gfx::Size m_endSize; }; diff --git a/src/app/ui/main_window.cpp b/src/app/ui/main_window.cpp index 4c59d1c28..2673794f9 100644 --- a/src/app/ui/main_window.cpp +++ b/src/app/ui/main_window.cpp @@ -93,7 +93,6 @@ MainWindow::MainWindow() , m_tooltipManager(new TooltipManager) , m_dock(new Dock) , m_customizableDock(new Dock) - , m_layoutSelector(new LayoutSelector) , m_mode(NormalMode) , m_homeView(nullptr) , m_scalePanic(nullptr) @@ -117,7 +116,7 @@ MainWindow::MainWindow() void MainWindow::initialize() { m_menuBar = std::make_unique(); - m_layoutSelector = std::make_unique(); + m_layoutSelector = std::make_unique(m_tooltipManager); // Register commands to load menus+shortcuts for these commands Editor::registerCommands();