/* routines for edit menu */

#include "PlotMap.h"

#define MIN_GRID_X 1
#define MAX_GRID_X 30
#define MIN_GRID_Y 1
#define MAX_GRID_Y 30

#define GRID_X 1
#define GRID_Y 2
#define GRID_OK 3
#define GRID_CANCEL 4

#define TEXT_STRING 1
#define TEXT_OK 2
#define TEXT_CANCEL 3

#define ANZ_FILL_OCEANS 12

/********** externals **********/

extern struct config config;
extern struct TextAttr myfont;
extern struct Screen *screen;
extern struct RastPort *rp;
extern PLANEPTR tmpras_mem;
extern UWORD old_maptype;
extern UWORD centerx, centery;
extern double act_vfactor, m_vfactor;
extern WORD box_x1, box_x2, box_y1, box_y2;
extern APTR vinfo;
extern struct Window *wd;
extern struct Gadget *gad_list;

extern void refresh_coord(WORD, WORD);
extern BOOL open_window(int, int, char *);
extern void close_window(void);

/********** Variablen, Daten **********/

static WORD fill_oceans_lon[] =
{
   -60*60+0,
   14*60+0,
   6*60+0,
   0*60+0,
   30*60+0,
   35*60+0,
   37*60+0,
   50*60+0,
   5*60+0,
   -5*60+0,
   40*60+0,
   52*60+0,
};

static WORD fill_oceans_lat[] =
{
   40*60+0,
   44*60+0,
   40*60+0,
   38*60+0,
   35*60+0,
   43*60+0,
   46*60+0,
   43*60+0,
   55*60+0,
   45*60+0,
   17*60+0,
   27*60+0,
};

/********** Routinen **********/

static void swap(WORD *a, WORD *b)
{
   WORD h = *a;
   *a = *b;
   *b = h;
}


static void drawbox(WORD x1, WORD y1, WORD x2, WORD y2, BOOL filled)
{
   if (x1 > x2)                  /* get coords into the right order */
      swap(&x1, &x2);
   if (y1 > y2)
      swap(&y1, &y2);

   if (filled)
      RectFill(rp, x1,y1, x2,y2);
   else
   {
      Line(rp, x1,y1, x2,y1);
      if (y1 != y2)
      {
         LineTo(rp, x2,y2);
         if (x1 != x2)
         {
            LineTo(rp, x1,y2);
            LineTo(rp, x1,y1+1);
         }
      }
   } /* else (filled) */
}


WORD calc_lon(WORD x)
/* returns rounded longitude for screen coord x */
{
   LONG t = ((x - centerx) * (box_x2 - box_x1) << 1) / screen->Width +
            ((box_x1 + box_x2) << 1) / 2;
   if (t >= 0)
      t = t + 1 >> 1;
   else
      t = t >> 1;
   return((WORD)t);
}


WORD calc_lat(WORD y)
/* returns rounded lattitude for screen coord y */
{
   LONG t = ( (LONG)((centery - y) * (box_y1 - box_y2) * act_vfactor)
            << 1) / screen->Height + ((box_y2 + box_y1) << 1) / 2;
   if (t >= 0)
      t = t + 1 >> 1;
   else
      t = t >> 1;
   return((WORD)t);
}


LONG calc_x(WORD lon)
/* return rounded screen x-coord. for longitude lon */
{
   LONG t = ((lon - (box_x1 + box_x2) / 2) * screen->Width << 1) /
            (box_x2 - box_x1);
   if (t >= 0)
      t = t + 1 >> 1;
   else
      t = t >> 1;
   t += centerx;
   return(t);
}


LONG calc_y(WORD lat)
/* return rounded screen y-coord for. lattitude lat */
{
   LONG t = - ((lat - (box_y2 + box_y1) / 2) * screen->Height << 1) /
            (box_y1 - box_y2) / act_vfactor;
   if (t >= 0)
      t = t + 1 >> 1;
   else
      t = t >> 1;
   t += centery;
   return(t);
}


