/************************************************************
**
** Application: SyncDiscs
**
** Title:       c.area
**
*************************************************************/

/*
*
* Copyright (c) 2017, David Pilling and Chris Johnson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the copyright holder nor the names of their
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

/* Include files */

#include "h.includes"

#include "Tasklib:h.wimpt"
#include "Tasklib:h.flex"
#include "Tasklib:h.sprite"
#include "Tasklib:h.transform"
#include "Tasklib:h.akbd"
#include "Tasklib:h.task"
#include "Tasklib:h.poll"
#include "Tasklib:h.temp"
#include "Tasklib:h.scrap"
#include "Tasklib:h.fsx"
#include "Tasklib:h.etc"
#include "Tasklib:h.xx2con"
#include "Tasklib:h.swis"
#include "Tasklib:h.save"
#include "Tasklib:h.bf"
#include "Tasklib:h.sp"
#include "Tasklib:h.key"
#include "Tasklib:h.font"
#include "Tasklib:h.pane"

/* from application */

#include "h.constants"
#include "h.reslink"
#include "h.mlo"
#include "h.main"
#include "h.config"
#include "h.area"



/************************************************************/

/* size of bars and corners of area */
#define SIZE  18
#define CSIZE 36

/* the height of the area topbar depends on the 'height' of the
** outline font used to display the area size. Therefore we need to
** set this dynamically on initialisation of program in function
** font_setup(), so use an int instead.
*/
static int top_size=SIZE;

/* flag to show we are actually dragging the area rather than eg moving
** to a different screen in a multi desktop set up
*/
static int dragging=0;

int areax0=200;
int areax1=600;
int areay0=200;
int areay1=600;

int aopen;

// area window tokens
#define TL 0
#define TR 1
#define BL 2
#define BR 3

#define TOP   4
#define BOT   5
#define LEFT  6
#define RIGHT 7


int handle[MAXW];

/****************************************************************************/
/* defs relating to coordinate window */

#define COORD_X 4          /* Coord window writable icon ids */
#define COORD_Y 5
#define COORD_W 6
#define COORD_H 7

#define XDOWN  9          /* Coord window bump icon ids */
#define XUP    10
#define YDOWN  11
#define YUP    12
#define WDOWN  13
#define WUP    14
#define HDOWN  15
#define HUP    16

int coordhandle = 0;
static win_position coord_pos;



int autocoord;

/****************************************************************************/


static int oldareax0;   /*  keep copy of grab area position */
static int oldwid;
static int oldareay0;
static int oldht;
static int oldw;
static int oldh;

/* config bool when set will attempt to use desktop font on OS 3.5 or later */
int UseDesktopFont = 0;
static char times;
/* flag to show desktop font is actually in use */
int desktop_font_in_use;
static int font_changed_msg_registered = 0;



/************************************************************/
/* forward function declarations */

static os_error * keycoord(int handle,int userhandle, int icon,int * key);
static os_error * changeicontext(wimp_w w, wimp_i i, char * newtext );
static os_error * font_convert_mptoos ( int xmp, int ymp, int *xos, int *yos );
static os_error * toptext(windowstr * win);
static os_error * topredrawsub(int handle,int userhandle,
                                wimp_redrawstr * redrawstr,int more);
static os_error * topredraw(int handle,int userhandle);
static os_error * coordicon(int handle,int userhandle,wimp_mousestr * m);
static os_error * update_coord_display(void);
static os_error * tidy_caret(int i, int len);
static os_error *paintcoords(char *s, int x, int y);
static os_error * wimp_set_font_colours ( int fg, int bg );
static os_error * font_release (void);

static os_error * coord_close(int handle,int userhandle);
/*******************************************************************************/









static os_error * dragwindow(wimp_mousestr * m)
{
 os_error   * err;
 wimp_dragstr drg;
 windowstr    window;

 err=getw(m->w,&window);
 if(!err)
 {
  drg.window=m->w;
  drg.type=wimp_MOVE_WIND;

  err=wimp_drag_box(&drg);
 }
 dragging=1;
 return(err);
}


/*******************************************************************************/

static int sizechanged(void)
{
  if (oldw!=(areax1-areax0)) return(1);
  if (oldh!=(areay1-areay0)) return(1);
  return(0);
}


/*******************************************************************************/

static os_error * areastack(int bhandle)
{
 os_error * err;
 err=NULL;

 open(handle[TL],areax0-CSIZE,areay1,areax0,areay1+CSIZE,0,0,bhandle);
 open(handle[TR],areax1,areay1,areax1+CSIZE,areay1+CSIZE,0,0,handle[TL]);
 open(handle[BL],areax0-CSIZE,areay0-CSIZE,areax0,areay0,0,0,handle[TR]);
 open(handle[BR],areax1,areay0-CSIZE,areax1+CSIZE,areay0,0,0,handle[BL]);

 open(handle[LEFT],areax0-SIZE,areay0,areax0,areay1,0,0,handle[BR]);
 open(handle[TOP],areax0,areay1,areax1,areay1+top_size,0,0,handle[LEFT]);
 open(handle[RIGHT],areax1,areay0,areax1+SIZE,areay1,0,0,handle[TOP]);
 open(handle[BOT],areax0,areay0-SIZE,areax1,areay0,0,0,handle[RIGHT]);


 if (coordhandle)
 {
   err=update_coord_display();
 }

 if (sizechanged()) refreshwindow(handle[TOP]);

 return(err);
}



/*******************************************************************************/

/*
 * The following function has been changed to check that the central
 * grab area contained within the boundaries of the four red bar
 * windows always contains at least one pixel. This is necessary
 * because in the original, dragging the corners in could result in the
 * four bars overlapping and the width or height of the grab area
 * would become -2 pixels. When these data were used in the savearea
 * routine it was possible for x0>=x1 and/or y0>=y1 to be passed to
 * the OS_SpriteOp call. This did not cause a crash, but the save
 * routine saved an area e.g. 2x2 instead of the nominal 0x0. Thus
 * the coordinate display did not reflect what was actually happening.
 * This was probably never noticed previously without the coordinate
 * display showing the size.
 *
 * It has also been changed to prevent the bounding box being moved
 * further off screen than is necessary to grab the edge of the screen.
 * In the past the box edge could be moved far offscreen, but the area
 * grab only grabbed actual screen. This meant the coordinate display
 * did not reflect what was actually happening.
 *
 * Further change has been to constrain mouse movement when area box
 * hits the edge of the screen. If not done, then when dragging, the
 * mouse continues to move towards the edge of the screen even if the
 * area box has hit the stops!
 */


#define MINPIXELSEP 3

