Nonlinear Slider for the Brush Size Options (#2824)

* nonlinear slider for tool size

* nonlinear slider for finger magnet and pinch tools
This commit is contained in:
shun-iwasawa 2019-10-11 12:13:41 +09:00 committed by GitHub
parent 6817df33ac
commit 76d093f2f4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 386 additions and 184 deletions

View file

@ -102,12 +102,20 @@ onSliderChanged(int value),
class DVAPI DoubleValueField : public QWidget {
Q_OBJECT
bool m_isLinearSlider;
protected:
RollerField *m_roller;
DoubleValueLineEdit *m_lineEdit;
QSlider *m_slider;
QWidget *m_spaceWidget;
void setLinearSlider(bool linear) { m_isLinearSlider = linear; }
private:
double pos2value(int x) const;
int value2pos(double v) const;
public:
DoubleValueField(QWidget *parent, DoubleValueLineEdit *lineEdit);
~DoubleValueField() {}
@ -158,7 +166,7 @@ signals:
void valueChanged(bool);
/*! This signal is emitted only when users edited the value by hand
*/
*/
void valueEditedByHand();
};

View file

@ -102,6 +102,8 @@ protected:
bool m_isMaxRangeLimited;
bool m_isLinear;
public:
DoubleValuePairField(QWidget *parent, bool isMaxRangeLimited,
DoubleValueLineEdit *leftLineEdit,
@ -174,6 +176,7 @@ protected:
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void setLinearSlider(bool linear) { m_isLinear = linear; }
protected slots:
/*! Set current left value to value in left text field; if necessary, if left
value is greater than right, change also current right value.

View file

@ -167,6 +167,7 @@ class DVAPI IntField : public QWidget {
IntLineEdit *m_lineEdit;
QSlider *m_slider;
bool m_isMaxRangeLimited;
bool m_isLinearSlider;
public:
IntField(QWidget *parent = 0, bool isMaxRangeLimited = true,
@ -205,6 +206,13 @@ public:
void setLineEditBackgroundColor(QColor color);
protected:
void setLinearSlider(bool linear) { m_isLinearSlider = linear; }
private:
int pos2value(int x) const;
int value2pos(int v) const;
protected slots:
/*! Set to value the text field. If text field value is different from \b
value

View file

@ -112,6 +112,8 @@ class DVAPI IntPairField : public QWidget {
bool m_isMaxRangeLimited;
bool m_isLinear;
public:
IntPairField(QWidget *parent = 0, bool isMaxRangeLimited = true);
~IntPairField() {}
@ -166,9 +168,9 @@ public:
protected:
/*! Return value corresponding \b x position. */
double pos2value(int x) const;
int pos2value(int x) const;
/*! Return x position corresponding \b value. */
int value2pos(double v) const;
int value2pos(int v) const;
/*! Set current value to \b value.
Set left or right value, or both, to value depending on
@ -182,6 +184,7 @@ protected:
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
void setLinearSlider(bool linear) { m_isLinear = linear; }
protected slots:
/*! Set current left value to value in left text field; if necessary, if left
value is greater than right, change also current right value.

View file

@ -112,7 +112,8 @@ public:
: TProperty(name)
, m_range(minValue, maxValue)
, m_value(minValue)
, m_isMaxRangeLimited(isMaxRangeLimited) {
, m_isMaxRangeLimited(isMaxRangeLimited)
, m_isLinearSlider(true) {
setValue(value);
}
@ -138,10 +139,14 @@ public:
bool isMaxRangeLimited() const { return m_isMaxRangeLimited; }
void setNonLinearSlider() { m_isLinearSlider = false; }
bool isLinearSlider() { return m_isLinearSlider; }
private:
Range m_range;
T m_value;
bool m_isMaxRangeLimited;
bool m_isLinearSlider;
};
//---------------------------------------------------------
@ -160,7 +165,8 @@ public:
double v0, double v1, bool isMaxRangeLimited = true)
: TProperty(name)
, m_range(Range(minValue, maxValue))
, m_isMaxRangeLimited(isMaxRangeLimited) {
, m_isMaxRangeLimited(isMaxRangeLimited)
, m_isLinearSlider(true) {
setValue(Value(v0, v1));
}
@ -184,10 +190,14 @@ public:
}
void accept(Visitor &v) override { v.visit(this); };
void setNonLinearSlider() { m_isLinearSlider = false; }
bool isLinearSlider() { return m_isLinearSlider; }
private:
Range m_range;
Value m_value;
bool m_isMaxRangeLimited;
bool m_isLinearSlider;
};
//---------------------------------------------------------
@ -201,7 +211,8 @@ public:
bool isMaxRangeLimited = true)
: TProperty(name)
, m_range(minValue, maxValue)
, m_isMaxRangeLimited(isMaxRangeLimited) {
, m_isMaxRangeLimited(isMaxRangeLimited)
, m_isLinearSlider(true) {
setValue(Value(v0, v1));
}
@ -225,10 +236,14 @@ public:
}
void accept(Visitor &v) override { v.visit(this); };
void setNonLinearSlider() { m_isLinearSlider = false; }
bool isLinearSlider() { return m_isLinearSlider; }
private:
Range m_range;
Value m_value;
bool m_isMaxRangeLimited;
bool m_isLinearSlider;
};
//---------------------------------------------------------

View file

@ -1,6 +1,6 @@
//------------------------------------------------------
/*! Finger Tool : 線のノイズを埋めるツール
*/
*/
#include "tstroke.h"
#include "tools/toolutils.h"
#include "tools/tool.h"
@ -313,12 +313,14 @@ FingerTool::FingerTool()
, m_selecting(false)
, m_tileSaver(0)
, m_cursor(ToolCursor::EraserCursor)
, m_toolSize("Size:", 1, 100, 10, false)
, m_toolSize("Size:", 1, 1000, 10, false)
, m_invert("Invert", false)
, m_firstTime(true)
, m_workingFrameId(TFrameId()) {
bind(TTool::ToonzImage);
m_toolSize.setNonLinearSlider();
m_prop.bind(m_toolSize);
m_prop.bind(m_invert);
@ -504,7 +506,7 @@ void FingerTool::onDeactivate() {
//-----------------------------------------------------------------------------
/*!
* onDeactivateにもMouseReleaseと同じ処理を行う
*/
*/
void FingerTool::finishBrush() {
if (TToonzImageP ti = (TToonzImageP)getImage(true)) {
if (m_rasterTrack) {
@ -576,9 +578,8 @@ void FingerTool::pick(const TPointD &pos) {
/*---
* pickLineモードのときPurePaintの部分をクリックしてもカレントStyleを変えない
* ---*/
if (ti &&
picker.pickTone(TScale(1.0 / subsampling) * pos +
TPointD(-0.5, -0.5)) == 255)
if (ti && picker.pickTone(TScale(1.0 / subsampling) * pos +
TPointD(-0.5, -0.5)) == 255)
return;
}

View file

@ -113,7 +113,7 @@ public:
FullColorBrushTool::FullColorBrushTool(std::string name)
: TTool(name)
, m_thickness("Size", 1, 100, 1, 5, false)
, m_thickness("Size", 1, 1000, 1, 5, false)
, m_pressure("Pressure", true)
, m_opacity("Opacity", 0, 100, 100, 100, true)
, m_hardness("Hardness:", 0, 100, 100)
@ -133,6 +133,8 @@ FullColorBrushTool::FullColorBrushTool(std::string name)
, m_firstTime(true) {
bind(TTool::RasterImage | TTool::EmptyTarget);
m_thickness.setNonLinearSlider();
m_prop.bind(m_thickness);
m_prop.bind(m_hardness);
m_prop.bind(m_opacity);
@ -302,7 +304,7 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos,
if (!viewer) return;
TRasterImageP ri = (TRasterImageP)getImage(true);
if (!ri) ri = (TRasterImageP)touchImage();
if (!ri) ri = (TRasterImageP)touchImage();
if (!ri) return;
@ -318,7 +320,13 @@ void FullColorBrushTool::leftButtonDown(const TPointD &pos,
TPointD rasCenter = ras->getCenterD();
TPointD point(pos + rasCenter);
double pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5;
double pressure;
if (getApplication()->getCurrentLevelStyle()->getTagId() ==
4001) // mypaint brush case
pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5;
else
pressure = m_enabledPressure ? e.m_pressure : 1.0;
m_tileSet = new TTileSetFullColor(ras->getSize());
m_tileSaver = new TTileSaverFullColor(ras, m_tileSet);
@ -358,7 +366,12 @@ void FullColorBrushTool::leftButtonDrag(const TPointD &pos,
TRasterP ras = ri->getRaster();
TPointD rasCenter = ras->getCenterD();
TPointD point(pos + rasCenter);
double pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5;
double pressure;
if (getApplication()->getCurrentLevelStyle()->getTagId() ==
4001) // mypaint brush case
pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5;
else
pressure = m_enabledPressure ? e.m_pressure : 1.0;
m_strokeSegmentRect.empty();
m_toonz_brush->strokeTo(point, pressure, restartBrushTimer());
@ -389,7 +402,12 @@ void FullColorBrushTool::leftButtonUp(const TPointD &pos,
TRasterP ras = ri->getRaster();
TPointD rasCenter = ras->getCenterD();
TPointD point(pos + rasCenter);
double pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5;
double pressure;
if (getApplication()->getCurrentLevelStyle()->getTagId() ==
4001) // mypaint brush case
pressure = m_enabledPressure && e.isTablet() ? e.m_pressure : 0.5;
else
pressure = m_enabledPressure ? e.m_pressure : 1.0;
m_strokeSegmentRect.empty();
m_toonz_brush->strokeTo(point, pressure, restartBrushTimer());
@ -747,13 +765,7 @@ void FullColorBrushTool::updateCurrentStyle() {
m_minCursorThick = std::max(m_thickness.getValue().first, 1);
m_maxCursorThick =
std::max(m_thickness.getValue().second, m_minCursorThick);
if (!m_enabledPressure) {
double minRadiusLog = log(0.5 * m_minCursorThick);
double maxRadiusLog = log(0.5 * m_maxCursorThick);
double avgRadiusLog = 0.5 * (minRadiusLog + maxRadiusLog);
double avgRadius = exp(avgRadiusLog);
m_minCursorThick = m_maxCursorThick = (int)round(2.0 * avgRadius);
}
if (!m_enabledPressure) m_minCursorThick = m_maxCursorThick;
}
// if this function is called from onEnter(), the clipping rect will not be

View file

@ -368,7 +368,7 @@ private:
FullColorEraserTool::FullColorEraserTool(std::string name)
: TTool(name)
, m_size("Size:", 1, 100, 5, false)
, m_size("Size:", 1, 1000, 5, false)
, m_opacity("Opacity:", 0, 100, 100)
, m_hardness("Hardness:", 0, 100, 100)
, m_eraseType("Type:")
@ -385,6 +385,8 @@ FullColorEraserTool::FullColorEraserTool(std::string name)
, m_isXsheetCell(false) {
bind(TTool::RasterImage);
m_size.setNonLinearSlider();
m_prop.bind(m_size);
m_prop.bind(m_hardness);
m_prop.bind(m_opacity);
@ -987,7 +989,7 @@ void FullColorEraserTool::update(const TRasterImageP &ri, TRectD selArea,
tileSet->add(raster, TRasterImageUtils::convertWorldToRaster(selArea, ri));
TUndo *undo;
undo = new RectFullColorUndo(tileSet, selArea, TStroke(),
undo = new RectFullColorUndo(tileSet, selArea, TStroke(),
m_eraseType.getValue(), level.getPointer(),
m_invertOption.getValue(), frameId);
TRect rect = TRasterImageUtils::eraseRect(ri, selArea);

View file

@ -118,7 +118,6 @@ class MagnetTool final : public TTool {
DoublePair m_extremes;
int m_cursorId;
double m_pointSize;
TUndo *m_undo;
typedef struct {
@ -142,11 +141,13 @@ public:
MagnetTool()
: TTool("T_Magnet")
, m_active(false)
, m_pointSize(-1)
, m_oldStrokesArray()
, m_toolSize("Size:", 0, 100, 20) // W_ToolOptions_MagnetTool
, m_toolSize("Size:", 10, 500, 20) // W_ToolOptions_MagnetTool
{
bind(TTool::Vectors);
m_toolSize.setNonLinearSlider();
m_prop.bind(m_toolSize);
}
@ -159,12 +160,8 @@ public:
m_cursorId = ToolCursor::MagnetCursor;
else
m_cursorId = ToolCursor::CURSOR_NO;
updatePointSize();
}
void onLeave() override { m_pointSize = -1; }
void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override {
TPointD p(pos);
@ -190,6 +187,8 @@ public:
m_hitStrokeCorners.clear();
m_strokeToModifyCorners.clear();
double pointSize = m_toolSize.getValue();
UINT i = 0;
for (; i < vi->getStrokeCount(); ++i) {
if (!vi->inCurrentGroup(i)) continue;
@ -198,11 +197,11 @@ public:
ref = stroke;
// calcola le intersezioni
std::vector<double> intersections;
intersect(*ref, p, m_pointSize, intersections);
intersect(*ref, p, pointSize, intersections);
if (intersections.empty()) {
if (increaseControlPoints(*ref,
TStrokePointDeformation(p, m_pointSize))) {
TStrokePointDeformation(p, pointSize))) {
m_changedStrokes.push_back(i);
m_strokeHit.push_back(ref);
@ -225,11 +224,11 @@ public:
splitStroke(*sc.m_parent, intersections, sc.m_splitted);
selectStrokeToMove(sc.m_splitted, p, m_pointSize, sc.m_splittedToMove);
selectStrokeToMove(sc.m_splitted, p, pointSize, sc.m_splittedToMove);
for (UINT ii = 0; ii < sc.m_splittedToMove.size(); ++ii) {
TStroke *temp = sc.m_splittedToMove[ii];
bool test = increaseControlPoints(
*temp, TStrokePointDeformation(p, m_pointSize));
*temp, TStrokePointDeformation(p, pointSize));
assert(test);
std::vector<int> *corners = new std::vector<int>;
@ -245,7 +244,7 @@ public:
}
m_oldStrokesArray.resize(m_changedStrokes.size());
for (i = 0; i < m_changedStrokes.size(); i++)
for (i = 0; i < m_changedStrokes.size(); i++)
m_oldStrokesArray[i] = new TStroke(*(vi->getStroke(m_changedStrokes[i])));
if (!strokeUndo.empty()) {
@ -288,19 +287,21 @@ leftButtonUp(p);
lefrightButtonDown(p);
}
*/
double pointSize = m_toolSize.getValue();
UINT i, j;
for (i = 0; i < m_strokeHit.size(); ++i)
modifyControlPoints(*m_strokeHit[i],
TStrokePointDeformation(offset, m_pointAtMouseDown,
m_pointSize * 0.7));
modifyControlPoints(
*m_strokeHit[i],
TStrokePointDeformation(offset, m_pointAtMouseDown, pointSize * 0.7));
for (i = 0; i < m_strokeToModify.size(); ++i)
for (j = 0; j < m_strokeToModify[i].m_splittedToMove.size(); ++j) {
TStroke *temp = m_strokeToModify[i].m_splittedToMove[j];
modifyControlPoints(*temp,
TStrokePointDeformation(offset, m_pointAtMouseDown,
m_pointSize * 0.7));
pointSize * 0.7));
}
m_pointAtMove = p;
@ -399,10 +400,10 @@ lefrightButtonDown(p);
// glPushMatrix();
// tglMultMatrix(viewMatrix);
if (m_pointSize > 0) {
tglColor(TPixel32::Red);
tglDrawCircle(m_pointAtMove, m_pointSize);
}
double pointSize = m_toolSize.getValue();
tglColor(TPixel32::Red);
tglDrawCircle(m_pointAtMove, pointSize);
if (!m_active) {
// glPopMatrix();
@ -439,31 +440,14 @@ lefrightButtonDown(p);
int getCursorId() const override { return m_cursorId; }
bool onPropertyChanged(std::string propertyName) override
{
if(propertyName == m_toolSize.getName()) {
updatePointSize();
bool onPropertyChanged(std::string propertyName) override {
if (propertyName == m_toolSize.getName()) {
invalidate();
}
return true;
}
private:
/// Update point size based on property.
void updatePointSize()
{
double x = m_toolSize.getValue();
double minRange = 1;
double maxRange = 100;
double minSize = 10;
double maxSize = 100;
m_pointSize =
(x - minRange) / (maxRange - minRange) * (maxSize - minSize) + minSize;
}
} magnetTool;
// TTool *getMagnetTool() {return &magnetTool;}

View file

@ -318,11 +318,13 @@ PaintBrushTool::PaintBrushTool()
, m_tileSaver(0)
, m_cursor(ToolCursor::EraserCursor)
// sostituire i nomi con quelli del current, tipo W_ToolOptions...
, m_toolSize("Size:", 1, 100, 10, false) // W_ToolOptions_BrushToolSize
, m_colorType("Mode:") // W_ToolOptions_InkOrPaint
, m_onlyEmptyAreas("Selective", false) // W_ToolOptions_Selective
, m_toolSize("Size:", 1, 1000, 10, false) // W_ToolOptions_BrushToolSize
, m_colorType("Mode:") // W_ToolOptions_InkOrPaint
, m_onlyEmptyAreas("Selective", false) // W_ToolOptions_Selective
, m_firstTime(true)
, m_workingFrameId(TFrameId()) {
m_toolSize.setNonLinearSlider();
m_colorType.addValue(LINES);
m_colorType.addValue(AREAS);
m_colorType.addValue(ALL);

View file

@ -81,6 +81,8 @@ PinchTool::PinchTool()
, m_selector(500, 10, 1000) {
bind(TTool::Vectors);
m_toolRange.setNonLinearSlider();
m_prop.bind(m_toolCornerSize);
m_prop.bind(m_autoOrManual);
m_prop.bind(m_toolRange);
@ -138,7 +140,7 @@ void PinchTool::updateInterfaceStatus(const TMouseEvent &event) {
m_status.key_event_ = ContextStatus::NONE;
// mutual exclusive
if (event.isCtrlPressed()) m_status.key_event_ = ContextStatus::CTRL;
if (event.isCtrlPressed()) m_status.key_event_ = ContextStatus::CTRL;
if (event.isShiftPressed()) m_status.key_event_ = ContextStatus::SHIFT;
// TODO: **DEVE** essere fatto dentro la costruzione di TMouseEvent
@ -357,7 +359,7 @@ void PinchTool::onEnter() {
//-----------------------------------------------------------------------------
void PinchTool::onLeave() {
if (!m_active) m_draw = false;
if (!m_active) m_draw = false;
m_status.stroke2change_ = 0;
// Abbiamo dovuto commentarlo perche' stranamente

View file

@ -281,7 +281,7 @@ void eraseStroke(const TToonzImageP &ti, TStroke *stroke,
if (!invert)
area = rasterErasedArea.enlarge(2);
else
area = ras->getBounds();
area = ras->getBounds();
TTileSetCM32 *tileSet = new TTileSetCM32(ras->getSize());
tileSet->add(ras, area);
TUndoManager::manager()->add(new RectRasterUndo(
@ -569,7 +569,7 @@ EraserTool inkPaintEraserTool("T_Eraser");
EraserTool::EraserTool(std::string name)
: TTool(name)
, m_toolSize("Size:", 1, 100, 10, false) // W_ToolOptions_EraserToolSize
, m_toolSize("Size:", 1, 1000, 10, false) // W_ToolOptions_EraserToolSize
, m_hardness("Hardness:", 0, 100, 100)
, m_eraseType("Type:") // W_ToolOptions_Erasetype
, m_colorType("Mode:") // W_ToolOptions_InkOrPaint
@ -592,6 +592,8 @@ EraserTool::EraserTool(std::string name)
, m_isLeftButtonPressed(false) {
bind(TTool::ToonzImage);
m_toolSize.setNonLinearSlider();
m_prop.bind(m_toolSize);
m_prop.bind(m_hardness);
m_prop.bind(m_eraseType);
@ -887,8 +889,8 @@ void EraserTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
int currentStyle = 0;
if (m_currentStyle.getValue())
currentStyle = TTool::getApplication()->getCurrentLevelStyleIndex();
m_tileSet = new TTileSetCM32(raster->getSize());
m_tileSaver = new TTileSaverCM32(raster, m_tileSet);
m_tileSet = new TTileSetCM32(raster->getSize());
m_tileSaver = new TTileSaverCM32(raster, m_tileSet);
TPointD halfThick(m_toolSize.getValue() * 0.5,
m_toolSize.getValue() * 0.5);
invalidateRect = TRectD(pos - halfThick, pos + halfThick);
@ -898,7 +900,7 @@ void EraserTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
m_colorTypeEraser = INK;
}
if (m_colorType.getValue() == AREAS) m_colorTypeEraser = PAINT;
if (m_colorType.getValue() == ALL) m_colorTypeEraser = INKNPAINT;
if (m_colorType.getValue() == ALL) m_colorTypeEraser = INKNPAINT;
m_normalEraser = new RasterStrokeGenerator(
raster, ERASE, m_colorTypeEraser, 0, intPos,
m_currentStyle.getValue(), currentStyle,
@ -1617,7 +1619,7 @@ void EraserTool::doMultiEraser(const TImageP &img, double t,
//--------------------------------------------------------------------------------------------------
/*!ドラッグ中にツールが切り替わった時、終了処理を行う
*/
*/
void EraserTool::onDeactivate() {
if (!m_isLeftButtonPressed || !m_selecting) return;
@ -1657,10 +1659,11 @@ void EraserTool::storeUndoAndRefresh() {
TUndoManager::manager()->add(new RasterBluredEraserUndo(
m_tileSet, m_points,
TTool::getApplication()->getCurrentLevelStyleIndex(),
m_currentStyle.getValue(), TTool::getApplication()
->getCurrentLevel()
->getLevel()
->getSimpleLevel(),
m_currentStyle.getValue(),
TTool::getApplication()
->getCurrentLevel()
->getLevel()
->getSimpleLevel(),
m_workingFrameId.isEmptyFrame() ? getCurrentFid() : m_workingFrameId,
m_toolSize.getValue(), m_hardness.getValue() * 0.01,
m_colorType.getValue()));
@ -1686,7 +1689,7 @@ void EraserTool::storeUndoAndRefresh() {
//--------------------------------------------------------------------------------------------------
/*! Brush、PaintBrush、EraserToolがPencilModeのときにTrueを返す
*/
*/
bool EraserTool::isPencilModeActive() {
return m_eraseType.getValue() == NORMALERASE && m_pencil.getValue();
}

View file

@ -148,6 +148,7 @@ ToolOptionSlider::ToolOptionSlider(TTool *tool, TDoubleProperty *property,
: DoubleField()
, ToolOptionControl(tool, property->getName(), toolHandle)
, m_property(property) {
setLinearSlider(property->isLinearSlider());
m_property->addListener(this);
TDoubleProperty::Range range = property->getRange();
setRange(range.first, range.second);
@ -250,6 +251,7 @@ ToolOptionPairSlider::ToolOptionPairSlider(TTool *tool,
: DoublePairField(0, property->isMaxRangeLimited())
, ToolOptionControl(tool, property->getName(), toolHandle)
, m_property(property) {
setLinearSlider(property->isLinearSlider());
m_property->addListener(this);
TDoublePairProperty::Value value = property->getValue();
TDoublePairProperty::Range range = property->getRange();
@ -377,6 +379,7 @@ ToolOptionIntPairSlider::ToolOptionIntPairSlider(TTool *tool,
: IntPairField(0, property->isMaxRangeLimited())
, ToolOptionControl(tool, property->getName(), toolHandle)
, m_property(property) {
setLinearSlider(property->isLinearSlider());
setLeftText(leftName);
setRightText(rightName);
m_property->addListener(this);
@ -491,6 +494,7 @@ ToolOptionIntSlider::ToolOptionIntSlider(TTool *tool, TIntProperty *property,
: IntField(0, property->isMaxRangeLimited())
, ToolOptionControl(tool, property->getName(), toolHandle)
, m_property(property) {
setLinearSlider(property->isLinearSlider());
m_property->addListener(this);
TIntProperty::Range range = property->getRange();
setRange(range.first, range.second);
@ -621,7 +625,7 @@ void ToolOptionCombo::loadEntries() {
}");
}
}
int tmpWidth = fontMetrics().width(items[i].UIName);
int tmpWidth = fontMetrics().width(items[i].UIName);
if (tmpWidth > maxWidth) maxWidth = tmpWidth;
}
@ -655,8 +659,8 @@ void ToolOptionCombo::onActivated(int index) {
void ToolOptionCombo::doShowPopup() {
if (Preferences::instance()->getDropdownShortcutsCycleOptions()) {
const TEnumProperty::Range &range = m_property->getRange();
int theIndex = currentIndex() + 1;
const TEnumProperty::Range &range = m_property->getRange();
int theIndex = currentIndex() + 1;
if (theIndex >= (int)range.size()) theIndex = 0;
doOnActivated(theIndex);
} else {
@ -738,8 +742,8 @@ void ToolOptionFontCombo::onActivated(int index) {
void ToolOptionFontCombo::doShowPopup() {
if (!isInVisibleViewer(this)) return;
if (Preferences::instance()->getDropdownShortcutsCycleOptions()) {
const TEnumProperty::Range &range = m_property->getRange();
int theIndex = currentIndex() + 1;
const TEnumProperty::Range &range = m_property->getRange();
int theIndex = currentIndex() + 1;
if (theIndex >= (int)range.size()) theIndex = 0;
onActivated(theIndex);
setCurrentIndex(theIndex);
@ -1415,8 +1419,8 @@ void PegbarCenterField::onChange(TMeasuredValue *fld, bool addToUndo) {
TStageObject *obj = xsh->getStageObject(objId);
double v = fld->getValue(TMeasuredValue::MainUnit);
TPointD center = obj->getCenter(frame);
double v = fld->getValue(TMeasuredValue::MainUnit);
TPointD center = obj->getCenter(frame);
if (!m_firstMouseDrag) m_oldCenter = center;
if (m_index == 0)
center.x = v;
@ -1507,7 +1511,7 @@ PropertyMenuButton::PropertyMenuButton(QWidget *parent, TTool *tool,
setIcon(icon);
setToolTip(tooltip);
QMenu *menu = new QMenu(tooltip, this);
QMenu *menu = new QMenu(tooltip, this);
if (!tooltip.isEmpty()) tooltip = tooltip + " ";
QActionGroup *actiongroup = new QActionGroup(this);
@ -1593,13 +1597,13 @@ bool SelectionScaleField::applyChange(bool addToUndo) {
return false;
DragSelectionTool::DragTool *scaleTool = createNewScaleTool(m_tool, 0);
double p = getValue();
if (p == 0) p = 0.00001;
DragSelectionTool::FourPoints points = m_tool->getBBox();
TPointD center = m_tool->getCenter();
TPointD p0M = points.getPoint(7);
TPointD p1M = points.getPoint(5);
TPointD pM1 = points.getPoint(6);
TPointD pM0 = points.getPoint(4);
if (p == 0) p = 0.00001;
DragSelectionTool::FourPoints points = m_tool->getBBox();
TPointD center = m_tool->getCenter();
TPointD p0M = points.getPoint(7);
TPointD p1M = points.getPoint(5);
TPointD pM1 = points.getPoint(6);
TPointD pM0 = points.getPoint(4);
int pointIndex;
TPointD sign(1, 1);
TPointD scaleFactor = m_tool->m_deformValues.m_scaleValue;

View file

@ -251,8 +251,9 @@ static void findMaxCurvPoints(TStroke *stroke, const float &angoloLim,
double estremo_int = 0;
double t = -1;
if (q != TPointD(0, 0)) {
t = 0.25 * (2 * q.x * q.x + 2 * q.y * q.y - q.x * p0.x + q.x * p2.x -
q.y * p0.y + q.y * p2.y) /
t = 0.25 *
(2 * q.x * q.x + 2 * q.y * q.y - q.x * p0.x + q.x * p2.x -
q.y * p0.y + q.y * p2.y) /
(q.x * q.x + q.y * q.y);
dp = -p0 + p2 + 2 * q - 4 * t * q; // First derivate of the curve
@ -286,7 +287,7 @@ static void findMaxCurvPoints(TStroke *stroke, const float &angoloLim,
if (estremo_sx >= estremo_dx)
t_ext = 0;
else
t_ext = 1;
t_ext = 1;
double maxEstremi = std::max(estremo_dx, estremo_sx);
if (maxEstremi > estremo_int) {
t = t_ext;
@ -600,9 +601,9 @@ public:
//=========================================================================================================
double computeThickness(double pressure, const TDoublePairProperty &property) {
double t = pressure * pressure * pressure;
double thick0 = property.getValue().first;
double thick1 = property.getValue().second;
double t = pressure * pressure * pressure;
double thick0 = property.getValue().first;
double thick1 = property.getValue().second;
if (thick1 < 0.0001) thick0 = thick1 = 0.0;
return (thick0 + (thick1 - thick0) * t) * 0.5;
}
@ -821,7 +822,7 @@ void SmoothStroke::generatePoints() {
ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType)
: TTool(name)
, m_rasThickness("Size", 1, 100, 1, 5)
, m_rasThickness("Size", 1, 1000, 1, 5)
, m_smooth("Smooth:", 0, 50, 0)
, m_hardness("Hardness:", 0, 100, 100)
, m_preset("Preset:")
@ -842,6 +843,8 @@ ToonzRasterBrushTool::ToonzRasterBrushTool(std::string name, int targetType)
, m_notifier(0) {
bind(targetType);
m_rasThickness.setNonLinearSlider();
m_prop[0].bind(m_rasThickness);
m_prop[0].bind(m_hardness);
m_prop[0].bind(m_smooth);
@ -1244,7 +1247,7 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos,
: maxThick;
/*--- ストロークの最初にMaxサイズの円が描かれてしまう不具合を防止する
* ---*/
* ---*/
if (m_pressure.getValue() && e.m_pressure == 1.0)
thickness = m_rasThickness.getValue().first;
@ -1305,7 +1308,7 @@ void ToonzRasterBrushTool::leftButtonDown(const TPointD &pos,
TRectD(m_brushPos - thickOffset, m_brushPos + thickOffset);
} else if (m_hardness.getValue() == 100 || m_pencil.getValue()) {
/*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる
* --*/
* --*/
if (!m_pencil.getValue()) thickness -= 1.0;
TThickPoint thickPoint(centeredPos + convert(ras->getCenter()),
@ -1408,7 +1411,7 @@ void ToonzRasterBrushTool::leftButtonDrag(const TPointD &pos,
} else if (m_rasterTrack &&
(m_hardness.getValue() == 100 || m_pencil.getValue())) {
/*-- Pencilモードでなく、Hardness=100 の場合のブラシサイズを1段階下げる
* --*/
* --*/
if (!m_pencil.getValue()) thickness -= 1.0;
TThickPoint thickPoint(centeredPos + rasCenter, thickness);
@ -1518,7 +1521,7 @@ void ToonzRasterBrushTool::leftButtonUp(const TPointD &pos,
//---------------------------------------------------------------------------------------------------------------
/*!
* onDeactivate時とMouseRelease時にと同じ終了処理を行う
*/
*/
void ToonzRasterBrushTool::finishRasterBrush(const TPointD &pos,
double pressureVal) {
TToonzImageP ti = TImageP(getImage(true));
@ -2096,7 +2099,7 @@ void ToonzRasterBrushTool::loadLastBrush() {
//------------------------------------------------------------------
/*! Brush、PaintBrush、EraserToolがPencilModeのときにTrueを返す
*/
*/
bool ToonzRasterBrushTool::isPencilModeActive() {
return getTargetType() == TTool::ToonzImage && m_pencil.getValue();
}

View file

@ -273,8 +273,9 @@ static void findMaxCurvPoints(TStroke *stroke, const float &angoloLim,
double estremo_int = 0;
double t = -1;
if (q != TPointD(0, 0)) {
t = 0.25 * (2 * q.x * q.x + 2 * q.y * q.y - q.x * p0.x + q.x * p2.x -
q.y * p0.y + q.y * p2.y) /
t = 0.25 *
(2 * q.x * q.x + 2 * q.y * q.y - q.x * p0.x + q.x * p2.x -
q.y * p0.y + q.y * p2.y) /
(q.x * q.x + q.y * q.y);
dp = -p0 + p2 + 2 * q - 4 * t * q; // First derivate of the curve
@ -308,7 +309,7 @@ static void findMaxCurvPoints(TStroke *stroke, const float &angoloLim,
if (estremo_sx >= estremo_dx)
t_ext = 0;
else
t_ext = 1;
t_ext = 1;
double maxEstremi = std::max(estremo_dx, estremo_sx);
if (maxEstremi > estremo_int) {
t = t_ext;
@ -454,9 +455,9 @@ void getAboveStyleIdSet(int styleId, TPaletteP palette,
double computeThickness(double pressure, const TDoublePairProperty &property,
bool isPath) {
if (isPath) return 0.0;
double t = pressure * pressure * pressure;
double thick0 = property.getValue().first;
double thick1 = property.getValue().second;
double t = pressure * pressure * pressure;
double thick0 = property.getValue().first;
double thick1 = property.getValue().second;
if (thick1 < 0.0001) thick0 = thick1 = 0.0;
return (thick0 + (thick1 - thick0) * t) * 0.5;
}
@ -471,7 +472,7 @@ double computeThickness(double pressure, const TDoublePairProperty &property,
ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType)
: TTool(name)
, m_thickness("Size", 0, 100, 0, 5)
, m_thickness("Size", 0, 1000, 0, 5)
, m_accuracy("Accuracy:", 1, 100, 20)
, m_smooth("Smooth:", 0, 50, 0)
, m_preset("Preset:")
@ -496,6 +497,9 @@ ToonzVectorBrushTool::ToonzVectorBrushTool(std::string name, int targetType)
, m_targetType(targetType)
, m_workingFrameId(TFrameId()) {
bind(targetType);
m_thickness.setNonLinearSlider();
m_prop[0].bind(m_thickness);
m_prop[0].bind(m_accuracy);
m_prop[0].bind(m_smooth);
@ -607,8 +611,8 @@ void ToonzVectorBrushTool::onActivate() {
void ToonzVectorBrushTool::onDeactivate() {
/*---
* onDeactivateにもMouseReleaseと同じ処理を行う
* ---*/
* onDeactivateにもMouseReleaseと同じ処理を行う
* ---*/
// End current stroke.
if (m_active && m_enabled) {
@ -684,7 +688,7 @@ void ToonzVectorBrushTool::leftButtonDown(const TPointD &pos,
/*--- ストロークの最初にMaxサイズの円が描かれてしまう不具合を防止する ---*/
if (m_pressure.getValue() && e.m_pressure == 1.0)
thickness = m_thickness.getValue().first * 0.5;
thickness = m_thickness.getValue().first * 0.5;
m_currThickness = thickness;
m_smoothStroke.beginStroke(m_smooth.getValue());
@ -1183,7 +1187,7 @@ void ToonzVectorBrushTool::checkStrokeSnapping(bool beforeMousePress,
if (Preferences::instance()->getVectorSnappingTarget() == 1) return;
TVectorImageP vi(getImage(false));
bool checkSnap = m_snap.getValue();
bool checkSnap = m_snap.getValue();
if (invertCheck) checkSnap = !checkSnap;
if (vi && checkSnap) {
m_dragDraw = true;
@ -1233,8 +1237,8 @@ void ToonzVectorBrushTool::checkStrokeSnapping(bool beforeMousePress,
}
}
if (snapFound) {
m_lastSnapPoint = TPointD(point1.x, point1.y);
m_foundLastSnap = true;
m_lastSnapPoint = TPointD(point1.x, point1.y);
m_foundLastSnap = true;
if (distance2 < 2.0) m_dragDraw = false;
}
}
@ -1251,7 +1255,7 @@ void ToonzVectorBrushTool::checkGuideSnapping(bool beforeMousePress,
beforeMousePress ? foundSnap = m_foundFirstSnap : foundSnap = m_foundLastSnap;
beforeMousePress ? snapPoint = m_firstSnapPoint : snapPoint = m_lastSnapPoint;
bool checkSnap = m_snap.getValue();
bool checkSnap = m_snap.getValue();
if (invertCheck) checkSnap = !checkSnap;
if (checkSnap) {
@ -1314,8 +1318,8 @@ void ToonzVectorBrushTool::checkGuideSnapping(bool beforeMousePress,
snapPoint.x = hGuide;
}
beforeMousePress ? m_foundFirstSnap = true : m_foundLastSnap = true;
beforeMousePress ? m_firstSnapPoint = snapPoint : m_lastSnapPoint =
snapPoint;
beforeMousePress ? m_firstSnapPoint = snapPoint
: m_lastSnapPoint = snapPoint;
}
}
}
@ -1638,7 +1642,7 @@ void ToonzVectorBrushTool::loadLastBrush() {
//------------------------------------------------------------------
/*! Brush、PaintBrush、EraserToolがPencilModeのときにTrueを返す
*/
*/
bool ToonzVectorBrushTool::isPencilModeActive() { return false; }
//==========================================================================================================

View file

@ -65,7 +65,7 @@ void mapToVector(const std::map<int, VIStroke *> &theMap,
std::vector<int> &theVect) {
assert(theMap.size() == theVect.size());
std::map<int, VIStroke *>::const_iterator it = theMap.begin();
UINT i = 0;
UINT i = 0;
for (; it != theMap.end(); ++it) {
theVect[i++] = it->first;
}
@ -146,7 +146,7 @@ public:
image->removeStrokes(newStrokeIndex, true, false);
std::map<int, VIStroke *>::const_iterator it = m_originalStrokes.begin();
UINT i = 0;
UINT i = 0;
VIStroke *s;
for (; it != m_originalStrokes.end(); ++it) {
s = cloneVIStroke(it->second);
@ -200,7 +200,7 @@ public:
image->removeStrokes(oldStrokeIndex, true, false);
std::map<int, VIStroke *>::const_iterator it = m_newStrokes.begin();
UINT i = 0;
UINT i = 0;
VIStroke *s;
for (; it != m_newStrokes.end(); ++it) {
s = cloneVIStroke(it->second);
@ -357,11 +357,11 @@ private:
EraserTool::EraserTool()
: TTool("T_Eraser")
, m_eraseType("Type:") // "W_ToolOptions_Erasetype"
, m_toolSize("Size:", 1, 100, 10) // "W_ToolOptions_EraserToolSize"
, m_selective("Selective", false) // "W_ToolOptions_Selective"
, m_invertOption("Invert", false) // "W_ToolOptions_Invert"
, m_multi("Frame Range", false) // "W_ToolOptions_FrameRange"
, m_eraseType("Type:") // "W_ToolOptions_Erasetype"
, m_toolSize("Size:", 1, 1000, 10) // "W_ToolOptions_EraserToolSize"
, m_selective("Selective", false) // "W_ToolOptions_Selective"
, m_invertOption("Invert", false) // "W_ToolOptions_Invert"
, m_multi("Frame Range", false) // "W_ToolOptions_FrameRange"
, m_pointSize(-1)
, m_undo(0)
, m_currCell(-1, -1)
@ -371,6 +371,8 @@ EraserTool::EraserTool()
, m_firstTime(true) {
bind(TTool::VectorImage);
m_toolSize.setNonLinearSlider();
m_prop.bind(m_toolSize);
m_prop.bind(m_eraseType);
m_eraseType.addValue(NORMAL_ERASE);
@ -1380,7 +1382,7 @@ void EraserTool::multiEreserRegion(TStroke *stroke, const TMouseEvent &e) {
//-----------------------------------------------------------------------------
/*! When the tool is switched during dragging, Erase end processing is performed
*/
*/
void EraserTool::onDeactivate() {
if (!m_active) return;

View file

@ -112,11 +112,11 @@ DoubleValueField::DoubleValueField(QWidget *parent,
bool ret = true;
ret = ret && connect(m_lineEdit, SIGNAL(valueChanged()),
SLOT(onLineEditValueChanged()));
ret = ret && connect(m_roller, SIGNAL(valueChanged(bool)),
ret = ret && connect(m_roller, SIGNAL(valueChanged(bool)),
SLOT(onRollerValueChanged(bool)));
ret = ret && connect(m_slider, SIGNAL(valueChanged(int)),
ret = ret && connect(m_slider, SIGNAL(valueChanged(int)),
SLOT(onSliderChanged(int)));
ret = ret &&
ret = ret &&
connect(m_slider, SIGNAL(sliderReleased()), SLOT(onSliderReleased()));
ret = ret && connect(m_lineEdit, SIGNAL(editingFinished()), this,
SIGNAL(valueEditedByHand()));
@ -133,6 +133,50 @@ DoubleValueField::DoubleValueField(QWidget *parent,
//-----------------------------------------------------------------------------
double DoubleValueField::pos2value(int x) const {
int dicimal = m_lineEdit->getDecimals();
if (m_isLinearSlider) return (double)x * pow(0.1, dicimal);
// nonlinear slider case
double rangeSize = (double)(m_slider->maximum() - m_slider->minimum());
double posRatio = (double)(x - m_slider->minimum()) / rangeSize;
double t;
if (posRatio <= 0.5)
t = 0.04 * posRatio;
else if (posRatio <= 0.75)
t = -0.02 + 0.08 * posRatio;
else if (posRatio <= 0.9)
t = -0.26 + 0.4 * posRatio;
else
t = -8.0 + 9.0 * posRatio;
double sliderValue = round((double)m_slider->minimum() + rangeSize * t);
return sliderValue * pow(0.1, dicimal);
}
//-----------------------------------------------------------------------------
int DoubleValueField::value2pos(double v) const {
int dicimal = m_lineEdit->getDecimals();
double sliderValue = round(v * pow(10., dicimal));
if (m_isLinearSlider) return (int)sliderValue;
// nonlinear slider case
double rangeSize = (double)(m_slider->maximum() - m_slider->minimum());
double valueRatio = (sliderValue - (double)m_slider->minimum()) / rangeSize;
double t;
if (valueRatio <= 0.02)
t = valueRatio / 0.04;
else if (valueRatio <= 0.04)
t = (valueRatio + 0.02) / 0.08;
else if (valueRatio <= 0.1)
t = (valueRatio + 0.26) / 0.4;
else
t = (valueRatio + 8.0) / 9.0;
return m_slider->minimum() + (int)(t * rangeSize);
}
//-----------------------------------------------------------------------------
void DoubleValueField::getRange(double &minValue, double &maxValue) {
m_lineEdit->getRange(minValue, maxValue);
}
@ -159,11 +203,7 @@ void DoubleValueField::setValue(double value) {
if (m_lineEdit->getValue() == value) return;
m_lineEdit->setValue(value);
m_roller->setValue(value);
int dicimal = m_lineEdit->getDecimals();
int sliderValue = (int)round(value * pow(10., dicimal));
m_slider->setValue(sliderValue);
m_slider->setValue(value2pos(value));
// forzo il repaint... non sempre si aggiorna e l'update non sembra risolvere
// il ptroblema!!!
m_slider->repaint();
@ -215,9 +255,8 @@ bool DoubleValueField::isRollerEnabled() { return m_roller->isEnabled(); }
//-----------------------------------------------------------------------------
void DoubleValueField::onSliderChanged(int value) {
int dicimal = m_lineEdit->getDecimals();
double val = double(value) * pow(0.1, dicimal);
void DoubleValueField::onSliderChanged(int sliderPos) {
double val = pos2value(sliderPos);
// Controllo necessario per evitare che il segnale di cambiamento venga emesso
// piu' volte.
@ -237,16 +276,15 @@ void DoubleValueField::onSliderChanged(int value) {
//-----------------------------------------------------------------------------
void DoubleValueField::onLineEditValueChanged() {
double value = m_lineEdit->getValue();
int dicimal = m_lineEdit->getDecimals();
int sliderValue = (int)round(value * pow(10., dicimal));
double value = m_lineEdit->getValue();
int dicimal = m_lineEdit->getDecimals();
// Control necessary to prevent the change signal from being emitted more than
// once.
if ((m_slider->value() == sliderValue && m_slider->isVisible()) ||
if ((pos2value(m_slider->value()) == value && m_slider->isVisible()) ||
(m_roller->getValue() == value && m_roller->isVisible()))
return;
m_slider->setValue(sliderValue);
m_slider->setValue(value2pos(value));
m_roller->setValue(value);
emit valueChanged(false);
}
@ -256,17 +294,14 @@ void DoubleValueField::onLineEditValueChanged() {
void DoubleValueField::onRollerValueChanged(bool isDragging) {
double value = m_roller->getValue();
int dicimal = m_lineEdit->getDecimals();
double sliderValue = value * pow(10., dicimal);
if (sliderValue == m_lineEdit->getValue()) {
assert(m_slider->value() == value || !m_slider->isVisible());
if (value == m_lineEdit->getValue()) {
assert(pos2value(m_slider->value()) == value || !m_slider->isVisible());
// Se isDragging e' falso e' giusto che venga emessa la notifica di
// cambiamento.
if (!isDragging) emit valueChanged(isDragging);
return;
}
m_slider->setValue(sliderValue);
m_slider->setValue(value2pos(value));
m_lineEdit->setValue(value);
// Faccio in modo che il cursore sia sulla prima cifra, cosi' se la stringa

View file

@ -68,7 +68,7 @@ DoubleValuePairField::DoubleValuePairField(QWidget *parent,
//---- signal-slot connections
bool ret = connect(m_leftLineEdit, SIGNAL(editingFinished()),
SLOT(onLeftEditingFinished()));
ret = ret && connect(m_rightLineEdit, SIGNAL(editingFinished()),
ret = ret && connect(m_rightLineEdit, SIGNAL(editingFinished()),
SLOT(onRightEditingFinished()));
assert(ret);
}
@ -76,16 +76,45 @@ DoubleValuePairField::DoubleValuePairField(QWidget *parent,
//-----------------------------------------------------------------------------
double DoubleValuePairField::pos2value(int x) const {
int xMin = m_leftMargin, xMax = width() - m_rightMargin;
return m_minValue + (m_maxValue - m_minValue) * (x - xMin) / (xMax - xMin);
int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1;
if (m_isLinear)
return m_minValue + (m_maxValue - m_minValue) * (x - xMin) / (xMax - xMin);
// nonlinear slider case
double posRatio = (double)(x - xMin) / (double)(xMax - xMin);
double t;
if (posRatio <= 0.5)
t = 0.04 * posRatio;
else if (posRatio <= 0.75)
t = -0.02 + 0.08 * posRatio;
else if (posRatio <= 0.9)
t = -0.26 + 0.4 * posRatio;
else
t = -8.0 + 9.0 * posRatio;
return m_minValue + (m_maxValue - m_minValue) * t;
}
//-----------------------------------------------------------------------------
int DoubleValuePairField::value2pos(double v) const {
int xMin = m_leftMargin, xMax = width() - m_rightMargin;
return xMin +
(int)(((xMax - xMin) * (v - m_minValue)) / (m_maxValue - m_minValue));
int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1;
if (m_isLinear)
return xMin + (int)(((xMax - xMin) * (v - m_minValue)) /
(m_maxValue - m_minValue));
// nonlinear slider case
double valueRatio =
(v - (double)m_minValue) / (double)(m_maxValue - m_minValue);
double t;
if (valueRatio <= 0.02)
t = valueRatio / 0.04;
else if (valueRatio <= 0.04)
t = (valueRatio + 0.02) / 0.08;
else if (valueRatio <= 0.1)
t = (valueRatio + 0.26) / 0.4;
else
t = (valueRatio + 8.0) / 9.0;
return xMin + (int)(t * (double)(xMax - xMin));
}
//-----------------------------------------------------------------------------
@ -266,7 +295,7 @@ void DoubleValuePairField::mousePressEvent(QMouseEvent *event) {
void DoubleValuePairField::mouseMoveEvent(QMouseEvent *event) {
if (event->buttons()) {
std::pair<double, double> oldValues = m_values;
int x = event->pos().x() + m_grabOffset;
int x = event->pos().x() + m_grabOffset;
setValue(pos2value(x));
if (oldValues != m_values) {
emit valuesChanged(true);
@ -291,7 +320,7 @@ void DoubleValuePairField::onLeftEditingFinished() {
if (!m_isMaxRangeLimited && value < m_minValue)
value = m_minValue;
else if (m_isMaxRangeLimited)
value = tcrop(value, m_minValue, m_maxValue);
value = tcrop(value, m_minValue, m_maxValue);
m_values.first = value;
if (m_values.first > m_values.second) {
m_values.second = m_values.first;
@ -307,7 +336,7 @@ void DoubleValuePairField::onRightEditingFinished() {
double value = m_rightLineEdit->getValue();
if (value == m_values.second) return;
if (m_isMaxRangeLimited) value = tcrop(value, m_minValue, m_maxValue);
m_values.second = value;
m_values.second = value;
if (m_values.second < m_values.first) {
m_values.first = m_values.second;
m_leftLineEdit->setValue(m_values.first);

View file

@ -11,6 +11,10 @@
#include <QFocusEvent>
#include <QPainter>
namespace {
const int NonLinearSliderPrecision = 2;
}
using namespace DVGui;
//=============================================================================
@ -250,7 +254,8 @@ IntField::IntField(QWidget *parent, bool isMaxRangeLimited, bool isRollerHide)
, m_lineEdit(0)
, m_slider(0)
, m_roller(0)
, m_isMaxRangeLimited(isMaxRangeLimited) {
, m_isMaxRangeLimited(isMaxRangeLimited)
, m_isLinearSlider(true) {
setObjectName("IntField");
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setMargin(0);
@ -279,7 +284,7 @@ IntField::IntField(QWidget *parent, bool isMaxRangeLimited, bool isRollerHide)
m_slider = new QSlider(Qt::Horizontal, this);
ret = ret && connect(m_slider, SIGNAL(valueChanged(int)), this,
SLOT(onSliderChanged(int)));
ret = ret && connect(m_slider, SIGNAL(sliderReleased()), this,
ret = ret && connect(m_slider, SIGNAL(sliderReleased()), this,
SLOT(onSliderReleased()));
ret = ret && connect(m_lineEdit, SIGNAL(editingFinished()), this,
@ -309,7 +314,11 @@ void IntField::setRange(int minValue, int maxValue) {
m_lineEdit->setRange(minValue, m_isMaxRangeLimited
? maxValue
: (std::numeric_limits<int>::max)());
m_slider->setRange(minValue, maxValue);
if (m_isLinearSlider)
m_slider->setRange(minValue, maxValue);
else
m_slider->setRange(minValue * pow(10., NonLinearSliderPrecision),
maxValue * pow(10., NonLinearSliderPrecision));
m_roller->setRange(minValue, maxValue);
}
@ -318,7 +327,7 @@ void IntField::setRange(int minValue, int maxValue) {
void IntField::setValue(int value) {
if (m_lineEdit->getValue() == value) return;
m_lineEdit->setValue(value);
m_slider->setSliderPosition(value);
m_slider->setSliderPosition(value2pos(value));
m_roller->setValue((double)value);
}
@ -369,7 +378,50 @@ void IntField::setLineEditBackgroundColor(QColor color) {
//-----------------------------------------------------------------------------
void IntField::onSliderChanged(int value) {
int IntField::pos2value(int x) const {
if (m_isLinearSlider) return x;
// nonlinear slider case
double rangeSize = (double)(m_slider->maximum() - m_slider->minimum());
double posRatio = (double)(x - m_slider->minimum()) / rangeSize;
double t;
if (posRatio <= 0.5)
t = 0.04 * posRatio;
else if (posRatio <= 0.75)
t = -0.02 + 0.08 * posRatio;
else if (posRatio <= 0.9)
t = -0.26 + 0.4 * posRatio;
else
t = -8.0 + 9.0 * posRatio;
double sliderVal = (double)m_slider->minimum() + rangeSize * t;
return (int)round(sliderVal * pow(0.1, NonLinearSliderPrecision));
}
//-----------------------------------------------------------------------------
int IntField::value2pos(int v) const {
if (m_isLinearSlider) return v;
// nonlinear slider case
double sliderVal = (double)v * pow(10., NonLinearSliderPrecision);
double rangeSize = (double)(m_slider->maximum() - m_slider->minimum());
double valueRatio = (double)(sliderVal - m_slider->minimum()) / rangeSize;
double t;
if (valueRatio <= 0.02)
t = valueRatio / 0.04;
else if (valueRatio <= 0.04)
t = (valueRatio + 0.02) / 0.08;
else if (valueRatio <= 0.1)
t = (valueRatio + 0.26) / 0.4;
else
t = (valueRatio + 8.0) / 9.0;
return m_slider->minimum() + (int)(t * rangeSize);
}
//-----------------------------------------------------------------------------
void IntField::onSliderChanged(int sliderPos) {
int value = pos2value(sliderPos);
// Controllo necessario per evitare che il segnale di cambiamento venga emesso
// piu' volte.
if (m_lineEdit->getValue() == value ||
@ -390,10 +442,10 @@ void IntField::onEditingFinished() {
double value = m_lineEdit->getValue();
// Controllo necessario per evitare che il segnale di cambiamento venga emesso
// piu' volte.
if ((m_slider->value() == value && m_slider->isVisible()) ||
if ((pos2value(m_slider->value()) == value && m_slider->isVisible()) ||
(int)m_roller->getValue() == value && m_roller->isVisible())
return;
m_slider->setValue(value);
m_slider->setValue(value2pos(value));
m_roller->setValue((double)value);
emit valueChanged(false);
}
@ -403,13 +455,13 @@ void IntField::onEditingFinished() {
void IntField::onRollerValueChanged(bool isDragging) {
int value = m_roller->getValue();
if (value == m_lineEdit->getValue()) {
assert(m_slider->value() == value || !m_slider->isVisible());
assert(pos2value(m_slider->value()) == value || !m_slider->isVisible());
// Se isDragging e' falso e' giusto che venga emessa la notifica di
// cambiamento.
if (!isDragging) emit valueChanged(isDragging);
return;
}
m_slider->setValue(value);
m_slider->setValue(value2pos(value));
m_lineEdit->setValue(value);
// Faccio in modo che il cursore sia sulla prima cifra, cosi' se la stringa

View file

@ -33,7 +33,8 @@ IntPairField::IntPairField(QWidget *parent, bool isMaxRangeLimited)
, m_grabIndex(-1)
, m_leftMargin(52)
, m_rightMargin(52)
, m_isMaxRangeLimited(isMaxRangeLimited) {
, m_isMaxRangeLimited(isMaxRangeLimited)
, m_isLinear(true) {
setObjectName("IntPairField");
setFixedHeight(WidgetHeight);
@ -63,7 +64,7 @@ IntPairField::IntPairField(QWidget *parent, bool isMaxRangeLimited)
//---signal-slot connections
bool ret = connect(m_leftLineEdit, SIGNAL(editingFinished()),
SLOT(onLeftEditingFinished()));
ret = ret && connect(m_rightLineEdit, SIGNAL(editingFinished()),
ret = ret && connect(m_rightLineEdit, SIGNAL(editingFinished()),
SLOT(onRightEditingFinished()));
assert(ret);
@ -71,17 +72,46 @@ IntPairField::IntPairField(QWidget *parent, bool isMaxRangeLimited)
//-----------------------------------------------------------------------------
double IntPairField::pos2value(int x) const {
int IntPairField::pos2value(int x) const {
int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1;
return m_minValue + (m_maxValue - m_minValue) * (x - xMin) / (xMax - xMin);
if (m_isLinear)
return m_minValue + (m_maxValue - m_minValue) * (x - xMin) / (xMax - xMin);
// nonlinear slider case
double posRatio = (double)(x - xMin) / (double)(xMax - xMin);
double t;
if (posRatio <= 0.5)
t = 0.04 * posRatio;
else if (posRatio <= 0.75)
t = -0.02 + 0.08 * posRatio;
else if (posRatio <= 0.9)
t = -0.26 + 0.4 * posRatio;
else
t = -8.0 + 9.0 * posRatio;
return m_minValue + (int)((double)(m_maxValue - m_minValue) * t);
}
//-----------------------------------------------------------------------------
int IntPairField::value2pos(double v) const {
int IntPairField::value2pos(int v) const {
int xMin = m_leftMargin, xMax = width() - m_rightMargin - 1;
return xMin +
(int)(((xMax - xMin) * (v - m_minValue)) / (m_maxValue - m_minValue));
if (m_isLinear)
return xMin +
((xMax - xMin) * (v - m_minValue)) / (m_maxValue - m_minValue);
// nonlinear slider case
double valueRatio =
(double)(v - m_minValue) / (double)(m_maxValue - m_minValue);
double t;
if (valueRatio <= 0.02)
t = valueRatio / 0.04;
else if (valueRatio <= 0.04)
t = (valueRatio + 0.02) / 0.08;
else if (valueRatio <= 0.1)
t = (valueRatio + 0.26) / 0.4;
else
t = (valueRatio + 8.0) / 9.0;
return xMin + (int)(t * (double)(xMax - xMin));
}
//-----------------------------------------------------------------------------
@ -258,7 +288,7 @@ void IntPairField::mousePressEvent(QMouseEvent *event) {
void IntPairField::mouseMoveEvent(QMouseEvent *event) {
if (event->buttons()) {
std::pair<int, int> oldValues = m_values;
int x = event->pos().x() + m_grabOffset;
int x = event->pos().x() + m_grabOffset;
setValue(pos2value(x));
if (oldValues == m_values) return;
@ -283,7 +313,7 @@ void IntPairField::onLeftEditingFinished() {
if (!m_isMaxRangeLimited && value < m_minValue)
value = m_minValue;
else if (m_isMaxRangeLimited)
value = tcrop(value, m_minValue, m_maxValue);
value = tcrop(value, m_minValue, m_maxValue);
m_values.first = value;
if (m_values.first > m_values.second) {
m_values.second = m_values.first;
@ -299,7 +329,7 @@ void IntPairField::onRightEditingFinished() {
int value = m_rightLineEdit->getValue();
if (value == m_values.second) return;
if (m_isMaxRangeLimited) value = tcrop(value, m_minValue, m_maxValue);
m_values.second = value;
m_values.second = value;
if (m_values.second < m_values.first) {
m_values.first = m_values.second;
m_leftLineEdit->setValue(m_values.first);