static BOOL calc_box_coord(WORD x1, WORD y1, WORD x2, WORD y2)
/* => FALSE: box too small, => TRUE: all ok */
{
   WORD b_x1, b_x2, b_y1, b_y2;

   if (x1 > x2)
      swap(&x1, &x2);
   if (y1 > y2)
      swap(&y1, &y2);

   if ((x1 == x2) || (y1 == y2))
   {
      TITLE_ERROR("Box too small!");
      return(FALSE);
   }
   else
   {
      b_x1 = calc_lon(x1);       /* nicht box_.. zuweisen, wird in */
      b_x2 = calc_lon(x2);       /* calc_lon() gebraucht */
      if ((old_maptype & MAP_MASK) == MAP_MERCATOR)
      {
         b_y1 = -90 + 2 * atan(exp((FLOAT)((centery - y1) / m_vfactor))) / RAD;
         b_y2 = -90 + 2 * atan(exp((FLOAT)((centery - y2) / m_vfactor))) / RAD;
      }
      else
      {
         b_y1 = calc_lat(y1);
         b_y2 = calc_lat(y2);
      }
      TITLE_NORMAL;

      box_x1 = b_x1;
      box_x2 = b_x2;
      box_y1 = b_y1;
      box_y2 = b_y2;
      return(TRUE);
   }
}


void fill_oceans(void)
/* fills oceans of current map with ocean color */
{
   UWORD i;
   LONG x,y;

   if (!tmpras_mem)                       /* just for savety */
   {
      TITLE_ERROR("No TmpRas allocated, can`t fill oceans!");
      return;
   }
   if (config.bg_color == config.ocean_color)
   {
      TITLE_ERROR("Background color = ocean color, can`t fill oceans!");
      return;
   }

   RMBTRAP_ON;
   MOUSE_WAIT;
   TITLE_MSG("Filling oceans, please wait");

   SetAPen(rp, config.ocean_color);
   for (i = 0; i < ANZ_FILL_OCEANS; i++)
   {
      x = calc_x(fill_oceans_lon[i]);
      y = calc_y(fill_oceans_lat[i]);
      if (x >= 0 && x < screen->Width && y >= 0 && y < screen->Height)
         if (ReadPixel(rp, x,y) == config.bg_color)
            Flood(rp, 1, x,y);
   } /* for (i) */

   TITLE_NORMAL;
   MOUSE_NORMAL;
   RMBTRAP_OFF;
}