static os_error * areaopen(int whandle,int userhandle,wimp_openstr * o)
{
 os_error * err;
 int        bhandle;
 int        dx0;
 int        dy0;
 int        dx1;
 int        dy1;

 int        x0;
 int        x1;
 int        y0;
 int        y1;
 int        solid;

 int        min_xsep;
 int        min_ysep;
 int        dneeded;
 mousestr   mouse;
 int        mx;
 int        my;
 int        reset_mouse;


 dx0=dx1=dy0=dy1=0;
 reset_mouse = 0;
 x0=o->box.x0;
 x1=o->box.x1;
 y0=o->box.y0;
 y1=o->box.y1;


 min_xsep=MINPIXELSEP<<mode.xeig;   /* min diff between left-right bars */
 min_ysep=MINPIXELSEP<<mode.yeig;   /* min diff between top-bottom bars */

 err=NULL;
 solid=0;

 bhandle=o->behind;


 err=getpointer(&mouse);

#ifdef NEVER
 /* check whether the pointer is on one of our windows */
 for (i = 0; i < MAXW; i++)
 {
   if (mouse.handle == handle[i])
   {
     our_window = TRUE;
     break;
   }
 }
#endif

 if (dragging)
 {
   /* Due to drag events
    * so limit movement to current screen area
    */

   if(userhandle<TOP) /* resize */
   {
     mx = mouse.x ;
     my = mouse.y ;
    switch(userhandle)
    {
     case TL:

             dy0 = 0;
             dx1 = 0;
             dx0 = x0 - (areax0 - CSIZE);
             /* size of area must not go negative */
             if ((areax0 + dx0) > (areax1 - min_xsep))
             {
               /* at limit - constrain mouse in x direction */
               dneeded = areax1 - min_xsep - areax0;
               mx = mx + dneeded - dx0;
               dx0 = dneeded;
               reset_mouse = 1;
             }
             dy1 = y1 - (areay1 + CSIZE);
             /* size of area must not go negative */
             if ((areay0 + min_ysep) > (areay1 + dy1))
             {
               /* at limit - constrain mouse in y direction */
               dneeded = areay0 + min_ysep - areay1;
               my = my + dneeded - dy1;
               dy1 = dneeded;
               reset_mouse = 1;
             }
             if (reset_mouse) setmouse(mx, my);
             break;

     case TR:
             dx0 = 0;
             dy0 = 0;
             dx1 = x1 - (areax1 + CSIZE);
             if ((areax0 + min_xsep) > (areax1 + dx1))
             {
               dneeded = areax0 + min_xsep - areax1;
               mx = mx + dneeded - dx1;
               dx1 = dneeded;
               reset_mouse = 1;
             }
             dy1 = y1 - (areay1 + CSIZE);
             if ((areay0 + min_ysep) > (areay1 + dy1))
             {
               dneeded = areay0 + min_ysep - areay1;
               my = my + dneeded - dy1;
               dy1 = dneeded;
               reset_mouse = 1;
             }
             if (reset_mouse) setmouse(mx, my);
             break;

     case BL:
             dx1 = 0;
             dy1 = 0;
             dx0 = x0 - (areax0 - CSIZE);
             if ((areax0 + dx0) > (areax1 - min_xsep))
             {
               /* at limit - constrain mouse in x direction */
               dneeded = areax1 - min_xsep - areax0;
               mx = mx + dneeded - dx0;
               dx0 = dneeded;
               reset_mouse = 1;
             }
             dy0 = y0 - (areay0 - CSIZE);
             if ((areay0 + dy0) > (areay1 - min_ysep))
             {
               dneeded = areay1 - min_ysep - areay0;
               my = my + dneeded - dy0;
               dy0 = dneeded;
               reset_mouse = 1;
             }
             if (reset_mouse) setmouse(mx, my);
             break;

     case BR:
             dx0 = 0;
             dy1 = 0;
             dx1 = x1 - (areax1 + CSIZE);
             if ((areax0 + min_xsep) > (areax1 + dx1))
             {
               dneeded = areax0 + min_xsep - areax1;
               mx = mx + dneeded - dx1;
               dx1 = dneeded;
               reset_mouse = 1;
             }
             dy0 = y0 - (areay0 - CSIZE);
             if ((areay0 + dy0) > (areay1 - min_ysep))
             {
               dneeded = areay1 - min_ysep - areay0;
               my = my + dneeded - dy0;
               dy0 = dneeded;
               reset_mouse = 1;
             }
             if (reset_mouse) setmouse(mx, my);
             break;
    }


    if(isctrl)
    {
     if(dx1)
     {
       if ((areax0+min_xsep)>areax1+2*dx1)
       {
         /* maintain minimum of 1 pixel width within area */
         dx1=(areax0-areax1+min_xsep)/2;
         dx0=-dx1;

       }
       else
       {
         /* check that left is not off screen */
         if ((areax0-dx1)<(-1<<mode.xeig))
         {
           dx0=areax0-(-1<<mode.xeig);
         }
         else
         {
           dx0=-dx1;
         }
       }
     }
     else
     {
       if ((areax0+min_xsep+2*dx0)>areax1)
       {
         /* maintain minimum of 1 pixel width within area */
         dx0=(areax1-areax0-min_xsep)/2;
         dx1=-dx0;
       }
       else
       {
         /* check that right is not off screen - dx0 is -ve */
         if ((areax1-dx0)>((mode.xwindlimit+2)<<mode.xeig))
         {
           dx1=areax1 - ((mode.xwindlimit+2)<<mode.xeig);
         }
         else
         {
           dx1=-dx0;
         }
       }
     }

     if(dy1)
     {
       if ((areay0+min_ysep)>areay1+2*dy1)
       {
         /* maintain minimum of 1 pixel width within area */
         dy1=(areay0-areay1+min_ysep)/2;
         dy0=-dy1;
       }
       else
       {
         /* check that bottom is not off screen */
         if ((areay0-dy1)<(-1<<mode.yeig))
         {
           dy0=areay0-(-1<<mode.yeig);
         }
         else
         {
           dy0=-dy1;
         }
       }
     }
     else
     {
       if ((areay0+min_ysep+2*dy0)>areay1)
       {
         dy0=(areay1-areay0-min_ysep)/2;
         dy1=-dy0;
       }
       else
       {
         /* check that top is not off screen - dy0 is -ve */
         if ((areay1-dy0)>((mode.ywindlimit+2)<<mode.yeig))
         {
           dy1=areay1 - ((mode.ywindlimit+2)<<mode.yeig);
         }
         else
         {
           dy1=-dy0;
         }
       }
     }
    }
    else
    {

      if(isshift)
      {
       if(dx1)
       {
         if ((areax0+dx1)<(-1<<mode.xeig))
         {
           dneeded=(-1<<mode.xeig)-areax0;
           /* now constrain the mouse position */
           setmouse(mouse.x + dneeded - dx1, mouse.y);
           dx1=dneeded;
         }
         dx0=dx1;
       }
       else
       {
         if ((areax1+dx0)>((mode.xwindlimit+2)<<mode.xeig))
         {
           dneeded=((mode.xwindlimit+2)<<mode.xeig)-areax1;
           setmouse(mouse.x + dneeded - dx0, mouse.y);
           dx0=dneeded;
         }
         dx1=dx0;
       }


       if(dy1)
       {
         if ((areay0+dy1)<(-1<<mode.yeig))
         {
           dneeded=(-1<<mode.yeig)-areay0;
           /* now constrain the mouse position */
           setmouse(mouse.x, mouse.y + dneeded - dy1);
           dy1=dneeded;
         }
         dy0=dy1;
       }
       else
       {
         if ((areay1+dy0)>((mode.ywindlimit+2)<<mode.yeig))
         {
           dneeded=((mode.ywindlimit+2)<<mode.yeig)-areay1;
           /* now constrain the mouse position */
           setmouse(mouse.x, mouse.y + dneeded - dy0);
           dy0=dneeded;
         }
         dy1=dy0;
       }
       solid=1;
      }
    }
   }
   else               /* solid */
   {
     /* Drag on a side of the area */
    switch(userhandle)
    {
     case LEFT:
       if ((isshift) || (isctrl))
       {
         /* just move left side */
         /* first check vertical movement of mouse */
         dneeded = y0 - areay0;
         my = mouse.y - dneeded;
         dx0 = x0 - (areax0 - SIZE);
         mx = mouse.x ;
         /* now check whether area is at or below smallest size */
         if ((areax0 + dx0) > (areax1 - min_xsep))
         {
           dneeded = areax1 - min_xsep - areax0;
           /* need to prevent pointer over running the side */
           mx = mx + dneeded - dx0;
           dx0 = dneeded;
         }
         /* prevent mouse moving up or down off the side */
         setmouse(mx, my);

         /* are we moving right side as well in opposite direction? */
         if (isctrl)
         {
           /* move right side */
           dx1 = -dx0;
           /* now check we have not moved side off screen */
           if ((areax1 + dx1) > ((mode.xwindlimit + 2) << mode.xeig))
           {
             dx1 = ((mode.xwindlimit + 2) << mode.xeig) - areax1;
           }
         }
         else
         {
           dx1 = 0;
         }

         /* top and bottom sides stay in same position */
         dy0 = 0;
         dy1 = 0;
       }
       else
       {
           dx1 = x1 - areax0;
           /* are we pushing off the left? */
           if ((areax0+dx1)<(-1<<mode.xeig))
           {
             /* no need to constrain mouse */
             dx1=(-1<<mode.xeig)-areax0;
           }
           else
           {
             /* are we pushing off the right? */
             if ((areax1+dx1)>((mode.xwindlimit+2)<<mode.xeig))
             {
               dneeded=((mode.xwindlimit+2)<<mode.xeig)-areax1;
               /* now constrain the mouse position */
               setmouse(mouse.x + dneeded - dx1, mouse.y);
               dx1 = dneeded;
             }
           }
           dx0=dx1;

           dy1=y1-areay1;
           /* are we pushing off the bottom? */
           if ((areay0+dy1)<(-1<<mode.yeig))
           {
             dneeded=(-1<<mode.yeig)-areay0;
             /* now constrain the mouse position */
             setmouse(mouse.x, mouse.y + dneeded - dy1);
             dy1=dneeded;
           }
           else
           {
             /* or pushing off the top? */
             if ((areay1+dy1)>((mode.ywindlimit+2)<<mode.yeig))
             {
               dneeded=((mode.ywindlimit+2)<<mode.yeig)-areay1;
               /* now constrain the mouse position */
               setmouse(mouse.x, mouse.y + dneeded - dy1);
               dy1=dneeded;
             }
           }
           dy0 = dy1;
       }
       break;

      case TOP:
       if ((isshift) || (isctrl))
       {
         /* just move top side */
         /* first check horizontal movement of mouse */
         dneeded = x0 - areax0;
         mx = mouse.x - dneeded;
         dy1 = y1 - (areay1 + top_size);
         my = mouse.y;
         if ((areay0 + min_ysep) > (areay1 + dy1))
         {
           dneeded = areay0 + min_ysep - areay1;
           /* need to prevent pointer over running the side */
           my = my + dneeded - dy1;
           dy1 = dneeded;
         }
         /* prevent mouse moving left or right off the side */
         setmouse(mx, my);

         /* are we moving bottom side as well in opposite direction? */
         if (isctrl)
         {
           /* move bottom side */
           dy0 = -dy1;
           /* now check we have not moved bottom off screen */
           if ((areay0 + dy0) < (-1 << mode.yeig))
           {
             dy0 = (-1 << mode.yeig) - areay0;
           }
         }
         else
         {
           dy0 = 0;
         }

         /* left and right sides stay in same position */
         dx0 = 0;
         dx1 = 0;
       }
       else
       {
           dx0=x0-areax0;

           /* are we pushing off the left? */
           if ((areax0+dx0)<(-1<<mode.xeig))
           {
             dneeded=(-1<<mode.xeig)-areax0;
             /* now constrain the mouse position */
             setmouse(mouse.x + dneeded - dx0, mouse.y);
             dx0 = dneeded;
           }
           else
           {
             /* are we pushing off the right? */
             if ((areax1+dx0)>((mode.xwindlimit+2)<<mode.xeig))
             {
               dneeded=((mode.xwindlimit+2)<<mode.xeig)-areax1;
               /* now constrain the mouse position */
               setmouse(mouse.x + dneeded - dx0, mouse.y);
               dx0 = dneeded;
             }
           }
           dx1=dx0;

           dy1=y1-(areay1+top_size);
           /* are we pushing off the bottom? */
           if ((areay0+dy1)<(-1<<mode.yeig))
           {
             dneeded=(-1<<mode.yeig)-areay0;
             /* now constrain the mouse position */
             setmouse(mouse.x, mouse.y + dneeded - dy1);
             dy1=dneeded;
           }
           else
           {
             /* or pushing off the top? */
             if ((areay1+dy1)>((mode.ywindlimit+2)<<mode.yeig))
             {
               /* no need to constrain mouse */
               dy1=((mode.ywindlimit+2)<<mode.yeig)-areay1;
             }
           }
           dy0=dy1;
       }
       break;

    case RIGHT:
       if ((isshift) || (isctrl))
       {
         /* just move right side */
         /* first check vertical movement of mouse */
         dneeded = y0 - areay0;
         my = mouse.y - dneeded;
         dx1 = x1 - (areax1 + SIZE);
         mx = mouse.x ;
         if ((areax1 + dx1) < (areax0 + min_xsep))
         {
           dneeded = areax0 + min_xsep - areax1;
           /* need to prevent pointer over running the side */
           mx = mx + dneeded - dx1;
           dx1 = dneeded;
         }
         /* prevent mouse moving up or down off the side */
         setmouse(mx, my);
         /* are we moving right side as well in opposite direction? */
         if (isctrl)
         {
           /* move opposite side as well in opposite direction */
           dx0 = -dx1;
           /* now check we have not moved side off screen */
           if ((areax0 + dx0) < (-1 << mode.xeig))
           {
             dx0 = (-1 << mode.xeig) - areax0;
           }
         }
         else
         {
           dx0 = 0;
         }

         /* top and bottom sides stay in same position */
         dy0 = 0;
         dy1 = 0;
       }
       else
       {
           dx0=x0-areax1;
           /* are we pushing off the left? */
           if ((areax0+dx0)<(-1<<mode.xeig))
           {
             dneeded=(-1<<mode.xeig)-areax0;
             /* now constrain the mouse position */
             setmouse(mouse.x + dneeded - dx0, mouse.y);
             dx0 = dneeded;
           }
           else
           {
             if ((areax1+dx0)>((mode.xwindlimit+2)<<mode.xeig))
             {
               /* no need to constrain mouse */
               dx0=((mode.xwindlimit+2)<<mode.xeig)-areax1;
             }
           }
           dx1=dx0;

           dy1=y1-areay1;
           /* are we pushing off the bottom? */
           if ((areay0+dy1)<(-1<<mode.yeig))
           {
             dneeded=(-1<<mode.yeig)-areay0;
             /* now constrain the mouse position */
             setmouse(mouse.x, mouse.y + dneeded - dy1);
             dy1=dneeded;
           }
           else
           {
             /* or pushing off the top? */
             if ((areay1+dy1)>((mode.ywindlimit+2)<<mode.yeig))
             {
               dneeded=((mode.ywindlimit+2)<<mode.yeig)-areay1;
               /* now constrain the mouse position */
               setmouse(mouse.x, mouse.y + dneeded - dy1);
               dy1=dneeded;
             }
           }
           dy0=dy1;
       }
       break;

      case BOT:
       if ((isshift) || (isctrl))
       {
         /* just move top side */
         /* first check horizontal movement of mouse */
         dneeded = x0 - areax0;
         mx = mouse.x - dneeded;
         dy0 = y0 - (areay0 - SIZE);
         my = mouse.y;
         if ((areay0 + dy0) > (areay1 - min_ysep))
         {
           dneeded = areay1 - min_ysep - areay0;
           /* need to prevent pointer over running the side */
           my = my + dneeded - dy0;
           dy0 = dneeded;
         }
         /* prevent mouse moving left or right off the side */
         setmouse(mx, my);

         /* are we moving top as well in opposite direction? */
         if (isctrl)
         {
           /* move top side */
           dy1 = -dy0;
           /* now check we have not moved top off screen */
           if ((areay1 + dy1) > ((mode.ywindlimit + 2) << mode.yeig))
           {
             dy1 = ((mode.ywindlimit + 2) << mode.yeig) - areay1;
           }
         }
         else
         {
           dy1 = 0;
         }

         /* left and right sides stay in same position */
         dx0 = 0;
         dx1 = 0;
       }
       else
       {
           dx0=x0-areax0;
           /* are we pushing off the left? */
           if ((areax0+dx0)<(-1<<mode.xeig))
           {
             dneeded=(-1<<mode.xeig)-areax0;
             /* now constrain the mouse position */
             setmouse(mouse.x + dneeded - dx0, mouse.y);
             dx0 = dneeded;
           }
           else
           {
             /* are we pushing off the right? */
             if ((areax1+dx0)>((mode.xwindlimit+2)<<mode.xeig))
             {
               dneeded=((mode.xwindlimit+2)<<mode.xeig)-areax1;
               /* now constrain the mouse position */
               setmouse(mouse.x + dneeded - dx0, mouse.y);
               dx0 = dneeded;
             }
           }
           dx1=dx0;

           dy1=y1-areay0;
           /* are we pushing off the bottom? */
           if ((areay0+dy1)<(-1<<mode.yeig))
           {
             /* no need to constrain mouse */
             dy1=(-1<<mode.yeig)-areay0;
           }
           else
           {
             /* or pushing off the top? */
             if ((areay1+dy1)>((mode.ywindlimit+2)<<mode.yeig))
             {
               dneeded=((mode.ywindlimit+2)<<mode.yeig)-areay1;
               /* now constrain the mouse position */
               setmouse(mouse.x, mouse.y + dneeded - dy1);
               dy1 = dneeded;
             }
           }
           dy0=dy1;
       }
       break;
    }
    if(!isshift) solid=1;
   }

   areax0+=dx0;
   if(areax0>areax1 && !solid) areax0=areax1;
   areax1+=dx1;
   if(areax1<areax0 && !solid) areax1=areax0;

   areay0+=dy0;
   if(areay0>areay1 && !solid) areay0=areay1;
   areay1+=dy1;
   if(areay1<areay0 && !solid) areay1=areay0;

   if (mouse.buttons==0) dragging=0;     /* drag must be finished and mouse released */

 }
 else

 {
   /* open calls are not a result of a mouse drag event, but
    * may be a result of e.g. MoreDesk changing screens
    * Do not want to have any forcing of snap area onscreen
    * Therefore just get the movement and calculate the new
    * position. Still need to deal with each component window
    * of the area outline. All parts of the box should move
    * by the same amount.
    */

   if(userhandle<TOP) /* resize */
   {
    switch(userhandle)
    {
     case TL:
             dx0=x0-(areax0-CSIZE);
             dx1=dx0;
             dy1=y1-(areay1+CSIZE);
             dy0=dy1;
             break;

     case TR:
             dx1=x1-(areax1+CSIZE);
             dy1=y1-(areay1+CSIZE);
             dx0=dx1;
             dy0=dy1;
             break;

     case BL:
             dx0=x0-(areax0-CSIZE);
             dy0=y0-(areay0-CSIZE);
             dx1=dx0;
             dy1=dy0;
             break;

     case BR:
             dy0=y0-(areay0-CSIZE);
             dx1=x1-(areax1+CSIZE);
             dx0=dx1;
             dy1=dy0;
             break;
    }

   }
   else               /* solid */
   {
    switch(userhandle)
    {
     case LEFT:
               dx0=x0-(areax0-SIZE);
               dy0=y0-areay0;
               dx1=x1-areax0;
               dy1=y1-areay1;
               break;

      case TOP:
               dx0=x0-areax0;
               dy0=y0-areay1;
               dx1=x1-areax1;
               dy1=y1-(areay1+top_size);
               break;

    case RIGHT:
               dx0=x0-areax1;
               dy0=y0-areay0;
               dx1=x1-(areax1+SIZE);
               dy1=y1-areay1;
               break;

      case BOT:
               dx0=x0-areax0;
               dy0=y0-(areay0-SIZE);
               dx1=x1-areax1;
               dy1=y1-areay0;
               break;
    }
    solid=1;



   }

   areax0+=dx0;
   areax1+=dx1;
   areay0+=dy0;
   areay1+=dy1;


 }



 err=areastack(bhandle);

 return(err);

 USE (whandle);
}




