// TT Open PixelMap (TTOPM) by Ronald Woelfel
// tomtom AT netzoffice dot de
// This all bases heavily on the HelloGhoti-Stuff by 
// Frederik De Kegel, see 
// http://ghotidigital.sourceforge.net/pages/HelloGhotiEN.html

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include <sys/reboot.h>
#include <sys/mount.h>

#include <errno.h>

#include <gd.h>
#include <gdfontl.h>
#include <gdfontt.h>
#include <gdfonts.h>
#include <gdfontmb.h>
#include <gdfontg.h>

// the following two lines are moved to ttopm-include.c
// #ifndef __fbrender_cpp__
// #define __fbrender_cpp__

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <math.h>

#include <linux/fb.h>
#include <sys/time.h>
#include <sys/mman.h>

// Defining color constants
// please note: capitalized colors are colors defined by helloghoti 
// colors for use with gd-functions end with col, eg. goldcol
// You can add an alpha transparence with addalpha.
#include "colors.c"

// defining filename for storing lat/long when exiting TTOPM
#define geoposfilename "./geopos.txt"

// constants for finding out the scroll direction
#define center      0
#define topright    1
#define right       2
#define downright   3
#define down        4
#define downleft    5
#define left        6
#define topleft     7
#define top         8

#define FIFO_BUFFER_SIZE 255

// delay of a quarter second prevents that a touch on
// the touchscreen is evaluated several times
#define moment 250000

#define LINELENGTH 255


// ===== global variables START =====
// char *gpsfifo_name="/var/run/gpspipe";
char gpsfifo_name[LINELENGTH];
int ScreenWidth;
int ScreenHeight;
char configfile[LINELENGTH];
char mapname[LINELENGTH];
int xtiles;
int ytiles;
int xvp;
int yvp;
int xtilesize;
int ytilesize;
int xvpstart;
int yvpstart;
int scrollstep;
int xvpsize;
int yvpsize;
int cachemaxtiles;
int toplefttile_x;           
int toplefttile_y;          
int zoomlevel;                 // first part of the path to the PNG file
int debug;                     // debug modus (0 or 1)
int showsz;                    // show small zoom window?
int screenrecord;              // invoke screenrecord.sh at every screenupdate?
int killttn;                   // should the navi-application killed at TTOPM start?
double cali_long1, cali_long2; // calibration data
double cali_lat1, cali_lat2;   // calibration data
int cali_x1, cali_x2;          // calibration data 
int cali_y1, cali_y2;          // calibration data

   

gdImagePtr tile[90000] = {0}; // tile[0] is not used
// 90000 pointer are enough for 300x300 tiles 
// more dynamic would be nice, eg:
//    gdImagePtr tile[xtiles*ytiles+1] = {0}; 

// ===== global variables END =====


#include "ttopm-include.c"
// => FbRender_Open, FbRender_Clear, FbRender_PutPixel
// const asciiTable, FbRender_BlitCharacter, FbRender_BlitCharacterItalic
// FbRender_BlitText, FbRender_BlitTextItalic, FbRender_Flush,
// FbRender_Scroll, TsScreen_Init, TsScreen_Exit, FixSqrt, DrawhorizontalLine,
// FillCircle, PutLinePoint
// new added functions: FB_PutPixel, FB_HLine, FB_VLine
// FB_Rect, FB_FilledRect, cross,cross2


#include "functions.c"
// => addalpha, wait_for_ts, loadconfigline, loadpng, getcolor,
// detect_direction, smallzoom, xytogeo, read_config,
// get_mem_from_proc, display_config_info


#include "gps.c"
// => process_longitude, process_latitude, process_nmea_rmc,
// readgpsfifo, meanvalue, avggps


#include "menue.c"
// => menuebuttons


// Read the display content and put all stuff in a gdImage.
// To be exactly: because there is no FbRender_GetPixel in
// HelloGhoti its not possible to read the displaycontent. 
// Instead the screen is rendered again and put directly in
// the referenced gdImage.
int read_display(gdImagePtr *im)
{
  int redpart,bluepart,greenpart;
  int c;
  int menuexzl;
  int menueyzl;

  *im=gdImageCreateTrueColor(ScreenWidth,ScreenHeight);
  for (menueyzl=0; menueyzl<yvpsize ; menueyzl++ )
  {
    for (menuexzl=0; menuexzl<xvpsize ; menuexzl++ )
    {
       c=getcolor(menuexzl+xvp,menueyzl+yvp);  
        redpart=gdTrueColorGetRed(c);
        bluepart=gdTrueColorGetBlue(c);
        greenpart=gdTrueColorGetGreen(c);
       gdImageSetPixel(*im, menuexzl,menueyzl, gdTrueColor(redpart,greenpart,bluepart));
    }
  }
  return 0;
}