static BOOL get_grid_steps(WORD *xstep, WORD *ystep)
/* => TRUE: cancelled or error, => FALSE: all ok, draw grid */
{
   struct NewGadget new_gad;
   struct Gadget *gad, *xstep_gad, *ystep_gad;
   int font_h, char_w;
   BOOL wd_ende = FALSE, ret = FALSE;

   font_h = myfont.ta_YSize;
   char_w = TextLength(rp, "M", 1);

   gad_list = NULL;
   gad = CreateContext(&gad_list);

   new_gad.ng_LeftEdge = screen->WBorLeft + 4 + 11*char_w;
   new_gad.ng_TopEdge = screen->WBorTop + myfont.ta_YSize + 3;
   new_gad.ng_Width = 90;
   new_gad.ng_Height = font_h + 4;
   new_gad.ng_GadgetText = "_XStep:    ";
   new_gad.ng_GadgetID = GRID_X;
   new_gad.ng_TextAttr = &myfont;
   new_gad.ng_Flags = PLACETEXT_LEFT;
   new_gad.ng_VisualInfo = vinfo;
   new_gad.ng_UserData = NULL;
   xstep_gad = gad = CreateGadget(SLIDER_KIND, gad, &new_gad,
            GT_Underscore,'_',  GTSL_Min,MIN_GRID_X,  GTSL_Max,MAX_GRID_X,
            GTSL_Level,*xstep,  GTSL_LevelFormat,"%2ld°",
            GTSL_MaxLevelLen,3,  GA_RelVerify,TRUE,
            TAG_DONE);

   new_gad.ng_TopEdge += font_h + 4 + INTERHEIGHT;
   new_gad.ng_GadgetText = "_YStep:    ";
   new_gad.ng_GadgetID = GRID_Y;
   ystep_gad = gad = CreateGadget(SLIDER_KIND, gad, &new_gad,
            GT_Underscore,'_',  GTSL_Min,MIN_GRID_Y,  GTSL_Max,MAX_GRID_Y,
            GTSL_Level,*ystep,  GTSL_LevelFormat,"%2ld°",
            GTSL_MaxLevelLen,3,  GA_RelVerify,TRUE,
            TAG_DONE);

   new_gad.ng_LeftEdge -= 11*char_w;
   new_gad.ng_TopEdge += font_h + 4 + INTERHEIGHT;
   new_gad.ng_Width = 6*char_w + 8;
   new_gad.ng_Height = font_h + 4;
   new_gad.ng_GadgetText = "_Ok";
   new_gad.ng_GadgetID = GRID_OK;
   new_gad.ng_Flags = PLACETEXT_IN;
   gad = CreateGadget(BUTTON_KIND, gad, &new_gad,
            GT_Underscore,'_',  TAG_DONE);

   new_gad.ng_LeftEdge += 5*char_w + 82;
   new_gad.ng_GadgetText = "_Cancel";
   new_gad.ng_GadgetID = GRID_CANCEL;
   gad = CreateGadget(BUTTON_KIND, gad, &new_gad,
            GT_Underscore,'_',  TAG_DONE);

   if (!gad)
   {
      FreeGadgets(gad_list);
      TITLE_ERROR("Can`t create gadgets!");
      return(TRUE);
   }

   if (!open_window(98 + 11*char_w, 3*font_h + 16 + 2*INTERHEIGHT,
            "Select grid steps"))
      return(TRUE);

   while (!wd_ende)
   {
      struct IntuiMessage *msg;
      ULONG class;
      UWORD code;

      WaitPort(wd->UserPort);
      while (!wd_ende && (msg = GT_GetIMsg(wd->UserPort)))
      {
         class = msg->Class;
         code = msg->Code;
         gad = (struct Gadget *)msg->IAddress; /* need not to be a gadget! */
         GT_ReplyIMsg(msg);

         switch (class)
         {
            case IDCMP_GADGETUP:
               switch (gad->GadgetID)
               {
                  case GRID_X:
                     *xstep = code;
                     break;
                  case GRID_Y:
                     *ystep = code;
                     break;
                  case GRID_OK:
                     wd_ende = TRUE;
                     break;
                  case GRID_CANCEL:
                     wd_ende = TRUE;
                     ret = TRUE;
                     break;
               } /* switch (GadgetID) */
               break;
            case IDCMP_VANILLAKEY:
               switch (code)
               {
                  case 'x':
                     if (++*xstep > MAX_GRID_X)
                        *xstep = MAX_GRID_X;
                     GT_SetGadgetAttrs(xstep_gad, wd, NULL,
                           GTSL_Level,*xstep,  TAG_DONE);
                     break;
                  case 'X':
                     if (--*xstep < MIN_GRID_X)
                        *xstep = MIN_GRID_X;
                     GT_SetGadgetAttrs(xstep_gad, wd, NULL,
                           GTSL_Level,*xstep,  TAG_DONE);
                     break;
                  case 'y':
                     if (++*ystep > MAX_GRID_Y)
                        *ystep = MAX_GRID_Y;
                     GT_SetGadgetAttrs(ystep_gad, wd, NULL,
                           GTSL_Level,*ystep,  TAG_DONE);
                     break;
                  case 'Y':
                     if (--*ystep < MIN_GRID_Y)
                        *ystep = MIN_GRID_Y;
                     GT_SetGadgetAttrs(ystep_gad, wd, NULL,
                           GTSL_Level,*ystep,  TAG_DONE);
                     break;
                  case 'o':
                  case 'O':
                     wd_ende = TRUE;
                     break;
                  case 'c':
                  case 'C':
                     wd_ende = TRUE;
                     ret = TRUE;
                     break;
               } /* switch (code) */
               break;
            case IDCMP_REFRESHWINDOW:
               GT_BeginRefresh(wd);
               GT_EndRefresh(wd, TRUE);
               break;
         } /* switch (class) */
      } /* while (GT_GetIMsg) */
   } /* while (!wd_ende) */

   close_window();
   if (ret)
      TITLE_ERROR("Draw grid cancelled");
   return(ret);
}


