summaryrefslogtreecommitdiff
path: root/src/Fl_Scroll.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'src/Fl_Scroll.cxx')
-rw-r--r--src/Fl_Scroll.cxx210
1 files changed, 210 insertions, 0 deletions
diff --git a/src/Fl_Scroll.cxx b/src/Fl_Scroll.cxx
new file mode 100644
index 000000000..b5cc49520
--- /dev/null
+++ b/src/Fl_Scroll.cxx
@@ -0,0 +1,210 @@
+// Fl_Scroll.C
+
+#include <FL/Fl.H>
+#include <FL/Fl_Scroll.H>
+#include <FL/fl_draw.H>
+
+// Insure the scrollbars are the last children:
+void Fl_Scroll::fix_scrollbar_order() {
+ Fl_Widget*const* a = array();
+ if (a[children()-1] != &scrollbar) {
+ Fl_Widget** a = (Fl_Widget**)array();
+ int i,j; for (i = j = 0; j < children(); j++)
+ if (a[j] != &hscrollbar && a[j] != &scrollbar) a[i++] = a[j];
+ a[i++] = &hscrollbar;
+ a[i++] = &scrollbar;
+ }
+}
+
+void Fl_Scroll::draw_clip(void* v,int X, int Y, int W, int H) {
+ fl_clip(X,Y,W,H);
+ Fl_Scroll* s = (Fl_Scroll*)v;
+ // erase background if there is a boxtype:
+ if (s->box() && !(s->damage()&128)) {
+ fl_color(s->color());
+ fl_rectf(X,Y,W,H);
+ }
+ Fl_Widget*const* a = s->array();
+ int R = X; int B = Y; // track bottom & right edge of all children
+ for (int i=s->children()-2; i--;) {
+ Fl_Widget& o = **a++;
+ s->draw_child(o);
+ s->draw_outside_label(o);
+ if (o.x()+o.w() > R) R = o.x()+o.w();
+ if (o.y()+o.h() > B) B = o.y()+o.h();
+ }
+ // fill any area to right & bottom of widgets:
+ if (R < X+W && B > Y) {
+ fl_color(s->color());
+ fl_rectf(R,Y,X+W-R,B-Y);
+ }
+ if (B < Y+H) {
+ fl_color(s->color());
+ fl_rectf(X,B,W,Y+H-B);
+ }
+ fl_pop_clip();
+}
+
+void Fl_Scroll::bbox(int& X, int& Y, int& W, int& H) {
+ X = x()+Fl::box_dx(box());
+ Y = y()+Fl::box_dy(box());
+ W = w()-Fl::box_dw(box());
+ H = h()-Fl::box_dh(box());
+ if (scrollbar.visible()) {
+ W -= scrollbar.w();
+ if (scrollbar.align() & FL_ALIGN_LEFT) X += scrollbar.w();
+ }
+ if (hscrollbar.visible()) {
+ H -= hscrollbar.h();
+ if (scrollbar.align() & FL_ALIGN_TOP) Y += hscrollbar.h();
+ }
+}
+
+void Fl_Scroll::draw() {
+ fix_scrollbar_order();
+ int X,Y,W,H; bbox(X,Y,W,H);
+
+ uchar d = damage();
+
+ if (d & 128) { // full redraw
+ draw_box(box(),x(),y(),w(),h(),color());
+ draw_clip(this, X, Y, W, H);
+ } else {
+ if (d & 2) { // scroll the contents:
+ fl_scroll(X, Y, W, H, oldx-xposition_, oldy-yposition_, draw_clip, this);
+ }
+ if (d & 1) { // draw damaged children
+ fl_clip(X, Y, W, H);
+ Fl_Widget*const* a = array();
+ for (int i=children()-2; i--;) update_child(**a++);
+ fl_pop_clip();
+ }
+ }
+
+ // accumulate bounding box of children:
+ int l = X; int r = X; int t = Y; int b = Y;
+ Fl_Widget*const* a = array();
+ for (int i=children()-2; i--;) {
+ Fl_Object* o = *a++;
+ if (o->x() < l) l = o->x();
+ if (o->y() < t) t = o->y();
+ if (o->x()+o->w() > r) r = o->x()+o->w();
+ if (o->y()+o->h() > b) b = o->y()+o->h();
+ }
+
+ // turn the scrollbars on and off as necessary:
+ for (int z = 0; z<2; z++) {
+ if ((type()&VERTICAL) && (type()&ALWAYS_ON || t < Y || b > Y+H)) {
+ if (!scrollbar.visible()) {
+ scrollbar.set_visible();
+ W -= scrollbar.w();
+ d = 128;
+ }
+ } else {
+ if (scrollbar.visible()) {
+ scrollbar.clear_visible();
+ draw_clip(this,
+ scrollbar.align()&FL_ALIGN_LEFT ? X-scrollbar.w() : X+W,
+ Y, scrollbar.w(), H);
+ W += scrollbar.w();
+ d = 128;
+ }
+ }
+ if ((type()&HORIZONTAL) && (type()&ALWAYS_ON || l < X || r > X+W)) {
+ if (!hscrollbar.visible()) {
+ hscrollbar.set_visible();
+ H -= hscrollbar.h();
+ d = 128;
+ }
+ } else {
+ if (hscrollbar.visible()) {
+ hscrollbar.clear_visible();
+ draw_clip(this, X,
+ scrollbar.align()&FL_ALIGN_TOP ? Y-hscrollbar.h() : Y+H,
+ W, hscrollbar.h());
+ H += hscrollbar.h();
+ d = 128;
+ }
+ }
+ }
+
+ scrollbar.resize(scrollbar.align()&FL_ALIGN_LEFT ? X-scrollbar.w() : X+W,
+ Y, scrollbar.w(), H);
+ scrollbar.value(oldy = yposition_ = Y, H, t, b-t);
+
+ hscrollbar.resize(X,
+ scrollbar.align()&FL_ALIGN_TOP ? Y-hscrollbar.h() : Y+H,
+ W, hscrollbar.h());
+ hscrollbar.value(oldx = xposition_ = X, W, l, r-l);
+
+ // draw the scrollbars:
+ if (d & 128) {
+ draw_child(scrollbar);
+ draw_child(hscrollbar);
+ if (scrollbar.visible() && hscrollbar.visible()) {
+ // fill in the little box in the corner
+ fl_color(color());
+ fl_rectf(scrollbar.x(), hscrollbar.y(), scrollbar.w(), hscrollbar.h());
+ }
+ } else {
+ update_child(scrollbar);
+ update_child(hscrollbar);
+ }
+}
+
+void Fl_Scroll::resize(int X, int Y, int W, int H) {
+ fix_scrollbar_order();
+ // move all the children:
+ Fl_Widget*const* a = array();
+ for (int i=children()-2; i--;) {
+ Fl_Object* o = *a++;
+ o->position(o->x()+X-x(), o->y()+Y-y());
+ }
+ Fl_Widget::resize(X,Y,W,H);
+}
+
+void Fl_Scroll::position(int X, int Y) {
+ int dx = xposition_-X;
+ int dy = yposition_-Y;
+ if (!dx && !dy) return;
+ xposition_ = X;
+ yposition_ = Y;
+ Fl_Widget*const* a = array();
+ for (int i=children(); i--;) {
+ Fl_Widget* o = *a++;
+ if (o == &hscrollbar || o == &scrollbar) continue;
+ o->position(o->x()+dx, o->y()+dy);
+ }
+ damage(2);
+}
+
+void Fl_Scroll::hscrollbar_cb(Fl_Widget* o, void*) {
+ Fl_Scroll* s = (Fl_Scroll*)(o->parent());
+ s->position(int(((Fl_Scrollbar*)o)->value()), s->yposition());
+}
+
+void Fl_Scroll::scrollbar_cb(Fl_Widget* o, void*) {
+ Fl_Scroll* s = (Fl_Scroll*)(o->parent());
+ s->position(s->xposition(), int(((Fl_Scrollbar*)o)->value()));
+}
+
+#define SLIDER_WIDTH 17
+
+Fl_Scroll::Fl_Scroll(int X,int Y,int W,int H,const char* L)
+ : Fl_Group(X,Y,W,H,L),
+ scrollbar(X+W-SLIDER_WIDTH,Y,SLIDER_WIDTH,H-SLIDER_WIDTH),
+ hscrollbar(X,Y+H-SLIDER_WIDTH,W-SLIDER_WIDTH,SLIDER_WIDTH) {
+ type(BOTH);
+ xposition_ = 0;
+ yposition_ = 0;
+ hscrollbar.type(FL_HORIZONTAL);
+ hscrollbar.callback(hscrollbar_cb);
+ scrollbar.callback(scrollbar_cb);
+}
+
+int Fl_Scroll::handle(int event) {
+ fix_scrollbar_order();
+ return Fl_Group::handle(event);
+}
+
+// end of Fl_Scroll.C