From cb844a4034e3445e7d15632fe5f00ee9c4330a97 Mon Sep 17 00:00:00 2001
From: YuSanka <yusanka@gmail.com>
Date: Mon, 16 Nov 2020 21:33:07 +0100
Subject: [PATCH] DoubleSlider's ruler is implemented in respect to the use
 with sequential printing of objects

---
 src/slic3r/GUI/DoubleSlider.cpp | 117 ++++++++++++++++++++------------
 src/slic3r/GUI/DoubleSlider.hpp |  12 +++-
 2 files changed, 85 insertions(+), 44 deletions(-)

diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp
index 64ea70514..40463288e 100644
--- a/src/slic3r/GUI/DoubleSlider.cpp
+++ b/src/slic3r/GUI/DoubleSlider.cpp
@@ -243,6 +243,12 @@ void Control::SetMaxValue(const int max_value)
     Update();
 }
 
+void Control::SetSliderValues(const std::vector<double>& values)
+{
+    m_values = values;
+    m_ruler.count = std::count(m_values.begin(), m_values.end(), m_values.front());
+}
+
 void Control::draw_scroll_line(wxDC& dc, const int lower_pos, const int higher_pos)
 {
     int width;
@@ -732,6 +738,15 @@ void Control::draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord& hig
     draw_thumb_text(dc, pos_l, ssLower);
 }
 
+void Control::draw_ticks_pair(wxDC& dc, wxCoord pos, wxCoord mid, int tick_len)
+{
+    int mid_space = 9;
+    is_horizontal() ? dc.DrawLine(pos, mid - (mid_space + tick_len), pos, mid - mid_space) :
+        dc.DrawLine(mid - (mid_space + tick_len), pos, mid - mid_space, pos);
+    is_horizontal() ? dc.DrawLine(pos, mid + (mid_space + tick_len), pos, mid + mid_space) :
+        dc.DrawLine(mid + (mid_space + tick_len), pos, mid + mid_space, pos);
+};
+
 void Control::draw_ticks(wxDC& dc)
 {
     if (m_draw_mode == dmSlaPrint)
@@ -743,11 +758,7 @@ void Control::draw_ticks(wxDC& dc)
     const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width;
     for (auto tick : m_ticks.ticks) {
         const wxCoord pos = get_position_from_value(tick.tick);
-
-        is_horizontal() ?   dc.DrawLine(pos, mid-14, pos, mid-9) :
-                            dc.DrawLine(mid - 14, pos/* - 1*/, mid - 9, pos/* - 1*/);
-        is_horizontal() ?   dc.DrawLine(pos, mid+14, pos, mid+9) :
-                            dc.DrawLine(mid + 14, pos/* - 1*/, mid + 9, pos/* - 1*/);
+        draw_ticks_pair(dc, pos, mid, 7);
 
         // if current tick if focused, we should to use a specific "focused" icon 
         bool focused_tick = m_moving_pos != wxDefaultPosition && tick.tick == get_tick_near_point(m_moving_pos);
@@ -883,38 +894,35 @@ void Control::draw_colored_band(wxDC& dc)
     }
 }
 
