Introduce AlphaEntry class and make InkOpacityField extend from it (fix #1544)

This commit is contained in:
Martín Capello 2024-01-10 15:27:17 -03:00
parent dd0e5addc9
commit b10390625f
7 changed files with 144 additions and 29 deletions

View File

@ -336,6 +336,7 @@ if(ENABLE_UI)
file_selector.cpp file_selector.cpp
modules/gfx.cpp modules/gfx.cpp
modules/gui.cpp modules/gui.cpp
ui/alpha_entry.cpp
ui/alpha_slider.cpp ui/alpha_slider.cpp
ui/app_menuitem.cpp ui/app_menuitem.cpp
ui/backup_indicator.cpp ui/backup_indicator.cpp

View File

@ -0,0 +1,67 @@
// Aseprite UI Library
// Copyright (C) 2024 Igara Studio S.A.
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/pref/preferences.h"
#include "app/ui/alpha_entry.h"
#include "base/scoped_value.h"
#include "gfx/rect.h"
#include "gfx/region.h"
#include "os/font.h"
#include "ui/fit_bounds.h"
#include "ui/manager.h"
#include "ui/message.h"
#include "ui/popup_window.h"
#include "ui/scale.h"
#include "ui/size_hint_event.h"
#include "ui/slider.h"
#include "ui/system.h"
#include "ui/theme.h"
#include <algorithm>
#include <cmath>
namespace app {
using namespace gfx;
AlphaEntry::AlphaEntry(AlphaSlider::Type type)
: IntEntry(0, 255)
{
m_slider = std::make_unique<AlphaSlider>(0, type);
m_slider->setFocusStop(false); // In this way the IntEntry doesn't lost the focus
m_slider->setTransparent(true);
m_slider->Change.connect([this] { this->onChangeSlider(); });
}
int AlphaEntry::getValue() const
{
int value = m_slider->convertTextToValue(text());
if (static_cast<AlphaSlider*>(m_slider.get())->getAlphaRange() == app::gen::AlphaRange::PERCENTAGE)
value = std::round(((double)m_slider->getMaxValue())*((double)value)/((double)100));
return std::clamp(value, m_min, m_max);
}
void AlphaEntry::setValue(int value)
{
value = std::clamp(value, m_min, m_max);
if (m_popupWindow && !m_changeFromSlider)
m_slider->setValue(value);
if (static_cast<AlphaSlider*>(m_slider.get())->getAlphaRange() == app::gen::AlphaRange::PERCENTAGE)
value = std::round(((double)100)*((double)value)/((double)m_slider->getMaxValue()));
setText(m_slider->convertValueToText(value));
onValueChange();
}
} // namespace app

36
src/app/ui/alpha_entry.h Normal file
View File

@ -0,0 +1,36 @@
// Aseprite UI Library
// Copyright (C) 2024 Igara Studio S.A.
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
#ifndef APP_UI_ALPHA_ENTRY_H_INCLUDED
#define APP_UI_ALPHA_ENTRY_H_INCLUDED
#pragma once
#include "ui/int_entry.h"
#include "app/ui/alpha_slider.h"
#include <memory>
using namespace ui;
namespace ui {
class CloseEvent;
class PopupWindow;
}
namespace app {
class AlphaEntry : public IntEntry {
public:
AlphaEntry(AlphaSlider::Type type);
int getValue() const override;
void setValue(int value) override;
};
} // namespace ui
#endif

View File

@ -34,6 +34,7 @@
#include "app/tools/tool.h" #include "app/tools/tool.h"
#include "app/tools/tool_box.h" #include "app/tools/tool_box.h"
#include "app/tools/tool_loop_modifiers.h" #include "app/tools/tool_loop_modifiers.h"
#include "app/ui/alpha_entry.h"
#include "app/ui/brush_popup.h" #include "app/ui/brush_popup.h"
#include "app/ui/button_set.h" #include "app/ui/button_set.h"
#include "app/ui/color_button.h" #include "app/ui/color_button.h"
@ -710,9 +711,9 @@ private:
obs::scoped_connection m_conn; obs::scoped_connection m_conn;
}; };
class ContextBar::InkOpacityField : public IntEntry { class ContextBar::InkOpacityField : public AlphaEntry {
public: public:
InkOpacityField() : IntEntry(0, 255) { InkOpacityField() : AlphaEntry(AlphaSlider::Type::OPACITY) {
} }
protected: protected:
@ -720,7 +721,7 @@ protected:
if (g_updatingFromCode) if (g_updatingFromCode)
return; return;
IntEntry::onValueChange(); AlphaEntry::onValueChange();
base::ScopedValue lockFlag(g_updatingFromCode, true); base::ScopedValue lockFlag(g_updatingFromCode, true);
int newValue = getValue(); int newValue = getValue();
@ -1914,6 +1915,8 @@ ContextBar::ContextBar(TooltipManager* tooltipManager,
[this]{ onFgOrBgColorChange(doc::Brush::ImageColor::MainColor); }); [this]{ onFgOrBgColorChange(doc::Brush::ImageColor::MainColor); });
m_bgColorConn = pref.colorBar.bgColor.AfterChange.connect( m_bgColorConn = pref.colorBar.bgColor.AfterChange.connect(
[this]{ onFgOrBgColorChange(doc::Brush::ImageColor::BackgroundColor); }); [this]{ onFgOrBgColorChange(doc::Brush::ImageColor::BackgroundColor); });
m_alphaRangeConn = pref.range.opacity.AfterChange.connect(
[this]{ onOpacityRangeChange(); });
m_keysConn = KeyboardShortcuts::instance()->UserChange.connect( m_keysConn = KeyboardShortcuts::instance()->UserChange.connect(
[this, tooltipManager]{ setupTooltips(tooltipManager); }); [this, tooltipManager]{ setupTooltips(tooltipManager); });
m_dropPixelsConn = m_dropPixels->DropPixels.connect(&ContextBar::onDropPixels, this); m_dropPixelsConn = m_dropPixels->DropPixels.connect(&ContextBar::onDropPixels, this);
@ -2056,6 +2059,11 @@ void ContextBar::onFgOrBgColorChange(doc::Brush::ImageColor imageColor)
} }
} }
void ContextBar::onOpacityRangeChange()
{
updateForActiveTool();
}
void ContextBar::onDropPixels(ContextBarObserver::DropAction action) void ContextBar::onDropPixels(ContextBarObserver::DropAction action)
{ {
notify_observers(&ContextBarObserver::onDropPixels, action); notify_observers(&ContextBarObserver::onDropPixels, action);
@ -2143,7 +2151,7 @@ void ContextBar::updateForTool(tools::Tool* tool)
m_contiguous->setSelected(toolPref->contiguous()); m_contiguous->setSelected(toolPref->contiguous());
m_inkType->setInkTypeIcon(toolPref->ink()); m_inkType->setInkTypeIcon(toolPref->ink());
m_inkOpacity->setTextf("%d", toolPref->opacity()); m_inkOpacity->setValue(toolPref->opacity());
hasInkWithOpacity = hasInkWithOpacity =
((isPaint && tools::inkHasOpacity(toolPref->ink())) || ((isPaint && tools::inkHasOpacity(toolPref->ink())) ||

View File

@ -123,6 +123,7 @@ namespace app {
void onBrushAngleChange(); void onBrushAngleChange();
void onSymmetryModeChange(); void onSymmetryModeChange();
void onFgOrBgColorChange(doc::Brush::ImageColor imageColor); void onFgOrBgColorChange(doc::Brush::ImageColor imageColor);
void onOpacityRangeChange();
void onDropPixels(ContextBarObserver::DropAction action); void onDropPixels(ContextBarObserver::DropAction action);
void updateSliceFields(const Site& site); void updateSliceFields(const Site& site);
@ -203,6 +204,7 @@ namespace app {
obs::scoped_connection m_symmModeConn; obs::scoped_connection m_symmModeConn;
obs::scoped_connection m_fgColorConn; obs::scoped_connection m_fgColorConn;
obs::scoped_connection m_bgColorConn; obs::scoped_connection m_bgColorConn;
obs::scoped_connection m_alphaRangeConn;
obs::scoped_connection m_keysConn; obs::scoped_connection m_keysConn;
obs::scoped_connection m_dropPixelsConn; obs::scoped_connection m_dropPixelsConn;
obs::scoped_connection m_sizeConn; obs::scoped_connection m_sizeConn;

View File

@ -36,13 +36,13 @@ IntEntry::IntEntry(int min, int max, SliderDelegate* sliderDelegate)
: Entry(int(std::floor(std::log10(double(max))))+1, "") : Entry(int(std::floor(std::log10(double(max))))+1, "")
, m_min(min) , m_min(min)
, m_max(max) , m_max(max)
, m_slider(m_min, m_max, m_min, sliderDelegate)
, m_popupWindow(nullptr) , m_popupWindow(nullptr)
, m_changeFromSlider(false) , m_changeFromSlider(false)
{ {
m_slider.setFocusStop(false); // In this way the IntEntry doesn't lost the focus m_slider = std::make_unique<Slider>(m_min, m_max, m_min, sliderDelegate);
m_slider.setTransparent(true); m_slider->setFocusStop(false); // In this way the IntEntry doesn't lost the focus
m_slider.Change.connect(&IntEntry::onChangeSlider, this); m_slider->setTransparent(true);
m_slider->Change.connect(&IntEntry::onChangeSlider, this);
initTheme(); initTheme();
} }
@ -53,7 +53,7 @@ IntEntry::~IntEntry()
int IntEntry::getValue() const int IntEntry::getValue() const
{ {
int value = m_slider.convertTextToValue(text()); int value = m_slider->convertTextToValue(text());
return std::clamp(value, m_min, m_max); return std::clamp(value, m_min, m_max);
} }
@ -61,10 +61,10 @@ void IntEntry::setValue(int value)
{ {
value = std::clamp(value, m_min, m_max); value = std::clamp(value, m_min, m_max);
setText(m_slider.convertValueToText(value)); setText(m_slider->convertValueToText(value));
if (m_popupWindow && !m_changeFromSlider) if (m_popupWindow && !m_changeFromSlider)
m_slider.setValue(value); m_slider->setValue(value);
onValueChange(); onValueChange();
} }
@ -92,7 +92,7 @@ bool IntEntry::onProcessMessage(Message* msg)
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg); MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
Widget* pick = manager()->pickFromScreenPos( Widget* pick = manager()->pickFromScreenPos(
display()->nativeWindow()->pointToScreen(mouseMsg->position())); display()->nativeWindow()->pointToScreen(mouseMsg->position()));
if (pick == &m_slider) { if (pick == m_slider.get()) {
releaseMouse(); releaseMouse();
MouseMessage mouseMsg2(kMouseDownMessage, MouseMessage mouseMsg2(kMouseDownMessage,
@ -140,7 +140,7 @@ bool IntEntry::onProcessMessage(Message* msg)
void IntEntry::onInitTheme(InitThemeEvent& ev) void IntEntry::onInitTheme(InitThemeEvent& ev)
{ {
Entry::onInitTheme(ev); Entry::onInitTheme(ev);
m_slider.initTheme(); // The slider might not be in the popup window m_slider->initTheme(); // The slider might not be in the popup window
if (m_popupWindow) if (m_popupWindow)
m_popupWindow->initTheme(); m_popupWindow->initTheme();
} }
@ -150,8 +150,8 @@ void IntEntry::onSizeHint(SizeHintEvent& ev)
int trailing = font()->textLength(getSuffix()); int trailing = font()->textLength(getSuffix());
trailing = std::max(trailing, 2*theme()->getEntryCaretSize(this).w); trailing = std::max(trailing, 2*theme()->getEntryCaretSize(this).w);
int min_w = font()->textLength(m_slider.convertValueToText(m_min)); int min_w = font()->textLength(m_slider->convertValueToText(m_min));
int max_w = font()->textLength(m_slider.convertValueToText(m_max)) + trailing; int max_w = font()->textLength(m_slider->convertValueToText(m_max)) + trailing;
int w = std::max(min_w, max_w); int w = std::max(min_w, max_w);
int h = textHeight(); int h = textHeight();
@ -175,7 +175,7 @@ void IntEntry::onValueChange()
void IntEntry::openPopup() void IntEntry::openPopup()
{ {
m_slider.setValue(getValue()); m_slider->setValue(getValue());
// We weren't able to reproduce it, but there are crash reports // We weren't able to reproduce it, but there are crash reports
// where this openPopup() function is called and the popup is still // where this openPopup() function is called and the popup is still
@ -186,7 +186,7 @@ void IntEntry::openPopup()
m_popupWindow = std::make_unique<TransparentPopupWindow>(PopupWindow::ClickBehavior::CloseOnClickInOtherWindow); m_popupWindow = std::make_unique<TransparentPopupWindow>(PopupWindow::ClickBehavior::CloseOnClickInOtherWindow);
m_popupWindow->setAutoRemap(false); m_popupWindow->setAutoRemap(false);
m_popupWindow->addChild(&m_slider); m_popupWindow->addChild(m_slider.get());
m_popupWindow->Close.connect(&IntEntry::onPopupClose, this); m_popupWindow->Close.connect(&IntEntry::onPopupClose, this);
fit_bounds( fit_bounds(
@ -229,7 +229,7 @@ void IntEntry::closePopup()
void IntEntry::onChangeSlider() void IntEntry::onChangeSlider()
{ {
base::ScopedValue lockFlag(m_changeFromSlider, true); base::ScopedValue lockFlag(m_changeFromSlider, true);
setValue(m_slider.getValue()); setValue(m_slider->getValue());
selectAllText(); selectAllText();
} }
@ -244,8 +244,8 @@ void IntEntry::onPopupClose(CloseEvent& ev)
void IntEntry::removeSlider() void IntEntry::removeSlider()
{ {
if (m_popupWindow && if (m_popupWindow &&
m_slider.parent() == m_popupWindow.get()) { m_slider->parent() == m_popupWindow.get()) {
m_popupWindow->removeChild(&m_slider); m_popupWindow->removeChild(m_slider.get());
} }
} }

View File

@ -22,32 +22,33 @@ namespace ui {
class IntEntry : public Entry { class IntEntry : public Entry {
public: public:
IntEntry(int min, int max, SliderDelegate* sliderDelegate = nullptr); IntEntry(int min, int max, SliderDelegate* sliderDelegate = nullptr);
~IntEntry(); virtual ~IntEntry();
int getValue() const; virtual int getValue() const;
void setValue(int value); virtual void setValue(int value);
protected: protected:
bool onProcessMessage(Message* msg) override; bool onProcessMessage(Message* msg) override;
void onInitTheme(InitThemeEvent& ev) override; void onInitTheme(InitThemeEvent& ev) override;
void onSizeHint(SizeHintEvent& ev) override; void onSizeHint(SizeHintEvent& ev) override;
void onChange() override; void onChange() override;
virtual void onChangeSlider();
// New events // New events
virtual void onValueChange(); virtual void onValueChange();
int m_min;
int m_max;
std::unique_ptr<PopupWindow> m_popupWindow;
bool m_changeFromSlider;
std::unique_ptr<Slider> m_slider;
private: private:
void openPopup(); void openPopup();
void closePopup(); void closePopup();
void onChangeSlider();
void onPopupClose(CloseEvent& ev); void onPopupClose(CloseEvent& ev);
void removeSlider(); void removeSlider();
int m_min;
int m_max;
Slider m_slider;
std::unique_ptr<PopupWindow> m_popupWindow;
bool m_changeFromSlider;
}; };
} // namespace ui } // namespace ui