From: ggu@chpc.org (Gary G. Gu)
Newsgroups: comp.windows.interviews
Subject: Help! Image, raster, redraw (maybe a bug in Image?)
Date: 2 Oct 92 20:11:27 GMT
Distribution: na
Organization: CHPC

Please help if you've had some experience with ivImage. Thank you.
I am using IV 3.1 beta.

In a program I'm writing, I need the ability to redraw different images
everytime an event occurs. To that end, I've written two small programs,
which are included below. The first program toggles between a big circle
and a small circle each time a push button is pressed. The second does
similar things (if it works) between two images. The first works, but the
second does not. The only difference is one uses Image and the other does 
not. If the programs are compiled to be `a.out', type `a.out' to run the
first and `a.out img1.tif img2.tif' the second. You need to have two
TIFF images.

My question: why does the first program work, but not the second?
It appears that the redraw function in Image might be writing over
the memory area allocated for Raster. Any help and/or suggestions are
appreciated. Thank you.

------------ toggle circle program ---------------
#include <IV-look/kit.h>
#include <InterViews/layout.h>
#include <InterViews/session.h>
#include <InterViews/window.h>
#include <InterViews/patch.h>
#include <InterViews/brush.h>
#include <InterViews/canvas.h>
#include <InterViews/color.h>

class Circle : public Glyph {
public:
    Circle(Coord radius, const Color*, const Brush*);
    virtual ~Circle();

    virtual void request(Requisition&) const;
    virtual void allocate(Canvas*, const Allocation&, Extension&);
    virtual void draw(Canvas*, const Allocation&) const;
private:
    Coord radius_;
    const Color* color_;
    const Brush* brush_;
};

Circle::Circle(Coord r, const Color* c, const Brush* b) {
    radius_ = r;
    Resource::ref(c);
    color_ = c;
    Resource::ref(b);
    brush_ = b;
}

Circle::~Circle() {
    Resource::unref(color_);
    Resource::unref(brush_);
}

void Circle::request(Requisition& req) const {
    Coord diameter = radius_ + radius_;
    Requirement rx(diameter, 0, 0, 0.5);
    Requirement ry(diameter, 0, 0, 0.5);
    req.require(Dimension_X, rx);
    req.require(Dimension_Y, ry);
}

void Circle::allocate(Canvas* c, const Allocation& a, Extension& ext) {
    ext.merge(c, a);
}

void Circle::draw(Canvas* c, const Allocation& a) const {
    const Coord r = radius_, x = a.x(), y = a.y();
    const Coord p0 = 1.00000000 * r;
    const Coord p1 = 0.89657547 * r;   // cos 30 * sqrt(1 + tan 15 * tan 15)
    const Coord p2 = 0.70710678 * r;   // cos 45
    const Coord p3 = 0.51763809 * r;   // cos 60 * sqrt(1 + tan 15 * tan 15)
    const Coord p4 = 0.26794919 * r;   // tan 15
    c->new_path();
    c->move_to(x+p0, y);
    c->curve_to(x+p2, y+p2, x+p0, y+p4, x+p1, y+p3);
    c->curve_to(x, y+p0, x+p3, y+p1, x+p4, y+p0);
    c->curve_to(x-p2, y+p2, x-p4, y+p0, x-p3, y+p1);
    c->curve_to(x-p0, y, x-p1, y + p3, x-p0, y+p4);
    c->curve_to(x-p2, y-p2, x-p0, y-p4, x-p1, y-p3);
    c->curve_to(x, y-p0, x-p3, y-p1, x-p4, y-p0);
    c->curve_to(x+p2, y-p2, x+p4, y-p0, x+p3, y-p1);
    c->curve_to(x+p0, y, x+p1, y-p3, x+p0, y-p4);
    c->close_path();
    c->stroke(color_, brush_);
}

class App {
public:
  App();
  Glyph* make(WidgetKit&);
  void action();
private:
  Patch* patch_;
  Coord one;
  Coord two;
};

declareActionCallback(App)
implementActionCallback(App)

App::App()
{
  one = 70;
  two = 50;
}

Glyph* App::make(WidgetKit& kit) 
{
  patch_ = new Patch( new Circle(one, kit.foreground(), new Brush(1.0)) );
  return patch_;
}

void
App::action ()
{
  WidgetKit& kit = *WidgetKit::instance();

  patch_->body( new Circle(two, kit.foreground(), new Brush(1.0)));
  patch_->reallocate();
  patch_->redraw();

  Coord tmp = one;
  one = two;
  two = tmp;
}

int 
main(int argc, char** argv) 
{
  Session* session = new Session("Image", argc, argv);
  WidgetKit& kit = *WidgetKit::instance();
  const LayoutKit& layout = *LayoutKit::instance();

  App* a = new App();
  session->run_window(
    new ApplicationWindow(
      layout.vcenter(
         kit.inset_frame(
            layout.vbox(
              kit.push_button(
                  "pushme",
	          new ActionCallback(App) (a, &App::action)
              ),
              layout.vglue(),
	      a->make(kit)
            )
         ),
       1.0
     )
   )
  );
}
--------------- end of program 1 --------------


--------- toggle two tiff images ---------------
#include <IV-look/kit.h>
#include <InterViews/layout.h>
#include <InterViews/session.h>
#include <InterViews/window.h>
#include <InterViews/tiff.h>
#include <InterViews/image.h>
#include <InterViews/patch.h>

class App {
public:
  App(int argc, char** argv);
  Glyph* make(WidgetKit&);
  void action();
private:
  Patch* patch_;
  Raster* one;
  Raster* two;
};

declareActionCallback(App)
implementActionCallback(App)

App::App(int argc, char** argv)
{
  one = TIFFRaster::load(argv[1]);
  two = TIFFRaster::load(argv[2]);
}

Glyph* App::make(WidgetKit& kit) 
{
  patch_ = new Patch( new Image(one) );
  return patch_;
}

void App::action ()
{
  patch_->body( new Image(two) );
  patch_->reallocate();
  patch_->redraw();
  Raster* tmp = one;   // swap pointers to Raster
  one = two;
  two = tmp;
}

int 
main(int argc, char** argv) 
{
  Session* session = new Session("Image", argc, argv);
  WidgetKit& kit = *WidgetKit::instance();
  const LayoutKit& layout = *LayoutKit::instance();

  App* a = new App(argc, argv);
  session->run_window(
    new ApplicationWindow(
      layout.vcenter(
        kit.outset_frame(
          layout.margin(
            layout.vbox(
                kit.push_button(
                  "pushme",
	          new ActionCallback(App) (a, &App::action)
                ),
              layout.vglue(),
	      a->make(kit)
            ),
            5.0
          )
         ),
         1.0
       )
    )
  );
}
------------ end of program 2 ----------------