-void Control::draw_ruler(wxDC& dc)
+void Control::Ruler::update(wxWindow* win, const std::vector<double>& values, double scroll_step)
 {
-    int height, width;
-    get_size(&width, &height);
-    const wxCoord mid = is_horizontal() ? 0.5 * height : 0.5 * width;
-
-    int DPI = GUI::get_dpi_for_window(this->GetParent());
+    int DPI = GUI::get_dpi_for_window(win);
     int pixels_per_sm = lround((double)(DPI) * 5.0/25.4);
 
-    int pow = -1;
+    int pow = -2;
     int step = 0;
-    double ruler_short_step;
+    auto end_it = count == 1 ? values.end() : values.begin() + lround(values.size() / count);
 
     while (pow < 3) {
+        int tick = 0;
         for (int istep : {1, 2, 5}) {
             double val = (double)istep * std::pow(10,pow);
-            auto val_it = std::lower_bound(m_values.begin(), m_values.end(), val - epsilon());
+            auto val_it = std::lower_bound(values.begin(), end_it, val - epsilon());
 
-            if (val_it == m_values.end())
+            if (val_it == values.end())
                 break;
-            int tick = val_it - m_values.begin();
+            int tick = val_it - values.begin();
 
-            if (lround(tick * get_scroll_step()) > pixels_per_sm) {
+            if (lround(tick * scroll_step) > pixels_per_sm) {
                 step = istep;
 
                 // find next tick with istep
                 val *= 2;
-                val_it = std::lower_bound(m_values.begin(), m_values.end(), val - epsilon());
+                val_it = std::lower_bound(values.begin(), end_it, val - epsilon());
                 // count of short ticks between ticks
-                int short_ticks_cnt = val_it == m_values.end() ? tick : val_it - m_values.begin() - tick;
+                int short_ticks_cnt = val_it == values.end() ? tick : val_it - values.begin() - tick;
                 // there couldn't be more then 10 short ticks between thicks
-                ruler_short_step = 0.1 * short_ticks_cnt;
+                short_step = 0.1 * short_ticks_cnt;
                 break;
             }
         }
@@ -923,24 +931,26 @@ void Control::draw_ruler(wxDC& dc)
         pow++;
     }
 
-    if (step == 0)
-        return; 
+    long_step = step == 0 ? -1.0 : (double)step* std::pow(10, pow);
+}
 
-    auto draw_ticks = [this, mid](wxDC& dc, wxCoord pos, int tick_len)
-    {
-        int mid_space = 9;
-        is_horizontal() ?   dc.DrawLine(pos, mid - (mid_space + tick_len), pos, mid - mid_space) :
-                            dc.DrawLine(mid - (mid_space + tick_len), pos, mid - mid_space, pos);
-        is_horizontal() ?   dc.DrawLine(pos, mid + (mid_space + tick_len), pos, mid + mid_space) :
-                            dc.DrawLine(mid + (mid_space + tick_len), pos, mid + mid_space, pos);
-    };
+void Control::draw_ruler(wxDC& dc)
+{
+    m_ruler.update(this->GetParent(), m_values, get_scroll_step());
+    if (!m_ruler.is_ok())
+        return;
 
-    auto draw_short_ticks = [this, draw_ticks, ruler_short_step](wxDC& dc, double& current_tick, int max_tick)
-    {
+    int height, width;
+    get_size(&width, &height);
+    const wxCoord mid = is_horizontal() ? 0.5 * height : 0.5 * width;    
+
+    auto draw_short_ticks = [this, mid](wxDC& dc, double& current_tick, int max_tick) {
         while (current_tick < max_tick) {
             wxCoord pos = get_position_from_value(lround(current_tick));
-            draw_ticks(dc, pos, 2);
-            current_tick += ruler_short_step;
+            draw_ticks_pair(dc, pos, mid, 2);
+            current_tick += m_ruler.short_step;
+            if (current_tick > m_max_value)
+                break;
         }
     };   
 
@@ -951,23 +961,44 @@ void Control::draw_ruler(wxDC& dc)
     double short_tick;
     int tick = 0;
     double value = 0.0;
+    int sequence = 0;
 
-    double interval = (double)step * std::pow(10, pow);
-    while (tick <= m_max_value)
-    {
-        value += interval;
+    while (tick <= m_max_value) {
+        value += m_ruler.long_step;
+        if (value > m_values.back() && sequence < m_ruler.count) {
+            value = m_ruler.long_step;
+            for (tick; tick < m_values.size(); tick++)
+                if (m_values[tick] < value)
+                    break;
+            // short ticks from the last tick to the end of current sequence
+            draw_short_ticks(dc, short_tick, tick);
+            sequence++;
+        }
         short_tick = tick;
-        auto val_it = std::lower_bound(m_values.begin(), m_values.end(), value - epsilon());
 
-        if (val_it == m_values.end())
+        for (tick; tick < m_values.size(); tick++) {
+            if (m_values[tick] == value)
+                break;
+            if (m_values[tick] > value) {
+                if (tick > 0)
+                    tick--;
+                break;
+            }
+        }
+        if (tick > m_max_value)
             break;
-        tick = val_it - m_values.begin();
 
         wxCoord pos = get_position_from_value(tick);
-        draw_ticks(dc, pos, 5);
+        draw_ticks_pair(dc, pos, mid, 5);
+        draw_tick_text(dc, wxPoint(mid, pos), tick);
 
-        draw_tick_text(dc, wxPoint(mid/* + 2*/, pos), tick);
         draw_short_ticks(dc, short_tick, tick);
+
+        if (value == m_values.back() && sequence < m_ruler.count) {
+            value = 0.0;
+            sequence++;
+            tick++;
+        }
     }
     // short ticks from the last tick to the end 
     draw_short_ticks(dc, short_tick, m_max_value);
diff --git a/src/slic3r/GUI/DoubleSlider.hpp b/src/slic3r/GUI/DoubleSlider.hpp
index f909f105a..f6e555934 100644
--- a/src/slic3r/GUI/DoubleSlider.hpp
+++ b/src/slic3r/GUI/DoubleSlider.hpp
@@ -219,7 +219,7 @@ public:
 
     void    SetMaxValue(const int max_value);
     void    SetKoefForLabels(const double koef)                { m_label_koef = koef; }
-    void    SetSliderValues(const std::vector<double>& values) { m_values = values; }
+    void    SetSliderValues(const std::vector<double>& values);
     void    ChangeOneLayerLock();
 
     Info   GetTicksValues() const;
@@ -288,6 +288,7 @@ protected:
     void    draw_scroll_line(wxDC& dc, const int lower_pos, const int higher_pos);
     void    draw_thumb(wxDC& dc, const wxCoord& pos_coord, const SelectedSlider& selection);
     void    draw_thumbs(wxDC& dc, const wxCoord& lower_pos, const wxCoord& higher_pos);
+    void    draw_ticks_pair(wxDC& dc, wxCoord pos, wxCoord mid, int tick_len);
     void    draw_ticks(wxDC& dc);
     void    draw_colored_band(wxDC& dc);
     void    draw_ruler(wxDC& dc);
@@ -416,6 +417,15 @@ private:
 
     std::vector<wxPen*> m_line_pens;
     std::vector<wxPen*> m_segm_pens;
+
+    struct Ruler {
+        double long_step;
+        double short_step;
+        int count { 1 }; // > 1 for sequential print
+
+        void update(wxWindow* win, const std::vector<double>& values, double scroll_step);
+        bool is_ok() { return long_step > 0 && short_step > 0; }
+    } m_ruler;
 };
 
 } // DoubleSlider;