From: patz@ipc1.rrzn.uni-hannover.de (Frank Patz)
Newsgroups: comp.windows.interviews
Subject: 2D scrolling?
Date: 18 Aug 92 20:10:20 GMT
Organization: RRZN
X-Newsreader: Tin 1.1 PL4

InterViews 3.1 beta

I've tried to code a 2D scrollbox "Viewer", based on TransformSetter
and Adjustable (see code below). Several weeks ago i've found this
approach in this group.  The Viewer should be able to show (=draw),
pick() a.s.o. PART of its body(), and to scroll this partial view over
the whole extent, i.e. the usual "window-with-scrollbars" model.
TransformSetter translates Viewer::body() by some vector
(Viewer::xform()) and during draw(), the canvas is clipped to the
Viewer's Extension. I thought (8-() this were the obvious solution
using InterViews.  Unfortunately "Viewer" does not work if it is not
the only glyph in its window or if the window is resized (i've made it
flexible w/ LayoutKit::flexible()) or if you put any Glyph in it,
except very special(=easy) ones...  Most problems are related with
allocate(), wich gives sometimes an Allocation with span = 0 or funny
alignments. Others are related with the Viewer contents, coming up
with different symptoms.

After spending lots of hours with that code: Can it be done
this way? If not, HOW can it be done?

thank you, frank
--- cut here ---
// viewer.h
#include <InterViews/patch.h>
#include <InterViews/adjust.h>
#include <InterViews/tformsetter.h>

class Viewer : public Patch, public Adjustable {
public:
  Viewer(Glyph*);
  virtual Coord lower(DimensionName) const;
  virtual Coord upper(DimensionName) const;
  virtual Coord length(DimensionName) const;
  virtual Coord cur_lower(DimensionName) const;
  virtual Coord cur_upper(DimensionName) const;
  virtual Coord cur_length(DimensionName) const;
  virtual void scroll_forward(DimensionName);
  virtual void scroll_backward(DimensionName);
  virtual void page_forward(DimensionName);
  virtual void page_backward(DimensionName);
  virtual void scroll_to(DimensionName, Coord lower);
  virtual void draw(Canvas*, const Allocation&) const;
  virtual void allocate(Canvas*, const Allocation&, Extension&);
private:
  void xform();
  Coord   _dx, _dy;
  Coord   _scroll_incr, _page_incr;
  TransformSetter* _xform;
};

// viewer.c
#include <InterViews/canvas.h>
#include <InterViews/layout.h>
#include "viewer.h"

Viewer::Viewer(Glyph* g) : Patch(_xform = new TransformSetter(g))
{ _dx = 0;
  _dy = 0;
  Transformer t(1,0,0,1,_dx,_dy);
  _xform->transformer(t);
  _scroll_incr = 25.5;   // my age
  _page_incr   = 51;     // ... twice 
}

void Viewer::allocate(Canvas *c, const Allocation& a, Extension& e)
{ 
  Patch::allocate(c,a,e);
  Coord xofs = (_dx + cur_length(Dimension_X)) - length(Dimension_X);
  if (xofs > 0) _dx -= xofs;
  Coord yofs = (_dy + cur_length(Dimension_Y)) - length(Dimension_Y);
  if (yofs > 0) _dy -= yofs;
  xform();
  notify(Dimension_X);
  notify(Dimension_Y);
}

void Viewer::draw(Canvas *c, const Allocation& a) const 
{
  Extension e;
  e.set(c,a);
  c->push_clipping();
  c->push_transform();
  c->transformer(Transformer());
  c->clip_rect(e.left(), e.bottom(), e.right(), e.top());
  c->pop_transform();
  Patch::draw(c,a);
  c->pop_clipping();
}

void Viewer::xform()
{
  Transformer t(1,0,0,1,
		-_dx, 
		(length(Dimension_Y) - (cur_length(Dimension_Y) + _dy)));

  _xform->transformer(t);
}

Coord Viewer::lower(DimensionName d) const
{
  return 0;
}

Coord Viewer::upper(DimensionName d) const
{
  Requisition r;
  body()->request(r);
  if (d == Dimension_X) return r.x_requirement().natural();
  if (d == Dimension_Y) return r.y_requirement().natural();
  return 0;
}

Coord Viewer::length(DimensionName d) const
{
  return upper(d) - lower(d);
}

Coord Viewer::cur_lower(DimensionName d) const
{
  if (d == Dimension_X) return _dx;
  if (d == Dimension_Y) return _dy;
  return 0;
}

Coord Viewer::cur_upper(DimensionName d) const
{
  if (d == Dimension_X) return _dx + cur_length(d);
  if (d == Dimension_Y) return _dy + cur_length(d);
  return 0;
}

Coord Viewer::cur_length(DimensionName d) const
{
  if (d == Dimension_X) return allocation().x_allotment().span();
  if (d == Dimension_Y) return allocation().y_allotment().span();
  return 0;
}

void Viewer::scroll_forward(DimensionName d)
{
  if (d == Dimension_X) scroll_to(d, _dx + _scroll_incr);
  if (d == Dimension_Y) scroll_to(d, _dy + _scroll_incr);
}

void Viewer::scroll_backward(DimensionName d)
{
  if (d == Dimension_X) scroll_to(d, _dx - _scroll_incr);
  if (d == Dimension_Y) scroll_to(d, _dy - _scroll_incr);
}


void Viewer::page_forward(DimensionName d)
{
  if (d == Dimension_X) scroll_to(d, _dx + _page_incr);
  if (d == Dimension_Y) scroll_to(d, _dy + _page_incr);
}

void Viewer::page_backward(DimensionName d)
{
  if (d == Dimension_X) scroll_to(d, _dx - _page_incr);
  if (d == Dimension_Y) scroll_to(d, _dy - _page_incr);
}

void Viewer::scroll_to(DimensionName d, Coord p)
{
  constrain(d, p);
  if (d == Dimension_X) _dx = p;
  if (d == Dimension_Y) _dy = p;

  xform();

  reallocate();
  redraw();
  notify(d);
}
-- 
frank patz/softwarelabor/lg rechnernetze und verteilte systeme
uni hannover/germany
<patz@rvs.uni-hannover.dbp.de>