// Brighten up the referenced gdImage.
// Its probably more nifty to use gdImageCopyMergeGray or 
// gdImageCopyMerge, see: http://www.libgd.org/CopyResize
int fade_display(gdImagePtr *im)
{
  int redpart,bluepart,greenpart;
  int c;
  int x,y;
  for (y=0; y < gdImageSY(*im) ; y++ )
  {
    for (x=0; x < gdImageSX(*im)  ; x++ )
    {
      c  = gdImageGetPixel(*im, x,y);
      redpart=gdTrueColorGetRed(c);
      bluepart=gdTrueColorGetBlue(c);
      greenpart=gdTrueColorGetGreen(c);
      if (redpart < (30)) redpart   += 120;
      if (greenpart < (30)) greenpart   += 120;
      if (bluepart < (30)) bluepart   += 120;
      if (redpart < (255-70)) redpart   += 70;
      if (greenpart < (255-70)) greenpart   += 70;
      if (bluepart < (255-70)) bluepart   += 70;
      gdImageSetPixel(*im, x,y, gdTrueColor(redpart,greenpart,bluepart));
    }
  }
  return 0;
}

// write the content of the gdImage to the screen
int write_display(gdImagePtr *im)
{
  int c;
  int menuexzl;
  int menueyzl;

  for (menueyzl=0; menueyzl<=ScreenHeight ; menueyzl++ )
  {
    for (menuexzl=0; menuexzl<=ScreenWidth ; menuexzl++ )
    {
       c = gdImageGetPixel(*im,menuexzl,menueyzl );
       FbRender_PutPixel((menuexzl),(menueyzl),
                          Color(
                           gdTrueColorGetRed(c), 
                           gdTrueColorGetGreen(c), 
                           gdTrueColorGetBlue(c)));
    }
  }
  FbRender_Flush();
  return 0;
}


// // oldstuff:
// // Draws a Window in the referenced gdImage
// int win_gpscoord(gdImagePtr *im,
//                  int winwidthpct,
// 		 int winheightpct,
// 		 int wintoppct,
// 		 char *s)
// {
//   // winwidthpct  = window width in percent
//   // winheightpct = window height in percent
//   // wintoppct    = window distance in percent from top
//   double longitude;
//   double latitude;
//   char latitudestring[255];
//   char longitudestring[255];
//   int winx1,winy1,winx2; // real coordinates of the rectangle
//   int winwidth;          // Window width (pixel)
//   int winheight;         // Window height (pixel)
// 
//   winwidth  = (ScreenWidth * winwidthpct)/100;
//   winheight = (ScreenHeight * winheightpct)/100; 
//   winy1 =     (ScreenHeight * wintoppct)/100;
//   winx1=(ScreenWidth-winwidth)/2;
//   winx2=ScreenWidth-winx1;
// 
//   gdImageFilledRectangle(*im, 0, 0, ScreenWidth, ScreenHeight, whitecol);
//   gdImageFilledRectangle(*im, winx1, winy1, winx2, winy1+winheight, goldcol);
//   gdImageRectangle(*im, winx1, winy1, winx2, winy1+winheight, goldenrodcol);
// 
//   avggps(1,&longitude,&latitude);
//   sprintf( latitudestring, "Breitengrad: %f", latitude);
//   sprintf( longitudestring, "Längengrad: %f", longitude);
// //  gdImageString(*im, gdFontGetLarge(), 10, 25, latitudestring, blackcol);
// //  gdImageString(*im, gdFontGetLarge(), 10, 40, longitudestring, blackcol);
//   FbRender_Flush();
//   return 0;
// }


int setscrollspeedmenue()
{
  int x=0, y=0, pen=0;
  gdImagePtr scrollmenue;

  read_display(&scrollmenue);
  fade_display(&scrollmenue);

  usleep(moment);
  while (TsScreen_pen(&x,&y,&pen));
  menuebuttons(&scrollmenue,"5 Pixel","10 Pixel","20 Pixel",
                  "30 Pixel","Exit","50 Pixel",
                  "100 Pixel","500 Pixel","1000 Pixel",
                  0);
  write_display(&scrollmenue);
  int DoExit = 0;
  while (!DoExit)
  {
     if (TsScreen_pen(&x,&y,&pen))
     {
      if ( detect_direction(x,y,15) == topleft )
        {  cross(x,y); FbRender_Flush();
	   scrollstep=5 ; DoExit=1;  }
      if ( detect_direction(x,y,15) == top )
        {  cross(x,y); FbRender_Flush();
	   scrollstep=10 ; DoExit=1; }
      if ( detect_direction(x,y,15) == topright )
        {  cross(x,y); FbRender_Flush();
	   scrollstep=20 ; DoExit=1; }
      if ( detect_direction(x,y,15) == left )
        {  cross(x,y); FbRender_Flush();
	   scrollstep=30 ; DoExit=1; }
      if ( detect_direction(x,y,15) == center )
        {  cross(x,y); FbRender_Flush();
	   DoExit=1; }
      if ( detect_direction(x,y,15) == right )
        {  cross(x,y); FbRender_Flush();
	   scrollstep=50 ; DoExit=1; }
      if ( detect_direction(x,y,15) == downleft )
        {  cross(x,y); FbRender_Flush();
	   scrollstep=100 ;DoExit=1; }
      if ( detect_direction(x,y,15) == down )
        {  cross(x,y); FbRender_Flush();
	   scrollstep=500 ;DoExit=1; }
      if ( detect_direction(x,y,15) == downright )
        {  cross(x,y); FbRender_Flush();
	   scrollstep=1000;DoExit=1; }
     }
  }
  usleep(moment);
  while (TsScreen_pen(&x,&y,&pen));
  return 0;
}

int draw_crosshair(gdImagePtr *im,int x,int y)
{
  gdImageLine(*im, x,y-15,x,y-5,blackcol);
  gdImageLine(*im, x,y+15,x,y+5,blackcol);
  gdImageLine(*im, x-15,y,x-5,y,blackcol);
  gdImageLine(*im, x+15,y,x+5,y,blackcol);
  gdImageArc(*im, x, y, 20, 20, 0, 360, blackcol);
  return 0;
}


int calibrate()
{
  int x=0, y=0, pen=0;
  int xdummy=0, ydummy=0, pendummy=0;
  gdImagePtr map;
  char statusline[LINELENGTH];

  read_display(&map);
  write_display(&map);
  gdImageDestroy(map);


  int DoExit = 0;
  while (!DoExit)
  {
    while (!TsScreen_pen(&x,&y,&pen));
    usleep(100000);
    while (TsScreen_pen(&xdummy,&ydummy,&pendummy));
    if ( x>(ScreenWidth<40) && y < 40 )
      DoExit=1;
    read_display(&map);
    draw_crosshair(&map,x,y);
    gdImageFilledRectangle(map,0,0,ScreenWidth,20,redcol);
    gdImageString(map, gdFontGetLarge(), ScreenWidth-40, 3, "EXIT", yellowcol);
    sprintf( statusline, "cali_x/cali_y: %d/%d", xvp+x,yvp+y);
    gdImageString(map, gdFontGetLarge(), 3, 3, statusline, whitecol);
    write_display(&map);
    gdImageDestroy(map);
  }
  
  read_display(&map);
  write_display(&map);
  gdImageDestroy(map);
  return 0;
}




int geocoords()
{
  int x=0, y=0, pen=0;
  int xdummy=0, ydummy=0, pendummy=0;
  gdImagePtr map;
  double latitude;
  double longitude;
  char statusline[LINELENGTH];

  read_display(&map);
  write_display(&map);
  gdImageDestroy(map);

  int DoExit = 0;
  while (!DoExit)
  {
    while (!TsScreen_pen(&x,&y,&pen));
    usleep(100000);
    while (TsScreen_pen(&xdummy,&ydummy,&pendummy));
    if ( x>(ScreenWidth<40) && y < 40 )
      DoExit=1;
    read_display(&map);
    draw_crosshair(&map,x,y);
    gdImageFilledRectangle(map,0,0,ScreenWidth,20,bluecol);
    gdImageString(map, gdFontGetLarge(), ScreenWidth-40, 3, "EXIT", yellowcol);
    xytogeo(xvp+x,yvp+y,&latitude,&longitude);
    sprintf( statusline, "Lat/Long: %f %f", latitude,longitude);
    gdImageString(map, gdFontGetLarge(), 3, 3, statusline, whitecol);
    write_display(&map);
    gdImageDestroy(map);
  }
  
  while (! TsScreen_pen(&x,&y,&pen));
  read_display(&map);
  write_display(&map);
  gdImageDestroy(map);
  return 0;
}


// shows the current position with a crosshair on the map and
// scrolls to the appropriate aperture of the map if necessary
// resource=1 => current GPS position
// resource=2 => file with geopos in it
int gpspos(int resource)
{
  double longdifference;
  double latdifference;

  double longitude;
  double latitude;
  double geolatdiff;
  double geolongdiff;
  double xfactor;
  double yfactor;
  double lat0;
  double long0;
  int xdifference;
  int ydifference;
  int x=0, y=0, pen=0;
  int xpixel,ypixel;
  
  usleep(moment);
  while (TsScreen_pen(&x,&y,&pen));

  // ##### compute xfactor and yfactor START #####
  longdifference = cali_long2-cali_long1;
  latdifference  = cali_lat2-cali_lat1;
  xdifference    = cali_x2-cali_x1; // necessary?
  ydifference    = cali_y2-cali_y1; // necessary?
  xfactor = (longdifference / xdifference);
  yfactor = (latdifference / ydifference);
  // ##### compute xfactor and yfactor END #####
  lat0  = cali_lat1  - (yfactor*cali_y1); // lat0 of the topleft corner
  long0 = cali_long1 - (xfactor*cali_x1); // long0 of the topleft corner

  if (resource==1)
  {
    avggps(5,&longitude,&latitude);
  }
  if (resource==2)
  {
    FILE *fp;
    char line[LINELENGTH];

    if((fp=fopen(geoposfilename,"r")) == NULL)
    {
      fprintf(stderr,"Error reading from geoposfile %s\n",geoposfilename);
      xvp=0; yvp=0;
      return 0;
    }
    else
    {
      if ( fgets(line,LINELENGTH,fp) )
      {
        sscanf( line, "%lf %lf", &latitude,&longitude);
        if (debug)
	  fprintf(stderr,"Lat/Long from geoposfile: %f/%f\n",latitude,longitude);
      }
      fclose(fp);
    }
  }

  geolatdiff=(lat0-latitude);     // distance in degree 
  geolongdiff=(long0-longitude);  // distance in degree
  xpixel=abs(geolongdiff/xfactor);
  ypixel=abs(geolatdiff/yfactor);
  // ypixel=(geolatdiff/yfactor);
  // for centring the current position in the middle of the screen
  xvp=xpixel-ScreenWidth/2;
  yvp=ypixel-ScreenHeight/2;
  
  return 0;
}



int newdisplaymenue()
{
  int x=0, y=0, pen=0;
  gdImagePtr menue;

  usleep(moment);
  while (TsScreen_pen(&x,&y,&pen));

  read_display(&menue);
  fade_display(&menue);
  menuebuttons(&menue,"Zoom out","Geo-Coords","Zoom in",
                          "GPS-Pos","Exit Menue","Calibrate",
                          "Scrollspeed","Debug on/off","Exit TTOPM",
                          0);
  write_display(&menue);
  gdImageDestroy(menue);


  int DoExit = 0;
  while (!DoExit)
  {
     if (TsScreen_pen(&x,&y,&pen))
     {
      if ( detect_direction(x,y,15) == down )
      {
	cross(x,y); FbRender_Flush();
        if (debug) 
	  { debug=0; DoExit=1; }
	else
	  { debug=1; DoExit=1; }
      }
      if ( detect_direction(x,y,15) == right )
      {
	cross(x,y); FbRender_Flush();
        calibrate();
        DoExit=1;
      }

      if ( detect_direction(x,y,15) == topright )
      {
        // Zoom in
	cross(x,y); FbRender_Flush();
        double latitude;
        double longitude;
	xytogeo(xvp+ScreenWidth/2,yvp+ScreenHeight/2,&latitude,&longitude);
        // write lat/long to geoposfile
        write_geopos_to_file(latitude,longitude);
	exit (2);
      }

      if ( detect_direction(x,y,15) == topleft )
      {
        // Zoom out
        double latitude;
        double longitude;
	xytogeo(xvp+ScreenWidth/2,yvp+ScreenHeight/2,&latitude,&longitude);
        // write lat/long to geoposfile
        write_geopos_to_file(latitude,longitude);
	exit (3);
      }
      if ( detect_direction(x,y,15) == downright )
      {
	// quit ttopm, a reboot is only necessary when ttn (= the native
	// TomTom application) has been killed
	cross(x,y); FbRender_Flush();
	fprintf(stderr,"\n");
        if ( killttn == 1 )
	  {
	    fprintf(stderr,"rebooting know\n");
	    system("/bin/sync");
	    system("/sbin/reboot");
	  }
        else 
	  {
	    fprintf(stderr,"normal exit");
	    exit(0);
	  }
      }
      if ( detect_direction(x,y,15) == left )
      {
	cross(x,y); FbRender_Flush();
        gpspos(1);
	usleep(moment);
        while (TsScreen_pen(&x,&y,&pen));
	return 0;
      }
      if ( detect_direction(x,y,15) == top )
      {
	cross(x,y); FbRender_Flush();
        geocoords();
        DoExit=1;
      }
      if ( detect_direction(x,y,15) == downleft )
      {
	cross(x,y); FbRender_Flush();
        setscrollspeedmenue(&menue);
        write_display(&menue);
        usleep(moment);
        while (TsScreen_pen(&x,&y,&pen));
      }
      if ( detect_direction(x,y,15) == center )
	cross(x,y); FbRender_Flush();
        DoExit=1;
     }
  }
  
  usleep(moment);
  while (TsScreen_pen(&x,&y,&pen));

  read_display(&menue);
  write_display(&menue);

  gdImageDestroy(menue);
  return 0;
}




// #####################################################

int main(int argc, char** argv)
{
  // if there is a first argument then it is the configfile
  if (argc > 1)
    strcpy(configfile, argv[1]);
  else
    strcpy(configfile, "/mnt/sdcard/ttopm/config.txt");
 
  int x=0, y=0, pen=0;
  int c;
  int knr;
  int knrmitte=0;
  int xoffset=0;           // When xvpsize and yvpsize are less than the
  int yoffset=0;           // real screen resolution. The screen aperture could
                           // be shifted with xoffset and yoffset from the topleft
			   // corner to a certain point. (normally not needed!)
  int xvpzl,yvpzl;         // ViewPoint (count through all pixels on screen)
  int kachelx1,kachely1;
  int kachelx2,kachely2;
  int xmiddle,ymiddle;     // virtual coordinates of the pixel in the center of the screen
  int xdiff,ydiff;         // distance between two tiles 
  int cachedtiles;

  read_config(); // load settings from configfile

  if (killttn == 1) {
    if ( system("killall ttn") ) 
     fprintf(stderr,"Error while executing: killall ttn"); 
    sleep (1);
    if ( system("./watchdog.sh & 2>/dev/null") ) 
     fprintf(stderr,"Error while executing: watchdog.sh"); 
  }
  TsScreen_Init();
  FbRender_Open();
  FbRender_Flush();
  FbRender_Clear(0, FbRender_ScreenHeight(), BLACK);
  FbRender_Flush();
  gpspos(2);

  display_config_info();

// ################ main loop START #################
  int DoExit = 0;
  while (!DoExit)
  {
          usleep(500);

          if (xvp+xvpsize > xtiles*xtilesize)
             xvp=xtiles*xtilesize-xvpsize;
      
          if (yvp+yvpsize > ytiles*ytilesize) {
             yvp=ytiles*ytilesize-yvpsize;
	  }

          if (xvp < 0 )
             xvp = 0;

          if (yvp < 0 )
             yvp = 0;


// --------- Memory Management START ----------
       if (debug)
         fprintf(stderr,"xvp/yvp: %d/%d\n",xvp,yvp);

       cachedtiles=0;
       for ( knr=1; knr<=(xtiles*ytiles); knr++  ) 
         if (tile[knr] != 0) 
           cachedtiles++;
       if (debug)
         fprintf(stderr,"cached: %d\n",cachedtiles);

       // --------- unload tiles START ----------
	  // loop passes all tile pointers. tiles which are to far
	  // away are discarded from memory.
          for ( knr=1; knr<=(xtiles*ytiles); knr++  ) 
	  {
	    // x1/y2 Kachelkoordinaten der Kachel aktuellen knr
	    // x1 => 0..(xtiles-1) y1 => 0..(ytiles-1)
	    kachelx2=(knr) % xtiles;  
	    kachely2=(knr) / xtiles;
            // calculate tile-coordinates of the tile which is displayed
	    // in the center of the screen
            xmiddle=xvp+(ScreenWidth/2);
            ymiddle=yvp+(ScreenHeight/2);
            knrmitte=(ymiddle/ytilesize)*xtiles+(xmiddle/xtilesize)+1;
            kachelx1=(knrmitte) % xtiles;  
            kachely1=(knrmitte) / xtiles;
            // calculate distance
            xdiff=abs(kachelx1-kachelx2);
            ydiff=abs(kachely1-kachely2);
            if ( ((xdiff+ydiff) > 2) && (cachedtiles>cachemaxtiles) ) {
              if (tile[knr] != 0) {
	        if (debug)
                  fprintf(stderr,"\nDelete tile %d xdiff: %d and ydiff %d\n ",knr,xdiff,ydiff);
                gdImageDestroy(tile[knr]);
	        tile[knr] = 0;
              }
            }
          }
	  kachelx1=(knrmitte) % xtiles;  
          kachely1=(knrmitte) / xtiles;
       // --------- unload tiles END ----------

       // --------- Load tiles START ----------
       for (yvpzl=0; yvpzl<(yvpsize+ytilesize) ; yvpzl=yvpzl+ytilesize ) {
            for (xvpzl=0; xvpzl<(xvpsize+xtilesize) ; xvpzl=xvpzl+xtilesize ) {
              // printf("%d/%d ",xvpzl+xvp,yvpzl+yvp); 
	      // find out tilenumber (see function getcolor)
              knr=((yvpzl+yvp)/ytilesize)*xtiles+((xvpzl+xvp)/xtilesize)+1;
              if (tile[knr] == 0) {
                if (debug) 
		  printf("\nLoad tile %d\n",knr);
                loadpng(&tile[knr],knr);
		
                if (debug)
		  printf("\nTile %d loaded\n",knr);
              }
	    }
       }
       // --------- Load tiles END ----------
// --------- Memory Management END ----------

// --------- Draw Screen START ----------
          for (yvpzl=0; yvpzl<yvpsize ; yvpzl++ )
          {
            for (xvpzl=0; xvpzl<xvpsize ; xvpzl++ )
            {
             c=getcolor(xvpzl+xvp,yvpzl+yvp);
             FbRender_PutPixel((xvpzl+xoffset),(yvpzl+yoffset),
                                Color(
                                 gdTrueColorGetRed(c), 
                                 gdTrueColorGetGreen(c), 
                                 gdTrueColorGetBlue(c)));
            }
          }
	  cross2(ScreenWidth/2,ScreenHeight/2);
	  if ( showsz==1 )
	    fastsmallzoom();

if (debug == 2)
{
   char debugline1[LINELENGTH];
   char debugline2[LINELENGTH];
   sprintf( debugline1, "Memory used: %d", 4*get_mem_from_proc());
   sprintf( debugline2, "Tiles loaded: %d", cachedtiles);

   FbRender_BlitText(10,10, BLACK, WHITE, debugline1);
   FbRender_BlitText(10,35, BLACK, WHITE, debugline2);
}
          FbRender_Flush();

// --------- Draw Screen END ----------



    //if (TsScreen_pen(&x,&y,&pen))
    while (! TsScreen_pen(&x,&y,&pen)); // NEU
    {

      if ( detect_direction(x,y,33) == topright )
      {
	  cross(x,y); FbRender_Flush();
          xvp=xvp+scrollstep;
          yvp=yvp-scrollstep;
      }
      else if ( detect_direction(x,y,33) == right )
      {
	  cross(x,y); FbRender_Flush();
          xvp=xvp+scrollstep;
      }
      else if ( detect_direction(x,y,33) == downright )
      {
	  cross(x,y); FbRender_Flush();
          xvp=xvp+scrollstep;
          yvp=yvp+scrollstep;
      }
      else if ( detect_direction(x,y,33) == topleft )
      {
	  cross(x,y); FbRender_Flush();
          xvp=xvp-scrollstep;
          yvp=yvp-scrollstep;
      }
      else if ( detect_direction(x,y,33) == left )
      {
	  cross(x,y); FbRender_Flush();
          xvp=xvp-scrollstep;
      }
      else if ( detect_direction(x,y,33) == downleft )
      {
	  cross(x,y); FbRender_Flush();
          xvp=xvp-scrollstep;
          yvp=yvp+scrollstep;
      }

      // down
      else if ( detect_direction(x,y,33) == down )
      {
	  cross(x,y); FbRender_Flush();
          yvp=yvp+scrollstep;
      }
      // top
      else if ( detect_direction(x,y,33) == top )
      {
	  cross(x,y); FbRender_Flush();
          yvp=yvp-scrollstep;
      }
      // center of screen
      else if ( detect_direction(x,y,33) == center )
      {
	  cross(x,y); FbRender_Flush();
          newdisplaymenue();
      }
    }
  }
// ################ main loop END #################

  return 0;
}
