view interface.pde @ 218:2e077cfc4f38

Cleanups.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 04 Sep 2018 19:24:59 +0300
parents b7c7b13b46c2
children 1c9deae71fb1
line wrap: on
line source

// This collects UI stuff, viewport
// i.e. Icons, color selectors and the like

//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[int('r')] = 1;
    }
    else
    if (par == 'n') {
        g_raster_no++;
        if (g_raster_no > 9)
            g_raster_no = 0;
        set_fixed_raster(g_raster_no);
        g_data[int('r')] = 1;
    }
    else
    if (par == 'x') {
        g_raster_offset_x++;
        if (g_raster_offset_x > 3)
            g_raster_offset_x = 0;
    }
    else
    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_uiscale and 'm' and 'M'
    // currently valid outputs are 0,10,20,1,11,21,2,12,22
    // flat variants: 100,110,120,101,111,121,102,112,122
    int base = 0;
    if (g_aspect == AR_FLAT) base = 100;
    if (g_uiscale == 1) base += 10;
    if (g_uiscale == 3) base += 20;
    if (g_data[int('M')] == 1 && g_data[int('m')] == 1) g_data[int('m')] = 0;
    if (g_data[int('m')] == 1) base += 1;
    if (g_data[int('M')] == 1) base += 2;
    return base;
}


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


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


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 | ((rr & 0xff) << 16) | ((gg & 0xff) << 8) | (bb & 0xff);
}


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)
{
    if (y1 < 0 || x1 < 0 || y1 + h >= height || x1 + w >= width)
        return;

    int ad = x1 + y1 * width;
    for (int yy = 0; yy < h; yy++)
    {
        for (int xx = 0; xx < w; xx++)
            pixels[ad + xx] = rgb;

        ad += width;
    }
}


