1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2 //
3 #ifndef SPECTMORPH_SCROLLVIEW_HH
4 #define SPECTMORPH_SCROLLVIEW_HH
5 
6 #include "smdrawutils.hh"
7 #include "smscrollbar.hh"
8 
9 namespace SpectMorph
10 {
11 
12 class ScrollView : public Widget
13 {
14   double view_width = 0;
15   double view_height = 0;
16   ScrollBar *h_scroll_bar = nullptr;
17   ScrollBar *v_scroll_bar = nullptr;
18   Widget *scroll_widget = 0;
19 
20 public:
ScrollView(Widget * parent)21   ScrollView (Widget *parent) :
22     Widget (parent)
23   {
24   }
25   ScrollView *
scroll_view()26   scroll_view() override
27   {
28     return this;
29   }
30   bool
is_scroll_child(Widget * w)31   is_scroll_child (Widget *w)
32   {
33     /* return true for scroll_widget and all its children */
34     return (w != this && w != h_scroll_bar && w != v_scroll_bar);
35   }
36   Rect
child_rect()37   child_rect()
38   {
39     return Rect (abs_x() + 2, abs_y() + 2, view_width - 4, view_height - 4);
40   }
41   void
draw(const DrawEvent & devent)42   draw (const DrawEvent& devent) override
43   {
44     DrawUtils du (devent.cr);
45 
46     du.round_box (0, 0, view_width, view_height, 1, 2, ThemeColor::MENU_BG);
47   }
48   void
set_scroll_widget(Widget * new_scroll_widget,bool hscroll,bool vscroll,bool center_zoom=false)49   set_scroll_widget (Widget *new_scroll_widget, bool hscroll, bool vscroll, bool center_zoom = false)
50   {
51     /* cleanup old scrollbars */
52     if (h_scroll_bar)
53       {
54         delete h_scroll_bar;
55         h_scroll_bar = nullptr;
56       }
57     if (v_scroll_bar)
58       {
59         delete v_scroll_bar;
60         v_scroll_bar = nullptr;
61       }
62 
63     scroll_widget = new_scroll_widget;
64 
65     view_width = width();
66     view_height = height();
67 
68     if (vscroll)
69       view_width -= 16;
70     if (hscroll)
71       view_height -= 16;
72 
73     /* create new scrollbars */
74     if (hscroll)
75       {
76         h_scroll_bar = new ScrollBar (this, 1, Orientation::HORIZONTAL);
77         h_scroll_bar->set_x (0);
78         h_scroll_bar->set_y (view_height);
79         h_scroll_bar->set_height (16);
80         h_scroll_bar->set_width (view_width);
81 
82         h_scroll_bar->set_scroll_factor (0.08);
83         h_scroll_bar->set_center_zoom (center_zoom);
84         connect (h_scroll_bar->signal_position_changed, this, &ScrollView::on_scroll_bar_changed);
85       }
86 
87     if (vscroll)
88       {
89         v_scroll_bar = new ScrollBar (this, 1, Orientation::VERTICAL);
90         v_scroll_bar->set_x (view_width);
91         v_scroll_bar->set_y (0);
92         v_scroll_bar->set_height (view_height);
93         v_scroll_bar->set_width (16);
94 
95         v_scroll_bar->set_scroll_factor (0.08);
96         v_scroll_bar->set_center_zoom (center_zoom);
97         connect (v_scroll_bar->signal_position_changed, this, &ScrollView::on_scroll_bar_changed);
98       }
99 
100     on_widget_size_changed();
101     on_scroll_bar_changed (0);
102   }
103   void
on_scroll_bar_changed(double)104   on_scroll_bar_changed (double)
105   {
106     double sx = 8;
107     double sy = 8;
108 
109     if (v_scroll_bar)
110       sy -= v_scroll_bar->pos() * (scroll_widget->height() + 16);
111     if (h_scroll_bar)
112       sx -= h_scroll_bar->pos() * (scroll_widget->width() + 16);
113 
114     scroll_widget->set_x (sx);
115     scroll_widget->set_y (sy);
116     update();
117   }
118   bool
scroll(double dx,double dy)119   scroll (double dx, double dy) override
120   {
121     if (v_scroll_bar)
122       return v_scroll_bar->scroll (dx, dy);
123 
124     return false;
125   }
126   void
on_widget_size_changed()127   on_widget_size_changed()
128   {
129     if (h_scroll_bar)
130       {
131         const double h_page_size = view_width / (scroll_widget->width() + 16);
132 
133         h_scroll_bar->set_enabled (h_page_size < 1.0);
134         h_scroll_bar->set_page_size (h_page_size);
135       }
136 
137     if (v_scroll_bar)
138       {
139         const double v_page_size = view_height / (scroll_widget->height() + 16);
140 
141         v_scroll_bar->set_enabled (v_page_size < 1.0);
142         v_scroll_bar->set_page_size (v_page_size);
143       }
144     // reposition widget on screen if necessary
145     on_scroll_bar_changed (0);
146   }
147 };
148 
149 }
150 
151 #endif
152