/*******************************************************************************/

static os_error * areaicon(int handle,int userhandle,wimp_mousestr * m)
{
 os_error * err;

 err=NULL;


 /* double click on grab area outline opens
  * coord window if not open */
 if (m->bbits==0x1 || m->bbits==0x4)
 {
   coord_open ();

 }

 if(m->bbits==0x40 || m->bbits==0x10)
 {
  err=dragwindow(m);
 }

 USE(handle);
 USE(userhandle);
 USE(m);

 return(err);
}





/*******************************************************************************/

static os_error * redcorner(windowstr * window,char * name)
{
 os_error * err;
 os_regset  rx;
 int        pixtrn[4];
 int        magblk[4];

 rx.r[0]=0x100;                 /* wimp_readpixtrans */
 rx.r[1]=(int)sprites;          /* wimp.colours      */
 rx.r[2]=(int)name;
 rx.r[6]=(int)magblk;
 rx.r[7]=(int)pixtrn;
 err=os_swix(0x40000+0xED,&rx);

 rx.r[0]=0x134;
 rx.r[1]=(int)sprites;
 rx.r[2]=(int)name;
 rx.r[3]=window->bx;
 rx.r[4]=window->by-(window->y1-window->y0);
 rx.r[5]=8;
 rx.r[6]=(int)magblk;
 rx.r[7]=(int)pixtrn;

 err=os_swix(OS_SpriteOp,&rx);

 return(err);
}




