Allright. There are a few misunderstanding in your code. You are actually 
creating a lot more work for yourself than needed.

I added comments inside your code:

On 09.04.2010, at 21:33, w. szukalski wrote:

> #include <stdlib.h>
> #include <stdio.h>
> #include <string.h>
> #include <unistd.h>
> 
> #include <FL/Fl.H>
> #include <FL/fl_draw.H>
> #include <FL/Enumerations.H>
> #include <FL/Fl_Widget.H>
> #include <FL/Fl_Double_Window.H>
> #include <FL/Fl_Image.H>
> #include <FL/Fl_Shared_Image.H>
> #include <FL/Fl_Group.H>
> #include <FL/Fl_Scrollbar.H>
> #include <FL/x.H>
> 
> #define CLICK_STEP 16
> #define CURSOR_STEP 16
> #define PAGE_STEP 64
> 
> #define DEFAULT_BACKGROUND FL_LIGHT1
> #define DEFAULT_CANVAS_BACKGROUND FL_DARK2
> 
> static Fl_Double_Window *main_win;
> static int win_w, win_h;
> 
> /*============================*/
> #define MAX_CLIP_W 700
> #define MAX_CLIP_H 300
> /*============================*/
> #define BAR_SIZE 17
> 
> #define WIN_X 50
> #define WIN_Y 50
> 
> #define CANVAS_MIN_W 5
> #define CANVAS_MIN_H 5
> #define BORDER_SIZE 5
> #define BUTTON_W 80
> #define BUTTON_H 25
> 
> #define NG_GROUP_W BUTTON_W*5 + 4
> #define NG_GROUP_H BUTTON_H + 4
> 
> #define HEADER_H 69
> #define HEADER_W NG_GROUP_W + 2 * (BUTTON_W + 10)
> 
> #define WINDOW_MIN_W HEADER_W + BORDER_SIZE + BORDER_SIZE
> #define WINDOW_MIN_H HEADER_H + CANVAS_MIN_H + BORDER_SIZE
> 
> #ifdef DEBUG_DRAW
> static int draw_count;
> #endif
> 
> 
> class Canvas: public Fl_Group
> {

OK, this is a good idea. By deriving from Group, your scroll bars can handle 
themselves and need no attention from you.

>    virtual void draw();

Allright, overriding draw() allows to draw your graphics

>    unsigned int iwidth, iheight;
>    Fl_Shared_Image *sim, *new_sim;
>    Fl_Scrollbar *vbar, *hbar;
>    int handle(int);
>    Fl_Color bgc;
>    int has_bgc, clip_w, clip_h, drag_x, drag_y;
>    unsigned char bgred, bggreen, bgblue;
> public:
>    Canvas(int x,int y,int w,int h, const char *l);
> 
>    Fl_Double_Window *win;
> 
>    int vbar_min_y, vbar_max_y;
>    int hbar_min_x, hbar_max_x;
> 
>    void draw_sim(const char *n);
> 
>    void put_bgcolor(unsigned char r, unsigned char g, unsigned char b)
>   {
>    bgred = r; bggreen = g; bgblue = b; has_bgc = 1;
>   }
> };
> 
> 
> Canvas::Canvas(int view_x,int view_y,int view_w,int view_h,const char *l)
>       :Fl_Group(view_x, view_y, view_w, view_h, l)
> {
> //AUTO IN FLTK13:     begin();
> 
> //    color(DEFAULT_CANVAS_BACKGROUND);
>       box(FL_FLAT_BOX);
>       sim = new_sim = NULL;
>       iwidth = iheight = 0;
>       bgc = FL_RED; has_bgc = 0;
> 
>       vbar = new Fl_Scrollbar(view_w - BAR_SIZE, 0, BAR_SIZE, view_h - 
> BAR_SIZE);
>       vbar->value(0, view_h, 0, CANVAS_MIN_H);
>       vbar->step(8.0);
>       vbar->align(FL_ALIGN_RIGHT);
>       vbar->type(FL_VERTICAL);
>       vbar->linesize(PAGE_STEP);
> 
>       hbar = new Fl_Scrollbar(0, view_h - BAR_SIZE, view_w - BAR_SIZE, 
> BAR_SIZE);
>       hbar->value(0, view_w, 0, CANVAS_MIN_W);
>       hbar->step(8.0);
>       hbar->align(FL_ALIGN_BOTTOM);
>       hbar->type(FL_HORIZONTAL);
>       hbar->linesize(PAGE_STEP);
> 
>       vbar_min_y = BAR_SIZE;
>       vbar_max_y = vbar->h() - BAR_SIZE;
>       hbar_min_x = BAR_SIZE;
>       hbar_max_x = hbar->w() - BAR_SIZE;
> 
>       clip_w = clip_h = 0;
>       drag_x = drag_y = 0;
>       fl_register_images();
>       win = main_win;
> 
>       end();
> }
> static Canvas *canvas;
> 
> int Canvas::handle(int event)
> {

OK, this is where the work starts...

>       int ex, ey, scroll_x, scroll_y, ek, max, dx, dy, step;
> 
>       if(!Fl::event_inside(x(), y(), w(), h() ) ) return 0;

Remove this line. Many events set no event position (Keyboard events for 
example). This call will keep keyboard events from your widget.

>       if(!hbar->visible() && !vbar->visible()) return 1;

You can do this (although it is obsolete, see below). However, returning 1 is 
false. This will eat up all events, even if FLTK was only checking if you would 
take a KEYBOARD event. By returning 1, the event will not be resent as a 
SHORTCUT and your menubar won't work, for example.

Instead, return to the original handle:
  return Fl_Group::handle(event);

>       ex = Fl::event_x(); ey = Fl::event_y(); step = 0;
> 
>       switch(event)
>   {
>       case FL_PUSH://event_key():LeftButton==1,MiddleButton==2,RightButton==3
> /*==================*/
> /* VBAR EVENT: */
>       if(vbar->visible()
>       && ex >= vbar->x()
>       && ex < vbar->x() + vbar->w()
>       && ey >= vbar->y()
>       && ey < vbar->y() + vbar->h())

There is absolutely no need to do this. If you simply call the original event 
handler instead, your vbar and hbar will do everything you need and better. 
More on that at the end of the function.

>  {
>       scroll_y = vbar->value();
> 
>       if(scroll_y > 0 && ey <= y() + scroll_y + vbar_min_y)
> {
>       step = -CLICK_STEP;
> }
>       else
>       if(ey >= y() + scroll_y + vbar->slider_size())
> {
>       step = CLICK_STEP;
> }
>       max = iheight - clip_h;
> 
>       if(step > 0 && scroll_y >= max) return 1;
>       if(step == 0) return 1;
>       if(step < 0 && scroll_y == 0) return 1;
> 
>       scroll_y += step;
> 
>       if(step > 0 && scroll_y > max)
>        scroll_y = max;
>       else
>       if(scroll_y < 0) scroll_y = 0;
> 
>       vbar->value(scroll_y, clip_h, 0, iheight);
> 
>       return 1;
>  }
> /* HBAR EVENT: */
>       if(hbar->visible()
>       && ex >= hbar->x()
>       && ex < hbar->x() + hbar->w()
>       && ey >= hbar->y()
>       && ey < hbar->y() + hbar->h())

Again, no need to handle a child widget yourself.

>  {
>       scroll_x = hbar->value();
> 
>       if(scroll_x > 0 && ex <= hbar_min_x + scroll_x + x())
> {
>       step = -CLICK_STEP;
> }
>       else
>       if(ex >= scroll_x + hbar->slider_size() + x())
> {
>       step = CLICK_STEP;
> }
>       max = iwidth - clip_w;
> 
>       if(step == 0) return 1;
>       if(step > 0 && scroll_x >= max) return 1;
>       if(step < 0 && scroll_x == 0) return 1;
> 
>       scroll_x += step;
> 
>       if(step > 0 && scroll_x > max)
>        scroll_x = max;
>       else
>       if(scroll_x < 0) scroll_x = 0;
> 
>       hbar->value(scroll_x, clip_w, 0, iwidth);
> 
>       return 1;
>  }
>       break;
> 
>       case FL_MOUSEWHEEL:
> /*==================*/
>       if(vbar->visible() && (dy = Fl::event_dy()))

FLTK will do this for you. Why would you want to do it manually.

>  {
>       max = iheight - clip_h;
>       scroll_y = vbar->value();
> 
>       if(dy < 0 && scroll_y == 0) return 1;
>       if(dy > 0 && scroll_y == max) return 1;
> 
>       scroll_y += dy * CURSOR_STEP;
> 
>       if(scroll_y < 0) scroll_y = 0;
>       else
>       if(scroll_y > max) scroll_y = max;
> 
>       vbar->value(scroll_y, clip_h, 0, iheight);
> 
>       return 1;
>  }
> 
>       if(hbar->visible() && (dx = Fl::event_dx()))
>  {
>       max = iwidth - clip_w;
>       scroll_x = hbar->value();
> 
>       if(dx < 0 && scroll_x == 0) return 1;
>       if(dx > 0 && scroll_x == max) return 1;
> 
>       scroll_x += dx * CURSOR_STEP;
> 
>       hbar->value(scroll_x, clip_w, 0, iwidth);
> 
>       return 1;
>  }
>       return 1;
> 
>       case FL_SHORTCUT:
> /*==================*/
>       ek = Fl::event_key(); scroll_x = hbar->value(); scroll_y = 
> vbar->value();

OK, this may be helpful for your particular application. 

>       if(vbar->visible())
>  {
>       if(ek == FL_Home)
> {
>       if(scroll_y > 0)
>        vbar->value(0, clip_h, 0, iheight);
> 
>       return 1;

Returning 1 is correct here, because you did use up the event. However, you 
only told the Scrollbar to change. To tell the group that a setting change and 
that it need to be drawn again, call
  redraw();
just before calling 
  return 1;

> }
>       if(ek == FL_End)
> {
>       max = iheight - clip_h;
> 
>       if(scroll_y < max)
>        vbar->value(max, clip_h, 0, iheight);
>       return 1;
> }
>       if(ek == FL_Page_Up)
> {
>       if(scroll_y == 0) return 1;
> 
>       if((scroll_y = vbar->value() - vbar->linesize()) < 0) scroll_y = 0;
> 
>       vbar->value(scroll_y, clip_h, 0, iheight);
> 
>       return 1;
> }
>       if(ek == FL_Page_Down)
> {
>       max = iheight - clip_h;
> 
>       if(scroll_y == max) return 1;
> 
>       if((scroll_y = vbar->value() + vbar->linesize()) > max) scroll_y = max;
> 
>       vbar->value(scroll_y, clip_h, 0, iheight);
> 
>       return 1;
> }
> 
>       if(ek == FL_Up)
> {
>       if(scroll_y == 0) return 1;
> 
>       if((scroll_y = vbar->value() - CURSOR_STEP) < 0) scroll_y = 0;
> 
>       vbar->value(scroll_y, clip_h, 0, iheight);
> 
>       return 1;
> }
>       if(ek == FL_Down)
> {
>       max = iheight - clip_h;
> 
>       if(scroll_y == max) return 1;
> 
>       if((scroll_y = vbar->value() + CURSOR_STEP) > max) scroll_y = max;
> 
>       vbar->value(scroll_y, clip_h, 0, iheight);
> 
>       return 1;
> }
>  }    /* if(vbar->visible()) */
> 
>       if(hbar->visible())
>  {
>       if(ek == FL_Left)
> {
>       if(scroll_x == 0) return 1;
> 
>       if((scroll_x = hbar->value() - CURSOR_STEP) < 0) scroll_x = 0;
> 
>       hbar->value(scroll_x, clip_w, 0, iwidth);
> 
>       return 1;
> }
>       if(ek == FL_Right)
> {
>       max = iwidth - clip_w;
> 
>       if(scroll_x == max) return 1;
> 
>       if((scroll_x = hbar->value() + CURSOR_STEP) > max) scroll_x = max;
> 
>       hbar->value(scroll_x, clip_w, 0, iwidth);
> 
>       return 1;
> }
>  }
>       break;
> 
>       case FL_DRAG:
> 

Again, no need to do all this by foot. Remove it.

> /* VBAR EVENT: */
>    if(vbar->visible()
>       && ex >= vbar->x()
>       && ex < vbar->x() + vbar->w()
>    && ey >= vbar->y()
>       && ey < vbar->y() + vbar->h())
>  {
>       if(ey > drag_y)
>        step = 3;
>       else
>       if(ey < drag_y)
>        step = -3;
>       else
>        return 1;
> 
>       drag_y = ey;
>       scroll_y = vbar->value();
>       max = iheight - clip_h;
> 
>    if(step > 0 && scroll_y >= max) return 1;
>    if(step == 0) return 1;
>    if(step < 0 && scroll_y == 0) return 1;
> 
>    scroll_y += step;
> 
>    if(step > 0 && scroll_y > max)
>     scroll_y = max;
>    else
>    if(scroll_y < 0) scroll_y = 0;
> 
>    vbar->value(scroll_y, clip_h, 0, iheight);
> 
>    return 1;
> 
>  }
> /* HBAR EVENT: */
>    if(hbar->visible()
>       && ex >= hbar->x()
>       && ex < hbar->x() + hbar->w()
>    && ey >= hbar->y()
>       && ey < hbar->y() + hbar->h())
>  {
>       if(ex > drag_x)
>        step = 3;
>       else
>       if(ex < drag_x)
>        step = -3;
>       else
>        return 1;
> 
>       drag_x = ex;
>       scroll_x = hbar->value();
>       max = iwidth - clip_w;
> 
>       if(step > 0 && scroll_x >= max) return 1;
>       if(step == 0) return 1;
>       if(step < 0 && scroll_x == 0) return 1;
> 
>       scroll_x += step;
> 
>       if(step > 0 && scroll_x > max)
>        scroll_x = max;
>       else
>       if(scroll_x < 0) scroll_x = 0;
> 
>       hbar->value(scroll_x, clip_w, 0, iwidth);
> 
>       return 1;
>  }
>       default: break;
> /*==================*/
>   }
>       return (Fl_Group::handle(event));

All right, this one is correct. It will handle all the scroll bars for you. 
There is just one thing you need to do with the scrollbars: When their value 
changes, the Group needs to be redrawn. Add a callbakc to the scrollbar just 
after creating the bar:

  vbar->callback(vbar_changed, my_canvas);

Then, add a shortcut. It needs to be static if it is part of your class:

  void vbar_changed(Fl_Widget *w, void *d) {
    Canvas *cv = (Canvas*)d;
    cv->redraw();
  }

> 
> }/* Canvas::handle() */


The rest of the code is fine.

 - Matthias
_______________________________________________
fltk mailing list
[email protected]
http://lists.easysw.com/mailman/listinfo/fltk

Reply via email to