void d_rect(int x1, int y1, int w, int h, int rgb)
{
//    if (y1 < 0 || x1 < 0 || y1 + h >= height || x1 + w >= width)
    if (y1 + h >= height || x1 + w >= width)
        return;

    int ad = x1 + y1 * width;
    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 += 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 ad = x1 + y1 * width;

    if (g_gridmode == GRIDMODE_NEW)
    {
        for (int yy = 0; yy < h; yy++)
        {
            for (int xx = 0; xx < w; xx++)
            {
                int s = pixels[ad + xx],
                    fout = 0;

                for (int qn = 0; qn < 16; qn++)
                {
                    if (g_rgb[qn] == s)
                    {
                        fout = g_grids[qn];
                        break;
                    }
                }

                pixels[ad + xx] = fout;
            }
            ad += width;
        }
    }
    else
    {
        for (int yy = 0; yy < h; yy++)
        {
            for (int xx = 0; xx < w; xx++)
            {
                int s = pixels[ad + xx],
                    r = (s >> 16) & 0xff,
                    g = (s >> 8) & 0xff,
                    b = (s) & 0xff;

                g += 64;

                r = int((r * 2) / 3);
                g = int((g * 2) / 3);
                b = int((b * 2) / 3);

                pixels[ad + xx] = 0xff000000 + r * 0x10000 + g * 0x100 + b;
            }
            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 cad, xx, yy, pop, far;
    int metal;

    yy = int(t / 16);
    xx = t - (yy * 16);

    xx *= 2;
    yy *= 2;

    int ad = 1024 + xx * 8 + yy * 2048;

    for (int y = 0; y < 16; y++)
    {
        for (int x = 0; x < 16; x++)
        {
            metal = 0xffa0a0a0;
            far = 0xff000000;

            if (t == 18 || (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;
            }

            cad = 65536 + (xx + int(x / 8)) + yy * 256 + y * 32;
            pop = (int(g_icons[cad]) == 0) ? 0 : 1;

            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_uiscale, yo + y * g_uiscale, g_uiscale, g_uiscale, far);
        }
        ad += 256;
    }
}


void drawchar(int xo, int yo, int t)
{
    //characters at the help box
    if (t < 32) return;

    t -= 32;
    int yy = int(t / 32);
    int xx = t - (yy * 32);
    yy = yy + 18;

    for (int y = 0; y < 8; y++)
    {
        int ad = 1024 + xx * 8 + yy * 2048 + y * 256;

        for (int x = 0; x < 8; x++)
        {
            int far;
            if (int(g_icons[ad + x]) != 0) {
                far = 0xffb0b0b0;
                if (g_bsize < 4) {
                    if (g_bsize + (g_btype * 4) + 96 == t) far = 0xffffff80;
                }
            } else {
                far = 0xff000000;
                if (g_spare && 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_uiscale, yo + y * g_uiscale, g_uiscale, g_uiscale, far);
        }
    }
}


boolean moicon(int xx, int yy, int ww, int hh)
{
    if (g_pgrab)
        return false;

    //check mouse/icon boundary without actually drawing the icon
    if (g_data[int('m')] == 0 && g_data[int('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;
    }
    else
    {
        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_pgrab)
        return false;

    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;
    }
    else
    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_pgrab)
        return false;

    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 xc, int yc, String mstr)
{
    //creating text into the help box
    for (int index = 0; index < mstr.length(); index++)
    {
        if (mstr.charCodeAt(index) != '|')
        {
            if (g_data[256 + xc + yc * 12] != byte(mstr.charCodeAt(index)))
            {
                g_data[256 + xc + yc * 12] = byte(mstr.charCodeAt(index));
                g_chaup[xc + yc * 16] = 1;
            }
            xc++;
        }
        else
        {
            xc = 0;
            yc++;
        }
    }
}


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


void message(String mstr)
{
    if (mstr.equals("*"))
    {
        g_msgctr = 100;
        return;
    }

    console.log("MSG: " + mstr);
    clearmsg();
    printat(0, 0, mstr);
    g_msgctr = 50;
}


void help(int mode, int xc, int yc)
{
    String teks;

    if (g_msgctr > 0 || g_pgrab)
        return;

    clearmsg();

    if (mode >= 1000)
    {
        xc = int(xc);
        yc = int(yc);

        if (g_phase == 1)
        switch (tool())
        {
            case 4:
            case 6:
                xc = abs(g_rx2 - g_rx) + 1;
                yc = abs(g_ry2 - g_ry) + 1;
                break;

            case 7:
                xc = abs(g_rx2 - g_rx) * 2 + 1;
                yc = abs(g_ry2 - g_ry) * 2 + 1;
                break;

            case 8:
                if (g_data[int('c')] == 1 || g_shift) {
                    xc = abs(g_rx2 - g_rx);
                    yc = abs(g_ry2 - g_ry);
                } //purkkaa
                else {
                    xc = abs(g_rx2 - g_rx) + 1;
                    yc = abs(g_ry2 - g_ry) + 1;
                }
                break;
        }

        // coordinates
        if (xc < X && yc < Y)
        {
            printat(0, 0, "Px:"+ str(xc));
            printat(6, 0, ", "+ str(yc));
            printat(0, 1, "Ch:"+ str(int(xc / 8)));
            printat(6, 1, ", "+ str(int(yc / 8)));

            if (tool() == 6 && g_phase == 1)
            {
                float av = getangel(g_rx2 - g_rx, g_ry2 - g_ry);

                printat(0, 2, nf(dist(0, 0, xc - 1, yc - 1), 0, 2));
                printat(0, 3, nf((av), 0, 2));
            }
        }
        return;
    }

    printat(7, 3, "Key:" + str(char(mode)));

    switch (char(mode))
    {
        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 'b':
            teks = "A.I.|Behavior|on/off";
            break;
        case 'B':
            teks = "Set border|[Export="+ (g_data[int('Q')] ? "Y" : "N") +"]";
            break;
        case 'C':
            teks = "Set backgnd";
            if (g_machine == PLUS4M || g_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':
            teks = "Switch to|"+ (!g_spare ? "spare" : "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 Multipaint [RMB=From Lstorage]";
            break;
        case 's':
            teks = "Save as Multipaint [RMB=To Lstorage]";
            break;
        case 'u':
            teks = "Undo u LMB|Redo U RMB";
            break;
        case 'U':
            teks = "Redo";
            break;
        case 'a':
            teks = "Bitmap only|on/off";
            break;
        case 'A':
            teks = "Export as|" + g_exportext;
            break;
        case 'e':
            teks = "Export PNG|"+ (g_data[int('Q')] ? "w/border" : "w/o border");
            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':
            if (g_formatname != "")
                teks = "Import as|" + g_formatname;
            else
                teks = "Format|Import:|no support";
            break;
        case 'W':
            if (g_formatname != "")
                teks = "Export as|" + g_formatname;
            else
                teks = "Format|Export:|no support";
            break;

        default:
            teks = "No Help";
            break;
    }

    printat(0, 0, teks);
}


void icontable(int xx, int yy, int tabletype, int realdraw)
{
    String pan = "";
    int x = 0, y = 0;

    g_data[int('9')] = (g_btype == 9) ? 1 : 0;

    // 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";

    for (int tit = 0; tit < pan.length(); tit++)
    {
        int ad = pan.charCodeAt(tit);
        if (g_repanel <= 0 && realdraw == 1)
        {
            if (ad != ';' && ad != ':' && ad != '.')
            {
                int icolor;
                if (ad == 'j' && g_spare)
                    icolor = 1;
                else
                    icolor = int(g_data[ad]);

                drawicon(xx + x, yy + y, ad - 48, icolor);
            }
            else
            if (ad == ';')
            {
                //draw the preset brush box
                drawchar(xx, yy, 128);
                drawchar(xx + 8 * g_uiscale, yy, 129);
                drawchar(xx + 16 * g_uiscale, yy, 130);
                drawchar(xx + 24 * g_uiscale, yy, 131);
                drawchar(xx, yy + 8 * g_uiscale, 132);
                drawchar(xx + 8 * g_uiscale, yy + 8 * g_uiscale, 133);
                drawchar(xx + 16 * g_uiscale, yy + 8 * g_uiscale, 134);
                drawchar(xx + 24 * g_uiscale, yy + 8 * g_uiscale, 135);
            }
        }

        //tooltip
        if (ad != ':' && ad != ';' && ad != '.')
        {
            if (realdraw == 0) {
                if (moicon(xx + x, yy + y, 16 * g_uiscale, 16 * g_uiscale)) help(ad);
            }
            if (doicon(xx + x, yy + y, 16 * g_uiscale, 16 * g_uiscale))
            {
                //println(g_realbutton);
                if (ad == 'C' && g_realbutton == RIGHT) ad = 'V';
                if (ad == 'B' && g_realbutton == RIGHT) ad = 'Q';
                if (ad == 'u' && g_realbutton == RIGHT) ad = 'U';
                if (ad == 'n' && g_realbutton == RIGHT) ad = 'N';
                if (ad == 'h' && g_realbutton == RIGHT) ad = 'H';
                if (ad == 'l' && g_realbutton == RIGHT) ad = 'L';
                if (ad == 's' && g_realbutton == RIGHT) ad = 'S';
                if (ad == 'j' && g_realbutton == RIGHT) ad = 'J';
                if (ad == 'g' && g_realbutton == RIGHT) ad = 'G';
                if (ad == 'r' && g_realbutton == RIGHT) ad = g_shift ? '(' : ')';
                command(int(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_uiscale, yy + jj * 8 * g_uiscale,
                    8 * g_uiscale, 8 * g_uiscale))
                    command(128 + ii + jj * 4);
            }
        }

        if (tabletype == 0)
        {
            x += 16 * g_uiscale;
            if (ad == '.') x = x - 8 * g_uiscale;
            if (x > 16 * g_uiscale)
            {
                x = 0;
                y += 16 * g_uiscale;
                if (ad == ':')
                    y -= 14 * g_uiscale;
            }
        }
        else
        if (tabletype == 1 || tabletype == 2)
        {
            y += 16 * g_uiscale;
            if (y > 16 * g_uiscale)
            {
                y = 0;
                x += 16 * g_uiscale;
            }
        }
    }
    g_data[int('9')] = 0;
}


int nextluminance(int f, int d)
{
    int res = f + d;

    if (g_machine == PLUS4 || g_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[int('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()
{
    g_dirty = true;

    //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_uiscale)) {
            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_uiscale, int(expand), 7 * g_uiscale)) {
            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_uiscale, int(expand), 7 * g_uiscale)) {
            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;
        }
    }

    for (int j = 0; j < 3; j++)
    {
        e_rect(int(x0), y0 + j * 10 * g_uiscale, int(x1 - x0), 7 * g_uiscale, g_rgb[258]);

        for (int i = 1; i < g_palsteps; i++) {
            e_rect(int(x0 + expand * i), y0 + j * 10 * g_uiscale, g_uiscale, 2 * g_uiscale, g_rgb[257]);
        }
    }

    e_rect(int(x0 + expand * g_r[g_farge] / divs), y0, int(expand), 7 * g_uiscale, g_rgb[260]);
    e_rect(int(x0 + expand * g_g[g_farge] / divs), y0 + 10 * g_uiscale, int(expand), 7 * g_uiscale, g_rgb[261]);
    e_rect(int(x0 + expand * g_b[g_farge] / divs), y0 + 20 * g_uiscale, int(expand), 7 * g_uiscale, 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_uiscale;
    yhei = 16 * g_uiscale;
    expand = 1;
    yfat = 4 * g_uiscale;
    bfat = 1 * g_uiscale;

    if (g_maxcolors > 60) {
        yhei = 4 * g_uiscale;
        yfat = 0;
        bfat = 1;
    }

    divus = 255 / g_palsteps;
    x = 0;
    y = 0;
    far = 0xff000000;

    maxp = g_maxcolors;
    xonko = int(int(512 / g_maxcolors) / 2) * g_uiscale;

    if (g_maxcolors > 32) {
        maxp = int(g_maxcolors / 2);
        xonko = int(1024 / g_maxcolors);
    }

    if (g_machine == PLUS4 || g_machine == PLUS4M)
        xonko = 15 * g_uiscale;

    for (x = 0; x < g_maxcolors; x++)
    {
        xloc = xo + x * xonko;
        yloc = yo + 8 * g_uiscale;
        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;
            }

            yloc--;
        }

        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 = x;
            if (g_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, int(xonko / 4), int(yhei / 4), far);
                    e_rect(xloc + xonko - xonko / 8, yloc + yhei - 3, int(xonko / 8), int(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 + int(xonko / 4), yloc + int(yhei / 4), int(xonko / 4), int(yhei / 4), far);
            }
            if (g_machine == PLUS4 || g_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 - int(xonko / 4) * 2, yloc + yhei - int(yhei / 4) * 2, int(xonko / 4), int(yhei / 4), far);
                }
            }
        }
    }
}


void messagebox(int ox, int oy)
{
    // lcd character display chardisplay textbox
    // coordinates. has its own "dirtychar"
    int cz = 8 * g_uiscale;
    for (int xx = 0; xx < 12; xx++)
    for (int yy = 0; yy < 4; 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_uiscale;
    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_uiscale, 12 * g_uiscale, bs * 2, g_rgb[int(g_realfront)]);
    if (doicon(ox, oy, bs * 2, bs * 3)) command(int('<'));
    if (g_machine == C64M || g_machine == MSX || g_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[257]);
        if (doicon(ox, oy + bs * 3, bs * 2, bs)) {
            if (g_shift == false) selectcolor(h, int(g_map[1]));
            if (g_shift) command(int('C'));
        }
    }
    if (g_machine == PLUS4M) {
        e_rect(ox, oy + bs * 3, bs, bs, g_rgb[int(g_map[1])]);
        e_rect(ox + 8 * g_uiscale, oy + bs * 3, bs, bs, g_rgb[int(g_map[2])]);
        d_rect(ox, oy + bs * 3, bs, bs, g_rgb[257]);
        d_rect(ox + 8 * g_uiscale, oy + bs * 3, bs, bs, g_rgb[257]);
        if (doicon(ox, oy + bs * 3, bs, bs)) {
            if (g_shift == false) selectcolor(h, int(g_map[1]));
            if (g_shift) command(int('C'));
        }
        if (doicon(ox + 8 * g_uiscale, oy + bs * 3, bs, bs)) {
            if (g_shift == false) selectcolor(h, int(g_map[2]));
            if (g_shift) command(int('V'));
        }
    }
}


void update_ui(boolean forced)
{
    if (g_repanel <= 0)
        g_repanel++;

    messagebox(width - 12 * 8 * g_uiscale, height - 4 * 8 * g_uiscale - g_uiscale);

    // when tooltipping, the panels are not really
    // drawn but used for easy coordinate reference
    if (g_repanel > 0 && !forced)
    {
        icontable(width - 32 * g_uiscale, 0, 0, 0);
        icontable(272 * g_uiscale, height - 32 * g_uiscale, 1, 0);
        //icontable(0,0,3,0);
        if (g_machine == PLUS4M || g_machine == PLUS4) {
            icontable(240 * g_uiscale, height - 32 * g_uiscale, 2, 0);
        }
    }
    else
    {
        icontable(width - 32 * g_uiscale - 1, 0, 0, 1);
        icontable(272 * g_uiscale, height - 32 * g_uiscale, 1, 1);
        palettebox(g_uiscale * 324 + 4, height - 32 * g_uiscale, width - (96 * g_uiscale) - 4);

        if (g_machine == PLUS4M || g_machine == PLUS4) {
            icontable(240 * g_uiscale, height - 32 * g_uiscale, 2, 1);
        }

        colorselector(0, height - 32 * g_uiscale);
        colorindicator(256 * g_uiscale, height - 32 * g_uiscale);
    }
}


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, psizex, psizey;
    int maxx, mayy, xcmag, ycmag, raddr;
    int left = 32 * g_uiscale;
    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[int('M')] == 1 && g_data[int('m')] == 1) g_data[int('m')] = 0;
    if (g_data[int('m')] == 1) makecolor(259, 48, 48, 48); //don't use border color in mag modes
    if (g_data[int('M')] == 1) makecolor(259, 48, 48, 48);

    psizex = g_magpix[mmode];
    psizey = g_magpiy[mmode];
    xcmag = psizex * 8;
    ycmag = psizey * 8;

    maxx = magx();
    mayy = magy();
    //borders & ultimate background

    if (g_boxreconstruct == 1) {
        g_boxreconstruct = 0;
        //between mag window and toolboxes
        if (g_data['m'] == 1 || g_data['M'] == 1)
        {
            e_rect(0, (mayy * psizex) * 8, maxx * psizex * 8, height - ((g_vedge + g_uiscale * 2) + (mayy * psizex * 8)), g_rgb[263]);
            e_rect((maxx * psizex) * 8, 0, width - (maxx * psizex * 8 + (g_hedge + g_uiscale * 2)), height - (g_vedge + g_uiscale), g_rgb[263]);
        }
        //  e_rect(width-(g_hedge+g_uiscale*2),0,g_hedge+g_uiscale*2,height,g_rgb[263]);
        //  e_rect(0,height-(g_vedge+g_uiscale*2),width,g_vedge+g_uiscale*2,g_rgb[263]);
    }

    if (g_boxreconstruct == 2)
    {
        //in case of full window update
        g_boxreconstruct = 0;
        e_rect(0, 0, width - (g_hedge + g_uiscale * 2 - 2), height - (g_vedge + g_uiscale * 2 - 2), g_rgb[259]);
    }

    if (g_pgrab)
    {
        // avoid preview window embarassment
        e_rect(width - (g_hedge + g_uiscale * 2), 0, g_hedge + g_uiscale * 2 - 1, height - 1, g_rgb[263]);
        e_rect(0, height - (g_vedge + g_uiscale * 2), width - 1, g_vedge + g_uiscale * 2 - 1, g_rgb[263]);
    }

    maxx--;
    mayy--;

    g_ofx = clampv(g_ofx, 0, MX - magx());
    g_ofy = clampv(g_ofy, 0, MY - magy());

    if (mmode == 10) {
        g_ofx = 0;
        g_ofy = 0;
        maxx = MX - 1;
        mayy = MY - 1;
        winsux = g_windowx;
        winsuy = g_windowy;
        xcmag = 16;
    } //mini
    else
    if (mmode == 0) {
        g_ofx = 0;
        g_ofy = 0;
        maxx = MX - 1;
        mayy = MY - 1;
        winsux = g_windowx;
        winsuy = g_windowy;
        xcmag = 24;
    } //normal
    else
    if (mmode == 20) {
        g_ofx = 0;
        g_ofy = 0;
        maxx = MX - 1;
        mayy = MY - 1;
        winsux = g_windowx;
        winsuy = g_windowy;
        xcmag = 32;
    } //maxi
    else
    if (mmode == 1 || mmode == 2 ||
        mmode == 11 || mmode == 12 ||
        mmode == 21 || mmode == 22)
    {
        winsux = 0;
        winsuy = 0;
        fill(32, 32, 32);
    }
    else
    if (mmode == 110)
    {
        g_ofx = 0;
        g_ofy = 0;
        maxx = MX - 1;
        mayy = MY - 1;
        winsux = g_windowx;
        winsuy = g_windowy;
        mag = 16;
    } //mini flat aspect
    else
    if (mmode == 100)
    {
        g_ofx = 0;
        g_ofy = 0;
        maxx = MX - 1;
        mayy = MY - 1;
        winsux = g_windowx;
        winsuy = g_windowy;
        mag = 24;
    } //normal flat aspect
    else
    if (mmode == 120)
    {
        g_ofx = 0;
        g_ofy = 0;
        maxx = MX - 1;
        mayy = MY - 1;
        winsux = g_windowx;
        winsuy = g_windowy;
        mag = 32;
    } //maxi flat aspect

    b = 0;
    c = 0;
    a = 5;

    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 (g_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 = int(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_pixelw == 2) {
                            rubx = chop2(x);
                        }
                        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_uiscale) + x * (8 * g_uiscale), yo * (64 * g_uiscale) + y * (8 * g_uiscale), 8 * g_uiscale, 8 * g_uiscale, 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;

                        //flat NORMI
                        case 100:
                            raddr = (xo * 24 + x * 3) + (yo * 16 + y * 2) * width;
                            raddr = raddr + g_windowx;
                            raddr = raddr + (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;
                            break;

                        case 101:
                            raddr = (xo * 72 + x * 9) + (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;
                            pixels[raddr + 6] = ari;
                            pixels[raddr + 7] = ari;
                            pixels[raddr + 8] = 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;
                            pixels[raddr + 8] = 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;
                            pixels[raddr + 8] = 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;
                            pixels[raddr + 8] = 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;
                            pixels[raddr + 8] = 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;
                            pixels[raddr + 8] = ari;
                            break;

                        case 102:
                            e_rect(xo * (8 * psizex) + x * (psizex), yo * (8 * psizey) + y * (psizey), psizex, psizey, g_rgb[fari]);
                            break;

                            // flat mini modes = probably redundant
                            // mini modes
                        case 110:
                            raddr = (xo * 24 + x * 3) + (yo * 16 + y * 2) * width;
                            raddr = raddr + g_windowx;
                            raddr = raddr + (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;
                            break;

                        case 111:
                            raddr = (xo * 72 + x * 9) + (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;
                            pixels[raddr + 6] = ari;
                            pixels[raddr + 7] = ari;
                            pixels[raddr + 8] = 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;
                            pixels[raddr + 8] = 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;
                            pixels[raddr + 8] = 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;
                            pixels[raddr + 8] = 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;
                            pixels[raddr + 8] = 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;
                            pixels[raddr + 8] = ari;
                            break;
                        case 112:
                            e_rect(xo * (8 * psizex) + x * (psizex), yo * (8 * psizey) + y * (psizey), psizex, psizey, g_rgb[fari]);
                            break;

                        // flat maxi modes
                        case 120:
                            raddr = (xo * (8 * 6) + x * 6) + (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;
                            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 121:
                            e_rect(xo * (8 * psizex) + x * (psizex), yo * (8 * psizey) + y * (psizey), psizex, psizey, g_rgb[fari]);
                            break;
                        case 122:
                            e_rect(xo * (8 * psizex) + x * (psizex), yo * (8 * psizey) + y * (psizey), psizex, psizey, 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[int('g')]) == 1)
            {
                if (chopv(xx * 8, g_gridx) == (xx * 8))
                {
                    t_rect(xo * psizex * 8 + winsux, yo * ycmag + winsuy, 1, ycmag, g_rgb[257]);
                    if (g_gridx == 4)
                    {
                        t_rect(xo * psizex * 8 + winsux + 4 * psizex, yo * ycmag + winsuy + 1, 1, ycmag / 2 - 2, g_rgb[257]);
                        t_rect(xo * psizex * 8 + winsux + 4 * psizex, yo * ycmag + winsuy + ycmag - ycmag / 2 + 2, 1, ycmag / 2 - 2, g_rgb[257]);
                    }
                }

                if (chopv(yy * 8, g_gridy) == (yy * 8))
                {
                    t_rect(xo * psizex * 8 + winsux + 1, yo * ycmag + winsuy, psizex * 8 - 1, 1, g_rgb[257]);
                    if (g_gridy == 4)
                    {
                        t_rect(xo * psizex * 8 + winsux + 1, yo * ycmag + winsuy + 4 * psizex, xcmag / 2 - 2, 1, g_rgb[257]);
                        t_rect(xo * psizex * 8 + winsux + 2 + xcmag - xcmag / 2, yo * ycmag + winsuy + 4 * psizex, xcmag / 2 - 2, 1, g_rgb[257]);
                    }
                }
            }
            g_redo[xx + yy * MX] = byte(1);
        } //dirty char?
    } //x char
}