void draw_grid(void)
/* draw grid on curr. map */
{
   WORD lon,lat;
   static WORD xstep=15,ystep=15;
   LONG x1,x2,y1,y2;

   if (get_grid_steps(&xstep, &ystep))
      return;

   RMBTRAP_ON;
   MOUSE_WAIT;
   TITLE_MSG("Drawing grid, please wait");

   y1 = max(0, calc_y(90*60));
   y2 = min(screen->Height-1, calc_y(-90*60));
   for (lon = 0; lon <= 180*60; lon += xstep*60)
   {
      if (lon == 0)
         SetAPen(rp, config.gridhigh_color);
      else
         SetAPen(rp, config.grid_color);

      x1 = calc_x(lon);
      if (x1 >= 0 && x1 < screen->Width)
         Line(rp, x1,y1, x1,y2);
   }
   for (lon = 0; lon >= -180*60; lon -= xstep*60)
   {
      if (lon == 0)
         SetAPen(rp, config.gridhigh_color);
      else
         SetAPen(rp, config.grid_color);

      x1 = calc_x(lon);
      if (x1 >= 0 && x1 < screen->Width)
         Line(rp, x1,y1, x1,y2);
   }

   x1 = max(0, calc_x(-180*60));
   x2 = min(screen->Width-1, calc_x(180*60));
   for (lat = 0; lat <= 90*60; lat += ystep*60)
   {
      if (lat == 0)
         SetAPen(rp, config.gridhigh_color);
      else
         SetAPen(rp, config.grid_color);

      y1 = calc_y(lat);
      if (y1 >= 0 && y1 < screen->Height)
         Line(rp, x1,y1, x2, y1);
   }
   for (lat = 0; lat >= -90*60; lat -= ystep*60)
   {
      if (lat == 0)
         SetAPen(rp, config.gridhigh_color);
      else
         SetAPen(rp, config.grid_color);

      y1 = calc_y(lat);
      if (y1 >= 0 && y1 < screen->Height)
         Line(rp, x1,y1, x2, y1);
   }

   TITLE_NORMAL;
   MOUSE_NORMAL;
   RMBTRAP_OFF;
}


void draw_shadow(void)
/* shadow curr. map */
{

   RMBTRAP_ON;
   MOUSE_WAIT;
   TITLE_MSG("Drawing shadow, please wait");


   TITLE_NORMAL;
   MOUSE_NORMAL;
   RMBTRAP_OFF;
}


void draw_line(void)
{
   struct IntuiMessage *msg;
   ULONG class;
   UWORD code;
   WORD mx=0,my=0, x1=-1,y1=-1, oldx,oldy;
   BOOL draw_ende = FALSE;

   IDCMP(IDCMP_INTUITICKS | IDCMP_MOUSEBUTTONS);
   RMBTRAP_ON;
   MOUSE_CROSS;
   TITLE_MSG("Draw line: press LMB, move mouse, release LMB; RMB = cancel");
   SetDrMd(rp, COMPLEMENT);
   SetWrMsk(rp, 0x01);

   while(!draw_ende)
   {
      WaitPort(main_wd->UserPort);
      while (!draw_ende && (msg = (struct IntuiMessage *)GetMsg(main_wd->UserPort)))
      {
         class = msg->Class;
         code = msg->Code;
         oldx = mx;
         oldy = my;
         mx = msg->MouseX;
         my = msg->MouseY;
         ReplyMsg((struct Message *)msg);

         switch (class)
         {
            case IDCMP_INTUITICKS:
               if ((mx != oldx) || (my != oldy))      /* avoid flicker */
               {
                  if (x1 != -1)
                  {
                     Line(rp, x1,y1, oldx,oldy);      /* delete old line */
                     mx = main_wd->MouseX;
                     my = main_wd->MouseY;
                     Line(rp, x1,y1, mx,my);          /* draw new line */
                  }
                  refresh_coord(mx,my);
               }
               break;
            case IDCMP_MOUSEBUTTONS:
               switch (code)
               {
                  case SELECTDOWN:
                     oldx = x1 = mx;
                     oldy = y1 = my;
                     WritePixel(rp, x1,y1);     /* set first point */
                     break;
                  case SELECTUP:
                     if (x1 != -1)  /* MB might be pressed on RELVERIFY- */
                     {              /* gad but released somewhere else */
                        Line(rp, x1,y1, oldx,oldy);   /* delete old line */
                        SetAPen(rp, config.line_color);
                        SetDrMd(rp, JAM2);
                        SetWrMsk(rp, 0xff);
                        Line(rp, x1,y1, mx,my);
                        draw_ende = TRUE;
                        TITLE_NORMAL;
                     }
                     break;
                  case MENUDOWN:
                     if (x1 != -1)
                        Line(rp, x1,y1, oldx,oldy);   /* delete old line */
                     draw_ende = TRUE;
                     TITLE_ERROR("Draw line cancelled");
                     break;
               } /* switch (code) */
               break;
         } /* switch (class) */
      } /* while (GetMsg()) */
   } /* while (!draw_ende) */

   SetWrMsk(rp, 0xff);
   SetDrMd(rp, JAM2);
   MOUSE_NORMAL;
   RMBTRAP_OFF;
   IDCMP(NORMAL_IDCMP);
}


