mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 12:11:15 -06:00 
			
		
		
		
	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 | ||||
| AlwaysBreakAfterReturnType: None | ||||
| AlwaysBreakBeforeMultilineStrings: false | ||||
| AlwaysBreakTemplateDeclarations: Yes | ||||
| AlwaysBreakTemplateDeclarations: false | ||||
| BinPackArguments: false | ||||
| BinPackParameters: false | ||||
| BraceWrapping:    | ||||
|  | @ -37,18 +37,18 @@ BraceWrapping: | |||
|   SplitEmptyFunction: false | ||||
|   SplitEmptyRecord: false | ||||
|   SplitEmptyNamespace: false | ||||
| BreakBeforeBinaryOperators: All | ||||
| BreakBeforeBinaryOperators: None | ||||
| BreakBeforeBraces: Custom | ||||
| BreakBeforeInheritanceComma: false | ||||
| BreakInheritanceList: BeforeColon | ||||
| BreakBeforeTernaryOperators: true | ||||
| BreakBeforeTernaryOperators: false | ||||
| BreakConstructorInitializersBeforeComma: false | ||||
| BreakConstructorInitializers: BeforeComma | ||||
| BreakAfterJavaFieldAnnotations: false | ||||
| BreakStringLiterals: true | ||||
| ColumnLimit:     75 | ||||
| CommentPragmas:  '^ IWYU pragma:' | ||||
| CompactNamespaces: false | ||||
| CompactNamespaces: true | ||||
| ConstructorInitializerAllOnOneLineOrOnePerLine: true | ||||
| ConstructorInitializerIndentWidth: 4 | ||||
| ContinuationIndentWidth: 4 | ||||
|  |  | |||
|  | @ -1,172 +1,218 @@ | |||
| #ifndef MTUTILS_HPP | ||||
| #define MTUTILS_HPP | ||||
| 
 | ||||
| #include <atomic>       // for std::atomic_flag and memory orders
 | ||||
| #include <mutex>        // for std::lock_guard
 | ||||
| #include <functional>   // for std::function
 | ||||
| #include <utility>      // for std::forward
 | ||||
| #include <atomic>     // for std::atomic_flag and memory orders
 | ||||
| #include <mutex>      // for std::lock_guard
 | ||||
| #include <functional> // for std::function
 | ||||
| #include <utility>    // for std::forward
 | ||||
| #include <algorithm> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| /// Handy little spin mutex for the cached meshes.
 | ||||
| /// Implements the "Lockable" concept
 | ||||
