mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-29 19:20:09 +00:00
Add save dynamics options between sessions (fix #3933)
This commit is contained in:
parent
9755efece4
commit
2cc15cda9e
@ -459,6 +459,21 @@
|
||||
<option id="refer_to" type="FillReferTo" default="FillReferTo::ACTIVE_LAYER" />
|
||||
<option id="pixel_connectivity" type="PixelConnectivity" default="PixelConnectivity::FOUR_CONNECTED" />
|
||||
</section>
|
||||
<section id="dynamics">
|
||||
<option id="stabilizer" type="bool" default="false" />
|
||||
<option id="stabilizer_factor" type="int" default="0" />
|
||||
<option id="size" type="app::tools::DynamicSensor" default="app::tools::DynamicSensor::Static" />
|
||||
<option id="angle" type="app::tools::DynamicSensor" default="app::tools::DynamicSensor::Static" />
|
||||
<option id="gradient" type="app::tools::DynamicSensor" default="app::tools::DynamicSensor::Static" />
|
||||
<option id="min_size" type="int" default="1" />
|
||||
<option id="min_angle" type="int" default="1" />
|
||||
<option id="color_from_to" type="app::tools::ColorFromTo" default="app::tools::ColorFromTo::BgToFg" />
|
||||
<option id="matrix_index" type="int" default="0" />
|
||||
<option id="min_pressure_threshold" type="double" default="0.1" />
|
||||
<option id="max_pressure_threshold" type="double" default="0.9" />
|
||||
<option id="min_velocity_threshold" type="double" default="0.1" />
|
||||
<option id="max_velocity_threshold" type="double" default="0.9" />
|
||||
</section>
|
||||
</tool>
|
||||
|
||||
<document>
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2018-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2018-2023 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2018 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -15,6 +15,7 @@
|
||||
#include "app/pref/option.h"
|
||||
#include "app/sprite_sheet_data_format.h"
|
||||
#include "app/sprite_sheet_type.h"
|
||||
#include "app/tools/dynamics.h"
|
||||
#include "app/tools/freehand_algorithm.h"
|
||||
#include "app/tools/ink_type.h"
|
||||
#include "app/tools/rotation_algorithm.h"
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "app/script/docobj.h"
|
||||
#include "app/script/engine.h"
|
||||
#include "app/script/luacpp.h"
|
||||
#include "app/tools/dynamics.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/remap.h"
|
||||
@ -333,6 +334,8 @@ FOR_ENUM(app::gen::SymmetryMode)
|
||||
FOR_ENUM(app::gen::TimelinePosition)
|
||||
FOR_ENUM(app::gen::ToGrayAlgorithm)
|
||||
FOR_ENUM(app::gen::WindowColorProfile)
|
||||
FOR_ENUM(app::tools::ColorFromTo)
|
||||
FOR_ENUM(app::tools::DynamicSensor)
|
||||
FOR_ENUM(app::tools::FreehandAlgorithm)
|
||||
FOR_ENUM(app::tools::RotationAlgorithm)
|
||||
FOR_ENUM(doc::AniDir)
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2023 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -25,6 +25,7 @@ namespace tools {
|
||||
};
|
||||
|
||||
struct DynamicsOptions {
|
||||
bool stabilizer = false;
|
||||
int stabilizerFactor = 0;
|
||||
DynamicSensor size = DynamicSensor::Static;
|
||||
DynamicSensor angle = DynamicSensor::Static;
|
||||
|
@ -1151,6 +1151,38 @@ public:
|
||||
: ButtonSet(1)
|
||||
, m_ctxBar(ctxBar) {
|
||||
addItem(SkinTheme::get(this)->parts.dynamics(), "dynamics_field");
|
||||
|
||||
// TODO: it would be better to initialize 'm_popup' at the time you
|
||||
// need to display the dynamic options in the 'switchPopup()'
|
||||
// function.
|
||||
// However, initialization during construction of the DynamicField
|
||||
// is an easy way to get the current dithering matrix given the
|
||||
// index of the selected item of the "dithering matrix" comboBox.
|
||||
m_popup.reset(new DynamicsPopup(this));
|
||||
m_popup->loadDynamicPref(
|
||||
&Preferences::instance().tool(App::instance()->activeTool()));
|
||||
m_popup->setOptionsGridVisibility(m_optionsGridVisibility);
|
||||
m_dynamics = m_popup->getDynamics();
|
||||
m_popup->Close.connect(
|
||||
[this](CloseEvent&){
|
||||
deselectItems();
|
||||
m_dynamics = m_popup->getDynamics();
|
||||
auto& dynaPref = Preferences::instance().tool(
|
||||
App::instance()->activeTool()).dynamics;
|
||||
dynaPref.stabilizer(m_dynamics.stabilizer);
|
||||
dynaPref.stabilizerFactor(m_dynamics.stabilizerFactor);
|
||||
dynaPref.size(m_dynamics.size);
|
||||
dynaPref.angle(m_dynamics.angle);
|
||||
dynaPref.gradient(m_dynamics.gradient);
|
||||
dynaPref.minSize.setValue(m_dynamics.minSize);
|
||||
dynaPref.minAngle.setValue(m_dynamics.minAngle);
|
||||
dynaPref.minPressureThreshold(m_dynamics.minPressureThreshold);
|
||||
dynaPref.minVelocityThreshold(m_dynamics.minVelocityThreshold);
|
||||
dynaPref.maxPressureThreshold(m_dynamics.maxPressureThreshold);
|
||||
dynaPref.maxVelocityThreshold(m_dynamics.maxVelocityThreshold);
|
||||
dynaPref.colorFromTo(m_dynamics.colorFromTo);
|
||||
dynaPref.matrixIndex(m_popup->ditheringIndex());
|
||||
});
|
||||
}
|
||||
|
||||
void switchPopup() {
|
||||
@ -1160,16 +1192,6 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_popup) {
|
||||
m_popup.reset(new DynamicsPopup(this));
|
||||
m_popup->setOptionsGridVisibility(m_optionsGridVisibility);
|
||||
m_popup->Close.connect(
|
||||
[this](CloseEvent&){
|
||||
deselectItems();
|
||||
m_dynamics = m_popup->getDynamics();
|
||||
});
|
||||
}
|
||||
|
||||
const gfx::Rect bounds = this->bounds();
|
||||
m_popup->remapWindow();
|
||||
fit_bounds(display(), m_popup.get(),
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020-2022 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2023 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -58,6 +58,8 @@ public:
|
||||
|
||||
float minThreshold() const { return m_minThreshold; }
|
||||
float maxThreshold() const { return m_maxThreshold; }
|
||||
void minThreshold(float min) { m_minThreshold = min; }
|
||||
void maxThreshold(float max) { m_maxThreshold = max; }
|
||||
void setSensorValue(float v) {
|
||||
m_sensorValue = v;
|
||||
invalidate();
|
||||
@ -211,20 +213,37 @@ DynamicsPopup::DynamicsPopup(Delegate* delegate)
|
||||
PopupWindow::EnterBehavior::DoNothingOnEnter)
|
||||
, m_delegate(delegate)
|
||||
, m_dynamics(new gen::Dynamics)
|
||||
, m_stabilizerFactorBackup(0)
|
||||
, m_ditheringSel(new DitheringSelector(DitheringSelector::SelectMatrix))
|
||||
, m_fromTo(tools::ColorFromTo::BgToFg)
|
||||
{
|
||||
m_dynamics->stabilizer()->Click.connect(
|
||||
[this](){
|
||||
if (m_dynamics->stabilizer()->isSelected() &&
|
||||
m_dynamics->stabilizerFactor()->getValue() == 0) {
|
||||
// TODO default value when we enable stabilizer when it's zero
|
||||
m_dynamics->stabilizerFactor()->setValue(16);
|
||||
if (m_dynamics->stabilizer()->isSelected()) {
|
||||
if (m_stabilizerFactorBackup == 0) {
|
||||
// TODO default value when we enable stabilizer when it's
|
||||
// zero
|
||||
m_dynamics->stabilizerFactor()->setValue(16);
|
||||
m_stabilizerFactorBackup = 16;
|
||||
}
|
||||
else {
|
||||
m_dynamics->stabilizerFactor()->setValue(
|
||||
m_stabilizerFactorBackup);
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_stabilizerFactorBackup =
|
||||
m_dynamics->stabilizerFactor()->getValue();
|
||||
m_dynamics->stabilizerFactor()->setValue(0);
|
||||
}
|
||||
|
||||
});
|
||||
m_dynamics->stabilizerFactor()->Change.connect(
|
||||
[this](){
|
||||
m_dynamics->stabilizer()->setSelected(m_dynamics->stabilizerFactor()->getValue() > 0);
|
||||
m_stabilizerFactorBackup =
|
||||
m_dynamics->stabilizerFactor()->getValue();
|
||||
m_dynamics->stabilizer()->setSelected(
|
||||
m_stabilizerFactorBackup > 0);
|
||||
});
|
||||
|
||||
m_dynamics->values()->ItemChange.connect(
|
||||
@ -259,8 +278,6 @@ DynamicsPopup::DynamicsPopup(Delegate* delegate)
|
||||
m_dynamics->pressurePlaceholder()->addChild(m_pressureThreshold = new ThresholdSlider);
|
||||
m_dynamics->velocityPlaceholder()->addChild(m_velocityThreshold = new ThresholdSlider);
|
||||
addChild(m_dynamics);
|
||||
|
||||
onValuesChange(nullptr);
|
||||
}
|
||||
|
||||
void DynamicsPopup::setOptionsGridVisibility(bool state)
|
||||
@ -270,16 +287,51 @@ void DynamicsPopup::setOptionsGridVisibility(bool state)
|
||||
expandWindow(sizeHint());
|
||||
}
|
||||
|
||||
int DynamicsPopup::ditheringIndex() const {
|
||||
if (m_ditheringSel)
|
||||
return m_ditheringSel->getSelectedItemIndex();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DynamicsPopup::loadDynamicPref(ToolPreferences* toolPref) {
|
||||
if (toolPref) {
|
||||
auto& dynaPref = toolPref->dynamics;
|
||||
m_dynamics->stabilizer()->setSelected(dynaPref.stabilizer());
|
||||
m_stabilizerFactorBackup = dynaPref.stabilizerFactor();
|
||||
m_dynamics->stabilizerFactor()->setValue(
|
||||
dynaPref.stabilizer() ? m_stabilizerFactorBackup : 0);
|
||||
m_dynamics->minSize()->setValue(dynaPref.minSize());
|
||||
m_dynamics->minAngle()->setValue(dynaPref.minAngle());
|
||||
m_pressureThreshold->minThreshold(dynaPref.minPressureThreshold());
|
||||
m_pressureThreshold->maxThreshold(dynaPref.maxPressureThreshold());
|
||||
m_velocityThreshold->minThreshold(dynaPref.minVelocityThreshold());
|
||||
m_velocityThreshold->maxThreshold(dynaPref.maxVelocityThreshold());
|
||||
m_fromTo = dynaPref.colorFromTo();
|
||||
|
||||
setCheck(SIZE_WITH_PRESSURE,
|
||||
dynaPref.size() == tools::DynamicSensor::Pressure);
|
||||
setCheck(SIZE_WITH_VELOCITY,
|
||||
dynaPref.size() == tools::DynamicSensor::Velocity);
|
||||
setCheck(ANGLE_WITH_PRESSURE,
|
||||
dynaPref.angle() == tools::DynamicSensor::Pressure);
|
||||
setCheck(ANGLE_WITH_VELOCITY,
|
||||
dynaPref.angle() == tools::DynamicSensor::Velocity);
|
||||
setCheck(GRADIENT_WITH_PRESSURE,
|
||||
dynaPref.gradient() == tools::DynamicSensor::Pressure);
|
||||
setCheck(GRADIENT_WITH_VELOCITY,
|
||||
dynaPref.gradient() == tools::DynamicSensor::Velocity);
|
||||
|
||||
if (m_ditheringSel)
|
||||
m_ditheringSel->setSelectedItemIndex(dynaPref.matrixIndex());
|
||||
}
|
||||
}
|
||||
|
||||
tools::DynamicsOptions DynamicsPopup::getDynamics() const
|
||||
{
|
||||
tools::DynamicsOptions opts;
|
||||
|
||||
if (m_dynamics->stabilizer()->isSelected()) {
|
||||
opts.stabilizerFactor = m_dynamics->stabilizerFactor()->getValue();
|
||||
}
|
||||
else {
|
||||
opts.stabilizerFactor = 0;
|
||||
}
|
||||
opts.stabilizer = m_dynamics->stabilizer()->isSelected();
|
||||
opts.stabilizerFactor = m_stabilizerFactorBackup;
|
||||
|
||||
opts.size =
|
||||
(isCheck(SIZE_WITH_PRESSURE) ? tools::DynamicSensor::Pressure:
|
||||
@ -367,9 +419,7 @@ void DynamicsPopup::onValuesChange(ButtonSet::Item* item)
|
||||
const bool any = (needsSize || needsAngle || needsGradient);
|
||||
doc::BrushRef brush = m_delegate->getActiveBrush();
|
||||
|
||||
if (needsSize && !m_dynamics->minSize()->isVisible()) {
|
||||
m_dynamics->minSize()->setValue(1);
|
||||
|
||||
if (needsSize) {
|
||||
int maxSize = brush->size();
|
||||
if (maxSize == 1) {
|
||||
// If brush size == 1, we put it to 4 so the user has some size
|
||||
@ -383,8 +433,7 @@ void DynamicsPopup::onValuesChange(ButtonSet::Item* item)
|
||||
m_dynamics->minSize()->setVisible(needsSize);
|
||||
m_dynamics->maxSize()->setVisible(needsSize);
|
||||
|
||||
if (needsAngle && !m_dynamics->minAngle()->isVisible()) {
|
||||
m_dynamics->minAngle()->setValue(brush->angle());
|
||||
if (needsAngle) {
|
||||
m_dynamics->maxAngle()->setValue(brush->angle());
|
||||
}
|
||||
m_dynamics->angleLabel()->setVisible(needsAngle);
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2020-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2020-2023 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
@ -8,6 +8,7 @@
|
||||
#define APP_UI_DYNAMICS_POPUP_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "app/pref/preferences.h"
|
||||
#include "app/tools/dynamics.h"
|
||||
#include "app/tools/velocity.h"
|
||||
#include "app/ui/button_set.h"
|
||||
@ -36,6 +37,8 @@ namespace app {
|
||||
|
||||
tools::DynamicsOptions getDynamics() const;
|
||||
void setOptionsGridVisibility(bool state);
|
||||
void loadDynamicPref(ToolPreferences* toolPref);
|
||||
int ditheringIndex() const;
|
||||
|
||||
private:
|
||||
class ThresholdSlider;
|
||||
@ -49,6 +52,10 @@ namespace app {
|
||||
|
||||
Delegate* m_delegate;
|
||||
gen::Dynamics* m_dynamics;
|
||||
// Used to memorize the 'stabilizer factor' slider value.
|
||||
// This helps to save the 'stabilizer factor' even if
|
||||
// 'stabilizer' check isn't selected.
|
||||
int m_stabilizerFactorBackup;
|
||||
DitheringSelector* m_ditheringSel;
|
||||
gfx::Region m_hotRegion;
|
||||
ThresholdSlider* m_pressureThreshold;
|
||||
|
Loading…
x
Reference in New Issue
Block a user