view Interface.pde @ 0:ebd5689e2985

Initial import of Multipaint sketch version 22.5.2017.
author Tero Heikkinen
date Tue, 03 Jul 2018 20:56:55 +0300
parents
children 5eb3559e1778
line wrap: on
line source

// This collects UI stuff that's not directly related to the viewport
// i.e. Icons, color selectors and the like, but also undo/spare

//fixed raster parameters
int g_raster_offset_x;
int g_raster_offset_y;
int g_raster_no;

byte[] g_depressed = new byte[256];

int g_fixedraster[]={
  1,0,0,0,1,0,0,0,
  0,0,1,0,0,0,1,0,
  1,0,0,0,1,0,0,0,
  0,0,1,0,0,0,1,0,
  1,0,0,0,1,0,0,0,
  0,0,1,0,0,0,1,0,
  1,0,0,0,1,0,0,0,
  0,0,1,0,0,0,1,0};

int g_rasterpatterns[]={
  
  0,1,1,1,0,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,0,1,1,1,0,1,
  1,1,1,1,1,1,1,1,
  0,1,1,1,0,1,1,1,
  1,1,1,1,1,1,1,1,
  1,1,0,1,1,1,0,1,
  1,1,1,1,1,1,1,1,
  
  0,1,1,1,0,1,1,1,
  1,1,0,1,1,1,0,1,
  0,1,1,1,0,1,1,1,
  1,1,0,1,1,1,0,1,
  0,1,1,1,0,1,1,1,
  1,1,0,1,1,1,0,1,
  0,1,1,1,0,1,1,1,
  1,1,0,1,1,1,0,1,
    
  0,1,1,1,0,1,1,1,
  1,0,1,0,1,0,1,0,
  1,1,0,1,1,1,0,1,
  1,0,1,0,1,0,1,0,
  0,1,1,1,0,1,1,1,
  1,0,1,0,1,0,1,0,
  1,1,0,1,1,1,0,1,
  1,0,1,0,1,0,1,0,
  
  1,0,1,0,1,0,1,0,
  0,1,0,1,0,1,0,1,
  1,0,1,0,1,0,1,0,
  0,1,0,1,0,1,0,1,
  1,0,1,0,1,0,1,0,
  0,1,0,1,0,1,0,1,
  1,0,1,0,1,0,1,0,
  0,1,0,1,0,1,0,1,

  1,0,0,0,1,0,0,0,
  0,1,0,1,0,1,0,1,
  0,0,1,0,0,0,1,0,
  0,1,0,1,0,1,0,1,
  1,0,0,0,1,0,0,0,
  0,1,0,1,0,1,0,1,
  0,0,1,0,0,0,1,0,
  0,1,0,1,0,1,0,1,
  
  1,0,0,0,1,0,0,0,
  0,0,1,0,0,0,1,0,
  1,0,0,0,1,0,0,0,
  0,0,1,0,0,0,1,0,
  1,0,0,0,1,0,0,0,
  0,0,1,0,0,0,1,0,
  1,0,0,0,1,0,0,0,
  0,0,1,0,0,0,1,0,
  
  1,0,0,0,1,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,1,0,0,0,1,0,
  0,0,0,0,0,0,0,0,
  1,0,0,0,1,0,0,0,
  0,0,0,0,0,0,0,0,
  0,0,1,0,0,0,1,0,
  0,0,0,0,0,0,0,0,
   
  1,1,1,1,1,1,1,1,
  0,0,0,0,0,0,0,0,
  1,1,1,1,1,1,1,1,
  0,0,0,0,0,0,0,0,
  1,1,1,1,1,1,1,1,
  0,0,0,0,0,0,0,0,
  1,1,1,1,1,1,1,1,
  0,0,0,0,0,0,0,0,
  
  1,0,1,0,1,0,1,0,
  0,0,0,0,0,0,0,0,
  1,0,1,0,1,0,1,0,
  0,0,0,0,0,0,0,0,
  1,0,1,0,1,0,1,0,
  0,0,0,0,0,0,0,0,
  1,0,1,0,1,0,1,0,
  0,0,0,0,0,0,0,0,

  1,0,1,0,1,0,1,0,
  1,0,1,0,1,0,1,0,
  1,0,1,0,1,0,1,0,
  1,0,1,0,1,0,1,0,
  1,0,1,0,1,0,1,0,
  1,0,1,0,1,0,1,0,
  1,0,1,0,1,0,1,0,
  1,0,1,0,1,0,1,0  
};


void setup_raster()
{
  g_raster_offset_x=0;
  g_raster_offset_y=0;
  g_raster_no=3;
  set_fixed_raster(g_raster_no);
}

void fixed_raster_command(int par)
{
  if(par=='p'){
    g_raster_no--;
    if(g_raster_no<0)g_raster_no=9;
    set_fixed_raster(g_raster_no);
    g_data['r']=1;
  }
  if(par=='n'){
    g_raster_no++;
    if(g_raster_no>9)g_raster_no=0;
    set_fixed_raster(g_raster_no);
    g_data['r']=1; 
  }
  if(par=='x'){
    g_raster_offset_x++;
    if(g_raster_offset_x>3)g_raster_offset_x=0;
  }
  if(par=='y'){
    g_raster_offset_y++;
    if(g_raster_offset_y>3)g_raster_offset_y=0;
  }  
}

int magmode()
{
  //return the mode "number" based on g_uizoom and 'm' and 'M'
  //currently valid outputs are 0,10,20,1,11,21,2,12,22
  int base=0;
  if(g_uizoom==1)base=10;
  if(g_uizoom==3)base=20;
  if(g_data['M']==1&&g_data['m']==1)g_data['m']=0;
  if(g_data['m']==1)base++;
  if(g_data['M']==1)base=base+2;
  return base;
}

int magx()
{
  //return the amount of horizontal 8x8 characters in current mode ('m' or 'M')
  int psize,mag;
  psize=g_magpix[magmode()];mag=psize*8;
  return (width-(33*g_uizoom))/mag;
}

int magy()
{
  //return the amount of vertical 8x8 characters in current mode ('m' or 'M')  
  int psize,mag;
  psize=g_magpiy[magmode()];mag=psize*8;
  return (height-(33*g_uizoom))/mag; //how many chars in a magmode
}

void ustats()
{
//a debug thingie in case the step undo does not work
//println("UINDEX:"+g_uindex[g_spare]);
//println("UTOP:"+g_utop[g_spare]);
//println("UBOTTOM:"+g_ubottom[g_spare]);
}

