/* Emacs, this is -*- C++ -*- */

#ifndef _PAGEOBJECT_H_
#define _PAGEOBJECT_H_


#include <qobject.h>
#include <qwidget.h>
#include <qrect.h>
#include <qpainter.h>
#include <qfile.h>


class Page;
class TreeItem;

/** Something that can be on a page.


	A PageObject is an object (a QObject, to be precise) that is
	on a page. (Thus the name.) Examples for a PageObject are Plots
	or (yet to be implemented) Arrows and Texts.

	The PageObject class defines the interface of all objects that
	can be on a page, plus it defines some common properties, e.g.
	the area an object covers on the page.

	@see #Page where PageObject´s are on.
	@see #Plot an example for a PageObject.
	@author Patrick Schemitz
*/

class PageObject : public QObject
{
  Q_OBJECT

public:

  /** Construct a page object.

	  Set all values to zero.
  */
  PageObject ();

  /** Destruct the page object.

	  This deletes the tree item.
  */
  ~PageObject ();

  /** The PageObject´s QObject.

	  Usually, this will just return a "this" pointer, and this
	  is the default implementation. This is unlikely to change.
  */
  virtual QObject* object () { return this; }

  /** The PageObject´s QWidget.

	  Every PageObject must have a QWidget in order to paint itself.

	  However, not every PageObject *is* a QWidget. A Plot, for
	  example, can *not* be a QWidget, because QWidgets cannot be
	  constructed before the QApplication has started. But the Plot
	  prototypes are constructed when they register themself to the
	  Plots() list, before main(). Thus, I´ve separated the object
	  from the widget. See the Plot implementation for the details.

	  PageObjects that *are* QWidgets may of course return "this"
	  as in object().

	  @see #Plot why widget() and object() are separated.
  */
  virtual QWidget* widget () = 0;

  /** Paint yourself on a QPainter.

	  Every PageObject must be able to paint itself on a given
	  QPainter. This may be the page window as well as a printer.
  */
  virtual void paint (QPainter*) = 0;

  /** A mouse press event in the PageObject.

	  When a mouse button is pressed in a page, the page checks
	  if there is a PageObject at the click position, and if there
	  is, passes on the QMouseEvent (after a transformation to
	  the widget´s coordiates).
  */
  virtual void mousePressEvent (QMouseEvent*) = 0;

  /** Tree entry for the PageObject.

	  Since PageObjects show up in the tree list, they must
	  provide a TreeItem entry.

	  When first invoked, the default implementation creates a
	  TreeItem and sets the pixmap to icon() and the text to
	  description(). This tree item is then returned. When you
	  don´t like this, you can redefine treeitem() or you can
	  change the tree item in your constructor:

	  treeitem()->setPixmap(myPixmap);
	  treeitem()->setText("Hello World");
  */
  virtual TreeItem* treeitem ();

  /** Called when the PageObject is about to become "active".

	  Some PageObjects, like Plots, have an activePlot pointer
	  which points to the "active" Plot. This is used to update
	  the main menu "Plot" entry.

	  The default implementation of this function just does nothing.
	  If your PageObject subclass has something like an activePlot,
	  you will have to reimplement it. If it doesn´t, just leave
	  this implementation.

	  @see #deactivate() the antagonist.
  */
  virtual void activate () {}

  /** Called when the PageObject is about to become "inactive".

	  See activate() for detailed description.

	  @see #activate() the agonist.
  */
  virtual void deactivate () {}

  /** Icon for the PageObject.

	  Every PageObject must provide one or two icon(s).
	  Depending on the type of the PageObject, you might
	  want separate icons for the active object and for the
	  inactive objects (Plots for example).

	  @see #changedTreeItem()
  */	  
  virtual QPixmap* icon () = 0;

  /** Gives a short description of the PageObject.

	  Every PageObject must provide a short description of
	  itself.
  */
  virtual const char* description () = 0;

  /** Store the PageObject to an already open QFile.

	  Every PageObject must be able to store itself to a file,
	  as well as to restore itself from a QFile.

	  The rules for storing/restoring are the following:
	  Your PageObject reads from the already opened QFile
	  until it hits a selfdefined end mark. You must make
	  sure that the complete entry of your PageObject is read,
	  since the QFile might contain multiple objects. When
	  you store a PageObject, you must make sure that you set
	  a unique end mark that your restore() function recognizes.

	  When Korigin writes objects to a file, it first writes the
	  class name, className(), to the file and then invokes the
	  class´s store() function. Then it writes the next object´s
	  className(), then invokes store() etc. Now when it comes to
	  read a file, Korigin reads the first line, interprets it as
	  the class name, instantiates the corresponding class and lets
	  the new instance restore() itself from the file. Then it reads
	  the next line and again interprets it as a class name...
	  You see, if your restore() function stops reading at the right
	  place, everything gets messed up. So be careful!

	  @see #restore()
  */
  virtual bool store (QFile&);

  /** Store the PageObject to an already open QFile.

	  Every PageObject must be able to store itself to a file,
	  as well as to restore itself from a QFile.

	  See @ref store for a detailed description of store/restore
	  mechanism.

	  @see #store()
  */
  virtual bool restore (QFile&);

  /** Returns the page the plot is on.

	  This is already implemented for you.

	  @see #setPage()
  */
  Page* page () { return the_page; }

  /** Set the page the plot is on.

	  This is already implemented for you.

	  @see #page()
  */
  void setPage (Page* p) { the_page = p; }

  /** Get the PageObject´s position on the page.

	  This is already implemented for you.

	  @see #setPosition()
  */
  void position (float& x, float& y) { x=the_x_pos, y=the_y_pos; }

  /** Set the PageObject´s position on the page.

	  This is already implemented for you.

	  @see #position()
  */
  void setPosition (float x, float y) { the_x_pos=x, the_y_pos=y; }

  /** Return the rectangle the PageObject occupies, in screen pixels.

	  This returns the area of the PageObject in real, screen pixels,
	  relative to the Page widget. This is needed when checking whether
	  a mouse click was in a PageObject or not. (Mouse positions are
	  in screen pixels, of course.) The physical area depends on the
	  size of the Page window.

	  There is also a virtual page resolution, independent of the Page
	  window size.

	  @see #virtual_area()
  */
  QRect pixel_area ();

  /** Return the rectangle the PageObject occupies, in virtual units.

	  These virtual units do not depend on the size of the Page window,
	  as the physical area, pixel_area(), does. The virtual size is
	  determinated by the page´s paper size (A4, Legal etc.), and the
	  assumed printer resolution. (Currently fixed to 300 dpi.)

	  @see #pixel_area()
  */
  QRect virtual_area ();

signals:

  /** Emitted when the page object changed its tree item.

	  For instance, when the icon is toggled from active to
	  inactive or vice versa. It is your concrete PageObject
	  subclass which must emit this signal.

	  This signal is connected to the tree view via the
	  PageObject´s page.
  */
  void changedTreeItem ();

protected:

  /** The PageObject´s tree item.

	  Usually, you won´t have to touch this directly. Specifically,
	  you shouldn´t delete it!
  */
  TreeItem* the_treeitem;

private:

  /// The PageObject´s page.
  Page* the_page;

  /// X position of the PageObject on it´s page.
  float the_x_pos;

  /// Y position of the PageObject on it´s page.
  float the_y_pos;
};

#endif

Documentation generated by patrick@nemesis on Tue Feb 10 23:05:12 MET 1998