| class SpinMutex { | ||||
|     std::atomic_flag m_flg; | ||||
| class SpinMutex | ||||
| { | ||||
|     std::atomic_flag                m_flg; | ||||
|     static const /*constexpr*/ auto MO_ACQ = std::memory_order_acquire; | ||||
|     static const /*constexpr*/ auto MO_REL = std::memory_order_release; | ||||
| 
 | ||||
| public: | ||||
|     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 void unlock() { m_flg.clear(MO_REL); } | ||||
| }; | ||||
| 
 | ||||
| /// A wrapper class around arbitrary object that needs thread safe caching.
 | ||||
| template<class T> class CachedObject { | ||||
| template<class T> class CachedObject | ||||
| { | ||||
| public: | ||||
|     // Method type which refreshes the object when it has been invalidated
 | ||||
|     using Setter = std::function<void(T&)>; | ||||
|     using Setter = std::function<void(T &)>; | ||||
| 
 | ||||
| private: | ||||
|     T m_obj;            // the object itself
 | ||||
|     bool m_valid;       // invalidation flag
 | ||||
|     SpinMutex m_lck;    // to make the caching thread safe
 | ||||
|     T         m_obj;   // the object itself
 | ||||
|     bool      m_valid; // invalidation flag
 | ||||
|     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: | ||||
| 
 | ||||
|     // Forwarded constructor
 | ||||
|     template<class...Args> inline CachedObject(Setter fn, Args&&...args): | ||||
|         m_obj(std::forward<Args>(args)...), m_valid(false), m_setter(fn) {} | ||||
|     template<class... Args> | ||||
|     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
 | ||||
|     // next retrieval (Setter will be called). The data that is used in
 | ||||
|     // the setter function should be guarded as well during modification so the
 | ||||
|     // modification has to take place in fn.
 | ||||
|     inline void invalidate(std::function<void()> fn) { | ||||
|         std::lock_guard<SpinMutex> lck(m_lck); fn(); m_valid = false; | ||||
|     // invalidate the value of the object. The object will be refreshed at
 | ||||
|     // 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 modification has to take place in fn.
 | ||||
|     inline void invalidate(std::function<void()> fn) | ||||
|     { | ||||
|         std::lock_guard<SpinMutex> lck(m_lck); | ||||
|         fn(); | ||||
|         m_valid = false; | ||||
|     } | ||||
| 
 | ||||
|     // Get the const object properly updated.
 | ||||
|     inline const T& get() { | ||||
|     inline const T &get() | ||||
|     { | ||||
|         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; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /// An std compatible random access iterator which uses indices to the source
 | ||||
| /// vector thus resistant to invalidation caused by relocations. It also "knows"
 | ||||
| /// its container. No comparison is neccesary to the container "end()" iterator.
 | ||||
| /// The template can be instantiated with a different value type than that of
 | ||||
| /// the container's but the types must be compatible. E.g. a base class of the
 | ||||
| /// contained objects is compatible.
 | ||||
| /// An std compatible random access iterator which uses indices to the
 | ||||
| /// source vector thus resistant to invalidation caused by relocations. It
 | ||||
| /// also "knows" its container. No comparison is neccesary to the container
 | ||||
| /// "end()" iterator. The template can be instantiated with a different
 | ||||
| /// value type than that of the container's but the types must be
 | ||||
| /// compatible. E.g. a base class of the contained objects is compatible.
 | ||||
| ///
 | ||||
| /// For a constant iterator, one can instantiate this template with a value
 | ||||
| /// 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 IndexBasedIterator { | ||||
| class IndexBasedIterator | ||||
| { | ||||
|     static const size_t NONE = size_t(-1); | ||||
| 
 | ||||
|     std::reference_wrapper<Vector> m_index_ref; | ||||
|     size_t m_idx = NONE; | ||||
| public: | ||||
|     size_t                         m_idx = NONE; | ||||
| 
 | ||||
|     using value_type = Value; | ||||
|     using pointer = Value *; | ||||
|     using reference = Value &; | ||||
|     using difference_type = long; | ||||
| public: | ||||
|     using value_type        = Value; | ||||
|     using pointer           = Value *; | ||||
|     using reference         = Value &; | ||||
|     using difference_type   = long; | ||||
|     using iterator_category = std::random_access_iterator_tag; | ||||
| 
 | ||||
|     inline explicit | ||||
|     IndexBasedIterator(Vector& index, size_t idx): | ||||
|         m_index_ref(index), m_idx(idx) {} | ||||
|     inline explicit IndexBasedIterator(Vector &index, size_t idx) | ||||
|         : m_index_ref(index), m_idx(idx) | ||||
|     {} | ||||
| 
 | ||||
|     // Post increment
 | ||||
|     inline IndexBasedIterator operator++(int) { | ||||
|         IndexBasedIterator cpy(*this); ++m_idx; return cpy; | ||||
|     inline IndexBasedIterator operator++(int) | ||||
|     { | ||||
|         IndexBasedIterator cpy(*this); | ||||
|         ++m_idx; | ||||
|         return cpy; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator operator--(int) { | ||||
|         IndexBasedIterator cpy(*this); --m_idx; return cpy; | ||||
|     inline IndexBasedIterator operator--(int) | ||||
|     { | ||||
|         IndexBasedIterator cpy(*this); | ||||
|         --m_idx; | ||||
|         return cpy; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator& operator++() { | ||||
|         ++m_idx; return *this; | ||||
|     inline IndexBasedIterator &operator++() | ||||
|     { | ||||
|         ++m_idx; | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator& operator--() { | ||||
|         --m_idx; return *this; | ||||
|     inline IndexBasedIterator &operator--() | ||||
|     { | ||||
|         --m_idx; | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator& operator+=(difference_type l) { | ||||
|         m_idx += size_t(l); return *this; | ||||
|     inline IndexBasedIterator &operator+=(difference_type l) | ||||
|     { | ||||
|         m_idx += size_t(l); | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator operator+(difference_type l) { | ||||
|         auto cpy = *this; cpy += l; return cpy; | ||||
|     inline IndexBasedIterator operator+(difference_type l) | ||||
|     { | ||||
|         auto cpy = *this; | ||||
|         cpy += l; | ||||
|         return cpy; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator& operator-=(difference_type l) { | ||||
|         m_idx -= size_t(l); return *this; | ||||
|     inline IndexBasedIterator &operator-=(difference_type l) | ||||
|     { | ||||
|         m_idx -= size_t(l); | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|     inline IndexBasedIterator operator-(difference_type l) { | ||||
|         auto cpy = *this; cpy -= l; return cpy; | ||||
|     inline IndexBasedIterator operator-(difference_type l) | ||||
|     { | ||||
|         auto cpy = *this; | ||||
|         cpy -= l; | ||||
|         return cpy; | ||||
|     } | ||||
| 
 | ||||
|     operator difference_type() { return difference_type(m_idx); } | ||||
| 
 | ||||
|     /// Tesing the end of the container... this is not possible with std
 | ||||
|     /// 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()); | ||||
|         return m_index_ref.get().operator[](m_idx); | ||||
|     } | ||||
| 
 | ||||
|     inline Value * operator->() const { | ||||
|     inline Value *operator->() const | ||||
|     { | ||||
|         assert(m_idx < m_index_ref.get().size()); | ||||
|         return &m_index_ref.get().operator[](m_idx); | ||||
|     } | ||||
| 
 | ||||
|     /// 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(); | ||||
|         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); | ||||
|     } | ||||
| 
 | ||||
|     inline bool operator <=(const IndexBasedIterator& other) { | ||||
|     inline bool operator<=(const IndexBasedIterator &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); | ||||
|     } | ||||
| 
 | ||||
|     inline bool operator >=(const IndexBasedIterator& other) { | ||||
|     inline bool operator>=(const IndexBasedIterator &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; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /// A very simple range concept implementation with iterator-like objects.
 | ||||
| template<class It> class Range { | ||||
| template<class It> class Range | ||||
| { | ||||
|     It from, to; | ||||
| public: | ||||
| 
 | ||||
| public: | ||||
|     // The class is ready for range based for loops.
 | ||||
|     It begin() const { return from; } | ||||
|     It end() const { return to; } | ||||
|  | @ -175,15 +221,17 @@ public: | |||
|     using Type = It; | ||||
| 
 | ||||
|     Range() = default; | ||||
|     Range(It &&b, It &&e): | ||||
|         from(std::forward<It>(b)), to(std::forward<It>(e)) {} | ||||
|     Range(It &&b, It &&e) | ||||
|         : from(std::forward<It>(b)), to(std::forward<It>(e)) | ||||
|     {} | ||||
| 
 | ||||
|     // Some useful container-like methods...
 | ||||
|     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(), | ||||
|                        container.end(), | ||||
|                        [](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
 | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #include "Model.hpp" | ||||
| #include "Geometry.hpp" | ||||
| #include "SVG.hpp" | ||||
| #include "MTUtils.hpp" | ||||
| 
 | ||||
| #include <libnest2d.h> | ||||
| 
 | ||||
|  | @ -820,15 +821,13 @@ bool arrange(Model &model,              // The model with the geometries | |||
|     BoundingBox bbb(bed); | ||||
| 
 | ||||
|     auto& cfn = stopcondition; | ||||
|      | ||||
|     coord_t md = ceil_i(min_obj_distance, 2) - SCALED_EPSILON; | ||||
| 
 | ||||
|     auto binbb = Box({ | ||||
|                          static_cast<libnest2d::Coord>(bbb.min(0)), | ||||
|                          static_cast<libnest2d::Coord>(bbb.min(1)) | ||||
|                      }, | ||||
|                      { | ||||
|                          static_cast<libnest2d::Coord>(bbb.max(0)), | ||||
|                          static_cast<libnest2d::Coord>(bbb.max(1)) | ||||
|                      }); | ||||
|     auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md, | ||||
|                       libnest2d::Coord{bbb.min(1)} - md}, | ||||
|                      {libnest2d::Coord{bbb.max(0)} + md, | ||||
|                       libnest2d::Coord{bbb.max(1)} + md}); | ||||
| 
 | ||||
|     switch(bedhint.type) { | ||||
|     case BedShapeType::BOX: { | ||||
|  | @ -916,15 +915,13 @@ void find_new_position(const Model &model, | |||
|     BedShapeHint bedhint = bedShape(bed); | ||||
| 
 | ||||
|     BoundingBox bbb(bed); | ||||
| 
 | ||||
|     auto binbb = Box({ | ||||
|                          static_cast<libnest2d::Coord>(bbb.min(0)), | ||||
|                          static_cast<libnest2d::Coord>(bbb.min(1)) | ||||
|                      }, | ||||
|                      { | ||||
|                          static_cast<libnest2d::Coord>(bbb.max(0)), | ||||
|                          static_cast<libnest2d::Coord>(bbb.max(1)) | ||||
|                      }); | ||||
|      | ||||
|     coord_t md = ceil_i(min_obj_distance, 2) - SCALED_EPSILON; | ||||
|      | ||||
|     auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md, | ||||
|                       libnest2d::Coord{bbb.min(1)} - md}, | ||||
|                      {libnest2d::Coord{bbb.max(0)} + md, | ||||
|                       libnest2d::Coord{bbb.max(1)} + md}); | ||||
| 
 | ||||
|     for(auto it = shapemap.begin(); it != shapemap.end(); ++it) { | ||||
|         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_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; | ||||
| 
 | ||||
|     // slider events
 | ||||
|  | @ -1638,6 +1641,9 @@ void DoubleSlider::msw_rescale() | |||
|     m_bmp_one_layer_unlock_off.msw_rescale(); | ||||
|     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(); | ||||
| 
 | ||||
|     SetMinSize(get_min_size()); | ||||
|  | @ -1874,8 +1880,11 @@ void DoubleSlider::render() | |||
|     //draw color print ticks
 | ||||
|     draw_ticks(dc); | ||||
| 
 | ||||
|     //draw color print ticks
 | ||||
|     //draw lock/unlock
 | ||||
|     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) | ||||
|  | @ -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); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|     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())  | ||||
|         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) | ||||
|  | @ -2169,7 +2196,10 @@ void DoubleSlider::ChangeOneLayerLock() | |||
| 
 | ||||
| void DoubleSlider::OnLeftDown(wxMouseEvent& event) | ||||
| { | ||||
|     if (HasCapture()) | ||||
|         return; | ||||
|     this->CaptureMouse(); | ||||
| 
 | ||||
|     wxClientDC dc(this); | ||||
|     wxPoint pos = event.GetLogicalPosition(dc); | ||||
|     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; | ||||
|     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; | ||||
|         if (!m_is_one_layer) { | ||||
|             SetLowerValue(m_min_value); | ||||
|  | @ -2187,20 +2218,36 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event) | |||
|         m_selection == ssLower ? correct_lower_value() : correct_higher_value(); | ||||
|         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 | ||||
|         detect_selected_slider(pos); | ||||
| 
 | ||||
|     if (!m_selection && m_is_enabled_tick_manipulation) { | ||||
|         const auto tick = is_point_near_tick(pos); | ||||
|         if (tick >= 0) | ||||
|     if (!m_selection) { | ||||
|         const int tick_val  = is_point_near_tick(pos); | ||||
|         /* 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)) { | ||||
|                 SetLowerValue(tick); | ||||
|             if (abs(mouse_val - m_lower_value) < abs(mouse_val - m_higher_value)) { | ||||
|                 SetLowerValue(mouse_val); | ||||
|                 correct_lower_value(); | ||||
|                 m_selection = ssLower; | ||||
|             } | ||||
|             else { | ||||
|                 SetHigherValue(tick); | ||||
|                 SetHigherValue(mouse_val); | ||||
|                 correct_higher_value(); | ||||
|                 m_selection = ssHigher; | ||||
|             } | ||||
|  | @ -2240,9 +2287,13 @@ void DoubleSlider::OnMotion(wxMouseEvent& event) | |||
| 
 | ||||
|     const wxClientDC dc(this); | ||||
|     const wxPoint pos = event.GetLogicalPosition(dc); | ||||
| 
 | ||||
|     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) { | ||||
|         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) { | ||||
|         if (m_selection == ssLower) { | ||||
|  | @ -2262,6 +2313,13 @@ void DoubleSlider::OnMotion(wxMouseEvent& event) | |||
|     Update(); | ||||
|     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) | ||||
|     { | ||||
|         wxCommandEvent e(wxEVT_SCROLL_CHANGED); | ||||
|  | @ -2412,7 +2470,9 @@ void DoubleSlider::OnChar(wxKeyEvent& event) | |||
| 
 | ||||
| void DoubleSlider::OnRightDown(wxMouseEvent& event) | ||||
| { | ||||
|     if (HasCapture()) return; | ||||
|     this->CaptureMouse(); | ||||
| 
 | ||||
|     const wxClientDC dc(this); | ||||
|     detect_selected_slider(event.GetLogicalPosition(dc)); | ||||
|     if (!m_selection) | ||||
|  |  | |||
|  | @ -742,6 +742,7 @@ protected: | |||
|     void    draw_ticks(wxDC& dc); | ||||
|     void    draw_colored_band(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_info_line_with_icon(wxDC& dc, const wxPoint& pos, SelectedSlider selection); | ||||
|     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_unlock_on; | ||||
|     ScalableBitmap    m_bmp_one_layer_unlock_off; | ||||
|     ScalableBitmap    m_bmp_revert; | ||||
|     SelectedSlider  m_selection; | ||||
|     bool        m_is_left_down = false; | ||||
|     bool        m_is_right_down = false; | ||||
|  | @ -796,9 +798,11 @@ private: | |||
|     wxRect      m_rect_higher_thumb; | ||||
|     wxRect      m_rect_tick_action; | ||||
|     wxRect      m_rect_one_layer_icon; | ||||
|     wxRect      m_rect_revert_icon; | ||||
|     wxSize      m_thumb_size; | ||||
|     int         m_tick_icon_dim; | ||||
|     int         m_lock_icon_dim; | ||||
|     int         m_revert_icon_dim; | ||||
|     long        m_style; | ||||
|     float       m_label_koef = 1.0; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Enrico Turri
						Enrico Turri