BOOL draw_box(BOOL flag, int selectbox)
/* => FALSE if selected box was too small or cancelled, else => TRUE */
{
   struct IntuiMessage *msg;
   ULONG class;
   UWORD code;
   WORD mx=0,my=0, x1=-1,y1=-1, oldx,oldy;
   BOOL draw_ende = FALSE, ret = TRUE;

   IDCMP(IDCMP_INTUITICKS | IDCMP_MOUSEBUTTONS);
   RMBTRAP_ON;
   MOUSE_CROSS;
   if (selectbox > 0)
      TITLE_MSG("Select box: press LMB, move mouse, release LMB; RMB = cancel");
   else
      TITLE_MSG("Draw box: press LMB, move mouse, release LMB; RMB = cancel");
   SetDrMd(rp, COMPLEMENT);
   SetWrMsk(rp, 0x01);                          /* for a bit more speed */

   while(!draw_ende)
   {
      WaitPort(main_wd->UserPort);
      while (!draw_ende && (msg = (struct IntuiMessage *)GetMsg(main_wd->UserPort)))
      {
         class = msg->Class;
         code = msg->Code;
         oldx = mx;
         oldy = my;
         mx = msg->MouseX;
         my = msg->MouseY;
         ReplyMsg((struct Message *)msg);

         if ((selectbox == 1) && (x1 != -1))       /* ohne Verzerrungen */
         {
            WORD box_w, box_h;
            box_w = abs(mx - x1);
            box_h = ((box_w * screen->Height << 1) / screen->Width + 1) >> 1;
            if (my >= y1)
               my = y1 + box_h;
            else
               my = y1 - box_h;
         }

         switch (class)
         {
            case IDCMP_INTUITICKS:
               if ((mx != oldx) || (my != oldy))      /* avoid flicker */
               {
                  if (x1 != -1)
                  {
                     drawbox(x1,y1, oldx,oldy, flag);
                     if (selectbox != 1)
                     {
                        mx = main_wd->MouseX;
                        my = main_wd->MouseY;
                     }
                     drawbox(x1,y1, mx,my, flag);
                  } /* if () */
                  refresh_coord(mx,my);
               }
               break;
            case IDCMP_MOUSEBUTTONS:
               switch (code)
               {
                  case SELECTDOWN:
                     oldx = x1 = mx;
                     oldy = y1 = my;
                     WritePixel(rp, x1,y1);     /* set first point */
                     break;
                  case SELECTUP:
                     if (x1 != -1)
                     {
                        drawbox(x1,y1, oldx,oldy, flag);
                        SetAPen(rp, config.box_color);
                        SetDrMd(rp, JAM2);
                        SetWrMsk(rp, 0xff);
                        if (selectbox > 0)
                           ret = calc_box_coord(x1,y1, mx,my);
                        else
                        {
                           drawbox(x1,y1, mx,my, flag);
                           TITLE_NORMAL;
                        }
                        draw_ende = TRUE;
                     }
                     break;
                  case MENUDOWN:
                     if (x1 != -1)
                        drawbox(x1,y1, oldx,oldy, flag);
                     draw_ende = TRUE;
                     ret = FALSE;
                     if (selectbox > 0)
                     {  /* { } must be here */
                        TITLE_ERROR("Select box cancelled");
                     }
                     else
                        TITLE_ERROR("Draw box cancelled");
                     break;
               } /* switch (code) */
               break;
         } /* switch (class) */
      } /* while (GetMsg()) */
   } /* while (!draw_ende) */

   SetWrMsk(rp, 0xff);
   SetDrMd(rp, JAM2);
   MOUSE_NORMAL;
   RMBTRAP_OFF;
   IDCMP(NORMAL_IDCMP);
   return(ret);
}