void store_undo() //to_undo
{
  if(g_spare==0)g_undob[g_uindex[g_spare]]=g_map.clone();
  if(g_spare==1)g_undobs[g_uindex[g_spare]]=g_map.clone();
  g_uindex[g_spare]++;
  if(g_uindex[g_spare]>10)g_uindex[g_spare]=0;
  if(g_uindex[g_spare]==g_ubottom[g_spare]){
    g_ubottom[g_spare]++;
    if(g_ubottom[g_spare]>10)g_ubottom[g_spare]=0;
  }  
  g_utop[g_spare]=g_uindex[g_spare];
  
  refreshpalette();
  ustats();
}

void restore_undo()
{
  if(g_uindex[g_spare]==g_ubottom[g_spare])return;
  if(g_spare==0)g_undob[g_uindex[g_spare]]=g_map.clone();
  if(g_spare==1)g_undobs[g_uindex[g_spare]]=g_map.clone();
  g_uindex[g_spare]--;
  if(g_uindex[g_spare]<0)g_uindex[g_spare]=10;
  if(g_spare==0)g_map=g_undob[g_uindex[g_spare]].clone();
  if(g_spare==1)g_map=g_undobs[g_uindex[g_spare]].clone();
  
  refreshpalette();
  ustats();
}

void redo_undo()
{
  if(g_uindex[g_spare]==g_utop[g_spare])return;
  g_uindex[g_spare]++;
  if(g_uindex[g_spare]>10)g_uindex[g_spare]=0;
  if(g_spare==0)g_map=g_undob[g_uindex[g_spare]].clone();
  if(g_spare==1)g_map=g_undobs[g_uindex[g_spare]].clone();
  if(g_uindex[g_spare]>10)g_uindex[g_spare]=0;
  refreshpalette();
  ustats();
}

void spare() //dpaint style spare page
{
  if(g_spare==0){// in REAL page, change to SPARE page
       g_swappage=g_sparepage.clone();g_sparepage=g_map.clone();
       g_map=g_swappage.clone();frame.setTitle(sfilename);
  }
  else
  {// in SPARE page, change to REAL page
       g_swappage=g_sparepage.clone();g_sparepage=g_map.clone();
       g_map=g_swappage.clone();frame.setTitle(filename);
  }
  g_spare=1-g_spare;
  g_realfront=byte(g_farge);g_realback=byte(g_backg);
  refreshpalette();
}

void switcher(int di)
{
  // this achieves varieties of whole screen copying
  // needed for brush copy and pre-drawing the shapes when a
  // tool is active etc.
  switch(di)
  {
    case 0:
      g_rmap=g_map.clone();
    break;
    case 1:
      g_map=g_rmap.clone();
      for(int i=0;i<1024;i++){
        if(g_remdo[i]==1){g_remdo[i]=0;g_redo[i]=0;}
      }
    break;
    case 2:
      g_brush=g_map.clone();
    break;
    case 3:
       g_sparepage=g_map.clone();
    break;
    case 4:
       g_map=g_sparepage.clone();
    break;
  }
}

void sussborder(){  
  makecolor(259,g_r[g_map[0]],g_g[g_map[0]],g_b[g_map[0]]);
  g_boxreconstruct=2;
}

void makecolor(int c, int rr,int gg,int bb)
{
  //0-255 go to g_map[] up until 1021-1023
  //the rest is not stored
  if(c<256){
    g_map[256+c*3]=byte(rr);
    g_map[256+c*3+1]=byte(gg);
    g_map[256+c*3+2]=byte(bb);
  }
  g_r[c]=rr;g_g[c]=gg;g_b[c]=bb;
  g_rgb[c]=0xff000000;
  g_rgb[c]=g_rgb[c]+rr*0x00010000;
  g_rgb[c]=g_rgb[c]+gg*0x00000100;
  g_rgb[c]=g_rgb[c]+bb*0x00000001;  
}

int fylli()
{
  //for the animated rubberband thingy
  g_rband++;
  if(g_rband>g_rbang){
    g_rband=0;g_rbang++;if(g_rbang>12)g_rbang=8;
  }
  if(g_rband>=3)return 0;
  return 1;
}

void e_rect(int x1,int y1,int w,int h,int rgb)
{
  int ad=x1+y1*width;
  //updatepixels has to be handled elsewhere
  for(int yy=0;yy<h;yy++){
    for(int xx=0;xx<w;xx++){
      pixels[ad+xx]=rgb;
    }
    ad=ad+width;
  }
}

void d_rect(int x1,int y1,int w,int h,int rgb)
{
  int ad=x1+y1*width;
  //updatepixels has to be handled elsewhere
  for(int yy=0;yy<h;yy++){
    for(int xx=0;xx<w;xx++){
      if(xx==0||yy==0||xx==w-1||yy==h-1)pixels[ad+xx]=rgb;
    }
    ad=ad+width;
  }
}

void t_rect(int x1,int y1,int w,int h,int rgb)
{
  // transparent rectangle
  // fixed tp, for grid drawing

  //the updatepixels rigmarole has to be handled elsewhere
  int r,g,b,s,fout;
  int ad=x1+y1*width;
  
  if(g_gridmode==NEW){
  for(int yy=0;yy<h;yy++){
    for(int xx=0;xx<w;xx++){
      s=pixels[ad+xx];fout=0;
      if(g_rgb[0]==s)fout=g_grids[0];
      if(g_rgb[1]==s)fout=g_grids[1];
      if(g_rgb[2]==s)fout=g_grids[2];
      if(g_rgb[3]==s)fout=g_grids[3];
      if(g_rgb[4]==s)fout=g_grids[4];
      if(g_rgb[5]==s)fout=g_grids[5];
      if(g_rgb[6]==s)fout=g_grids[6];
      if(g_rgb[7]==s)fout=g_grids[7];
      if(g_rgb[8]==s)fout=g_grids[8];
      if(g_rgb[9]==s)fout=g_grids[9];
      if(g_rgb[10]==s)fout=g_grids[10];
      if(g_rgb[11]==s)fout=g_grids[11];
      if(g_rgb[12]==s)fout=g_grids[12];
      if(g_rgb[13]==s)fout=g_grids[13];
      if(g_rgb[14]==s)fout=g_grids[14];
      if(g_rgb[15]==s)fout=g_grids[15];      
      pixels[ad+xx]=fout;
    }
    ad=ad+width;
  }
  return;
  }
  
  for(int yy=0;yy<h;yy++){
    for(int xx=0;xx<w;xx++){
      s=pixels[ad+xx];  
      r=s&0x00ff0000;r=r>>16;
      g=s&0x0000ff00;g=g>>8;
      b=s&0x000000ff;
      g=g+64;
      r=r*2;g=g*2;b=b*2;
      r=r/3;g=g/3;b=b/3;
      pixels[ad+xx]=0xff000000+r*0x10000+g*0x100+b;
    }
    ad=ad+width;
  }  
}


// parameter store/restore in case some functions need to bypass grid, attribute modes etc

void storeparameters()
{
  for(int i=0;i<=255;i++)
  {
    g_data[767+i]=g_data[i];
  }
}

void restoreparameters()
{
  for(int i=0;i<=255;i++)
  {
    g_data[i]=g_data[767+i];
  }
}

void drawtext(int xo,int yo, String ss)
{
  //draw a bunch of text maybe not needed
  for(int i=0;i<ss.length();i++){
    drawchar(xo+i*8*2,yo,ss.charAt(i));
  }
}

void drawicon(int xo,int yo, int t,int mm)
{
  //draw one icon
  int ad,cad,xx,yy,pop,far;
  int metal;
  yy=t/16;xx=t-yy*16;xx=xx*2;yy=yy*2;
  ad=1024+xx*8+yy*2048;
    for(int y=0;y<=15;y++){            
       for(int x=0;x<=15;x++){    
         metal=0xffa0a0a0;
         far=0xff000000;
         if(t==18){
           if(x<15&&y<15)far=int(g_rgb[g_farge]);
         }
         if(t==19&&g_backmode==1){
           if(x<15&&y<15)far=int(g_rgb[g_farge]);
         }
         if(g_depressed[t]>0)metal=0xff606060;
         
         if(x==0||y==0){
           metal=0xffe0e0e0;
           if(g_depressed[t]>0)metal=0xff303030;
           if(t==56||t==9)metal=0xffa0a0a0;
         }
         pop=1;cad=65536+(xx+x/8)+yy*256+y*32; 
         if(int(g_icons[cad])==0)pop=0;
         if(int(g_icons[ad+x])==pop){
            far=metal;
            if(mm==1)far=0xffffff80;
         }
         if(t==66){//raster icon
           if(x>=1&&y>=2&&x<=13&&y<=12){
             far=metal;if(mm==1)far=0xffffff80;
             if(get_raster(x+1,y)==1)far=0xff000000;
          }
        }
        e_rect(xo+x*g_uizoom,yo+y*g_uizoom,g_uizoom,g_uizoom,far);
      }
      ad=ad+256;
    }
}

void drawchar(int xo,int yo, int t)
{
  //characters at the help box
  int ad,cad,x,y,xx,yy,far;
  far=0xff000000;
  t=t-32;yy=t/32;
  xx=t-yy*32;yy=yy+18;
    for(y=0;y<=7;y++){     
       cad=65536+xx+yy*256+y*32;ad=1024+xx*8+yy*2048+y*256;          
       for(x=0;x<=7;x++){    
          if(int(g_icons[ad+x])==1){
             far=0xffb0b0b0;
             if(g_bsize<4){
               if(g_bsize+(g_btype*4)+96==t)far=0xffffff80;
             }
          }
          else
          {
            far=0xff000000;
            if(g_spare==1&&t<=95)far=0xff008000;//different background color for spare mode
            if(g_msgctr>0&&t+32<128)far=0xff0000ff;//different background color
          }
          e_rect(xo+x*g_uizoom,yo+y*g_uizoom,g_uizoom,g_uizoom,far);
        }
    }
}

boolean moicon(int xx,int yy,int ww,int hh)
{
  //check mouse/icon boundary without actually drawing the icon
  if(g_data['m']==0&&g_data['M']==0){
    if(g_mx+g_windowx>=xx&&g_mx+g_windowx<xx+ww&&g_my+g_windowy>=yy&&g_my+g_windowy<yy+hh)return true;
  }
  if(g_data['m']==1||g_data['M']==1){
    if(g_mx>=xx&&g_mx<=xx+ww&&g_my>=yy&&g_my<=yy+hh)return true;
  }
  return false;
}

boolean doicon_drag(int xx,int yy,int ww,int hh)
{
   if(g_iconx>=xx&&g_iconx<xx+ww&&g_icony>=yy&&g_icony<yy+hh){
    g_iconx=-1;g_icony=-1;
    g_repanel=-2;
    return true;
  }
  if(g_piconx>=xx&&g_piconx<xx+ww&&g_picony>=yy&&g_picony<yy+hh){
    g_piconx=-1;g_picony=-1;
    g_repanel=-2;
    return true;
  }
  return false;
}

boolean doicon(int xx,int yy,int ww,int hh)
{
  if(g_iconx>=xx&&g_iconx<xx+ww&&g_icony>=yy&&g_icony<yy+hh){
    g_iconx=-1;g_icony=-1;
    g_repanel=-2;    
    return true;
  }
  return false;
}

void printat(int xx,int yy,String tex)
{
  //creating text into the help box
  for(int tit=0;tit<tex.length();tit++){
    if(tex.charAt(tit)!='|'){
      if(g_data[256+xx+yy*12]!=byte(tex.charAt(tit))){
        g_data[256+xx+yy*12]=byte(tex.charAt(tit));
        g_chaup[xx+yy*16]=1;
      }
    }
    xx++;
    if(tex.charAt(tit)=='|'){xx=0;yy++;}
  }
}

void clearmsg()
{
  for (int y=0;y<=3;y++){
    for (int x=0;x<=11;x++){
       g_data[256+x+y*12]=byte(32);
       g_chaup[x+y*16]=1;
    }
  }
}

void message(String tex)
{
  if(tex.equals("*")){g_msgctr=100;return;}
  clearmsg();
  printat(0,0,tex);
  g_msgctr=50;
}


void help(int a)
{
  String teks;
  int b,byt,ad,valu;
  if(g_msgctr>0)return;
  teks="No Help";
  clearmsg();
  if(a>=1000){
    a=a-1000;
    b=a/X;
    a=a-(b*X);
    if(tool()==4&&g_phase==1){      
        a=abs(g_rx2-g_rx)+1;b=abs(g_ry2-g_ry)+1;
    }
    if(tool()==6&&g_phase==1){      
        a=abs(g_rx2-g_rx)+1;b=abs(g_ry2-g_ry)+1;
    }
    if(tool()==7&&g_phase==1){      
        a=abs(g_rx2-g_rx)*2+1;b=abs(g_ry2-g_ry)*2+1;
    }
    if(tool()==8&&g_phase==1){      
        a=abs(g_rx2-g_rx)+1;b=abs(g_ry2-g_ry)+1;
        if(g_data['c']==1||g_shift){a--;b--;}//purkkaa
    }   
    //coordinates

    if(a<X&&b<Y){
        printat(0,0,str(a));
        printat(4,0,str(b));
        printat(0,1,str(a/8));
        printat(4,1,str(b/8));
        if(tool()==6&&g_phase==1){
            printat(0,2,nf(dist(0,0,a-1,b-1),0,2));             
            float av = getangel(g_rx2-g_rx,g_ry2-g_ry);
            printat(0,3,nf((av),0,2));  
        }
        byt=a/8;
        ad=1024+byt*8+b*X;
        valu=g_map[ad+0]*128+g_map[ad+1]*64+g_map[ad+2]*32+g_map[ad+3]*16+g_map[ad+4]*8+g_map[ad+5]*4+g_map[ad+6]*2+g_map[ad+7]*1;
    }
    return;
  }
  
  printat(7,3,"Key:"+char(a));
  
  switch(a){
    case '.':
      teks="Preset pens|.=reset";
    break;
    case TAB:
      teks="Pick color";
    break;
    case'<':
      teks="Swap colors|Right<>Left";
    break;
    case'>':
      teks="Pick backgnd|shift=set";
      if(g_backmode==0)teks="Pick backgnd|not here";
    break;
    case'1':
      teks="Draw";
    break;
    case'2':
      teks="Spray can";
    break;
    case'3':
      teks="Continuous|Draw";
    break;
    case'4':
      teks="Grab brush";
    break;
    case'5':
      teks="Flood fill";
    break;
    case'8':
      teks="Rectangle";
    break;
    case'7':
      teks="Ellipse";
    break;
    case'6':
      teks="Line";
    break;
    case'9':
      teks="Brush tool";
    break;    
    case'0':
      teks="Magnifier|m=direct";
    break;    
    case'a':
      teks="Bitmap only|on/off";
    break;
    case'A':
      teks="Export as|"+g_expname;
    break;
    case'b':
      teks="A.I.|Behavior|on/off";
    break;
    case'B':
      teks="Set border|[Export=N]";
      if(g_data['Q']==1)teks="Set border|[Export=Y]";
    break;
    case'C':
      teks="Set backgnd";
      if(machine==PLUS4M||machine==PLUS4)teks="Set backgnd|V/RMB=back2";
      if(int(g_map[1])==255)teks="Set backnd|-Not here";
    break;
    case'i':
      teks="Increase|luminance";
    break;
    case'k':
      teks="Decrease|luminance";
    break;
    case'r':
      teks="Fill raster|on/off|RMB=swap";
    break;
    case'R':
      teks="Raster from|brush|on/off";
    break;
    case'd':
      teks="Recolor|right->left|on/off";
    break;
    case'p':
      teks="Brush|recolor|on/off";
    break;
    case'q':
      teks="IQ mode|on/off";
    break;
    case't':
      teks="Tile mode|on/off";
    break;
    case'x':
      teks="Brush|flip X|on/off";
    break;
    case'y':
      teks="Brush|flip Y|on/off";
    break;
    case'z':
      teks="Brush|rotate";
    break;
    case'h':
      teks="Pen size "+(g_bsize+1)+"|LMB/h=less|RMB/H=bigger";
    break;
    case'j':
      if(g_spare==0){ teks="Switch to|spare page|RMB=CopyTo";}
        else
      {teks="Switch to|front page|RMB=CopyTo";}
    break;
    case'f':
      teks="Geometry|fill|on/off";
    break;
    case'c':
      teks="Constrain|to grid|on/off";
    break;
    case'm':
      teks="Magnify|on/off";
    break;
    case'g':
      teks="Draw grid|on/off|G=size "+str(g_gridx);
    break;    
    case'X':
      teks="Mirror X|on/off";
    break;
    case'Y':
      teks="Mirror Y|on/off";
    break;
    case'l':
      teks="Load data|bin/png";
    break;
    case's':
      teks="Save as|[RMB=Save]|bin/png";
    break;
    case'u':
      teks="Undo u LMB|Redo U RMB";
    break;
    case'U':
      teks="Redo";
    break;
    case'e':
      teks="Export PNG";
    break;
    case'E':
      teks="Export as|source";
    break;
    case'o':
      teks="Clear|screen";
    break;
    case 'O':
      teks="Export|specific";
    break;
    case 'n':
      teks="Playbrush|on/off|RMB=speed";
    break;
    case 'w':
      teks="Format|Import:|no support";
      if(g_formatname!="")teks="Import as|"+g_formatname;
    break;
    case 'W':
      teks="Export:|no support";
      if(g_formatname!="")teks="Export as|"+g_formatname;
    break;
  }
  printat(0,0,teks);
}

void icontable(int xx,int yy,int tabletype,int realdraw)
{
  String pan="";
  int x,y,ad;
  g_data['9']=0;
  if(g_btype==9)g_data['9']=1;
  
  // the main and sideboard icon panel order
  if(tabletype==0)pan=";;h9::123456::78::pzxy::XYtn::lsEAwW::jc0g::uo::.b";
  if(tabletype==1)pan="BCrRfd";
  if(tabletype==2)pan="ik";
  
  x=0;y=0;
  
  for(int tit=0;tit<pan.length();tit++){
    ad=pan.charAt(tit);
    if(g_repanel<=0){
      if(ad!=';'&&ad!=':'&&ad!='.'){
        if(realdraw==1){
          int icolor=g_data[ad];
          if(ad=='j'&&g_spare==1)icolor=1;
          drawicon(xx+x,yy+y,ad-48,icolor);
        }
      }
      if(ad==';'){//draw the preset brush box
        if(realdraw==1){
          drawchar(xx,yy,128);
          drawchar(xx+8*g_uizoom,yy,129);
          drawchar(xx+16*g_uizoom,yy,130);
          drawchar(xx+24*g_uizoom,yy,131);
          drawchar(xx,yy+8*g_uizoom,132);
          drawchar(xx+8*g_uizoom,yy+8*g_uizoom,133);
          drawchar(xx+16*g_uizoom,yy+8*g_uizoom,134);
          drawchar(xx+24*g_uizoom,yy+8*g_uizoom,135);
        }      
      }
    }
    
    //tooltip
    if(ad!=':'&&ad!=';'&&ad!='.'){
      if(realdraw==0){
        if(moicon(xx+x,yy+y,16*g_uizoom,16*g_uizoom))help(ad);
      }
      if (doicon(xx+x,yy+y,16*g_uizoom,16*g_uizoom)){
        //println(g_realbutton);
        if(ad=='C'&&g_realbutton==39)ad='V';
        if(ad=='B'&&g_realbutton==39)ad='Q';
        if(ad=='u'&&g_realbutton==39)ad='U';
        if(ad=='n'&&g_realbutton==39)ad='N';     
        if(ad=='h'&&g_realbutton==39)ad='H';
        if(ad=='s'&&g_realbutton==39)ad='S';
        if(ad=='j'&&g_realbutton==39)ad='J';
        if(ad=='g'&&g_realbutton==39)ad='G';
        if(ad=='r'&&g_realbutton==39){
          ad=')';if(g_shift)ad='(';
        }        
        command(ad);g_msgctr=50;
      } 
    }
    if(ad==';'){
      for(int ii=0;ii<=3;ii++){
        for(int jj=0;jj<=1;jj++){
          if(doicon(xx+ii*8*g_uizoom,yy+jj*8*g_uizoom,8*g_uizoom,8*g_uizoom))command(128+ii+jj*4);
        }
      }
    }
    if(tabletype==0){
      x=x+16*g_uizoom;
      if(ad=='.')x=x-8*g_uizoom;
      if(x>16*g_uizoom){
        x=0;y=y+16*g_uizoom;
        if(ad==':')y=y-14*g_uizoom;
      }
    }
    if(tabletype==1||tabletype==2){
      y=y+16*g_uizoom;
      if(y>16*g_uizoom){y=0;x=x+16*g_uizoom;}
    }
  }
  g_data['9']=0;
}

int nextluminance(int f,int d)
{
  int res=f+d;
  if(machine==PLUS4||machine==PLUS4M){
    if(f+d*15>120)return f;
    if(f+d*15<1)return f;
    if(d==1)return f+15;
    if(d==-1)return f-15;
    return res;
  }
  
  if(g_map[13]==C64){//here the "C64" is generic across C64,C64M and potential FLI modes
    int out[]={6,1,11,15,8,10,9,13,14,2,3,4,5,1,12,7}; // from "Ptoing"
    if(d==1)res=out[f];
    if(d==-1){
      if(f==0)return 0;
      for(int i=0;i<g_maxcolors;i++){
          if(out[i]==f)res=i;
      }
    }
  }
  
  if(g_map[13]==MSX){
    int out[]={ 1, 4, 9,10, 6,12,13,14, 5, 3, 7,15, 2, 8,11,15}; // calculated Y
    if(d==1)res=out[f];
    if(d==-1)
    {
      if(f==0)return 0;
        for(int i=0;i<g_maxcolors-1;i++){
            if(out[i]==f)res=i;
        }
    }
  }
  return res;
}



int tool()
{
  //returns the current tool #, for convenience
  //as there is no "tool" variable really 
  for(int i='0';i<='9';i++){
    if(g_data[i]==1)return i-'0';
  }
  return 0;
}

void set_tool(int s)
{
  //set current tool, for convenience
  for(int i='0';i<='9';i++){
    g_data[i]=0;
  }
  g_data[48+s]=byte(1);
  g_map[12]=byte(s);
}

void selectcolor(int hand,int x)
{
  if(x>=g_maxcolors)x=x-g_maxcolors;
  if(x<0)x=x+g_maxcolors;
  if(hand==0){
    g_farge=x;g_ofarge=x; //kludgey, the colour and the "original colour"
    if(g_btype==9)g_data['p']=1;
    g_realfront=byte(g_farge);
    g_realback=byte(g_backg);
  }
  if(hand==1){
    g_backg=x;
    g_realback=byte(g_backg);
    g_realfront=byte(g_farge);
  }
}

void refresh()
{
  //refreshes all "dirty chars" and icon panels
  for(int i=0;i<MX*MY;i++){
    g_redo[i]=byte(0);g_remdo[i]=byte(1);
  }
  if(g_boxreconstruct==0)g_boxreconstruct=1;
  //elsewhere use g_boxreconstruct=2 for complete window reconstruction
}

void refresh_all()
{
  refresh();g_boxreconstruct=2;
}

void palettebox(float x0,int y0,float x1)
{
   if(g_palsteps==0)return;
   float expand=((x1-x0)/g_palsteps);
   int divs=int(255/(g_palsteps-1));
   for(int i=0;i<g_palsteps;i++){   
       if(doicon_drag(int(x0+expand*i),y0,int(expand),7*g_uizoom)){g_r[g_farge]=int(i*divs);message("RED:"+i);makecolor(g_farge,g_r[g_farge],g_g[g_farge],g_b[g_farge]);refresh();g_boxreconstruct=2;}
       if(doicon_drag(int(x0+expand*i),y0+10*g_uizoom,int(expand),7*g_uizoom)){g_g[g_farge]=int(i*divs);message("GREEN:"+i);makecolor(g_farge,g_r[g_farge],g_g[g_farge],g_b[g_farge]);refresh();g_boxreconstruct=2;}
       if(doicon_drag(int(x0+expand*i),y0+20*g_uizoom,int(expand),7*g_uizoom)){g_b[g_farge]=int(i*divs);message("BLUE:"+i);makecolor(g_farge,g_r[g_farge],g_g[g_farge],g_b[g_farge]);refresh();g_boxreconstruct=2;}
   }
   e_rect(int(x0),y0,int(x1-x0),7*g_uizoom,g_rgb[258]);   
   e_rect(int(x0),y0+10*g_uizoom,int(x1-x0),7*g_uizoom,g_rgb[258]);
   e_rect(int(x0),y0+20*g_uizoom,int(x1-x0),7*g_uizoom,g_rgb[258]);
    
   for(int i=1;i<g_palsteps;i++){
     e_rect(int(x0+expand*i),y0,g_uizoom,2*g_uizoom,g_rgb[257]);
     e_rect(int(x0+expand*i),y0+10*g_uizoom,g_uizoom,2*g_uizoom,g_rgb[257]);
     e_rect(int(x0+expand*i),y0+20*g_uizoom,g_uizoom,2*g_uizoom,g_rgb[257]);     
   }        
   e_rect(int(x0+expand*g_r[g_farge]/divs),y0, int(expand),7*g_uizoom,g_rgb[260]);
   e_rect(int(x0+expand*g_g[g_farge]/divs),y0+10*g_uizoom, int(expand),7*g_uizoom,g_rgb[261]);
   e_rect(int(x0+expand*g_b[g_farge]/divs),y0+20*g_uizoom, int(expand),7*g_uizoom,g_rgb[262]);
}

void colorselector(int xo,int yo)
{
  int x,y,ad,yfat;
  int far,xonko,yhei,maxp,xloc,yloc;
  int bfat;
  float expand,divus;
  xonko=16*g_uizoom;yhei=16*g_uizoom;expand=1;yfat=4*g_uizoom;bfat=1*g_uizoom;
  if(g_maxcolors>60){yhei=4*g_uizoom;yfat=0;bfat=1;}
  divus=255/g_palsteps;
  x=0;y=0;far=0xff000000;
  
  maxp=g_maxcolors;xonko=512/g_maxcolors;
  xonko=xonko/2;xonko=xonko*g_uizoom;
   
  if(g_maxcolors>32){maxp=g_maxcolors/2;xonko=1024/g_maxcolors;}
  if(machine==PLUS4||machine==PLUS4M)xonko=15*g_uizoom;
   
     for(x=0;x<g_maxcolors;x++){
       xloc=xo+x*xonko;yloc=yo+8*g_uizoom;
         if(g_maxcolors>60){yloc=yo+yhei*7;
           if(x>15&&x<=30){xloc=xo+(x-15)*xonko;yloc=yo+yhei*6+yfat*2;}
           if(x>30&&x<=45){xloc=xo+(x-30)*xonko;yloc=yo+yhei*5+yfat*4;}
           if(x>45&&x<=60){xloc=xo+(x-45)*xonko;yloc=yo+yhei*4+yfat*6;}
           if(x>60&&x<=75){xloc=xo+(x-60)*xonko;yloc=yo+yhei*3+yfat*8;}
           if(x>75&&x<=90){xloc=xo+(x-75)*xonko;yloc=yo+yhei*2+yfat*10;}
           if(x>90&&x<=105){xloc=xo+(x-90)*xonko;yloc=yo+yhei*1+yfat*12;}
           if(x>105&&x<=120){xloc=xo+(x-105)*xonko;yloc=yo+yhei*0+yfat*14;}      
         }
      if(doicon_drag(xloc,yloc,xonko,yhei))
      {
        if(mouseButton==LEFT||mouseButton==CENTER){
          selectcolor(0,x);
        }  
        if(mouseButton==RIGHT){
          selectcolor(1,x);g_button=LEFT;
        }
      }
    
      if(g_repanel<=0){
        int index;
        index=x;
        if(machine==MSX&&x==0)index=g_map[1];
        e_rect(xloc,yloc,xonko,yhei,g_rgb[index]); // the colour blocks
        far=0xff000000;
        if(g_farge==x)far=0xff808080;
        e_rect(xloc,yloc-yfat,xonko,yfat,far);
        if(doicon(xloc,yloc-yfat,xonko,yfat))selectcolor(0,x);
        
        far=0xff000000;     
        if(g_backg==x&&yfat>0)far=0xff808080;
        
        e_rect(xloc,yloc+yhei,xonko,yfat,far); 
        if(doicon(xloc,yloc+yhei,xonko,yfat))selectcolor(1,x);
        if(yfat==0){
          if(g_farge==x){
            e_rect(xloc,yloc,xonko/4,yhei/4,far);
            e_rect(xloc,yloc+1,xonko/8,yhei/4,far);
          }
          if(g_backg==x){
            e_rect(xloc+xonko-xonko/4,yloc+yhei-2,xonko/4,yhei/4,far);
            e_rect(xloc+xonko-xonko/8,yloc+yhei-3,xonko/8,yhei/4,far);
          }
        }
        if(int(g_map[0])==x){
          far=0xff000000;
          if(dist(g_r[x],g_g[x],g_b[x],0,0,0)<1)far=0xffffffff;
          e_rect(xloc,yloc,xonko,bfat,far);
          e_rect(xloc,yloc+yhei-bfat,xonko,bfat,far);
          e_rect(xloc,yloc,bfat,yhei,far);
          e_rect(xloc+xonko-bfat,yloc,bfat,yhei,far);
        }
        if(int(g_map[1])==x){
          far=0xff000000;
          if(dist(g_r[x],g_g[x],g_b[x],0,0,0)<1)far=0xffffffff;       
          e_rect(xloc+xonko/4,yloc+yhei/4,xonko/4,yhei/4,far);
        }
        if(machine==PLUS4||machine==PLUS4M){
          if(int(g_map[1])!=255&&int(g_map[2])==x){
          far=0xff000000;
          if(dist(g_r[x],g_g[x],g_b[x],0,0,0)<1)far=0xffffffff;            
            e_rect(xloc+xonko-(xonko/4)*2,yloc+yhei-(yhei/4)*2,xonko/4,yhei/4,far);
          }
        }
    }
  }
}

void messagebox(int ox,int oy)
{
  int cz=8*g_uizoom;
  // lcd character display chardisplay textbox
  // coordinates. has its own "dirtychar"
  for(int xx=0;xx<=11;xx++){
    for(int yy=0;yy<=3;yy++){
      if(g_chaup[xx+yy*16]==1){
        g_chaup[xx+yy*16]=0;
        drawchar(ox+xx*cz,oy+yy*cz,g_data[256+xx+yy*12]);
      }
    }
  }
}

void colorindicator(int ox,int oy)
{
  int bs=8*g_uizoom;
  int h=0;
  if(g_button==RIGHT)h=1;
  e_rect(ox,oy,bs*2,bs*4,g_rgb[int(g_realback)]);
  e_rect(ox+bs/2,oy+4*g_uizoom,12*g_uizoom,bs*2,g_rgb[int(g_realfront)]);  
  if(doicon(ox,oy,bs*2,bs*3))command('<');
  if(machine==C64M||machine==MSX||machine==AMIGA){
    e_rect(ox,oy+bs*3,bs*2,bs,g_rgb[int(g_map[1])]);
    d_rect(ox,oy+bs*3,bs*2,bs,g_rgb[int(257)]);
    if(doicon(ox,oy+bs*3,bs*2,bs))
    {
      if(g_shift==false)selectcolor(h,int(g_map[1]));
      if(g_shift)command('C');
    }
  }
  if(machine==PLUS4M){
    e_rect(ox,oy+bs*3,bs,bs,g_rgb[int(g_map[1])]);    
    e_rect(ox+8*g_uizoom,oy+bs*3,bs,bs,g_rgb[int(g_map[2])]);
    d_rect(ox,oy+bs*3,bs,bs,g_rgb[int(257)]);    
    d_rect(ox+8*g_uizoom,oy+bs*3,bs,bs,g_rgb[int(257)]);    
    if(doicon(ox,oy+bs*3,bs,bs))
    {
      if(g_shift==false)selectcolor(h,int(g_map[1]));
      if(g_shift)command('C');
    }
    if(doicon(ox+8*g_uizoom,oy+bs*3,bs,bs))
    {
      if(g_shift==false)selectcolor(h,int(g_map[2])); 
      if(g_shift)command('V');  
    }
  }
}

void update_ui()
{
  if(g_iconmode==1){
    for(int i=0;i<=80000;i++){
      g_icons[i]=g_map[i];
    }
  }
  
  if(g_repanel<=0)g_repanel++;
  messagebox(width-12*8*g_uizoom,height-4*8*g_uizoom);   

  // when tooltipping, the panels are not really
  // drawn but used for easy coordinate reference
      
  if(g_repanel>0){
    icontable(width-32*g_uizoom,0,0,0);
    icontable(272*g_uizoom,height-32*g_uizoom,1,0);
    if(machine==PLUS4M||machine==PLUS4){ 
      icontable(240*g_uizoom,height-32*g_uizoom,2,0); 
    }    
    return;
  }

  if(g_repanel>0)return;
   
  icontable(width-32*g_uizoom-1,0,0,1);
  icontable(272*g_uizoom,height-32*g_uizoom,1,1);
  palettebox(g_uizoom*324+4,height-32*g_uizoom,width-(96*g_uizoom)-4);
  if(machine==PLUS4M||machine==PLUS4){ 
    icontable(240*g_uizoom,height-32*g_uizoom,2,1); 
  }
  colorselector(0,height-32*g_uizoom);
  colorindicator(256*g_uizoom,height-32*g_uizoom);
}

void magport()
{
  int b=g_uizoom*2;
  int xo=0;int yo=0;
  for(int y=0;y<Y;y++){
    for(int x=0;x<X;x++){
      int raddr=(xo*24+x)+(yo*24+y)*width;
      pixels[raddr]=int(g_rgb[easygetcolor(x,y)]);
    }
  }
}

void viewport()
{
  // formerly void redo()
  // main machine screen redraw
  // and dirty char update
  int xx,yy,xo,yo,xwin,ywin,x,y,winsux,winsuy,rubx;
  int ad,cad,a,b,c,mmode,fari,psize;
  int zonx,zony,maxx,mayy,mag,raddr;
  int left=32*g_uizoom;
  raddr=0;winsux=0;winsuy=0;
  if(g_backmode==0)g_map[1]=0;//some computers have overall background

  mmode=magmode();
  fari=0;
  makecolor(259,g_r[g_map[0]],g_g[g_map[0]],g_b[g_map[0]]);//use border color
  if(g_data['M']==1&&g_data['m']==1)g_data['m']=0;
  if(g_data['m']==1)makecolor(259,48,48,48);//don't use border color in mag modes
  if(g_data['M']==1)makecolor(259,48,48,48);

  psize=g_magpix[mmode];mag=psize*8;
  maxx=magx();mayy=magy();
  
  if(g_boxreconstruct==1){
    g_boxreconstruct=0;
    e_rect(0,(mayy*psize)*8,maxx*psize*8,height-((g_vedge+g_uizoom*2)+(mayy*psize*8)),g_rgb[259]);
    e_rect((maxx*psize)*8,0,width-(maxx*psize*8+(g_hedge+g_uizoom*2)),height-(g_vedge+g_uizoom),g_rgb[259]);   
  }
  if(g_boxreconstruct==2){//in case of full window update
    g_boxreconstruct=0;
    e_rect(0,0,width-(g_hedge+g_uizoom*2),height-(g_vedge+g_uizoom*2),g_rgb[259]);
  }
  
  maxx--;mayy--;
  zonx=MX-magx();zony=MY-magy();
   
  if(g_ofx>zonx)g_ofx=zonx;
  if(g_ofy>zony)g_ofy=zony;
  if(g_ofx<0)g_ofx=0;
  if(g_ofy<0)g_ofy=0;

  if(mmode==10){g_ofx=0;g_ofy=0;maxx=MX-1;mayy=MY-1;winsux=g_windowx;winsuy=g_windowy;mag=16;}//mini  
  if(mmode==0){g_ofx=0;g_ofy=0;maxx=MX-1;mayy=MY-1;winsux=g_windowx;winsuy=g_windowy;mag=24;}//normal
  if(mmode==20){g_ofx=0;g_ofy=0;maxx=MX-1;mayy=MY-1;winsux=g_windowx;winsuy=g_windowy;mag=32;}//maxi

  b=0;c=0;a=5;
  
  if(mmode==1||mmode==2||mmode==11||mmode==12||mmode==21||mmode==22){
    winsux=0;winsuy=0;fill(32,32,32);
  }
  
  for(ywin=0;ywin<=mayy;ywin++){
    for(xwin=0;xwin<=maxx;xwin++){
  
      // source coords: is 0,0 if not magged
      xx=g_ofx+xwin;yy=g_ofy+ywin;
      // divided into character area blocks
      // which are only updated if necessary
      xo=xwin;yo=ywin;
    
      if(int(g_redo[xx+yy*MX])==0){
    
        for(y=0;y<=7;y++){//pixel rows inside "char"

          switch(g_multic){
            case 0:
              cad=65536+xx+((yy*X)+y*MX);
              a=int(g_map[cad]);b=int(g_map[(MX*MY)*8+cad]);c=int(g_map[(MX*MY)*8+cad]);
            break;
            case 1:
              cad=65536+xx+(yy*MX);
              a=int(g_map[cad]);b=int(g_map[cad+1000]);c=int(g_map[cad+2000]);
              if(machine==PLUS4M){c=int(g_map[2]);}
            break;
            case 2:
              cad=65536+xx+((yy*X)+y*MX);
              a=int(g_map[cad]);b=int(g_map[(MX*MY)*8+cad]);c=int(g_map[(MX*MY)*8+cad]);
            break;
          }
    
          ad=1024+xx*8+yy*(X*8)+y*X;
              
          int po,vop;
          
          for(x=0;x<=7;x++){//pixel columns inside pixel row
            vop=x/2;
            if(g_multic==0){
              if(int(g_map[ad+x])==1){
                fari=a;if(fari==0)fari=g_map[1];
              }
              else{
                fari=b;if(fari==0)fari=g_map[1];
              }
            }
            if(g_multic==1)
            {
              po=int(g_map[ad+vop*2])+int(g_map[ad+vop*2+1]*2);
              if(po==0)fari=g_map[1];//00 comes from $d021 in real c64 and background 1 in plus/4
              if(po==1)fari=a;//10
              if(po==2)fari=b;//01
              if(po==3)fari=c; //g_map[2];//11 // comes from $d800 in real c64 and background 2 in plus/4             
            }
            if(g_multic==2){// "amiga" mode
              fari=int(g_map[ad+x]);
            }
            
            if(g_rubbermode==1){// rubberband mode
              rubx=x;if(g_multic==1||g_hzoomer==2){rubx=x/2;rubx=rubx*2;}
              if(fylli()==1){
                if(xx*8+rubx==g_rx||xx*8+rubx==g_rx2)
                {
                  if(yy*8+y>=g_ry&&yy*8+y<=g_ry2)fari=256;              
                  if(yy*8+y>=g_ry&&yy*8+y<=g_ry2)fari=256;                  
                }
                if(yy*8+y==g_ry||yy*8+y==g_ry2){
                  if(xx*8+x>=g_rx&&xx*8+x<=g_rx2)fari=256;
                  if(xx*8+x>=g_rx&&xx*8+x<=g_rx2)fari=256;
                }
              }
            }
            
           color ari=g_rgb[fari];
            switch(mmode){
              case 0:
                    raddr=(xo*24+x*3)+(yo*24+y*3)*width;raddr=raddr+g_windowx+g_windowy*width;              
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;
                    raddr=raddr+width;             
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;
                    raddr=raddr+width;
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;               
              break;
              case 1:
                    raddr=(xo*64+x*8)+(yo*64+y*8)*width;              
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;pixels[raddr+6]=ari;pixels[raddr+7]=ari;              
                    raddr=raddr+width;             
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;pixels[raddr+6]=ari;pixels[raddr+7]=ari;   
                    raddr=raddr+width;
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;pixels[raddr+6]=ari;pixels[raddr+7]=ari;
                    raddr=raddr+width;
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;pixels[raddr+6]=ari;pixels[raddr+7]=ari;
                    raddr=raddr+width;             
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;pixels[raddr+6]=ari;pixels[raddr+7]=ari;   
                    raddr=raddr+width;
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;pixels[raddr+6]=ari;pixels[raddr+7]=ari;
                    raddr=raddr+width;
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;pixels[raddr+6]=ari;pixels[raddr+7]=ari;
                    raddr=raddr+width;
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;pixels[raddr+6]=ari;pixels[raddr+7]=ari;        
              break;
              case 2:
                    e_rect(xo*(64*g_uizoom)+x*(8*g_uizoom),yo*(64*g_uizoom)+y*(8*g_uizoom),8*g_uizoom,8*g_uizoom,g_rgb[fari]);
              break;
              // mini modes
              case 10:  
                    raddr=(xo*16+x*2)+(yo*8+y)*width*2;raddr=raddr+g_windowx+g_windowy*width;           
                    pixels[raddr]=ari;pixels[raddr+1]=ari;
                    raddr=raddr+width;
                    pixels[raddr]=ari;pixels[raddr+1]=ari;              
              break;
              case 11:  
                    raddr=(xo*48+x*6)+(yo*48+y*6)*width;         
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;          
                    raddr=raddr+width;
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;           
                    raddr=raddr+width;   
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;           
                    raddr=raddr+width;   
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;         
                    raddr=raddr+width;
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;            
                    raddr=raddr+width;
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;pixels[raddr+4]=ari;pixels[raddr+5]=ari;         
              break;     
              case 12:
                    e_rect(xo*(64*g_wzoom)+x*(8*g_wzoom),yo*(64*g_wzoom)+y*(8*g_wzoom),8*g_wzoom,8*g_wzoom,g_rgb[fari]);
              break;
              // maxi modes
              case 20:
                    raddr=(xo*(8*4)+x*4)+(yo*(8*4)+y*4)*width;raddr=raddr+g_windowx+g_windowy*width;              
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;
                    raddr=raddr+width;             
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;
                    raddr=raddr+width;
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;
                    raddr=raddr+width;              
                    pixels[raddr]=ari;pixels[raddr+1]=ari;pixels[raddr+2]=ari;pixels[raddr+3]=ari;
              break;    
              case 21:
                    e_rect(xo*(32*g_wzoom)+x*(4*g_wzoom),yo*(32*g_wzoom)+y*(4*g_wzoom),4*g_wzoom,4*g_wzoom,g_rgb[fari]);        
              break;
              case 22:
                    e_rect(xo*(64*g_wzoom)+x*(8*g_wzoom),yo*(64*g_wzoom)+y*(8*g_wzoom),8*g_wzoom,8*g_wzoom,g_rgb[fari]);        
              break;
            }
        }//one pixel inside pixel row
    }//one pixel row inside char
    
    //draw grid
    //can in principle be non-square
    if(int(g_data['g'])==1){
      int lapx;
      lapx=(xx*8)/g_gridx;lapx=lapx*g_gridx;
      if(lapx==(xx*8)){
        t_rect(xo*mag+winsux,yo*mag+winsuy,1,mag,g_rgb[257]);
        if(g_gridx==4){
          t_rect(xo*mag+winsux+4*psize,yo*mag+winsuy+1,1,mag/2-2,g_rgb[257]);
          t_rect(xo*mag+winsux+4*psize,yo*mag+winsuy+mag-mag/2+2,1,mag/2-2,g_rgb[257]);          
        }
      }
      lapx=(yy*8)/g_gridy;lapx=lapx*g_gridy;
      if(lapx==(yy*8)){
        t_rect(xo*mag+winsux+1,yo*mag+winsuy,mag-1,1,g_rgb[257]);
        if(g_gridy==4){
          t_rect(xo*mag+winsux+1,yo*mag+winsuy+4*psize,mag/2-2,1,g_rgb[257]);
          t_rect(xo*mag+winsux+2+mag-mag/2,yo*mag+winsuy+4*psize,mag/2-2,1,g_rgb[257]);          
        }
      }
    }
    g_redo[xx+yy*MX]=byte(1);
  } //dirty char?
  }//x char
 }//y char
}