mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-30 15:32:38 +00:00
Add sensor tweaks to specify min/max thresholds of the sensor input
In this way we can translate the sensor input to a better output range for our specific device (mouse, stylus, etc.).
This commit is contained in:
parent
8677c809fe
commit
1d15bacdcd
@ -526,22 +526,23 @@ pressure = Pressure
|
|||||||
pressure_tooltip = Control parameters through the pen pressure sensor
|
pressure_tooltip = Control parameters through the pen pressure sensor
|
||||||
velocity = Velocity
|
velocity = Velocity
|
||||||
velocity_tooltip = Control parameters through the mouse velocity
|
velocity_tooltip = Control parameters through the mouse velocity
|
||||||
size = Size:
|
size = Size
|
||||||
size_tooltip = <<<END
|
size_tooltip = <<<END
|
||||||
Change the brush size
|
Change the brush size
|
||||||
depending on the sensor value
|
depending on the sensor value
|
||||||
END
|
END
|
||||||
angle = Angle:
|
angle = Angle
|
||||||
angle_tooltip = <<<END
|
angle_tooltip = <<<END
|
||||||
Change the brush angle
|
Change the brush angle
|
||||||
depending on the sensor value
|
depending on the sensor value
|
||||||
END
|
END
|
||||||
gradient = Gradient:
|
gradient = Gradient
|
||||||
gradient_tooltip = <<<END
|
gradient_tooltip = <<<END
|
||||||
Gradient between foreground
|
Gradient between foreground
|
||||||
and background colors
|
and background colors
|
||||||
END
|
END
|
||||||
max_point_value = Max Point Value:
|
max_point_value = Max Point Value:
|
||||||
|
sensors_tweaks = Sensor Tweaks
|
||||||
|
|
||||||
[export_file]
|
[export_file]
|
||||||
title = Export File
|
title = Export File
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
</buttonset>
|
</buttonset>
|
||||||
</hbox>
|
</hbox>
|
||||||
|
|
||||||
<separator id="separator" text="@.max_point_value" horizontal="true" />
|
|
||||||
|
|
||||||
<grid id="options" columns="2" childspacing="0" expansive="true">
|
<grid id="options" columns="2" childspacing="0" expansive="true">
|
||||||
|
<separator id="separator" text="@.max_point_value" horizontal="true" cell_hspan="2" />
|
||||||
|
|
||||||
<label id="max_size_label" text="@.size" style="mini_label" />
|
<label id="max_size_label" text="@.size" style="mini_label" />
|
||||||
<slider id="max_size" value="64" min="1" max="64" cell_align="horizontal" />
|
<slider id="max_size" value="64" min="1" max="64" cell_align="horizontal" />
|
||||||
|
|
||||||
@ -33,6 +33,13 @@
|
|||||||
|
|
||||||
<label id="gradient_label" text="@.gradient" style="mini_label" />
|
<label id="gradient_label" text="@.gradient" style="mini_label" />
|
||||||
<hbox id="gradient_placeholder" />
|
<hbox id="gradient_placeholder" />
|
||||||
|
|
||||||
|
<separator id="separator2" text="@.sensors_tweaks" horizontal="true" cell_hspan="2" />
|
||||||
|
|
||||||
|
<label id="pressure_label" text="@.pressure" style="mini_label" />
|
||||||
|
<hbox id="pressure_placeholder" cell_align="horizontal" />
|
||||||
|
<label id="velocity_label" text="@.velocity" style="mini_label" />
|
||||||
|
<hbox id="velocity_placeholder" cell_align="horizontal" />
|
||||||
</grid>
|
</grid>
|
||||||
|
|
||||||
</vbox>
|
</vbox>
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#define APP_TOOLS_DYNAMICS_H_INCLUDED
|
#define APP_TOOLS_DYNAMICS_H_INCLUDED
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "render/dithering_algorithm.h"
|
|
||||||
#include "render/dithering_matrix.h"
|
#include "render/dithering_matrix.h"
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
@ -26,8 +25,9 @@ namespace tools {
|
|||||||
DynamicSensor gradient = DynamicSensor::Static;
|
DynamicSensor gradient = DynamicSensor::Static;
|
||||||
int maxSize = 0;
|
int maxSize = 0;
|
||||||
int maxAngle = 0;
|
int maxAngle = 0;
|
||||||
render::DitheringAlgorithm ditheringAlgorithm = render::DitheringAlgorithm::None;
|
|
||||||
render::DitheringMatrix ditheringMatrix;
|
render::DitheringMatrix ditheringMatrix;
|
||||||
|
float minPressureThreshold = 0.0f, maxPressureThreshold = 1.0f;
|
||||||
|
float minVelocityThreshold = 0.0f, maxVelocityThreshold = 1.0f;
|
||||||
|
|
||||||
bool isDynamic() const {
|
bool isDynamic() const {
|
||||||
return (size != DynamicSensor::Static ||
|
return (size != DynamicSensor::Static ||
|
||||||
|
@ -420,12 +420,44 @@ void ToolLoopManager::adjustPointWithDynamics(const Pointer& pointer,
|
|||||||
// Pressure
|
// Pressure
|
||||||
bool hasP = (pointer.type() == Pointer::Type::Pen ||
|
bool hasP = (pointer.type() == Pointer::Type::Pen ||
|
||||||
pointer.type() == Pointer::Type::Eraser);
|
pointer.type() == Pointer::Type::Eraser);
|
||||||
float p = (hasP ? pointer.pressure(): 1.0f);
|
float p = 1.0f;
|
||||||
|
if (hasP) {
|
||||||
|
p = pointer.pressure();
|
||||||
|
if (p < m_dynamics.minPressureThreshold) {
|
||||||
|
p = 0.0f;
|
||||||
|
}
|
||||||
|
else if (p > m_dynamics.maxPressureThreshold ||
|
||||||
|
// To avoid div by zero
|
||||||
|
m_dynamics.minPressureThreshold == m_dynamics.maxPressureThreshold) {
|
||||||
|
p = 1.0f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p =
|
||||||
|
(p - m_dynamics.minPressureThreshold) /
|
||||||
|
(m_dynamics.maxPressureThreshold - m_dynamics.minPressureThreshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
ASSERT(p >= 0.0f && p <= 1.0f);
|
ASSERT(p >= 0.0f && p <= 1.0f);
|
||||||
|
p = base::clamp(p, 0.0f, 1.0f);
|
||||||
|
|
||||||
// Velocity
|
// Velocity
|
||||||
float v = float(std::sqrt(m_velocity.x*m_velocity.x +
|
float v = float(std::sqrt(m_velocity.x*m_velocity.x +
|
||||||
m_velocity.y*m_velocity.y)) / 16.0f; // TODO 16 should be configurable
|
m_velocity.y*m_velocity.y)) / 32.0f; // TODO 32 should be configurable
|
||||||
|
v = base::clamp(v, 0.0f, 1.0f);
|
||||||
|
if (v < m_dynamics.minVelocityThreshold) {
|
||||||
|
v = 0.0f;
|
||||||
|
}
|
||||||
|
else if (v > m_dynamics.maxVelocityThreshold ||
|
||||||
|
// To avoid div by zero
|
||||||
|
m_dynamics.minVelocityThreshold == m_dynamics.maxVelocityThreshold) {
|
||||||
|
v = 1.0f;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
v =
|
||||||
|
(v - m_dynamics.minVelocityThreshold) /
|
||||||
|
(m_dynamics.maxVelocityThreshold - m_dynamics.minVelocityThreshold);
|
||||||
|
}
|
||||||
|
ASSERT(v >= 0.0f && v <= 1.0f);
|
||||||
v = base::clamp(v, 0.0f, 1.0f);
|
v = base::clamp(v, 0.0f, 1.0f);
|
||||||
|
|
||||||
switch (m_dynamics.size) {
|
switch (m_dynamics.size) {
|
||||||
|
@ -13,10 +13,18 @@
|
|||||||
#include "app/ui/dithering_selector.h"
|
#include "app/ui/dithering_selector.h"
|
||||||
#include "app/ui/skin/skin_theme.h"
|
#include "app/ui/skin/skin_theme.h"
|
||||||
#include "base/clamp.h"
|
#include "base/clamp.h"
|
||||||
|
#include "os/font.h"
|
||||||
|
#include "os/surface.h"
|
||||||
#include "ui/message.h"
|
#include "ui/message.h"
|
||||||
|
#include "ui/paint_event.h"
|
||||||
|
#include "ui/scale.h"
|
||||||
|
#include "ui/size_hint_event.h"
|
||||||
|
#include "ui/widget.h"
|
||||||
|
|
||||||
#include "dynamics.xml.h"
|
#include "dynamics.xml.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
|
|
||||||
@ -42,6 +50,163 @@ enum {
|
|||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
// Special slider to set min/max values of a sensor
|
||||||
|
class DynamicsPopup::MinMaxSlider : public Widget {
|
||||||
|
public:
|
||||||
|
MinMaxSlider() {
|
||||||
|
setExpansive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
float minThreshold() const { return m_minThreshold; }
|
||||||
|
float maxThreshold() const { return m_maxThreshold; }
|
||||||
|
void setSensorValue(float v) {
|
||||||
|
m_sensorValue = v;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onInitTheme(InitThemeEvent& ev) override {
|
||||||
|
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||||
|
setBorder(
|
||||||
|
gfx::Border(
|
||||||
|
theme->parts.miniSliderEmpty()->bitmapW()->width(),
|
||||||
|
theme->parts.miniSliderEmpty()->bitmapN()->height(),
|
||||||
|
theme->parts.miniSliderEmpty()->bitmapE()->width(),
|
||||||
|
theme->parts.miniSliderEmpty()->bitmapS()->height()));
|
||||||
|
|
||||||
|
Widget::onInitTheme(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSizeHint(SizeHintEvent& ev) override {
|
||||||
|
int w = 0;
|
||||||
|
int h = 2*textHeight();
|
||||||
|
|
||||||
|
w += border().width();
|
||||||
|
h += border().height();
|
||||||
|
|
||||||
|
ev.setSizeHint(w, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onPaint(PaintEvent& ev) override {
|
||||||
|
Graphics* g = ev.graphics();
|
||||||
|
SkinTheme* theme = static_cast<SkinTheme*>(this->theme());
|
||||||
|
gfx::Rect rc = clientBounds();
|
||||||
|
gfx::Color bgcolor = bgColor();
|
||||||
|
g->fillRect(bgcolor, rc);
|
||||||
|
|
||||||
|
rc.shrink(border());
|
||||||
|
const int minX = this->minX();
|
||||||
|
const int maxX = this->maxX();
|
||||||
|
rc = clientBounds();
|
||||||
|
|
||||||
|
// Draw customized background
|
||||||
|
const skin::SkinPartPtr& nw = theme->parts.miniSliderEmpty();
|
||||||
|
os::Surface* thumb =
|
||||||
|
(hasFocus() ? theme->parts.miniSliderThumbFocused()->bitmap(0):
|
||||||
|
theme->parts.miniSliderThumb()->bitmap(0));
|
||||||
|
|
||||||
|
// Draw background
|
||||||
|
g->fillRect(bgcolor, rc);
|
||||||
|
|
||||||
|
// Draw thumb
|
||||||
|
int thumb_y = rc.y;
|
||||||
|
rc.shrink(gfx::Border(0, thumb->height(), 0, 0));
|
||||||
|
|
||||||
|
// Draw borders
|
||||||
|
if (rc.h > 4*guiscale()) {
|
||||||
|
rc.shrink(gfx::Border(3, 0, 3, 1) * guiscale());
|
||||||
|
theme->drawRect(g, rc, nw.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
const int sensorW = float(rc.w)*m_sensorValue;
|
||||||
|
|
||||||
|
// Draw background
|
||||||
|
if (m_minThreshold > 0.0f) {
|
||||||
|
theme->drawRect(
|
||||||
|
g, gfx::Rect(rc.x, rc.y, minX-rc.x, rc.h),
|
||||||
|
theme->parts.miniSliderFull().get());
|
||||||
|
}
|
||||||
|
if (m_maxThreshold < 1.0f) {
|
||||||
|
theme->drawRect(
|
||||||
|
g, gfx::Rect(maxX, rc.y, rc.x2()-maxX, rc.h),
|
||||||
|
theme->parts.miniSliderFull().get());
|
||||||
|
}
|
||||||
|
|
||||||
|
g->fillRect(theme->colors.sliderEmptyText(),
|
||||||
|
gfx::Rect(rc.x, rc.y+rc.h/2-rc.h/8, sensorW, rc.h/4));
|
||||||
|
|
||||||
|
g->drawRgbaSurface(thumb, minX-thumb->width()/2, thumb_y);
|
||||||
|
g->drawRgbaSurface(thumb, maxX-thumb->width()/2, thumb_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool onProcessMessage(Message* msg) override {
|
||||||
|
switch (msg->type()) {
|
||||||
|
|
||||||
|
case kMouseDownMessage: {
|
||||||
|
auto mouseMsg = static_cast<MouseMessage*>(msg);
|
||||||
|
const int u = mouseMsg->position().x - origin().x;
|
||||||
|
const int minX = this->minX();
|
||||||
|
const int maxX = this->maxX();
|
||||||
|
if (ABS(u-minX) <
|
||||||
|
ABS(u-maxX))
|
||||||
|
capture = Capture::Min;
|
||||||
|
else
|
||||||
|
capture = Capture::Max;
|
||||||
|
captureMouse();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case kMouseUpMessage:
|
||||||
|
if (hasCapture())
|
||||||
|
releaseMouse();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kMouseMoveMessage: {
|
||||||
|
if (!hasCapture())
|
||||||
|
break;
|
||||||
|
|
||||||
|
auto mouseMsg = static_cast<MouseMessage*>(msg);
|
||||||
|
const gfx::Rect rc = bounds();
|
||||||
|
float u = (mouseMsg->position().x - rc.x) / float(rc.w);
|
||||||
|
u = base::clamp(u, 0.0f, 1.0f);
|
||||||
|
switch (capture) {
|
||||||
|
case Capture::Min:
|
||||||
|
m_minThreshold = u;
|
||||||
|
if (m_maxThreshold < u)
|
||||||
|
m_maxThreshold = u;
|
||||||
|
invalidate();
|
||||||
|
break;
|
||||||
|
case Capture::Max:
|
||||||
|
m_maxThreshold = u;
|
||||||
|
if (m_minThreshold > u)
|
||||||
|
m_minThreshold = u;
|
||||||
|
invalidate();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Widget::onProcessMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int minX() const {
|
||||||
|
gfx::Rect rc = clientBounds();
|
||||||
|
return rc.x + float(rc.w)*m_minThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxX() const {
|
||||||
|
gfx::Rect rc = clientBounds();
|
||||||
|
return rc.x + float(rc.w)*m_maxThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Capture { Min, Max };
|
||||||
|
|
||||||
|
float m_minThreshold = 0.1f;
|
||||||
|
float m_sensorValue = 0.0f;
|
||||||
|
float m_maxThreshold = 0.9f;
|
||||||
|
Capture capture;
|
||||||
|
};
|
||||||
|
|
||||||
DynamicsPopup::DynamicsPopup(Delegate* delegate)
|
DynamicsPopup::DynamicsPopup(Delegate* delegate)
|
||||||
: PopupWindow("",
|
: PopupWindow("",
|
||||||
PopupWindow::ClickBehavior::CloseOnClickOutsideHotRegion,
|
PopupWindow::ClickBehavior::CloseOnClickOutsideHotRegion,
|
||||||
@ -56,6 +221,8 @@ DynamicsPopup::DynamicsPopup(Delegate* delegate)
|
|||||||
});
|
});
|
||||||
|
|
||||||
m_dynamics->gradientPlaceholder()->addChild(m_ditheringSel);
|
m_dynamics->gradientPlaceholder()->addChild(m_ditheringSel);
|
||||||
|
m_dynamics->pressurePlaceholder()->addChild(m_pressureTweaks = new MinMaxSlider);
|
||||||
|
m_dynamics->velocityPlaceholder()->addChild(m_velocityTweaks = new MinMaxSlider);
|
||||||
addChild(m_dynamics);
|
addChild(m_dynamics);
|
||||||
|
|
||||||
onValuesChange(nullptr);
|
onValuesChange(nullptr);
|
||||||
@ -78,8 +245,13 @@ tools::DynamicsOptions DynamicsPopup::getDynamics() const
|
|||||||
tools::DynamicSensor::Static);
|
tools::DynamicSensor::Static);
|
||||||
opts.maxSize = m_dynamics->maxSize()->getValue();
|
opts.maxSize = m_dynamics->maxSize()->getValue();
|
||||||
opts.maxAngle = m_dynamics->maxAngle()->getValue();
|
opts.maxAngle = m_dynamics->maxAngle()->getValue();
|
||||||
opts.ditheringAlgorithm = m_ditheringSel->ditheringAlgorithm();
|
|
||||||
opts.ditheringMatrix = m_ditheringSel->ditheringMatrix();
|
opts.ditheringMatrix = m_ditheringSel->ditheringMatrix();
|
||||||
|
|
||||||
|
opts.minPressureThreshold = m_pressureTweaks->minThreshold();
|
||||||
|
opts.maxPressureThreshold = m_pressureTweaks->maxThreshold();
|
||||||
|
opts.minVelocityThreshold = m_velocityTweaks->minThreshold();
|
||||||
|
opts.maxVelocityThreshold = m_velocityTweaks->maxThreshold();
|
||||||
|
|
||||||
return opts;
|
return opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,6 +301,12 @@ void DynamicsPopup::onValuesChange(ButtonSet::Item* item)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool hasPressure = (isCheck(SIZE_WITH_PRESSURE) ||
|
||||||
|
isCheck(ANGLE_WITH_PRESSURE) ||
|
||||||
|
isCheck(GRADIENT_WITH_PRESSURE));
|
||||||
|
const bool hasVelocity = (isCheck(SIZE_WITH_VELOCITY) ||
|
||||||
|
isCheck(ANGLE_WITH_VELOCITY) ||
|
||||||
|
isCheck(GRADIENT_WITH_VELOCITY));
|
||||||
const bool needsSize = (isCheck(SIZE_WITH_PRESSURE) ||
|
const bool needsSize = (isCheck(SIZE_WITH_PRESSURE) ||
|
||||||
isCheck(SIZE_WITH_VELOCITY));
|
isCheck(SIZE_WITH_VELOCITY));
|
||||||
const bool needsAngle = (isCheck(ANGLE_WITH_PRESSURE) ||
|
const bool needsAngle = (isCheck(ANGLE_WITH_PRESSURE) ||
|
||||||
@ -156,6 +334,11 @@ void DynamicsPopup::onValuesChange(ButtonSet::Item* item)
|
|||||||
|
|
||||||
m_dynamics->separator()->setVisible(any);
|
m_dynamics->separator()->setVisible(any);
|
||||||
m_dynamics->options()->setVisible(any);
|
m_dynamics->options()->setVisible(any);
|
||||||
|
m_dynamics->separator2()->setVisible(any);
|
||||||
|
m_dynamics->pressureLabel()->setVisible(hasPressure);
|
||||||
|
m_dynamics->pressurePlaceholder()->setVisible(hasPressure);
|
||||||
|
m_dynamics->velocityLabel()->setVisible(hasVelocity);
|
||||||
|
m_dynamics->velocityPlaceholder()->setVisible(hasVelocity);
|
||||||
|
|
||||||
auto oldBounds = bounds();
|
auto oldBounds = bounds();
|
||||||
layout();
|
layout();
|
||||||
@ -171,13 +354,58 @@ void DynamicsPopup::onValuesChange(ButtonSet::Item* item)
|
|||||||
bool DynamicsPopup::onProcessMessage(Message* msg)
|
bool DynamicsPopup::onProcessMessage(Message* msg)
|
||||||
{
|
{
|
||||||
switch (msg->type()) {
|
switch (msg->type()) {
|
||||||
|
|
||||||
case kOpenMessage:
|
case kOpenMessage:
|
||||||
m_hotRegion = gfx::Region(bounds());
|
m_hotRegion = gfx::Region(bounds());
|
||||||
setHotRegion(m_hotRegion);
|
setHotRegion(m_hotRegion);
|
||||||
|
manager()->addMessageFilter(kMouseMoveMessage, this);
|
||||||
|
disableFlags(IGNORE_MOUSE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kCloseMessage:
|
case kCloseMessage:
|
||||||
m_hotRegion.clear();
|
m_hotRegion.clear();
|
||||||
|
manager()->removeMessageFilter(kMouseMoveMessage, this);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case kMouseEnterMessage: {
|
||||||
|
auto mouseMsg = static_cast<MouseMessage*>(msg);
|
||||||
|
m_lastPos = mouseMsg->position();
|
||||||
|
m_velocity = gfx::Point(0, 0);
|
||||||
|
m_lastPointerT = base::current_tick();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case kMouseMoveMessage: {
|
||||||
|
auto mouseMsg = static_cast<MouseMessage*>(msg);
|
||||||
|
|
||||||
|
if (mouseMsg->pointerType() == PointerType::Pen ||
|
||||||
|
mouseMsg->pointerType() == PointerType::Eraser) {
|
||||||
|
if (m_dynamics->pressurePlaceholder()->isVisible()) {
|
||||||
|
m_pressureTweaks->setSensorValue(mouseMsg->pressure());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_dynamics->velocityPlaceholder()->isVisible()) {
|
||||||
|
// TODO merge this with ToolLoopManager::getSpriteStrokePt() and
|
||||||
|
// ToolLoopManager::adjustPointWithDynamics()
|
||||||
|
const base::tick_t t = base::current_tick();
|
||||||
|
const base::tick_t dt = t - m_lastPointerT;
|
||||||
|
m_lastPointerT = t;
|
||||||
|
|
||||||
|
float a = base::clamp(float(dt) / 50.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
|
gfx::Point newVelocity(mouseMsg->position() - m_lastPos);
|
||||||
|
m_velocity.x = (1.0f-a)*m_velocity.x + a*newVelocity.x;
|
||||||
|
m_velocity.y = (1.0f-a)*m_velocity.y + a*newVelocity.y;
|
||||||
|
m_lastPos = mouseMsg->position();
|
||||||
|
|
||||||
|
float v = float(std::sqrt(m_velocity.x*m_velocity.x +
|
||||||
|
m_velocity.y*m_velocity.y)) / 32.0f; // TODO 32 should be configurable
|
||||||
|
v = base::clamp(v, 0.0f, 1.0f);
|
||||||
|
m_velocityTweaks->setSensorValue(v);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return PopupWindow::onProcessMessage(msg);
|
return PopupWindow::onProcessMessage(msg);
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
#include "app/tools/dynamics.h"
|
#include "app/tools/dynamics.h"
|
||||||
#include "app/ui/button_set.h"
|
#include "app/ui/button_set.h"
|
||||||
|
#include "base/time.h"
|
||||||
#include "doc/brush.h"
|
#include "doc/brush.h"
|
||||||
#include "gfx/region.h"
|
#include "gfx/region.h"
|
||||||
#include "ui/popup_window.h"
|
#include "ui/popup_window.h"
|
||||||
@ -33,6 +34,8 @@ namespace app {
|
|||||||
tools::DynamicsOptions getDynamics() const;
|
tools::DynamicsOptions getDynamics() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class MinMaxSlider;
|
||||||
|
|
||||||
void setCheck(int i, bool state);
|
void setCheck(int i, bool state);
|
||||||
bool isCheck(int i) const;
|
bool isCheck(int i) const;
|
||||||
void onValuesChange(ButtonSet::Item* item);
|
void onValuesChange(ButtonSet::Item* item);
|
||||||
@ -42,6 +45,10 @@ namespace app {
|
|||||||
gen::Dynamics* m_dynamics;
|
gen::Dynamics* m_dynamics;
|
||||||
DitheringSelector* m_ditheringSel;
|
DitheringSelector* m_ditheringSel;
|
||||||
gfx::Region m_hotRegion;
|
gfx::Region m_hotRegion;
|
||||||
|
MinMaxSlider* m_pressureTweaks;
|
||||||
|
MinMaxSlider* m_velocityTweaks;
|
||||||
|
gfx::Point m_lastPos, m_velocity;
|
||||||
|
base::tick_t m_lastPointerT;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
@ -146,8 +146,11 @@ public:
|
|||||||
, m_secondaryColor(button == tools::ToolLoop::Left ? m_bgColor: m_fgColor)
|
, m_secondaryColor(button == tools::ToolLoop::Left ? m_bgColor: m_fgColor)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_UI // TODO add dynamics support when UI is not enabled
|
#ifdef ENABLE_UI // TODO add dynamics support when UI is not enabled
|
||||||
if (m_controller->isFreehand())
|
if (m_controller->isFreehand() &&
|
||||||
|
!m_ink->isEraser() &&
|
||||||
|
!m_pointShape->isFloodFill()) {
|
||||||
m_dynamics = App::instance()->contextBar()->getDynamics();
|
m_dynamics = App::instance()->contextBar()->getDynamics();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_tracePolicy == tools::TracePolicy::Accumulate ||
|
if (m_tracePolicy == tools::TracePolicy::Accumulate ||
|
||||||
|
Loading…
x
Reference in New Issue
Block a user