static BOOL get_text(char *str)
/* => TRUE: cancelled, => FALSE: all ok, print text */
{
   struct NewGadget new_gad;
   struct Gadget *gad, *str_gad;
   int font_h, char_w;
   BOOL wd_ende = FALSE, ret = FALSE;

   font_h = myfont.ta_YSize;
   char_w = TextLength(rp, "M", 1);

   gad_list = NULL;
   gad = CreateContext(&gad_list);

   new_gad.ng_LeftEdge = screen->WBorLeft + 4 + 6*char_w;
   new_gad.ng_TopEdge = screen->WBorTop + myfont.ta_YSize + 3;
   new_gad.ng_Width = 20*char_w + 12;
   new_gad.ng_Height = font_h + 6;
   new_gad.ng_GadgetText = "_Text:";
   new_gad.ng_GadgetID = TEXT_STRING;
   new_gad.ng_TextAttr = &myfont;
   new_gad.ng_Flags = PLACETEXT_LEFT;
   new_gad.ng_VisualInfo = vinfo;
   new_gad.ng_UserData = NULL;
   str_gad = gad = CreateGadget(STRING_KIND, gad, &new_gad,
            GT_Underscore,'_',  GTST_String,str,  GTST_MaxChars,79,
            TAG_DONE);

   new_gad.ng_LeftEdge -= 6*char_w;
   new_gad.ng_TopEdge += font_h + 6 + INTERHEIGHT;
   new_gad.ng_Width = 6*char_w + 8;
   new_gad.ng_Height = font_h + 4;
   new_gad.ng_GadgetText = "_Ok";
   new_gad.ng_GadgetID = TEXT_OK;
   new_gad.ng_Flags = PLACETEXT_IN;
   gad = CreateGadget(BUTTON_KIND, gad, &new_gad,
            GT_Underscore,'_',  TAG_DONE);

   new_gad.ng_LeftEdge += 20*char_w + 4;
   new_gad.ng_GadgetText = "_Cancel";
   new_gad.ng_GadgetID = TEXT_CANCEL;
   gad = CreateGadget(BUTTON_KIND, gad, &new_gad,
            GT_Underscore,'_',  TAG_DONE);

   if (!gad)
   {
      FreeGadgets(gad_list);
      TITLE_ERROR("Can`t create gadgets!");
      return(TRUE);
   }

   if (!open_window(26*char_w + 12 + 8, 2*font_h + 10 + INTERHEIGHT + 4,
                     "Enter text"))
      return(TRUE);

   while (!wd_ende)
   {
      struct IntuiMessage *msg;
      ULONG class;
      UWORD code;

      WaitPort(wd->UserPort);
      while (!wd_ende && (msg = GT_GetIMsg(wd->UserPort)))
      {
         class = msg->Class;
         code = msg->Code;
         gad = (struct Gadget *)msg->IAddress; /* need not to be a gadget! */
         GT_ReplyIMsg(msg);

         switch (class)
         {
            case IDCMP_ACTIVEWINDOW:
               ActivateGadget(str_gad, wd, NULL);
               break;
            case IDCMP_GADGETUP:
               switch (gad->GadgetID)
               {
                  case TEXT_OK:
                     wd_ende = TRUE;
                     break;
                  case TEXT_CANCEL:
                     wd_ende = TRUE;
                     ret = TRUE;
                     break;
               } /* switch (GadgetID) */
               break;
            case IDCMP_VANILLAKEY:
               switch (code)
               {
                  case 't':
                  case 'T':
                     ActivateGadget(str_gad, wd, NULL);
                     break;
                  case 'o':
                  case 'O':
                     wd_ende = TRUE;
                     break;
                  case 'c':
                  case 'C':
                     wd_ende = TRUE;
                     ret = TRUE;
                     break;
               } /* switch (code) */
               break;
            case IDCMP_REFRESHWINDOW:
               GT_BeginRefresh(wd);
               GT_EndRefresh(wd, TRUE);
               break;
         } /* switch (class) */
      } /* while (GT_GetIMsg) */
   } /* while (!wd_ende) */

   strcpy(str, ((struct StringInfo *)str_gad->SpecialInfo)->Buffer);
   close_window();                  /* also frees gadgets */
   if (ret)
      TITLE_ERROR("Text cancelled");
   return(ret);
}

