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