
(********************************************************************)
(*                                                                  *)
(*  graph.s7i     Basic graphic library                             *)
(*  Copyright (C) 1994, 1995, 2004, 2005  Thomas Mertes             *)
(*                                                                  *)
(*  This file is part of the Seed7 Runtime Library.                 *)
(*                                                                  *)
(*  The Seed7 Runtime Library is free software; you can             *)
(*  redistribute it and/or modify it under the terms of the GNU     *)
(*  Lesser General Public License as published by the Free Software *)
(*  Foundation; either version 2.1 of the License, or (at your      *)
(*  option) any later version.                                      *)
(*                                                                  *)
(*  The Seed7 Runtime Library is distributed in the hope that it    *)
(*  will be useful, but WITHOUT ANY WARRANTY; without even the      *)
(*  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(*  PURPOSE.  See the GNU Lesser General Public License for more    *)
(*  details.                                                        *)
(*                                                                  *)
(*  You should have received a copy of the GNU Lesser General       *)
(*  Public License along with this program; if not, write to the    *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


include "float.s7i";
include "bstring.s7i";


const type: PRIMITIVE_WINDOW is newtype;

IN_PARAM_IS_REFERENCE(PRIMITIVE_WINDOW);

const proc: (ref PRIMITIVE_WINDOW: dest) ::= (in PRIMITIVE_WINDOW: source)     is action "DRW_CREATE";
const proc: destroy (ref PRIMITIVE_WINDOW: aValue)                             is action "DRW_DESTR";
const proc: (inout PRIMITIVE_WINDOW: dest) := (in PRIMITIVE_WINDOW: source)    is action "DRW_CPY";
const func boolean: (in PRIMITIVE_WINDOW: win1) = (in PRIMITIVE_WINDOW: win2)  is action "DRW_EQ";
const func boolean: (in PRIMITIVE_WINDOW: win1) <> (in PRIMITIVE_WINDOW: win2) is action "DRW_NE";
const func PRIMITIVE_WINDOW: _GENERATE_EMPTY_WINDOW                            is action "DRW_EMPTY";
const PRIMITIVE_WINDOW: (attr PRIMITIVE_WINDOW) . value                        is _GENERATE_EMPTY_WINDOW;
(*
const func PRIMITIVE_WINDOW: (attr PRIMITIVE_WINDOW) conv (in char: ch)        is action "CHR_CONV";
const func char: (attr char) conv (in PRIMITIVE_WINDOW: aWindow)               is action "CHR_CONV";
*)

const type: pixel is newtype;

IN_PARAM_IS_VALUE(pixel);

const proc: (ref pixel: dest) ::= (in pixel: source)       is action "INT_CREATE";
const proc: destroy (ref pixel: aValue)                    is action "GEN_DESTR";
const proc: (inout pixel: dest) := (in pixel: source)      is action "INT_CPY";
const func boolean: (in pixel: pix1) = (in pixel: pix2)    is action "INT_EQ";
const func boolean: (in pixel: pix1) <> (in pixel: pix2)   is action "INT_NE";
const func pixel: (attr pixel) conv (in integer: num)      is action "INT_ICONV3";
const func integer: (attr integer) conv (in pixel: aPixel) is action "INT_ICONV3";
const func integer: ord (in pixel: aPixel)                 is action "INT_ICONV1";
const pixel: (attr pixel) . value                          is pixel conv 0;


const proc: DRAW_POINT (inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y)                   is action "DRW_POINT";
const proc: DRAW_PPOINT (inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y,
    in pixel: col)                                  is action "DRW_PPOINT";
const proc: DRAW_LINE (inout PRIMITIVE_WINDOW: aWindow,
    in integer: x1, in integer: y1,
    in integer: x2, in integer: y2)                 is action "DRW_LINE";
const proc: DRAW_PLINE (inout PRIMITIVE_WINDOW: aWindow,
    in integer: x1, in integer: y1,
    in integer: x2, in integer: y2,
    in pixel: col)                                  is action "DRW_PLINE";
const proc: DRAW_RECT (inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y,
    in integer: width, in integer: height)          is action "DRW_RECT";
const proc: DRAW_PRECT (inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y,
    in integer: width, in integer: height,
    in pixel: col)                                  is action "DRW_PRECT";
const proc: DRAW_CIRCLE(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y,
    in integer: radius)                             is action "DRW_CIRCLE";
const proc: DRAW_CIRCLE(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y,
    in integer: radius, in pixel: col)              is action "DRW_PCIRCLE";
const proc: DRAW_CLEAR(inout PRIMITIVE_WINDOW: aWindow,
    in pixel: col)                                  is action "DRW_CLEAR";
const proc: FILL_CIRCLE(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y,
    in integer: radius)                             is action "DRW_FCIRCLE";
const proc: FILL_CIRCLE(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y,
    in integer: radius, in pixel: col)              is action "DRW_PFCIRCLE";
const proc: DRAW_ARC(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y, in integer: radius,
    in float: startAngle, in float: sweepAngle)     is action "DRW_ARC";
const proc: DRAW_ARC(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y, in integer: radius,
    in float: startAngle, in float: sweepAngle,
    in pixel: col)                                  is action "DRW_PARC";
const proc: FILL_ARCCHORD(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y, in integer: radius,
    in float: startAngle, in float: sweepAngle)     is action "DRW_FARCCHORD";
const proc: FILL_ARCCHORD(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y, in integer: radius,
    in float: startAngle, in float: sweepAngle,
    in pixel: col)                                  is action "DRW_PFARCCHORD";
const proc: FILL_ARCPIESLICE(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y, in integer: radius,
    in float: startAngle, in float: sweepAngle)     is action "DRW_FARCPIESLICE";
const proc: FILL_ARCPIESLICE(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y, in integer: radius,
    in float: startAngle, in float: sweepAngle,
    in pixel: col)                                  is action "DRW_PFARCPIESLICE";
const proc: DRAW_ARC2(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x1, in integer: y1, in integer: x2,
    in integer: y2, in integer: radius)             is action "DRW_ARC2";
const proc: FILL_ELLIPSE(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y,
    in integer: width, in integer: height)          is action "DRW_FELLIPSE";
const proc: FILL_ELLIPSE(inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y,
    in integer: width, in integer: height,
    in pixel: col)                                  is action "DRW_PFELLIPSE";
const proc: DRAW_FLUSH                              is action "DRW_FLUSH";
const func PRIMITIVE_WINDOW: PRIMITIVE_GRAPHIC_OPEN (
    ref integer: xPos, ref integer: yPos,
    ref integer: width, ref integer: height,
    ref string: window_name)                        is action "DRW_OPEN";

(**
 *  Create a sub window inside of ''parent_window''.
 *  The new sub window has no window decorations and is not managed by
 *  the window manager. If the empty window is used as ''parent_window''
 *  an unmanaged top level window without window decorations is generated.
 *  The coordinates ''xPos'' and ''yPos'' are measured relative to the top
 *  left corner of the ''parent_window'' drawing area (inside of the window
 *  decorations). If the empty window is used as ''parent_window'' the
 *  coordinates ''xPos'' and ''yPos'' are measured relative to the top left
 *  corner of the screen.
 *  @param parent-window Parent window (can be the empty window).
 *  @param xPos X-position of the left corner of the new window.
 *  @param yPos Y-position of the left corner of the new window.
 *  @param width Width of the new window.
 *  @param height Height of the new window.
 *  @return the new generated window.
 *)
const func PRIMITIVE_WINDOW: openSubWindow (
    in PRIMITIVE_WINDOW: aWindow,
    ref integer: xPos, ref integer: yPos,
    ref integer: width, ref integer: height)        is action "DRW_OPEN_SUB_WINDOW";

const func PRIMITIVE_WINDOW: DRAW_GET (
    in PRIMITIVE_WINDOW: aWindow,
    ref integer: left, ref integer: upper,
    ref integer: width, ref integer: height)        is action "DRW_GET";

(**
 *  Capture a rectangular area from the screen.
 *  The function takes a screenshot of the rectangular area.
 *  The ''left'' and ''upper'' coordinates are measured relative to
 *  the top left corner of the screen.
 *  @param left X-position of the upper left corner of the capture area.
 *  @param upper Y-position of the upper left corner of the capture area.
 *  @param widht Width of the capture area.
 *  @param height Height of the capture area.
 *  @return the content of the rectangular screen area as pixmap.
 *  @exception RANGE_ERROR If ''height'' or ''width'' are negative.
 *)
const func PRIMITIVE_WINDOW: capturePixmap (
    ref integer: left, ref integer: upper,
    ref integer: width, ref integer: height)        is action "DRW_CAPTURE";

const func bstring: getImage (
    in PRIMITIVE_WINDOW: aWindow)                   is action "DRW_GETIMAGE";
const func pixel: getPixel (
    in PRIMITIVE_WINDOW: aWindow,
    ref integer: x, ref integer: y)                 is action "DRW_GETPIXEL";
const func pixel: getPixel (
    in bstring: bImage, in integer: width,
    in integer: height, in integer: x,
    in integer: y)                                  is action "DRW_GETIMAGEPIXEL";
const proc: DRAW_PUT (
    inout PRIMITIVE_WINDOW: aWindow, in PRIMITIVE_WINDOW: pixmap,
    ref integer: x, ref integer: y)                 is action "DRW_PUT";

(**
 *  Copy a rectangular area from ''sourceWindow'' to ''destWindow''.
 *  Coordinates are measured relative to the top left corner of the
 *  corresponding window drawing area (inside of the window decorations).
 *  @param sourceWindow Source window.
 *  @param destWindow Destination window.
 *  @param src_x X-position of the top left corner of the source area.
 *  @param src_y Y-position of the top left corner of the source area.
 *  @param width Width of the rectangular area.
 *  @param height Height of the rectangular area.
 *  @param dest_x X-position of the top left corner of the destination area.
 *  @param dest_y Y-position of the top left corner of the destination area.
 *)
const proc: copyArea (in PRIMITIVE_WINDOW: sourceWindow,
    inout PRIMITIVE_WINDOW: destWindow,
    ref integer: src_x, ref integer: src_y,
    ref integer: width, ref integer: height,
    ref integer: dest_x, ref integer: dest_y)       is action "DRW_COPYAREA";

const proc: SET_TRANSPARENTCOLOR (in PRIMITIVE_WINDOW: pixmap,
    ref pixel: col)                                 is action "DRW_SETTRANSPARENTCOLOR";
const func integer: hashCode (in PRIMITIVE_WINDOW: aWindow) is action "DRW_HASHCODE";
const func integer: compare (in PRIMITIVE_WINDOW: window1,
                             in PRIMITIVE_WINDOW: window2)  is action "DRW_CMP";
const proc: setContent (inout PRIMITIVE_WINDOW: aWindow,
    in PRIMITIVE_WINDOW: pixmap)                            is action "DRW_SETCONTENT";
const func pixel: rgbPixel (ref integer: red,
    ref integer: green, ref integer: blue)          is action "DRW_RGBCOL";
const proc: DRAW_PIXEL_TO_RGB (
    in pixel: col, inout integer: red,
    inout integer: green, inout integer: blue)      is action "DRW_PIXELTORGB";
const proc: SET_COLOR (ref pixel: aWindow)          is action "DRW_COLOR";
const proc: SET_BACKGROUND (ref pixel: aWindow)     is action "DRW_BACKGROUND";
const proc: DRAW_TEXT (inout PRIMITIVE_WINDOW: aWindow,
    ref integer: x, ref integer: y, in string: stri,
    ref pixel: col, ref pixel: bkcol)               is action "DRW_TEXT";

(**
 *  Determine the height of the screen in pixels.
 *)
const func integer: screenHeight                    is action "DRW_SCREEN_HEIGHT";

(**
 *  Determine the width of the screen in pixels.
 *)
const func integer: screenWidth                     is action "DRW_SCREEN_WIDTH";

(**
 *  Determine the height of the window drawing area in pixels.
 *  This excludes window decorations at top and bottom. Add top and bottom
 *  border widths to get the height inclusive window decorations.
 *)
const func integer: height (in PRIMITIVE_WINDOW: aWindow)   is action "DRW_HEIGHT";

(**
 *  Determine the width of the window drawing area in pixels.
 *  This excludes window declarations left and right. Add left and right
 *  border widths to get the width inclusive window decorations.
 *)
const func integer: width (in PRIMITIVE_WINDOW: aWindow)    is action "DRW_WIDTH";

(**
 *  Determine the X position of the top left corner of a window in pixels.
 *  If window decorations are present this uses the top left corner of
 *  the window decorations. For a sub window the X position is relative
 *  to the top left corner of the parent window drawing area (inside of
 *  the window decorations). For top level windows the X position is
 *  relative to the top left corner of the screen.
 *  @exception RANGE_ERROR If ''actual_window'' is a pixmap.
 *)
const func integer: xPos (in PRIMITIVE_WINDOW: aWindow)     is action "DRW_XPOS";

(**
 *  Determine the Y position of the top left corner of a window in pixels.
 *  If window decorations are present this uses the top left corner of
 *  the window decorations. For a sub window the Y position is relative
 *  to the top left corner of the parent window drawing area (inside of
 *  the window decorations). For top level windows the Y position is
 *  relative to the top left corner of the screen.
 *  @exception RANGE_ERROR If ''actual_window'' is a pixmap.
 *)
const func integer: yPos (in PRIMITIVE_WINDOW: aWindow)     is action "DRW_YPOS";

(**
 *  Move the top left corner of a window to the coordinates x/y.
 *  If window decorations are present the top left corner of the
 *  window decorations will be at the position x/y. For a sub window
 *  the position is relative to the top left corner of the parent window
 *  drawing area (inside of the window decorations). For top level windows
 *  the position is relative to the top left corner of the screen.
 *)
const proc: setPos (in PRIMITIVE_WINDOW: aWindow,
    in integer: xPos, in integer: yPos)                     is action "DRW_SETPOS";

(**
 *  Lower a window to the bottom so that it does not obscure any other window.
 *)
const proc: toBottom (in PRIMITIVE_WINDOW: aWindow) is action "DRW_TOBOTTOM";

(**
 *  Raise a window to the top so that no other window obscures it.
 *)
const proc: toTop (in PRIMITIVE_WINDOW: aWindow)    is action "DRW_TOTOP";

(**
 *  Determine the border widths of a window in pixels.
 *  These are the widths of the window decorations in the succession
 *  top, right, bottom, left.
 *  @return an array with border widths (top, right, bottom, left).
 *)
const func array integer: getBorder (in PRIMITIVE_WINDOW: aWindow) is action "DRW_BORDER";

(**
 *  Return the X position of the pointer relative to the specified window.
 *  The point of origin is the top left corner of the drawing area
 *  of the given 'actual_window' (inside of the window decorations).
 *  If 'actual_window' is the empty window the pointer X position is
 *  relative to the top left corner of the screen.
 *)
const func integer: pointerXPos (in PRIMITIVE_WINDOW: aWindow) is action "DRW_POINTER_XPOS";

(**
 *  Return the Y position of the pointer relative to the specified window.
 *  The point of origin is the top left corner of the drawing area
 *  of the given 'actual_window' (inside of the window decorations).
 *  If 'actual_window' is the empty window the pointer Y position is
 *  relative to the top left corner of the screen.
 *)
const func integer: pointerYPos (in PRIMITIVE_WINDOW: aWindow) is action "DRW_POINTER_YPOS";


const proc: SET_CLOSE_ACTION (in PRIMITIVE_WINDOW: aWindow, in integer: closeAction) is action "DRW_SETCLOSEACTION";

(**
 *  Enumeration type to describe the action of the window close button.
 *  * CLOSE_PROGRAM Close the program.
 *  * RETURN_KEY The function getc(GRAPH_KEYBOARD) will return KEY_CLOSE.
 *  * RAISE_EXCEPTION Raise the exception CLOSE_ERROR.
 *)
const type: windowCloseAction is new enum
    CLOSE_PROGRAM, RETURN_KEY, RAISE_EXCEPTION
  end enum;

(**
 *  Set the action triggered by the close button of ''aWindow''.
 *  When windows are created the close action is set to CLOSE_PROGRAM.
 *  @param aWindow Window for which the close action is specified.
 *  @param closeAction Action to execute if the close button is pressed.
 *)
const proc: setCloseAction (in PRIMITIVE_WINDOW: aWindow, in windowCloseAction: closeAction) is
  return SET_CLOSE_ACTION(aWindow, ord(closeAction));


const type: pointList is newtype;

IN_PARAM_IS_REFERENCE(pointList);

const proc: destroy (ref pointList: aValue)                       is action "BST_DESTR";
const proc: (ref pointList: dest) ::= (ref pointList: source)     is action "BST_CREATE";
const proc: (inout pointList: dest) := (ref pointList: source)    is action "BST_CPY";

const func pointList: _GENERATE_EMPTY_POINT_LIST                  is action "BST_EMPTY";
const pointList: (attr pointList) . value                         is _GENERATE_EMPTY_POINT_LIST;

(**
 *  The function 'genPointList' creates a 'pointList'.
 *  It converts an array of alternate x and y values to a 'pointList'.
 *  @return a pointList with the points from the array.
 *  @exception RANGE_ERROR If the length of the array is odd.
 *)
const func pointList: genPointList (ref array integer: coordinates) is action "DRW_GENPOINTLIST";

(**
 *  Converts a 'pointList' to an array of (X,Y) coordinates.
 *  @return an array of alternate x and y values.
 *)
const func array integer: xyArray (ref pointList: aPointList)     is action "DRW_CONVPOINTLIST";

const func pointList: scale (in pointList: basePoints, in integer: scale) is func
  result
    var pointList: scaledPoints is pointList.value;
  local
    var array integer: coordinates is 0 times 0;
    var integer: index is 0;
  begin
    coordinates := xyArray(basePoints);
    for key index range coordinates do
      coordinates[index] *:= scale;
    end for;
    scaledPoints := genPointList(coordinates);
  end func;

const proc: DRAW_POLYLINE (inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y, in pointList: point_list,
    ref pixel: col)                                               is action "DRW_POLYLINE";
const proc: FILL_POLYLINE (inout PRIMITIVE_WINDOW: aWindow,
    in integer: x, in integer: y, in pointList: point_list,
    ref pixel: col)                                               is action "DRW_FPOLYLINE";