void text(void)
{
   struct IntuiMessage *msg;
   ULONG class;
   UWORD code;
   WORD mx=0,my=0, oldx,oldy, txtlen;
   static char txt[80] = "";
   BOOL draw_ende = FALSE;

   if (get_text(txt))
      return;
   txtlen = strlen(txt);

   IDCMP(IDCMP_INTUITICKS | IDCMP_MOUSEBUTTONS);
   RMBTRAP_ON;
   MOUSE_CROSS;
   TITLE_MSG("Text: LMB = put text, RMB = cancel");
   SetDrMd(rp, JAM1 | COMPLEMENT);
   SetWrMsk(rp, 0x01);

   while(!draw_ende)
   {
      WaitPort(main_wd->UserPort);
      while (!draw_ende && (msg = (struct IntuiMessage *)GetMsg(main_wd->UserPort)))
      {
         class = msg->Class;
         code = msg->Code;
         oldx = mx;
         oldy = my;
         mx = msg->MouseX;
         my = msg->MouseY;
         ReplyMsg((struct Message *)msg);

         switch (class)
         {
            case IDCMP_INTUITICKS:
               if ((mx != oldx) || (my != oldy))      /* avoid flicker */
               {
                  if (oldx != -1)               /* for first draw */
                  {
                     Move(rp, oldx,oldy);
                     Text(rp, txt, txtlen);
                  }
                  mx = main_wd->MouseX;
                  my = main_wd->MouseY;
                  Move(rp, mx,my);
                  Text(rp, txt, txtlen);
                  refresh_coord(mx,my);
               }
               break;
            case IDCMP_MOUSEBUTTONS:
               switch (code)
               {
                  case SELECTDOWN:
                     Move(rp, oldx,oldy);
                     Text(rp, txt, txtlen);
                     SetAPen(rp, config.text_color);
                     SetDrMd(rp, JAM1);
                     SetWrMsk(rp, 0xff);
                     Move(rp, mx,my);
                     Text(rp, txt, txtlen);
                     draw_ende = TRUE;
                     TITLE_NORMAL;
                     break;
                  case MENUDOWN:
                     Move(rp, oldx,oldy);
                     Text(rp, txt, txtlen);
                     draw_ende = TRUE;
                     TITLE_ERROR("Text cancelled");
                     break;
               } /* switch (code) */
               break;
         } /* switch (class) */
      } /* while (GetMsg()) */
   } /* while (!draw_ende) */

   SetWrMsk(rp, 0xff);
   SetDrMd(rp, JAM2);
   MOUSE_NORMAL;
   RMBTRAP_OFF;
   IDCMP(NORMAL_IDCMP);
}


void flood_fill(void)
{
   struct IntuiMessage *msg;
   ULONG class;
   UWORD code;
   WORD mx=0,my=0, oldx,oldy;
   BOOL draw_ende = FALSE;

   if (!tmpras_mem)                       /* just for savety */
   {
      TITLE_ERROR("No TmpRas allocated, can`t flood fill!");
      return;
   }

   IDCMP(IDCMP_INTUITICKS | IDCMP_MOUSEBUTTONS);
   RMBTRAP_ON;
   MOUSE_CROSS;
   TITLE_MSG("Flood fill: LMB = fill, RMB = cancel");

   while(!draw_ende)
   {
      WaitPort(main_wd->UserPort);
      while (!draw_ende && (msg = (struct IntuiMessage *)GetMsg(main_wd->UserPort)))
      {
         class = msg->Class;
         code = msg->Code;
         oldx = mx;
         oldy = my;
         mx = msg->MouseX;
         my = msg->MouseY;
         ReplyMsg((struct Message *)msg);

         switch (class)
         {
            case IDCMP_INTUITICKS:
               if ((mx != oldx) || (my != oldy))
                  refresh_coord(mx,my);
               break;
            case IDCMP_MOUSEBUTTONS:
               switch (code)
               {
                  case SELECTDOWN:
                     if (ReadPixel(rp, mx,my) != config.flood_color)
                     {
                        MOUSE_WAIT;
                        SetAPen(rp, config.flood_color);
                        Flood(rp, 1, mx,my);
                     }
                     draw_ende = TRUE;
                     TITLE_NORMAL;
                     break;
                  case MENUDOWN:
                     draw_ende = TRUE;
                     TITLE_ERROR("Flood fill cancelled");
                     break;
               } /* switch (code) */
               break;
         } /* switch (class) */
      } /* while (GetMsg()) */
   } /* while (!draw_ende) */

   MOUSE_NORMAL;
   RMBTRAP_OFF;
   IDCMP(NORMAL_IDCMP);
}