/*******************************************************************************/

static char * cnames[]={"lt","rt","lb","rb"};


static os_error * arearedrawsub(int handle,int userhandle,
                                wimp_redrawstr * redrawstr,int more)
{
 os_error * err;
 windowstr  window;

 err=NULL;

 while(more)
 {
  getw(handle,&window);
  redcorner(&window,cnames[userhandle]);
  err=wimp_get_rectangle(redrawstr,&more);
  if(err) break;
 }

 return(err);
}


/*******************************************************************************/

static os_error * arearedraw(int handle,int userhandle)
{
 os_error     * err;
 wimp_redrawstr redrawstr;
 int            more;
 redrawstr.w=handle;
 err=wimp_redraw_wind(&redrawstr,&more);
 if(!err) err=arearedrawsub(handle,userhandle,&redrawstr,more);
 return(err);
}




/*******************************************************************************/

/* set the pointer to required shape from named sprite held in
   application sprite pool on pointer entering one of the border
   windows and reset to system pointer when pointer leaves border
*/

static os_error * areaptr(int handle, int userhandle, int enter)
{
  os_error     * err;
  os_regset      rx;
  char           name[12];

  rx.r[0]=256+36;                  /* set pointer shape */
  rx.r[1]=(int)sprites;            /* sprite area ptr */
  rx.r[3]=2;                       /* pointer no (1-4) */
  rx.r[6]=0;                       /* ptr to scale factors, 0 for mode default */
  rx.r[7]=0;                       /* pixel translation table */
  if(enter)                        /* entering border area */
  {
    if (userhandle<TOP)            /* corner objects */
    {
      strcpy(name,"p_resize");     /* name of sprite to use */
      rx.r[4]=0;                   /* active point x offset */
      rx.r[5]=0;                   /* active point y offset */
    }
    else                           /* sides */
    {
      strcpy(name,"p_move");       /* name of sprite to use */
      rx.r[4]=11;                  /* active point x offset */
      rx.r[5]=11;                  /* active point y offset */
    }
    rx.r[2]=(int)name;
    err=os_swix(OS_SpriteOp, &rx);
    if(!err)
    {
      rx.r[0]=106;                 /* select pointer */
      rx.r[1]=2;                   /* pointer no (1-4) */
      err=os_swix(OS_Byte, &rx);
    }
  }
  else                             /* leaving border area */
  {
    rx.r[0]=106;                   /* select pointer */
    rx.r[1]=1;                     /* pointer no (1-4) */
    err=os_swix(OS_Byte, &rx);
  }
  return(err);

 USE (handle);
}


/*******************************************************************************/

/*
  Set pointer to ptr no 2 without doing any setting of the shape.
  Used to set the user pointer after e.g. a mode change which resets
  the pointer to system pointer #1
*/

os_error * setuserptr (void)
{
  os_regset      rx;

  rx.r[0]=106;
  rx.r[1]=2;
  return(os_swix(OS_Byte, &rx));
}





/*******************************************************************************/

os_error * closearea(void)
{
 os_error * err;
 int        i;

 err=NULL;

 if(aopen)
 {
  for(i=0;i<TOP;i++)
  {
   remredrawevent(arearedraw,handle[i],i);
   remhelpevent (NULL, handle[i], TCORNER);
  }

  for(i=0;i<MAXW;i++)
  {
   remclickevent(areaicon,handle[i],i);
   remopenevent(areaopen,handle[i],i);
   rempointerevent(areaptr,handle[i],i);
  }

    for(i=BOT;i<MAXW;i++)
    {
      remhelpevent (NULL, handle[i], TBAR);
    }


  remredrawevent(topredraw,handle[TOP],TOP);
  remhelpevent (NULL, handle[TOP], TBAR2);

  /* now finally close and delete all the windows */
  for(i=0;i<MAXW;i++)
  {
   err=closedown(&handle[i]);
  }

  aopen=0;

  font_release ();

   /* dispose of coord window */
   if(!err)
   {
     if (coordhandle)
     {
       coord_close (0,0);
     }
   }
 }

 return(err);
}



/*******************************************************************************/

os_error * openarea(void)
{
 os_error * err;
 int        i;
 wimp_wind * wp;

 err=NULL;

 if(!aopen)
 {
  for(i=0;i<TOP;i++)
  {
   err=findtemp(TCORNER,&wp);
   if(err) break;
   err=wimp_create_wind(wp,&handle[i]);
   if(err) break;
  }

  if(!err)
  {
   for(i=BOT;i<MAXW;i++)
   {
    err=findtemp(TBAR,&wp);
    if(err) break;
    err=wimp_create_wind(wp,&handle[i]);
    if(err) break;
   }

   /* now the top bar */
   if(!err)
   {
     err=findtemp(TBAR2,&wp);
     if(!err) err=wimp_create_wind(wp,&handle[TOP]);
   }

   aopen=1;

   if(!err)
   {
    for(i=0;i<MAXW;i++)
    {
     addclickevent(areaicon,handle[i],i);
     addopenevent(areaopen,handle[i],i);
     addpointerevent(areaptr,handle[i],i);
    }

    for(i=0;i<TOP;i++)
    {
     addredrawevent(arearedraw,handle[i],i);
     addhelpevent (NULL, handle[i], TCORNER);
    }

    for(i=BOT;i<MAXW;i++)
    {
      addhelpevent (NULL, handle[i], TBAR);
    }

    /* redraw top bar */
    addredrawevent(topredraw,handle[TOP],TOP);
    addhelpevent (NULL, handle[TOP], TBAR2);

     err = font_setup();

     /* and now open it */
      if (autocoord)
      {
        coord_open ();
      }

    areastack(-1);
   }
  }
 }

 return(err);
}




/*****************************************************************************/

static int fhandle;

os_error * openfillwindow(int colour)
{
 os_error * err;
 wimp_wind * wp;

 err=NULL;

 if(!fhandle)
 {
  err=findtemp(TFILL,&wp);

  wp->colours[wimp_WCWKAREABACK]=colour;
  /* Need to make sure window extent is large enough */
  wp->ex.x0 = 0;
  wp->ex.y0 = areay0 - areay1 - 8;
  wp->ex.x1 = areax1 - areax0 + 8;
  wp->ex.y1 = 0;

  if(!err)
  {
   err=wimp_create_wind(wp,&fhandle);
   if(!err) err=open(fhandle,areax0,areay0,areax1,areay1,0,0,handle[BOT]);
  }
 }

 return(err);
}




/*******************************************************************************/

os_error * closefillwindow(void)
{
 return(closedown(&fhandle));
}





/***********************************************************/


/* update coord display
 * --------------------
 * keep a copy of the last coords and only update
 * the values in the icons if they have changed.
 * This prevents flicker of non-changing values.
 * Probably a bit faster than using the TASK lib
 * function writeiconfc which constructs the string
 * and compares it with the current contents of the
 * icon.
 *
 * The values areax0, areax1, areay0 and areay1 are in
 * os units, and delineate the limits of the windows
 * used to construct the border of the grab area.
 * The actual grab area is one pixel inside (outside)
 * the window boundaries. Hence the adjustment of the
 * converted values.
 *
 * Compare savearea() in c.config
 */

static os_error * update_coord_display(void)

{
  os_error * err;
  char buffer[12];
  int w,h;

  err=NULL;
   if (areax0!=oldareax0)
   {
     sprintf(buffer,"%d",(areax0>>mode.xeig)+1);
     err=changeicontext(coordhandle,COORD_X,buffer);
     oldareax0=areax0;
   }
   if(!err)
   {
     if (areay0!=oldareay0)
     {
       sprintf(buffer,"%d",(areay0>>mode.yeig)+1);
       err=changeicontext(coordhandle,COORD_Y,buffer);
       oldareay0=areay0;
     }
   }
   if(!err)
   {
     w=areax1-areax0;
     if (w!=oldwid)
     {
       sprintf(buffer,"%d",(w>>mode.xeig)-2);
       err=changeicontext(coordhandle,COORD_W,buffer);
       oldwid=w;
     }
   }
   if(!err)
   {
     h=areay1-areay0;
     if (h!=oldht)
     {
       sprintf(buffer,"%d",(h>>mode.yeig)-2);
       err=changeicontext(coordhandle,COORD_H,buffer);
       oldht=h;
     }
   }

  return(err);
}





/*******************************************************************************/

static os_error * changeicontext(wimp_w w, wimp_i i, char * newtext )

{
  os_error *err;
  wimp_icon iconinfo;

  /* get icon info */
  err=wimp_get_icon_info(w, i, &iconinfo);
  if(!err)
  {
    strcpy(iconinfo.data.indirecttext.buffer, newtext);
    err=wimp_set_icon_state(w,i,(wimp_iconflags)0,(wimp_iconflags)0);
  }
  if(!err) err=tidy_caret(i, strlen(newtext));
  return(err);
}



/*******************************************************************************/

static os_error * setcoordicontovalue (wimp_i i, int val)
{
  os_error *err;
  wimp_icon iconinfo;
  char buffer[12];

  /* get icon info */
  err=wimp_get_icon_info(coordhandle, i, &iconinfo);
  if(!err)
  {
    sprintf(buffer,"%d",val);
    strcpy(iconinfo.data.indirecttext.buffer, buffer);
    err=wimp_set_icon_state(coordhandle,i,(wimp_iconflags)0,(wimp_iconflags)0);
  }
  return(err);
}



/*******************************************************************************/

static os_error * areastack_in_position(void)

{
 os_error * err;
 wimp_wstate winds;

 /* get position in stack of top bar */
 err = wimp_get_wind_state (handle[TL], &winds);
 if (!err) areastack(winds.o.behind);
 return(err);
}



/*******************************************************************************/

#if 0

static os_error * areastack_back_one_in_stack (void)

{
 os_error * err;
 wimp_wstate winds;

 /* get position in stack of top bar */
 err=wimp_get_wind_state(handle[TL],&winds);
 areastack(winds.o.behind + 1);
 return(err);
}

#endif


/*******************************************************************************/

static os_error * areastack_forward_one_in_stack (void)

{
 os_error * err;
 wimp_wstate winds;

 /* get position in stack of top bar */
 err = wimp_get_wind_state (handle[TL], &winds);
 if (!err) err = wimp_get_wind_state (winds.o.behind, &winds);
 if (!err) areastack (winds.o.behind);
 return (err);
}




/*******************************************************************************/

static os_error * set_area_coords(void)
{
 os_error * err;
 wimp_icon iconinfo;
 int x0,y0,wid,ht;

 /* get the values */
  /* get icon info */
  err=wimp_get_icon_info(coordhandle, COORD_X, &iconinfo);
  if (!err)
  {
    x0=atoi(iconinfo.data.indirecttext.buffer);
    err=wimp_get_icon_info(coordhandle, COORD_Y, &iconinfo);
    if (!err)
    {
      y0=atoi(iconinfo.data.indirecttext.buffer);
      err=wimp_get_icon_info(coordhandle, COORD_W, &iconinfo);
      if (!err)
      {
        wid=atoi(iconinfo.data.indirecttext.buffer);
        err=wimp_get_icon_info(coordhandle, COORD_H, &iconinfo);
        if (!err)
        {
          ht=atoi(iconinfo.data.indirecttext.buffer);
          /* now check bounds and write back any corrected
           * values. Not strictly necessary, but under certain
           * conditions the anti-flicker tests can prevent the
           * write back in areastack (when the user has set
           * out-of-bounds values twice in succession - the
           * corrected value doesn't change the second time
           * so the incorrect value is left in the icon).
           * Something to think about!
           */
          if (wid<1)
          {
            /* can't be less than 1 px */
            wid=1;
            setcoordicontovalue (COORD_W,wid);
          }
          if(wid>mode.xwindlimit1)
          {
            /* can't be wider than screen */
            wid=mode.xwindlimit1;
            setcoordicontovalue (COORD_W,wid);
          }
          if (ht<1)
          {
            /* can't be less than 1 px */
            ht=1;
            setcoordicontovalue (COORD_H,ht);
          }
          if(ht>mode.ywindlimit1)
          {
            /* can't be taller than screen */
            ht=mode.ywindlimit1;
            setcoordicontovalue (COORD_H,ht);
          }
          /* need to check the area box is not put completely off screen */
          if(x0>mode.xwindlimit)
          {
            x0=mode.xwindlimit;
            setcoordicontovalue (COORD_X,x0);
          }
          if(y0>mode.ywindlimit)
          {
            y0=mode.ywindlimit;
            setcoordicontovalue (COORD_Y,y0);
          }
          if((x0+wid)<0)
          {
            x0=-wid;
            setcoordicontovalue (COORD_X,x0);
          }
          if((y0+ht)<0)
          {
            y0=-ht;
            setcoordicontovalue (COORD_Y,y0);
          }
          /* now need to adjust values to take account of fact that the
           * values x0,y0,ht,wid refer to actual grab area, while areax0
           * etc are the boundaries of the surrounding defining windows
           */
          x0-=1;
          y0-=1;
          wid+=2;
          ht+=2;
          /* now change pixels to os units */
          x0=x0<<mode.xeig;
          wid=wid<<mode.xeig;
          y0=y0<<mode.yeig;
          ht=ht<<mode.yeig;
          /* now set the new coords */
          areax0=x0;
          areay0=y0;
          areax1=x0+wid;
          areay1=y0+ht;
          /* redraw box at new coords */
          areastack_in_position();
        }
      }
    }
  }
 return(err);
}

/*******************************************************************************/

/* Functions dealing with the coordinate display window */

/*******************************************************************************/


static os_error * coord_setup(void)
{
  os_error * err = NULL;
  char buffer[16];
  int w, h;

  sprintf (buffer, "%d", (areax0>>mode.xeig) + 1);
  err = changeicontext (coordhandle, COORD_X, buffer);
  if(!err)
  {
    sprintf (buffer, "%d", (areay0>>mode.yeig) + 1);
    err = changeicontext (coordhandle, COORD_Y, buffer);
  }
  if(!err)
  {
    w = areax1 - areax0;
    sprintf (buffer, "%d", (w>>mode.xeig) - 2);
    err = changeicontext (coordhandle, COORD_W, buffer);
  }
  if(!err)
  {
    h = areay1-areay0;
    sprintf (buffer, "%d", (h>>mode.yeig) - 2);
    err = changeicontext (coordhandle, COORD_H, buffer);
  }

  return (err);
}




/*-----------------------------------------------------------------------------*/

os_error * coord_open(void)

{
  os_error * err;


  if (coordhandle)
  {
    err = forward (coordhandle, 0, NULL);
  }
  else
  {
    err = createwindow(TCOORD, &coordhandle);
    if (!err)
    {
      addcloseevent(coord_close, coordhandle,1);
      addclickevent(coordicon,coordhandle,1);
      addkeyevent(keycoord, coordhandle,1);
      addhelpevent (NULL, coordhandle, TCOORD);

      coord_setup();

      /* open window at centre */
      if (coord_pos.reopen)
      {
        open (coordhandle, coord_pos.x0, coord_pos.y0,
        coord_pos.x1, coord_pos.y1, 0, 0, -1);
      }
      else
      {
        popup (coordhandle, 0);
        /* populate the window_pos struct with current values */
        coord_pos.reopen = 1;
      }
    }
  }


 return (err);
}




/*-----------------------------------------------------------------------------*/

static os_error * coord_close(int handle,int userhandle)

{
 os_error * err;

 err=NULL;

  wos_savewindposition (coordhandle, &coord_pos);

  remcloseevent(coord_close, coordhandle,1);
  remclickevent(coordicon,coordhandle,1);
  remkeyevent(keycoord, coordhandle,1);
  remhelpevent (NULL, coordhandle, TCOORD);

  err = wimp_close_wind (coordhandle);
  coordhandle = NULL;

  USE(handle);
  USE(userhandle);
  return(err);
}


/*-----------------------------------------------------------------------------*/

static os_error * keycoord(int handle,int userhandle, int icon,int * key)

{
 os_error * err;

 err=NULL;


 switch (*key)
 {
   case 13:
   case 0x18E:
   case 0x18F:
     err=set_area_coords();
     break;

   case 6:
     if (isshift)
     {
       areastack_forward_one_in_stack();
     }
     else
     {
       areastack(-1);
     }
     break;

   case 2:
     areastack(-2);
////     areastack_back_one_in_stack();
     break;

 }

 USE(handle);
 USE(userhandle);
 USE(icon);

 return(err);
}


/*******************************************************************************/

static os_error * topredraw(int handle,int userhandle)
{
 os_error     * err;
 wimp_redrawstr redrawstr;
 int            more;
 redrawstr.w=handle;
 err=wimp_redraw_wind(&redrawstr,&more);
 if(!err) err=topredrawsub(handle,userhandle,&redrawstr,more);
 return(err);
}


/*******************************************************************************/

static os_error * topredrawsub(int handle,int userhandle,
                                wimp_redrawstr * redrawstr,int more)
{
 os_error * err;
 windowstr  window;

 err=NULL;

 while(more)
 {
  getw(handle,&window);
  toptext(&window);
  err=wimp_get_rectangle(redrawstr,&more);
  if(err) break;
 }

 return(err);

 USE(userhandle);
}


/*******************************************************************************/

static os_error * toptext(windowstr * win)
{
  os_error     * err;
  char buffer[12];
  font_info fi;
  int w,h;
  int w1,w2;
  int x1,y1;
  int xoffset;


  err=NULL;
  /* construct string to print */
  oldw=areax1-areax0;
  w=(oldw>>1)-2;
  oldh=areay1-areay0;
  h=(oldh>>1)-2;
  sprintf(buffer,"%d%c%d", w, times, h);
  /* get width */
  font_stringbbox(buffer,&fi);
  x1=fi.maxx-fi.minx;
  font_convert_mptoos(x1,0,&w1,&y1);
  w2=win->x1 - win->x0;
  xoffset=(w2-w1)/2;

  font_setfont(fonthandle);
  wimp_set_font_colours(7,11);
  paintcoords(buffer,win->bx+xoffset,win->by-top_size+4);
  return (err);
}



/*******************************************************************************/

static os_error *tidy_caret(int i, int len)
{
  os_error * err;
  wimp_caretstr caret;

   err=wimp_get_caret_pos(&caret);
   if(!err)
   {
     if((caret.w==coordhandle) && (caret.i==i))
     {
       if(caret.index>len) caret.index=len;
       caret.height=-1;
       caret.x=0;
       caret.y=0;
       err=wimp_set_caret_pos(&caret);
     }
   }

 return(err);
}




/*******************************************************************************/

static os_error * geticonvalue ( int i, int *val)
{
 os_error * err;
 wimp_icon iconinfo;

 err=wimp_get_icon_info(coordhandle, i, &iconinfo);
 if(!err)
 {
   *val=atoi(iconinfo.data.indirecttext.buffer);
 }
 return(err);
}



/*******************************************************************************/

static os_error * writeiconvalue ( int i, int val )
{
 os_error * err;
 wimp_icon iconinfo;
 char buffer[12];
 int len;

 err=wimp_get_icon_info(coordhandle, i, &iconinfo);
 if(!err)
 {
   sprintf(buffer,"%d",val);
   len=strlen(buffer);
   strcpy(iconinfo.data.indirecttext.buffer, buffer);
   err=wimp_set_icon_state(coordhandle,i,(wimp_iconflags)0,(wimp_iconflags)0);
 }
 /* we need to deal with caret in case len of text has changed */
 if(!err) err=tidy_caret(i, len);

 return(err);
}



/*******************************************************************************/

static os_error * coordicon(int handle,int userhandle,wimp_mousestr * m)
{
 os_error * err;
 int inc=1;
 int val,v2;

 err = NULL;

 if(isshift) inc=10;
 if(isctrl) inc=20;

 if(m->bbits==1) inc=-inc;  /* adjust button */
 switch(m->i)
 {
   case XDOWN:
     /* simply invert inc and use the same code as for up bump */
     inc=-inc;
   case XUP:
     err=geticonvalue (COORD_X,&val);
     if(!err)
     {
       val+=inc;
       /* adjust may be being used as well as select */
       val=FLOOR(val,0);
       err=geticonvalue (COORD_W,&v2);
       if(!err)
       {
         if ((val+v2)>(mode.xwindlimit1))
         {
           val=mode.xwindlimit1-v2;
         }
         err=writeiconvalue(COORD_X,val);
       }
     }
     break;

   case YDOWN:
     inc=-inc;
   case YUP:
     err=geticonvalue (COORD_Y,&val);
     if(!err)
     {
       val+=inc;
       /* adjust may be being used as well as select */
       val=FLOOR(val,0);
       err=geticonvalue (COORD_H,&v2);
       if(!err)
       {
         if ((val+v2)>(mode.ywindlimit1))
         {
           val=mode.ywindlimit1-v2;
         }
         err=writeiconvalue(COORD_Y,val);
       }
     }
     break;

   case WDOWN:
     inc=-inc;
   case WUP:
     err=geticonvalue (COORD_W,&val);
     if(!err)
     {
       val+=inc;
       /* adjust may be being used as well as select */
       val=FLOOR(val,1);
       err=geticonvalue (COORD_X,&v2);
       if(!err)
       {
         if ((val+v2)>(mode.xwindlimit1))
         {
           val=mode.xwindlimit1-v2;
         }
         err=writeiconvalue(COORD_W,val);
       }
     }
     break;

   case HDOWN:
     inc=-inc;
   case HUP:
     err=geticonvalue (COORD_H,&val);
     if(!err)
     {
       val+=inc;
       /* adjust may be being used as well as select */
       val=FLOOR(val,1);
       err=geticonvalue (COORD_Y,&v2);
       if(!err)
       {
         if ((val+v2)>(mode.ywindlimit1))
         {
           val=mode.ywindlimit1-v2;
         }
         err=writeiconvalue(COORD_H,val);
       }
     }
     break;

 }

 if (!err) err=set_area_coords();
 return(err);

 USE(handle);
 USE(userhandle);
}



/**************************************************************/
/*                    Font stuff                              */
/**************************************************************/

/* use the font manager and either a preset outline font or
   the configured desktop font */


#define FONTNAME "Homerton.Medium"
#define FONTSIZE 12

#define wimp_FONTCHANGED 0x400CF

#define ConverttoOS      0x00040088


/*******************************************************************************/

static os_error * font_convert_mptoos ( int xmp, int ymp, int *xos, int *yos )
{
  os_error *err;
  os_regset r;

  r.r[0] = 0;
  r.r[1] = xmp;
  r.r[2] = ymp;
  err = os_swix(ConverttoOS, &r);
  *xos=r.r[1];
  *yos=r.r[2];
  return(err);
}



