Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer
This commit is contained in:
commit
53d1ff879c
5 changed files with 222 additions and 104 deletions
|
@ -18,7 +18,7 @@ AllowShortLoopsOnASingleLine: true
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
AlwaysBreakAfterReturnType: None
|
AlwaysBreakAfterReturnType: None
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
AlwaysBreakTemplateDeclarations: Yes
|
AlwaysBreakTemplateDeclarations: false
|
||||||
BinPackArguments: false
|
BinPackArguments: false
|
||||||
BinPackParameters: false
|
BinPackParameters: false
|
||||||
BraceWrapping:
|
BraceWrapping:
|
||||||
|
@ -37,18 +37,18 @@ BraceWrapping:
|
||||||
SplitEmptyFunction: false
|
SplitEmptyFunction: false
|
||||||
SplitEmptyRecord: false
|
SplitEmptyRecord: false
|
||||||
SplitEmptyNamespace: false
|
SplitEmptyNamespace: false
|
||||||
BreakBeforeBinaryOperators: All
|
BreakBeforeBinaryOperators: None
|
||||||
BreakBeforeBraces: Custom
|
BreakBeforeBraces: Custom
|
||||||
BreakBeforeInheritanceComma: false
|
BreakBeforeInheritanceComma: false
|
||||||
BreakInheritanceList: BeforeColon
|
BreakInheritanceList: BeforeColon
|
||||||
BreakBeforeTernaryOperators: true
|
BreakBeforeTernaryOperators: false
|
||||||
BreakConstructorInitializersBeforeComma: false
|
BreakConstructorInitializersBeforeComma: false
|
||||||
BreakConstructorInitializers: BeforeComma
|
BreakConstructorInitializers: BeforeComma
|
||||||
BreakAfterJavaFieldAnnotations: false
|
BreakAfterJavaFieldAnnotations: false
|
||||||
BreakStringLiterals: true
|
BreakStringLiterals: true
|
||||||
ColumnLimit: 75
|
ColumnLimit: 75
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
CompactNamespaces: false
|
CompactNamespaces: true
|
||||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
ConstructorInitializerIndentWidth: 4
|
ConstructorInitializerIndentWidth: 4
|
||||||
ContinuationIndentWidth: 4
|
ContinuationIndentWidth: 4
|
||||||
|
|
|
@ -1,172 +1,218 @@
|
||||||
#ifndef MTUTILS_HPP
|
#ifndef MTUTILS_HPP
|
||||||
#define MTUTILS_HPP
|
#define MTUTILS_HPP
|
||||||
|
|
||||||
#include <atomic> // for std::atomic_flag and memory orders
|
#include <atomic> // for std::atomic_flag and memory orders
|
||||||
#include <mutex> // for std::lock_guard
|
#include <mutex> // for std::lock_guard
|
||||||
#include <functional> // for std::function
|
#include <functional> // for std::function
|
||||||
#include <utility> // for std::forward
|
#include <utility> // for std::forward
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
/// Handy little spin mutex for the cached meshes.
|
/// Handy little spin mutex for the cached meshes.
|
||||||
/// Implements the "Lockable" concept
|
/// Implements the "Lockable" concept
|
||||||
class SpinMutex {
|
class SpinMutex
|
||||||
std::atomic_flag m_flg;
|
{
|
||||||
|
std::atomic_flag m_flg;
|
||||||
static const /*constexpr*/ auto MO_ACQ = std::memory_order_acquire;
|
static const /*constexpr*/ auto MO_ACQ = std::memory_order_acquire;
|
||||||
static const /*constexpr*/ auto MO_REL = std::memory_order_release;
|
static const /*constexpr*/ auto MO_REL = std::memory_order_release;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
inline SpinMutex() { m_flg.clear(MO_REL); }
|
inline SpinMutex() { m_flg.clear(MO_REL); }
|
||||||
inline void lock() { while(m_flg.test_and_set(MO_ACQ)); }
|
inline void lock() { while (m_flg.test_and_set(MO_ACQ)) ; }
|
||||||
inline bool try_lock() { return !m_flg.test_and_set(MO_ACQ); }
|
inline bool try_lock() { return !m_flg.test_and_set(MO_ACQ); }
|
||||||
inline void unlock() { m_flg.clear(MO_REL); }
|
inline void unlock() { m_flg.clear(MO_REL); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A wrapper class around arbitrary object that needs thread safe caching.
|
/// A wrapper class around arbitrary object that needs thread safe caching.
|
||||||
template<class T> class CachedObject {
|
template<class T> class CachedObject
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
// Method type which refreshes the object when it has been invalidated
|
// Method type which refreshes the object when it has been invalidated
|
||||||
using Setter = std::function<void(T&)>;
|
using Setter = std::function<void(T &)>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T m_obj; // the object itself
|
T m_obj; // the object itself
|
||||||
bool m_valid; // invalidation flag
|
bool m_valid; // invalidation flag
|
||||||
SpinMutex m_lck; // to make the caching thread safe
|
SpinMutex m_lck; // to make the caching thread safe
|
||||||
|
|
||||||
|
// the setter will be called just before the object's const value is
|
||||||
|
// about to be retrieved.
|
||||||
|
std::function<void(T &)> m_setter;
|
||||||
|
|
||||||
// the setter will be called just before the object's const value is about
|
|
||||||
// to be retrieved.
|
|
||||||
std::function<void(T&)> m_setter;
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// Forwarded constructor
|
// Forwarded constructor
|
||||||
template<class...Args> inline CachedObject(Setter fn, Args&&...args):
|
template<class... Args>
|
||||||
m_obj(std::forward<Args>(args)...), m_valid(false), m_setter(fn) {}
|
inline CachedObject(Setter fn, Args &&... args)
|
||||||
|
: m_obj(std::forward<Args>(args)...), m_valid(false), m_setter(fn)
|
||||||
|
{}
|
||||||
|
|
||||||
// invalidate the value of the object. The object will be refreshed at the
|
// invalidate the value of the object. The object will be refreshed at
|
||||||
// next retrieval (Setter will be called). The data that is used in
|
// the next retrieval (Setter will be called). The data that is used in
|
||||||
// the setter function should be guarded as well during modification so the
|
// the setter function should be guarded as well during modification so
|
||||||
// modification has to take place in fn.
|
// the modification has to take place in fn.
|
||||||
inline void invalidate(std::function<void()> fn) {
|
inline void invalidate(std::function<void()> fn)
|
||||||
std::lock_guard<SpinMutex> lck(m_lck); fn(); m_valid = false;
|
{
|
||||||
|
std::lock_guard<SpinMutex> lck(m_lck);
|
||||||
|
fn();
|
||||||
|
m_valid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the const object properly updated.
|
// Get the const object properly updated.
|
||||||
inline const T& get() {
|
inline const T &get()
|
||||||
|
{
|
||||||
std::lock_guard<SpinMutex> lck(m_lck);
|
std::lock_guard<SpinMutex> lck(m_lck);
|
||||||
if(!m_valid) { m_setter(m_obj); m_valid = true; }
|
if (!m_valid) {
|
||||||
|
m_setter(m_obj);
|
||||||
|
m_valid = true;
|
||||||
|
}
|
||||||
return m_obj;
|
return m_obj;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An std compatible random access iterator which uses indices to the source
|
/// An std compatible random access iterator which uses indices to the
|
||||||
/// vector thus resistant to invalidation caused by relocations. It also "knows"
|
/// source vector thus resistant to invalidation caused by relocations. It
|
||||||
/// its container. No comparison is neccesary to the container "end()" iterator.
|
/// also "knows" its container. No comparison is neccesary to the container
|
||||||
/// The template can be instantiated with a different value type than that of
|
/// "end()" iterator. The template can be instantiated with a different
|
||||||
/// the container's but the types must be compatible. E.g. a base class of the
|
/// value type than that of the container's but the types must be
|
||||||
/// contained objects is compatible.
|
/// compatible. E.g. a base class of the contained objects is compatible.
|
||||||
///
|
///
|
||||||
/// For a constant iterator, one can instantiate this template with a value
|
/// For a constant iterator, one can instantiate this template with a value
|
||||||
/// type preceded with 'const'.
|
/// type preceded with 'const'.
|
||||||
template<class Vector, // The container type, must be random access...
|
template<class Vector, // The container type, must be random access...
|
||||||
class Value = typename Vector::value_type // The value type
|
class Value = typename Vector::value_type // The value type
|
||||||
>
|
>
|
||||||
class IndexBasedIterator {
|
class IndexBasedIterator
|
||||||
|
{
|
||||||
static const size_t NONE = size_t(-1);
|
static const size_t NONE = size_t(-1);
|
||||||
|
|
||||||
std::reference_wrapper<Vector> m_index_ref;
|
std::reference_wrapper<Vector> m_index_ref;
|
||||||
size_t m_idx = NONE;
|
size_t m_idx = NONE;
|
||||||
public:
|
|
||||||
|
|
||||||
using value_type = Value;
|
public:
|
||||||
using pointer = Value *;
|
using value_type = Value;
|
||||||
using reference = Value &;
|
using pointer = Value *;
|
||||||
using difference_type = long;
|
using reference = Value &;
|
||||||
|
using difference_type = long;
|
||||||
using iterator_category = std::random_access_iterator_tag;
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
|
||||||
inline explicit
|
inline explicit IndexBasedIterator(Vector &index, size_t idx)
|
||||||
IndexBasedIterator(Vector& index, size_t idx):
|
: m_index_ref(index), m_idx(idx)
|
||||||
m_index_ref(index), m_idx(idx) {}
|
{}
|
||||||
|
|
||||||
// Post increment
|
// Post increment
|
||||||
inline IndexBasedIterator operator++(int) {
|
inline IndexBasedIterator operator++(int)
|
||||||
IndexBasedIterator cpy(*this); ++m_idx; return cpy;
|
{
|
||||||
|
IndexBasedIterator cpy(*this);
|
||||||
|
++m_idx;
|
||||||
|
return cpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexBasedIterator operator--(int) {
|
inline IndexBasedIterator operator--(int)
|
||||||
IndexBasedIterator cpy(*this); --m_idx; return cpy;
|
{
|
||||||
|
IndexBasedIterator cpy(*this);
|
||||||
|
--m_idx;
|
||||||
|
return cpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexBasedIterator& operator++() {
|
inline IndexBasedIterator &operator++()
|
||||||
++m_idx; return *this;
|
{
|
||||||
|
++m_idx;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexBasedIterator& operator--() {
|
inline IndexBasedIterator &operator--()
|
||||||
--m_idx; return *this;
|
{
|
||||||
|
--m_idx;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexBasedIterator& operator+=(difference_type l) {
|
inline IndexBasedIterator &operator+=(difference_type l)
|
||||||
m_idx += size_t(l); return *this;
|
{
|
||||||
|
m_idx += size_t(l);
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexBasedIterator operator+(difference_type l) {
|
inline IndexBasedIterator operator+(difference_type l)
|
||||||
auto cpy = *this; cpy += l; return cpy;
|
{
|
||||||
|
auto cpy = *this;
|
||||||
|
cpy += l;
|
||||||
|
return cpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexBasedIterator& operator-=(difference_type l) {
|
inline IndexBasedIterator &operator-=(difference_type l)
|
||||||
m_idx -= size_t(l); return *this;
|
{
|
||||||
|
m_idx -= size_t(l);
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline IndexBasedIterator operator-(difference_type l) {
|
inline IndexBasedIterator operator-(difference_type l)
|
||||||
auto cpy = *this; cpy -= l; return cpy;
|
{
|
||||||
|
auto cpy = *this;
|
||||||
|
cpy -= l;
|
||||||
|
return cpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator difference_type() { return difference_type(m_idx); }
|
operator difference_type() { return difference_type(m_idx); }
|
||||||
|
|
||||||
/// Tesing the end of the container... this is not possible with std
|
/// Tesing the end of the container... this is not possible with std
|
||||||
/// iterators.
|
/// iterators.
|
||||||
inline bool is_end() const { return m_idx >= m_index_ref.get().size();}
|
inline bool is_end() const
|
||||||
|
{
|
||||||
|
return m_idx >= m_index_ref.get().size();
|
||||||
|
}
|
||||||
|
|
||||||
inline Value & operator*() const {
|
inline Value &operator*() const
|
||||||
|
{
|
||||||
assert(m_idx < m_index_ref.get().size());
|
assert(m_idx < m_index_ref.get().size());
|
||||||
return m_index_ref.get().operator[](m_idx);
|
return m_index_ref.get().operator[](m_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Value * operator->() const {
|
inline Value *operator->() const
|
||||||
|
{
|
||||||
assert(m_idx < m_index_ref.get().size());
|
assert(m_idx < m_index_ref.get().size());
|
||||||
return &m_index_ref.get().operator[](m_idx);
|
return &m_index_ref.get().operator[](m_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If both iterators point past the container, they are equal...
|
/// If both iterators point past the container, they are equal...
|
||||||
inline bool operator ==(const IndexBasedIterator& other) {
|
inline bool operator==(const IndexBasedIterator &other)
|
||||||
|
{
|
||||||
size_t e = m_index_ref.get().size();
|
size_t e = m_index_ref.get().size();
|
||||||
return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e);
|
return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator !=(const IndexBasedIterator& other) {
|
inline bool operator!=(const IndexBasedIterator &other)
|
||||||
|
{
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator <=(const IndexBasedIterator& other) {
|
inline bool operator<=(const IndexBasedIterator &other)
|
||||||
|
{
|
||||||
return (m_idx < other.m_idx) || (*this == other);
|
return (m_idx < other.m_idx) || (*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator <(const IndexBasedIterator& other) {
|
inline bool operator<(const IndexBasedIterator &other)
|
||||||
|
{
|
||||||
return m_idx < other.m_idx && (*this != other);
|
return m_idx < other.m_idx && (*this != other);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator >=(const IndexBasedIterator& other) {
|
inline bool operator>=(const IndexBasedIterator &other)
|
||||||
|
{
|
||||||
return m_idx > other.m_idx || *this == other;
|
return m_idx > other.m_idx || *this == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool operator >(const IndexBasedIterator& other) {
|
inline bool operator>(const IndexBasedIterator &other)
|
||||||
|
{
|
||||||
return m_idx > other.m_idx && *this != other;
|
return m_idx > other.m_idx && *this != other;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A very simple range concept implementation with iterator-like objects.
|
/// A very simple range concept implementation with iterator-like objects.
|
||||||
template<class It> class Range {
|
template<class It> class Range
|
||||||
|
{
|
||||||
It from, to;
|
It from, to;
|
||||||
public:
|
|
||||||
|
|
||||||
|
public:
|
||||||
// The class is ready for range based for loops.
|
// The class is ready for range based for loops.
|
||||||
It begin() const { return from; }
|
It begin() const { return from; }
|
||||||
It end() const { return to; }
|
It end() const { return to; }
|
||||||
|
@ -175,15 +221,17 @@ public:
|
||||||
using Type = It;
|
using Type = It;
|
||||||
|
|
||||||
Range() = default;
|
Range() = default;
|
||||||
Range(It &&b, It &&e):
|
Range(It &&b, It &&e)
|
||||||
from(std::forward<It>(b)), to(std::forward<It>(e)) {}
|
: from(std::forward<It>(b)), to(std::forward<It>(e))
|
||||||
|
{}
|
||||||
|
|
||||||
// Some useful container-like methods...
|
// Some useful container-like methods...
|
||||||
inline size_t size() const { return end() - begin(); }
|
inline size_t size() const { return end() - begin(); }
|
||||||
inline bool empty() const { return size() == 0; }
|
inline bool empty() const { return size() == 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class C> bool all_of(const C &container) {
|
template<class C> bool all_of(const C &container)
|
||||||
|
{
|
||||||
return std::all_of(container.begin(),
|
return std::all_of(container.begin(),
|
||||||
container.end(),
|
container.end(),
|
||||||
[](const typename C::value_type &v) {
|
[](const typename C::value_type &v) {
|
||||||
|
@ -191,6 +239,15 @@ template<class C> bool all_of(const C &container) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class X, class Y> inline X ceil_i(X x, Y y)
|
||||||
|
{
|
||||||
|
static_assert(std::is_integral<X>::value &&
|
||||||
|
std::is_integral<Y>::value && sizeof(X) >= sizeof(Y),
|
||||||
|
"");
|
||||||
|
|
||||||
|
return (x % y) ? x / y + 1 : x / y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Slic3r
|
||||||
|
|
||||||
#endif // MTUTILS_HPP
|
#endif // MTUTILS_HPP
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "Model.hpp"
|
#include "Model.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
#include "SVG.hpp"
|
#include "SVG.hpp"
|
||||||
|
#include "MTUtils.hpp"
|
||||||
|
|
||||||
#include <libnest2d.h>
|
#include <libnest2d.h>
|
||||||
|
|
||||||
|
@ -820,15 +821,13 @@ bool arrange(Model &model, // The model with the geometries
|
||||||
BoundingBox bbb(bed);
|
BoundingBox bbb(bed);
|
||||||
|
|
||||||
auto& cfn = stopcondition;
|
auto& cfn = stopcondition;
|
||||||
|
|
||||||
|
coord_t md = ceil_i(min_obj_distance, 2) - SCALED_EPSILON;
|
||||||
|
|
||||||
auto binbb = Box({
|
auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md,
|
||||||
static_cast<libnest2d::Coord>(bbb.min(0)),
|
libnest2d::Coord{bbb.min(1)} - md},
|
||||||
static_cast<libnest2d::Coord>(bbb.min(1))
|
{libnest2d::Coord{bbb.max(0)} + md,
|
||||||
},
|
libnest2d::Coord{bbb.max(1)} + md});
|
||||||
{
|
|
||||||
static_cast<libnest2d::Coord>(bbb.max(0)),
|
|
||||||
static_cast<libnest2d::Coord>(bbb.max(1))
|
|
||||||
});
|
|
||||||
|
|
||||||
switch(bedhint.type) {
|
switch(bedhint.type) {
|
||||||
case BedShapeType::BOX: {
|
case BedShapeType::BOX: {
|
||||||
|
@ -916,15 +915,13 @@ void find_new_position(const Model &model,
|
||||||
BedShapeHint bedhint = bedShape(bed);
|
BedShapeHint bedhint = bedShape(bed);
|
||||||
|
|
||||||
BoundingBox bbb(bed);
|
BoundingBox bbb(bed);
|
||||||
|
|
||||||
auto binbb = Box({
|
coord_t md = ceil_i(min_obj_distance, 2) - SCALED_EPSILON;
|
||||||
static_cast<libnest2d::Coord>(bbb.min(0)),
|
|
||||||
static_cast<libnest2d::Coord>(bbb.min(1))
|
auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md,
|
||||||
},
|
libnest2d::Coord{bbb.min(1)} - md},
|
||||||
{
|
{libnest2d::Coord{bbb.max(0)} + md,
|
||||||
static_cast<libnest2d::Coord>(bbb.max(0)),
|
libnest2d::Coord{bbb.max(1)} + md});
|
||||||
static_cast<libnest2d::Coord>(bbb.max(1))
|
|
||||||
});
|
|
||||||
|
|
||||||
for(auto it = shapemap.begin(); it != shapemap.end(); ++it) {
|
for(auto it = shapemap.begin(); it != shapemap.end(); ++it) {
|
||||||
if(std::find(toadd.begin(), toadd.end(), it->first) == toadd.end()) {
|
if(std::find(toadd.begin(), toadd.end(), it->first) == toadd.end()) {
|
||||||
|
|
|
@ -1583,6 +1583,9 @@ DoubleSlider::DoubleSlider( wxWindow *parent,
|
||||||
m_bmp_one_layer_unlock_off = ScalableBitmap(this, "one_layer_unlock_off.png");
|
m_bmp_one_layer_unlock_off = ScalableBitmap(this, "one_layer_unlock_off.png");
|
||||||
m_lock_icon_dim = m_bmp_one_layer_lock_on.bmp().GetSize().x;
|
m_lock_icon_dim = m_bmp_one_layer_lock_on.bmp().GetSize().x;
|
||||||
|
|
||||||
|
m_bmp_revert = ScalableBitmap(this, "undo");
|
||||||
|
m_revert_icon_dim = m_bmp_revert.bmp().GetSize().x;
|
||||||
|
|
||||||
m_selection = ssUndef;
|
m_selection = ssUndef;
|
||||||
|
|
||||||
// slider events
|
// slider events
|
||||||
|
@ -1638,6 +1641,9 @@ void DoubleSlider::msw_rescale()
|
||||||
m_bmp_one_layer_unlock_off.msw_rescale();
|
m_bmp_one_layer_unlock_off.msw_rescale();
|
||||||
m_lock_icon_dim = m_bmp_one_layer_lock_on.bmp().GetSize().x;
|
m_lock_icon_dim = m_bmp_one_layer_lock_on.bmp().GetSize().x;
|
||||||
|
|
||||||
|
m_bmp_revert.msw_rescale();
|
||||||
|
m_revert_icon_dim = m_bmp_revert.bmp().GetSize().x;
|
||||||
|
|
||||||
SLIDER_MARGIN = 4 + Slic3r::GUI::wxGetApp().em_unit();
|
SLIDER_MARGIN = 4 + Slic3r::GUI::wxGetApp().em_unit();
|
||||||
|
|
||||||
SetMinSize(get_min_size());
|
SetMinSize(get_min_size());
|
||||||
|
@ -1874,8 +1880,11 @@ void DoubleSlider::render()
|
||||||
//draw color print ticks
|
//draw color print ticks
|
||||||
draw_ticks(dc);
|
draw_ticks(dc);
|
||||||
|
|
||||||
//draw color print ticks
|
//draw lock/unlock
|
||||||
draw_one_layer_icon(dc);
|
draw_one_layer_icon(dc);
|
||||||
|
|
||||||
|
//draw revert bitmap (if it's shown)
|
||||||
|
draw_revert_icon(dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_end)
|
void DoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoint pt_end)
|
||||||
|
@ -2102,6 +2111,24 @@ void DoubleSlider::draw_one_layer_icon(wxDC& dc)
|
||||||
m_rect_one_layer_icon = wxRect(x_draw, y_draw, m_lock_icon_dim, m_lock_icon_dim);
|
m_rect_one_layer_icon = wxRect(x_draw, y_draw, m_lock_icon_dim, m_lock_icon_dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DoubleSlider::draw_revert_icon(wxDC& dc)
|
||||||
|
{
|
||||||
|
if (m_ticks.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
int width, height;
|
||||||
|
get_size(&width, &height);
|
||||||
|
|
||||||
|
wxCoord x_draw, y_draw;
|
||||||
|
is_horizontal() ? x_draw = width-2 : x_draw = 0.25*SLIDER_MARGIN;
|
||||||
|
is_horizontal() ? y_draw = 0.25*SLIDER_MARGIN: y_draw = height-2;
|
||||||
|
|
||||||
|
dc.DrawBitmap(m_bmp_revert.bmp(), x_draw, y_draw);
|
||||||
|
|
||||||
|
//update rect of the lock/unlock icon
|
||||||
|
m_rect_revert_icon = wxRect(x_draw, y_draw, m_revert_icon_dim, m_revert_icon_dim);
|
||||||
|
}
|
||||||
|
|
||||||
void DoubleSlider::update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection)
|
void DoubleSlider::update_thumb_rect(const wxCoord& begin_x, const wxCoord& begin_y, const SelectedSlider& selection)
|
||||||
{
|
{
|
||||||
const wxRect& rect = wxRect(begin_x, begin_y, m_thumb_size.x, m_thumb_size.y);
|
const wxRect& rect = wxRect(begin_x, begin_y, m_thumb_size.x, m_thumb_size.y);
|
||||||
|
@ -2118,8 +2145,8 @@ int DoubleSlider::get_value_from_position(const wxCoord x, const wxCoord y)
|
||||||
|
|
||||||
if (is_horizontal())
|
if (is_horizontal())
|
||||||
return int(double(x - SLIDER_MARGIN) / step + 0.5);
|
return int(double(x - SLIDER_MARGIN) / step + 0.5);
|
||||||
else
|
|
||||||
return int(m_min_value + double(height - SLIDER_MARGIN - y) / step + 0.5);
|
return int(m_min_value + double(height - SLIDER_MARGIN - y) / step + 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoubleSlider::detect_selected_slider(const wxPoint& pt)
|
void DoubleSlider::detect_selected_slider(const wxPoint& pt)
|
||||||
|
@ -2169,7 +2196,10 @@ void DoubleSlider::ChangeOneLayerLock()
|
||||||
|
|
||||||
void DoubleSlider::OnLeftDown(wxMouseEvent& event)
|
void DoubleSlider::OnLeftDown(wxMouseEvent& event)
|
||||||
{
|
{
|
||||||
|
if (HasCapture())
|
||||||
|
return;
|
||||||
this->CaptureMouse();
|
this->CaptureMouse();
|
||||||
|
|
||||||
wxClientDC dc(this);
|
wxClientDC dc(this);
|
||||||
wxPoint pos = event.GetLogicalPosition(dc);
|
wxPoint pos = event.GetLogicalPosition(dc);
|
||||||
if (is_point_in_rect(pos, m_rect_tick_action) && m_is_enabled_tick_manipulation) {
|
if (is_point_in_rect(pos, m_rect_tick_action) && m_is_enabled_tick_manipulation) {
|
||||||
|
@ -2179,6 +2209,7 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event)
|
||||||
|
|
||||||
m_is_left_down = true;
|
m_is_left_down = true;
|
||||||
if (is_point_in_rect(pos, m_rect_one_layer_icon)) {
|
if (is_point_in_rect(pos, m_rect_one_layer_icon)) {
|
||||||
|
// switch on/off one layer mode
|
||||||
m_is_one_layer = !m_is_one_layer;
|
m_is_one_layer = !m_is_one_layer;
|
||||||
if (!m_is_one_layer) {
|
if (!m_is_one_layer) {
|
||||||
SetLowerValue(m_min_value);
|
SetLowerValue(m_min_value);
|
||||||
|
@ -2187,20 +2218,36 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event)
|
||||||
m_selection == ssLower ? correct_lower_value() : correct_higher_value();
|
m_selection == ssLower ? correct_lower_value() : correct_higher_value();
|
||||||
if (!m_selection) m_selection = ssHigher;
|
if (!m_selection) m_selection = ssHigher;
|
||||||
}
|
}
|
||||||
|
else if (is_point_in_rect(pos, m_rect_revert_icon)) {
|
||||||
|
// discard all color changes
|
||||||
|
SetLowerValue(m_min_value);
|
||||||
|
SetHigherValue(m_max_value);
|
||||||
|
|
||||||
|
m_selection == ssLower ? correct_lower_value() : correct_higher_value();
|
||||||
|
if (!m_selection) m_selection = ssHigher;
|
||||||
|
|
||||||
|
m_ticks.clear();
|
||||||
|
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
detect_selected_slider(pos);
|
detect_selected_slider(pos);
|
||||||
|
|
||||||
if (!m_selection && m_is_enabled_tick_manipulation) {
|
if (!m_selection) {
|
||||||
const auto tick = is_point_near_tick(pos);
|
const int tick_val = is_point_near_tick(pos);
|
||||||
if (tick >= 0)
|
/* Set current thumb position to the nearest tick (if it is)
|
||||||
|
* OR to a value corresponding to the mouse click
|
||||||
|
* */
|
||||||
|
const int mouse_val = tick_val >= 0 && m_is_enabled_tick_manipulation ? tick_val :
|
||||||
|
get_value_from_position(pos.x, pos.y);
|
||||||
|
if (mouse_val >= 0)
|
||||||
{
|
{
|
||||||
if (abs(tick - m_lower_value) < abs(tick - m_higher_value)) {
|
if (abs(mouse_val - m_lower_value) < abs(mouse_val - m_higher_value)) {
|
||||||
SetLowerValue(tick);
|
SetLowerValue(mouse_val);
|
||||||
correct_lower_value();
|
correct_lower_value();
|
||||||
m_selection = ssLower;
|
m_selection = ssLower;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
SetHigherValue(tick);
|
SetHigherValue(mouse_val);
|
||||||
correct_higher_value();
|
correct_higher_value();
|
||||||
m_selection = ssHigher;
|
m_selection = ssHigher;
|
||||||
}
|
}
|
||||||
|
@ -2240,9 +2287,13 @@ void DoubleSlider::OnMotion(wxMouseEvent& event)
|
||||||
|
|
||||||
const wxClientDC dc(this);
|
const wxClientDC dc(this);
|
||||||
const wxPoint pos = event.GetLogicalPosition(dc);
|
const wxPoint pos = event.GetLogicalPosition(dc);
|
||||||
|
|
||||||
m_is_one_layer_icon_focesed = is_point_in_rect(pos, m_rect_one_layer_icon);
|
m_is_one_layer_icon_focesed = is_point_in_rect(pos, m_rect_one_layer_icon);
|
||||||
|
bool is_revert_icon_focused = false;
|
||||||
|
|
||||||
if (!m_is_left_down && !m_is_one_layer) {
|
if (!m_is_left_down && !m_is_one_layer) {
|
||||||
m_is_action_icon_focesed = is_point_in_rect(pos, m_rect_tick_action);
|
m_is_action_icon_focesed = is_point_in_rect(pos, m_rect_tick_action);
|
||||||
|
is_revert_icon_focused = !m_ticks.empty() && is_point_in_rect(pos, m_rect_revert_icon);
|
||||||
}
|
}
|
||||||
else if (m_is_left_down || m_is_right_down) {
|
else if (m_is_left_down || m_is_right_down) {
|
||||||
if (m_selection == ssLower) {
|
if (m_selection == ssLower) {
|
||||||
|
@ -2262,6 +2313,13 @@ void DoubleSlider::OnMotion(wxMouseEvent& event)
|
||||||
Update();
|
Update();
|
||||||
event.Skip();
|
event.Skip();
|
||||||
|
|
||||||
|
// Set tooltips with information for each icon
|
||||||
|
const wxString tooltip = m_is_one_layer_icon_focesed ? _(L("One layer mode")) :
|
||||||
|
m_is_action_icon_focesed ? _(L("Add/Del color change")) :
|
||||||
|
is_revert_icon_focused ? _(L("Discard all color changes")) :
|
||||||
|
wxEmptyString;
|
||||||
|
this->SetToolTip(tooltip);
|
||||||
|
|
||||||
if (action)
|
if (action)
|
||||||
{
|
{
|
||||||
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
|
wxCommandEvent e(wxEVT_SCROLL_CHANGED);
|
||||||
|
@ -2412,7 +2470,9 @@ void DoubleSlider::OnChar(wxKeyEvent& event)
|
||||||
|
|
||||||
void DoubleSlider::OnRightDown(wxMouseEvent& event)
|
void DoubleSlider::OnRightDown(wxMouseEvent& event)
|
||||||
{
|
{
|
||||||
|
if (HasCapture()) return;
|
||||||
this->CaptureMouse();
|
this->CaptureMouse();
|
||||||
|
|
||||||
const wxClientDC dc(this);
|
const wxClientDC dc(this);
|
||||||
detect_selected_slider(event.GetLogicalPosition(dc));
|
detect_selected_slider(event.GetLogicalPosition(dc));
|
||||||
if (!m_selection)
|
if (!m_selection)
|
||||||
|
|
|
@ -742,6 +742,7 @@ protected:
|
||||||
void draw_ticks(wxDC& dc);
|
void draw_ticks(wxDC& dc);
|
||||||
void draw_colored_band(wxDC& dc);
|
void draw_colored_band(wxDC& dc);
|
||||||
void draw_one_layer_icon(wxDC& dc);
|
void draw_one_layer_icon(wxDC& dc);
|
||||||
|
void draw_revert_icon(wxDC& dc);
|
||||||
void draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection);
|
void draw_thumb_item(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection);
|
||||||
void draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, SelectedSlider selection);
|
void draw_info_line_with_icon(wxDC& dc, const wxPoint& pos, SelectedSlider selection);
|
||||||
void draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const;
|
void draw_thumb_text(wxDC& dc, const wxPoint& pos, const SelectedSlider& selection) const;
|
||||||
|
@ -783,6 +784,7 @@ private:
|
||||||
ScalableBitmap m_bmp_one_layer_lock_off;
|
ScalableBitmap m_bmp_one_layer_lock_off;
|
||||||
ScalableBitmap m_bmp_one_layer_unlock_on;
|
ScalableBitmap m_bmp_one_layer_unlock_on;
|
||||||
ScalableBitmap m_bmp_one_layer_unlock_off;
|
ScalableBitmap m_bmp_one_layer_unlock_off;
|
||||||
|
ScalableBitmap m_bmp_revert;
|
||||||
SelectedSlider m_selection;
|
SelectedSlider m_selection;
|
||||||
bool m_is_left_down = false;
|
bool m_is_left_down = false;
|
||||||
bool m_is_right_down = false;
|
bool m_is_right_down = false;
|
||||||
|
@ -796,9 +798,11 @@ private:
|
||||||
wxRect m_rect_higher_thumb;
|
wxRect m_rect_higher_thumb;
|
||||||
wxRect m_rect_tick_action;
|
wxRect m_rect_tick_action;
|
||||||
wxRect m_rect_one_layer_icon;
|
wxRect m_rect_one_layer_icon;
|
||||||
|
wxRect m_rect_revert_icon;
|
||||||
wxSize m_thumb_size;
|
wxSize m_thumb_size;
|
||||||
int m_tick_icon_dim;
|
int m_tick_icon_dim;
|
||||||
int m_lock_icon_dim;
|
int m_lock_icon_dim;
|
||||||
|
int m_revert_icon_dim;
|
||||||
long m_style;
|
long m_style;
|
||||||
float m_label_koef = 1.0;
|
float m_label_koef = 1.0;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue