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

View File

@ -123,6 +123,7 @@ namespace app {
void onBrushAngleChange();
void onSymmetryModeChange();
void onFgOrBgColorChange(doc::Brush::ImageColor imageColor);
void onOpacityRangeChange();
void onDropPixels(ContextBarObserver::DropAction action);
void updateSliceFields(const Site& site);
@ -203,6 +204,7 @@ namespace app {
obs::scoped_connection m_symmModeConn;
obs::scoped_connection m_fgColorConn;
obs::scoped_connection m_bgColorConn;
obs::scoped_connection m_alphaRangeConn;
obs::scoped_connection m_keysConn;
obs::scoped_connection m_dropPixelsConn;
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, "")
, m_min(min)
, m_max(max)
, m_slider(m_min, m_max, m_min, sliderDelegate)
, m_popupWindow(nullptr)
, m_changeFromSlider(false)
{
m_slider.setFocusStop(false); // In this way the IntEntry doesn't lost the focus
m_slider.setTransparent(true);
m_slider.Change.connect(&IntEntry::onChangeSlider, this);
m_slider = std::make_unique<Slider>(m_min, m_max, m_min, sliderDelegate);
m_slider->setFocusStop(false); // In this way the IntEntry doesn't lost the focus
m_slider->setTransparent(true);
m_slider->Change.connect(&IntEntry::onChangeSlider, this);
initTheme();
}
@ -53,7 +53,7 @@ IntEntry::~IntEntry()
int IntEntry::getValue() const
{
int value = m_slider.convertTextToValue(text());
int value = m_slider->convertTextToValue(text());
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);
setText(m_slider.convertValueToText(value));
setText(m_slider->convertValueToText(value));
if (m_popupWindow && !m_changeFromSlider)
m_slider.setValue(value);
m_slider->setValue(value);
onValueChange();
}
@ -92,7 +92,7 @@ bool IntEntry::onProcessMessage(Message* msg)
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
Widget* pick = manager()->pickFromScreenPos(
display()->nativeWindow()->pointToScreen(mouseMsg->position()));
if (pick == &m_slider) {
if (pick == m_slider.get()) {
releaseMouse();
MouseMessage mouseMsg2(kMouseDownMessage,
@ -140,7 +140,7 @@ bool IntEntry::onProcessMessage(Message* msg)
void IntEntry::onInitTheme(InitThemeEvent& 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)
m_popupWindow->initTheme();
}
@ -150,8 +150,8 @@ void IntEntry::onSizeHint(SizeHintEvent& ev)
int trailing = font()->textLength(getSuffix());
trailing = std::max(trailing, 2*theme()->getEntryCaretSize(this).w);
int min_w = font()->textLength(m_slider.convertValueToText(m_min));
int max_w = font()->textLength(m_slider.convertValueToText(m_max)) + trailing;
int min_w = font()->textLength(m_slider->convertValueToText(m_min));
int max_w = font()->textLength(m_slider->convertValueToText(m_max)) + trailing;
int w = std::max(min_w, max_w);
int h = textHeight();
@ -175,7 +175,7 @@ void IntEntry::onValueChange()
void IntEntry::openPopup()
{
m_slider.setValue(getValue());
m_slider->setValue(getValue());
// We weren't able to reproduce it, but there are crash reports
// 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->setAutoRemap(false);
m_popupWindow->addChild(&m_slider);
m_popupWindow->addChild(m_slider.get());
m_popupWindow->Close.connect(&IntEntry::onPopupClose, this);
fit_bounds(
@ -229,7 +229,7 @@ void IntEntry::closePopup()
void IntEntry::onChangeSlider()
{
base::ScopedValue lockFlag(m_changeFromSlider, true);
setValue(m_slider.getValue());
setValue(m_slider->getValue());
selectAllText();
}
@ -244,8 +244,8 @@ void IntEntry::onPopupClose(CloseEvent& ev)
void IntEntry::removeSlider()
{
if (m_popupWindow &&
m_slider.parent() == m_popupWindow.get()) {
m_popupWindow->removeChild(&m_slider);
m_slider->parent() == m_popupWindow.get()) {
m_popupWindow->removeChild(m_slider.get());
}
}

View File

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