/*******************************************************************************/

os_error * set_top_bar_height (void)
{
  os_error *err;
  font_info box;
  int y_mp;
  int x1_mp;
  int x2_mp;
  int x_os, y_os;

  err = font_stringbbox ("1234567890", &box);
  if (!err)
  {
    y_mp = box.maxy - box.miny;
    if (!err) err = font_convert_mptoos(0, y_mp, &x_os, &y_os);
    if (!err)
    {
      /* set height of top bar (in os units) to ht + 8 os units */
      y_os += 8;
      top_size = FLOOR(y_os,SIZE);
    }
    font_stringbbox ("88", &box);
    x1_mp = box.maxx - box.minx;
    font_stringbbox ("88", &box);
    x2_mp = box.maxx - box.minx;
    font_convert_mptoos(x1_mp, x2_mp, &x_os, &y_os);
    if ((x_os - y_os) < 4)
      times = 'x';         /* l.c. x */
    else
      times = '';         /* multiplication symbol */
  }

  return (err);
}




/*******************************************************************************/

/*
 * After a desktop font change or a mode change, although the wimp will
 * request a redraw of the screen, the size of the top bar may have
 * changed due to a change of font or vdu variables, so we need to reopen
 * it to ensure it is redrawn correctly.
 */
os_error * force_resize_topbar (void)
{
  os_error *err = NULL;
  wimp_wstate ws;

  /* do nothing if area is not open */
  if (aopen)
  {
    err = wimp_get_wind_state (handle[TOP], &ws);
    open (handle[TOP], areax0, areay1, areax1, areay1+top_size, 0, 0, ws.o.behind);
    refreshwindow(handle[TOP]);
  }

  return (NULL);
}



/*******************************************************************************/

os_error * font_setdefaultfont (font * fhandle)
{
  desktop_font_in_use = 0;
  return (font_find (FONTNAME, FONTSIZE*16, FONTSIZE*16, 0, 0, fhandle));
}




/*******************************************************************************/

static os_error * DesktopFontChanged (wimp_msgstr * msg, int * ack)
{
  os_error *err = NULL;

  /* now set ourselves up to use the new font */
  /* extract the new fonthandle for the desktop font from the msg */
  fonthandle = (font)msg->data.words[0];

  /* check it is not the system font */
  if (fonthandle == 0)
  {
    /* if system font revert to default outline font */
    font_setdefaultfont (&fonthandle);
  }
  else
  {
    err = font_setfont (fonthandle);
  }
  if (!err)
  {
    err = set_top_bar_height ();
  }

  force_resize_topbar ();

  return (err);

  USE(msg);
  USE(ack);
}


/*******************************************************************************/

/* returns font handle of outline font - value of zero is system font
 * if error - returns zero
*/

font font_getdesktopfonthandle(void)
{
  os_error *err;
  os_regset reg;

  /* check to see whether desktop font is an outline font */
  reg.r[0] = 8;  /* read font handle of desktop font */
  err = os_swix (Wimp_ReadSysInfo | XOS_Bit, &reg);
  if (!err)
  {
    return(reg.r[0]);
  }
  else
    return(0);
}



/*******************************************************************************/

os_error * font_setdesktopfont ( font fh )
{
  os_error *err;

  /* set fonthandle accordingly */
  fonthandle = fh;
  desktop_font_in_use = 1;
  /* now register handler for Message_FontChanged, but only do it once */
  if (!font_changed_msg_registered)
  {
    err = addmessage (DesktopFontChanged, wimp_FONTCHANGED);
    if (!err) font_changed_msg_registered = 1;
  }
  /* need to set the font since the following call to font_stringbbox()
   * acts on the current font
  */
  err = font_setfont (fonthandle);

  return(err);
}





/*******************************************************************************/

os_error * font_setup(void)

{
  os_error *err = NULL;
  font fh;

  /* unset desktop font flag */
  desktop_font_in_use = 0;

  /* now see whether user wishes to use desktop font if available */
  if ((wimpversion >= 350) && UseDesktopFont )
  {
    /* check to see whether desktop font is an outline font */
    fh = font_getdesktopfonthandle();
    if (fh)
    {
      /* we have an outline desktop font */
      font_setdesktopfont(fh);
    }
  }

  if (!desktop_font_in_use)
  {
    /* use our predefined outline font instead of desktop font */
    /* finding the font will set it to current */
    err = font_find(FONTNAME,FONTSIZE*16,FONTSIZE*16,0,0,&fonthandle);
  }

  /* now find the max height of numerical chars in this font */
  if(!err)
  {
    err = set_top_bar_height ();
  }
  return(err);
}


#define Paint  0x00040086

/*******************************************************************************/

static os_error *paintcoords(char *s, int x, int y)

{

os_regset r;

r.r[0] = (int)fonthandle;
r.r[1] = (int)s;
r.r[2] = 0x110;
r.r[3] = x;
r.r[4] = y;

return (os_swix(Paint, &r));

}



/*******************************************************************************/

#define SetFontColours 0x400F3

static os_error * wimp_set_font_colours ( int fg, int bg )
{
  os_regset r;

  r.r[0] = 0;
  r.r[1] = bg;
  r.r[2] = fg;

  return(os_swix(SetFontColours, &r));
}




/*******************************************************************************/

static os_error * font_release (void)
{
  os_error *err;

  if (!desktop_font_in_use) font_lose(fonthandle);
  if (font_changed_msg_registered)
  {
    err = remmessage (DesktopFontChanged, wimp_FONTCHANGED);
    font_changed_msg_registered = 0;
  }
  return (NULL);
}



/**************************************************************/
/*             Mode changed stuff                             */
/**************************************************************/



/* Function called after we have received a mode changed message */

os_error * area_update_on_mode_change (void)
{
  mousestr   mouse;
  int i;
  int xlimit;
  int ylimit;
  int moveby;
  int recreate = 0;

  /* Check whether the area position has become off screen because
   * it was at the top/right of a screen that has become smaller
   * after the mode change
  */

  /* Find the new screen size limit */
  xlimit = (mode.xwindlimit)<<mode.xeig;
  ylimit = (mode.ywindlimit)<<mode.yeig;

  if (areax1 > xlimit)
  {
    moveby = xlimit - areax1;         /* This is negative */
    areax1 += moveby;
    areax0 += moveby;
    recreate = 1;
  }

  if (areay1 > ylimit)
  {
    moveby = ylimit - areay1;         /* This is negative */
    areay1 += moveby;
    areay0 += moveby;
    recreate = 1;
  }

  /* need to do other house keeping only if snap area is open */

  /* Best way I have found to force the area back onscreen is to
   * delete and then recreate the area windows. Otherwise the normal
   * areaopen code seems to put the area back where it started - ie
   * offscreen, in spite of having recalculated the new position above.
  */

 if (aopen)
 {
   if (recreate) closearea ();

   /*
    On a mode change the pointer shape is reset to the default by the wimp.
    If the snap area is open, and the pointer is over the
    border, then it should be showing the move or resize pointer.
    Thus we have to check whether the snap area 'owns' the pointer
    and change it accordingly
   */

   getpointer (&mouse);
   for (i=0; i<MAXW; i++)
   {
     if (mouse.handle == handle[i])
     {
       /* over one of our windows */
       setuserptr ();
       break;
     }
   }

   if (recreate) openarea ();

 }
  return (NULL);
}



/**************************************************************/


/*************  End of c.area  ***********************/










