view events.pde @ 206:efbd833065f5

Change PNG export to be triggered via alt+shift+W.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 29 Aug 2018 15:13:13 +0300
parents 3b1afb0b9b30
children 2e077cfc4f38
line wrap: on
line source

//collects mouse/key events and directly related command parsing


boolean insidewindow(int xc, int yc)
{
    // XXX is this correct?
    return (xc > width - g_hedge || yc > height - g_vedge);
}


void keyPressed()
{
    g_dirty = true;
    if (key == ESC)
    {
        key = 0;
    }
    else
    if (key == CODED)
    {
        switch (keyCode)
        {
            case RIGHT:
                g_ofx++;
                break;

            case LEFT:
                g_ofx--;
                break;

            case UP:
                g_ofy--;
                break;

            case DOWN:
                g_ofy++;
                break;

            case COMMAND:
                if (platform == MACOSX)
                    g_control = true;
                break;

            case CONTROL:
                if (platform != MACOSX)
                    g_control = true;
                break;

            case SHIFT:
                g_shift = true;
                break;

            case ALT:
                g_alt = true;
                break;
        }

        refresh();
    }
    else
    {
        // send to the indirect key handling
        // so commands can be invoked elsewhere too
        command(int(key));
    }
}


void keyReleased()
{
    if (key == CODED)
    {
        switch (keyCode)
        {
            case COMMAND:
                if (platform == MACOSX)
                    g_control = false;
                break;

            case CONTROL:
                if (platform != MACOSX)
                    g_control = false;
                break;

            case SHIFT:
                g_shift = false;
                break;

            case ALT:
                g_alt = false;
                break;
        }
    }
}


void mouseMoved()
{
    g_dirty = true;

    if (moicon(16 * 16 * g_uiscale, height - 32 * g_uiscale, 16 * g_uiscale, 24 * g_uiscale)) help(int('<'));
    if (moicon(16 * 16 * g_uiscale, height - 8 * g_uiscale, 16 * g_uiscale, 8 * g_uiscale)) help(int('>'));
    if (moicon(0, height - 32 * g_uiscale, 15 * 16 * g_uiscale, 32 * g_uiscale)) help(TAB);
    if (moicon(width - 32 * g_uiscale, 0, 32 * g_uiscale, 16 * g_uiscale)) help(int('.'));
}


void mouseScrolled()
{
    if (mouseScroll < -0.1) command(g_wheelup);
    if (mouseScroll > 0.1) command(g_wheeldown);
}


void mouseDragged()
{
    mouseMoved();

    g_iconx = mouseX;
    g_icony = mouseY;

    if (g_pgrab)
    {
        g_prevx = g_iconx + g_phandlex;
        g_prevy = g_icony + g_phandley;
    }
    else
    if (insidewindow(g_iconx, g_icony))
    {
        if (g_phase == 0)
        {
            g_piconx = g_iconx;
            g_picony = g_icony;
            g_repanel = -2;
            g_tooltrigger = 100;
        }
        else
        {
            g_piconx = -1;
            g_picony = -1;
        }
    }
    else
    {
        if (mouseButton == CENTER)
            return;

        if (g_tooltrigger == 0)
            g_tooltrigger = 1;
    }

    g_iconx = -1;
    g_icony = -1;
}


void mousePressed()
{
    g_dirty = true;
    if (g_pgrab)
        return;

    int msx, msy, tt = tool();

    g_iconx = mouseX;
    g_icony = mouseY;
    g_button = mouseButton;
    g_realbutton = g_button;

    if (g_preview == 1 &&
        g_iconx > g_prevx && g_icony > g_prevy &&
        g_iconx < g_prevx + X + 16 && g_icony < g_prevy + Y + 16)
    {
        g_pgrab = true;
        g_button = 0; //important
        g_realbutton = 0;
        g_phandlex = g_prevx - g_iconx;
        g_phandley = g_prevy - g_icony;
    }
    else
    if (insidewindow(g_iconx, g_icony))
    {
        if (g_phase == 0)
        {
            g_repanel = -2;
            g_tooltrigger = 100;
            g_piconx = g_iconx;
            g_picony = g_icony;
        }
        else
        {
            g_iconx = -1;
            g_icony = -1;
        }
    }
    else
    {
        g_msx = g_iconx;
        g_msy = g_icony;

        if (g_button == CENTER)
        {
            command(g_middlebutton);
            g_phase = 1;
            return;

            //g_button = 255;
            //g_repanel = -2;
            //if (g_shift) g_button = 254;
        }
        else
        {
            if (g_data[int('m')] == 0 && g_data[int('M')] == 0)
            {
                msx = g_iconx - g_windowx;
                msy = g_icony - g_windowy;
            } else {
                msx = g_iconx;
                msy = g_icony;
            }

            // XXX weird logic again .. might not make sense
            if ((tt != 5 && tt != 4) ||
                (tt == 4 && g_button == RIGHT))
                store_undo();

            g_phase = 0;
            do_tool(msx, msy, g_button);
            g_phase = 1;
        }

    }
}


void mouseReleased()
{
    int tt = tool();

    g_dirty = true;
    g_tooltrigger = 0;
    g_klikkeri = false;

    if (g_phase == 1)
    switch (tt)
    {
        case 8:
            do_rectangle(g_rx, g_ry, g_rx2, g_ry2);
            g_phase = 0;
            break;

        case 7:
            do_circle(g_rx, g_ry, g_rx2, g_ry2);
            g_phase = 0;
            break;

        case 6:
            do_line(g_rx, g_ry, g_rx2, g_ry2, 0);
            g_phase = 0;
            break;
    }

    if (g_data[int('4')] == 1)
    {
        if (g_phase == 1) {
            g_phase = 0;
            g_rubbermode = 0;
            refresh();
            g_data[int('4')] = 0;
            g_data[int('d')] = 0;
            g_data[int('r')] = 0;
            g_data[int('R')] = 0;
            g_data[int('x')] = 0;
            g_data[int('y')] = 0;
            g_data[int('q')] = 0;
            g_data[int('p')] = 0;
            g_data[int('t')] = 0;
            g_data[int('n')] = 0;
            switcher(2);

            if (g_pixelw == 2)
            {
                g_rx = chop2(g_rx);
                g_rx2 = chop2(g_rx2);
            }

            g_bsourcex = clampv(g_rx, 0, X - 1);
            g_bsourcey = clampv(g_ry, 0, Y - 1);
            g_bsourcex2 = clampv(g_rx2, 0, X - 1);
            g_bsourcey2 = clampv(g_ry2, 0, Y - 1);

            set_tool(1);
            g_btype = 9;
            g_repanel = -2;

            if (g_button == RIGHT)
            {
                storeparameters();
                g_data[int('f')] = 1;
                g_data[int('X')] = 0;
                g_data[int('Y')] = 0;
                doborx(g_rx, g_ry, g_rx2, g_ry2);
                restoreparameters();
            }
        }
        consistency();
    }

    if (g_phase == 1)
    {
        g_phase = 0;
        g_rubbermode = 0;
        refresh(); //needed otherwise the pen color is kept e.g. after right mousebutton
    }

    update_preview_window();
    g_pgrab = false;
}


void maghelper(int rel)
{
    if (rel < 0)
    {
        if (g_data[int('M')] == 1 || g_data[int('m')] == 1)
        {
            command('m');
            refresh();
        }
    }
    else
    {
        if (g_data[int('m')] == 0 && g_data[int('M')] == 0)
        {
            command('m');
            refresh();
        }
        else
        if (g_data[int('m')] == 1 && g_data[int('M')] == 0)
        {
            command('M');
            refresh();
        }
    }
}


void macro_command(int ckey)
{
    //filter out load/save
    if (ckey == 's' || ckey == 'S' || ckey == 'l' ||
        ckey == 'E' || ckey == 'w' || ckey == 'W' ||
        ckey == 'A')
        return;

    command(ckey);
}


void command(int ckey)
{
    g_dirty = true;

    //keypresses change g_data[] values directly as 1/0 switches
    //handling these presses "indirectly" adds complexity here
    //but is valuable elsewhere = corresponding icons have shortcuts automatically

    if (ckey == '-') ckey = 'h';
    if (ckey == '+') ckey = 'H';

    if (ckey == BACKSPACE)
    {
        message("Preview|on/off");

        if (++g_preview > 1)
            g_preview = 0;

        update_preview_window();
        refresh();
        g_boxreconstruct = 2;
    }

    if (ckey == TAB) {
        if (g_shift == false) {
            if (g_britemode == 1) {
                if (g_realfront == 7) g_realfront = -1;
                if (g_realfront == 15) g_realfront = 7;
            }
            selectcolor(0, g_realfront + 1);
            g_repanel = -2;
        } else {
            if (g_britemode == 1) {
                if (g_realfront == 8) g_realfront = 16;
                if (g_realfront == 0) g_realfront = 8;
            }
            selectcolor(0, g_realfront - 1);
            g_repanel = -2;
        }
    }

    //println("ckey+"+ckey);
    if (g_control == true)
    {
        int UNDO = 26,
            REDO = 25,
            PASTE = 22,
            SAVE = 19,
            LOAD = 15,
            NEW = 14,
            COPY = 3,
            COPYALT = 24,
            ALL = 1;

        if (platform == MACOSX)
        {
            UNDO = 122;
            REDO = 25;
            PASTE = 22;
            SAVE = 115;
            LOAD = 111;
            NEW = 110;
            COPY = 99;
            COPYALT = 120;
            ALL = 97;
        }

        switch (ckey)
        {
            case UNDO: ckey = g_shift ? 'U' : 'u'; break;
            case REDO: ckey = 'U'; break;
            case PASTE: ckey = '9'; break;
            case SAVE: ckey = g_shift ? 's' : 'S'; break;
            case LOAD: ckey = 'l'; break;
            case NEW: ckey = 'o'; break;

            case COPY:
            case COPYALT: ckey = '4'; break;

            case ALL:
                switcher(2);
                g_bsourcex = 0;
                g_bsourcey = 0;
                g_bsourcex2 = X - 1;
                g_bsourcey2 = Y - 1;
                ckey = '9';
                g_data[int('p')] = 0;
                g_data[int('x')] = 0;
                g_data[int('y')] = 0;
                g_data[int('q')] = 0;
                g_data[int('z')] = 0;
                g_phase = 0;
                g_rubbermode = 0;
                set_tool(1);
                break;
        }
    }

    if (ckey >= 128 && ckey <= 131)
    {
        g_bsize = ckey - 128;
        g_btype = 0;
    }
    else
    if (ckey >= 132 && ckey <= 135)
    {
        g_bsize = ckey - 132;
        g_btype = 1;
    }
    else
    if (ckey == ' ' || ckey == '.')
    {
        if (ckey == '.')
        {
            g_bsize = 0;
            g_btype = 0;
            g_data[int('n')] = 0;
        }
        ckey = '3';
    }
    else
    if (ckey == g_wheeldown)
        maghelper(-1);
    else
    if (ckey == g_wheelup)
        maghelper(1);
    else
    if (ckey == ',')
    {
        g_repanel = -2;
        do_tool(mouseX, mouseY, 255);
        do_tool(g_mx, g_my, 255);
        return;
    }
    else
    if (ckey == 'v')
    {
        g_repanel = -2;
        // do_tool(mouseX,mouseY,254);
        do_tool(g_mx, g_my, 254);
        return;
    }
    else
    if (ckey == '[')
    {
        fixed_raster_command(int('x'));
        message("R.OFFSET " + str(g_raster_offset_x) + "." + str(g_raster_offset_y));
        g_repanel = -2;
        return;
    }
    else
    if (ckey == ']')
    {
        fixed_raster_command(int('y'));
        message("R.OFFSET " + str(g_raster_offset_x) + "." + str(g_raster_offset_y));
        g_repanel = -2;
        return;
    }
    else
    if (ckey == '(')
    {
        fixed_raster_command(int('p'));
        message("RASTER " + str(g_raster_no) + "/9|[=PREV|]=NEXT");
        g_repanel = -2;
        return;
    }
    else
    if (ckey == ')')
    {
        fixed_raster_command(int('n'));
        message("RASTER " + str(g_raster_no) + "/9|[=PREV|]=NEXT");
        g_repanel = -2;
        return;
    }
    else
    if (ckey == '>')
    {
        selectcolor(0, g_rgb[int(g_map[1])]);
        message("Current=Back");
        g_repanel = -2;
        return;
    }
    else
    if (ckey == '<')
    {
        g_repanel = -2;
        int swap = g_farge;
        g_farge = g_backg;
        g_ofarge = g_farge;
        g_backg = swap;
        g_realfront = byte(g_farge);
        g_realback = byte(g_backg);
    }
    else
    if (ckey == '0')
    {
        if (g_data[int('m')] == 0 && g_data[int('M')] == 0)
        {
            if (tool() != 0)
                g_prevtool = tool();
        }
        else
            ckey = 'm';
    }
    else
    if (ckey == '9')
    {
        g_repanel = -2;
        g_btype = 9;
        return;
    }

    // Intentional break in else -chain

    if (ckey >= '0' && ckey <= '8')
    {
        g_repanel = -2;
        set_tool(ckey - 48);
        g_phase = 0;
        g_rubbermode = 0;
        g_rx = -1;
        g_ry = -1;
        g_rx2 = -1;
        g_ry2 = -1;

        if (g_data[ckey] > 1)
            g_data[ckey] = 0;

        if (ckey == '4')
        {
            g_data[int('x')] = 0;
            g_data[int('y')] = 0;
            g_data[int('h')] = 0;
            g_data[int('q')] = 0;
            g_data[int('t')] = 0;
            g_data[int('n')] = 0;
        }
    }

    if (ckey >= 'A' && ckey <= 'Z')
    {
        g_repanel = -2;
        g_data[ckey]++;
        if (g_data[ckey] > 1) g_data[ckey] = 0;

        if (ckey == 'Q') {
            g_repanel = -2;
            g_msgctr = 0;
            help(int('B'));
            g_msgctr = 50;
        }
        if (ckey == 'G') {
            g_data[int('G')] = 0;
            switch (g_gridx) {
                case 8:
                    g_gridx = 16;
                    g_gridy = 16;
                    break;
                case 16:
                    g_gridx = 4;
                    g_gridy = 4;
                    break;
                case 4:
                    g_gridx = 8;
                    g_gridy = 8;
                    break;
            }
            g_repanel = -2;
            g_msgctr = 0;
            help(int('g'));
            g_msgctr = 50;
        }

        if (ckey == 'G') {
            if (g_data[int('g')] == 0) g_data[int('g')] = 1;
        }

        if (g_data[int('M')] == 0)
            g_boxreconstruct = 2;
        else
        {
            if (ckey == 'M')
            {
                g_ofx = int(g_storedcoordx / 8) - int(magx() / 2);
                g_ofy = int(g_storedcoordy / 8) - int(magy() / 2);
                g_data[int('m')] = 0;
                message("Super|Magnify");

                if (tool() == 0)
                {
                    set_tool(g_prevtool);
                    g_phase = 0;
                    g_rubbermode = 0;
                }
            }
        }

        if (g_data[int('B')] == 1) {
            changeborder(LEFT);
            if (g_machine == MSX)
                g_data[int('C')] = 1;
        }

        if (g_data[int('C')] == 1) {
            g_data[int('C')] = 0;
            if (int(g_map[1]) != 255) {
                store_undo();
                if (g_machine == PLUS4M && g_farge == g_map[2]) {
                    message("1st and 2nd|can't be|same");
                    refresh();
                    return;
                }
                g_map[1] = byte(g_farge);

                if (g_machine == MSX) {
                    g_map[0] = byte(g_farge);
                    sussborder();
                }
                message("Set back|color");
            }
        }
        if (g_data[int('V')] == 1) {
            g_data[int('V')] = 0;
            if (int(g_map[1]) != 255) {
                store_undo();
                if (g_machine == PLUS4M && g_farge == g_map[1]) {
                    message("1st and 2nd|can't be|same");
                    refresh();
                    return;
                }
                g_map[2] = byte(g_farge);
                message("Set 2nd|back color");
            }
        }
        if (g_data[int('N')] == 1) {
            g_data[int('N')] = 0;
            if (++g_animspeed > 3)
                g_animspeed = 0;
            message("Playbrush|speed=" + g_animspeed);
        }
        refresh();
    }

    if (ckey >= 'a' && ckey <= 'z')
    {
        g_repanel = -2;
        g_data[ckey]++;
        if (g_data[ckey] > 1)
        {
            if (ckey == 'm' || ckey == 'M')
            {
                g_boxreconstruct = 2;
                g_data[int('M')] = 0;
                g_data[int('m')] = 0;
            }
            g_data[ckey] = 0;
        }

        if (g_data[int('t')] == 1 && ckey == 't')
            message("Tile mode");

        if (ckey == 'n' && g_data[int('n')] == 1)
        {
            switcher(2);
            infersize();

            // infersize() may modify this, so check makes sense
            if (g_data[int('n')] == 1)
            {
                command(int('1'));
                command(int('9'));
                g_data[int('p')] = 0;
                g_data[int('x')] = 0;
                g_data[int('y')] = 0;
                g_data[int('q')] = 0;
                g_data[int('t')] = 0;
            }
        }

        if (g_data[int('i')] == 1) {
            g_data[int('i')] = 0;
            selectcolor(0, nextluminance(g_farge, 1));
        }
        if (g_data[int('k')] == 1) {
            g_data[int('k')] = 0;
            selectcolor(0, nextluminance(g_farge, -1));
        }
        if (g_data[int('d')] == 0) {
            if (ckey == 'd') consistency();
        }
        if (g_data[int('z')] == 1) {
            g_data[int('z')] = 0;
            int orient;
            orient = g_data[int('x')] * 100 + g_data[int('y')] * 10 + g_data[int('q')];
            if (orient == 0) {
                g_data[int('x')] = 0;
                g_data[int('y')] = 0;
                g_data[int('q')] = 1;
            }
            if (orient == 1) {
                g_data[int('x')] = 1;
                g_data[int('y')] = 1;
                g_data[int('q')] = 0;
            }
            if (orient == 110) {
                g_data[int('x')] = 1;
                g_data[int('y')] = 1;
                g_data[int('q')] = 1;
            }
            if (orient == 111) {
                g_data[int('x')] = 0;
                g_data[int('y')] = 0;
                g_data[int('q')] = 0;
            }
            if (orient == 100) {
                g_data[int('x')] = 0;
                g_data[int('y')] = 1;
                g_data[int('q')] = 1;
            }
            if (orient == 11) {
                g_data[int('x')] = 0;
                g_data[int('y')] = 1;
                g_data[int('q')] = 0;
            }
            if (orient == 10) {
                g_data[int('x')] = 1;
                g_data[int('y')] = 0;
                g_data[int('q')] = 1;
            }
            if (orient == 101) {
                g_data[int('x')] = 1;
                g_data[int('y')] = 0;
                g_data[int('q')] = 0;
            }
            message("Rotate|brush");
        }

        if (ckey == 'm') {
            if (g_data[int('M')] == 1) {
                g_data[int('m')] = 0;
                ckey = 0;
                g_boxreconstruct = 2;
                refresh();
            }
            g_data[int('M')] = 0;
        }

        if (g_data[int('m')] == 1) {
            if (ckey == 'm') {
                g_data[int('M')] = 0;
                g_ofx = int(g_storedcoordx / 8) - int(magx() / 2);
                g_ofy = int(g_storedcoordy / 8) - int(magy() / 2);
                message("Magnify");
                if (tool() == 0) {
                    set_tool(g_prevtool);
                    g_phase = 0;
                    g_rubbermode = 0;
                }
            }
        }
        refresh();
    }

    if (g_data[int('J')] == 1) {
        g_data[int('J')] = 0;
        g_data[int('j')] = 0;
        spare();
        store_undo();
        message("Copied to|" + (g_spare ? "Spare" : "Front"));
        switcher(4);
        spare();
    }

    if (g_data[int('j')] == 1) {
        g_data[int('j')] = 0;
        spare();
        message((g_spare ? "Spare" : "Front") + " Page");
        makecolor(259, g_r[g_map[0]], g_g[g_map[0]], g_b[g_map[0]]);
        g_boxreconstruct = 2;
    }

    if (g_data[int('O')] == 1) {
        g_data[int('O')] = 0;
        store_undo();
        for (int xx = 0; xx < X * Y; xx++) {
            g_map[1024 + xx] = 0;
        }
        for (int xx = 0; xx < X; xx++)
        for (int yy = 0; yy < Y; yy++)
        {
            g_farge = g_backg;
            makepoint(xx, yy);
            g_farge = g_ofarge;
        }
    }

    if (g_data[int('o')] == 1) {
        g_data[int('o')] = 0;
        message("Clear all");
        store_undo();
        storeparameters();
        g_data[int('r')] = 0;
        g_data[int('R')] = 0;
        g_data[int('d')] = 0;
        g_data[int('t')] = 0;

        for (int xx = 0; xx < X * Y; xx++) {
            g_map[1024 + xx] = 0;
        }

        for (int xx = 0; xx < X; xx++) {
            for (int yy = 0; yy < Y; yy++) {
                g_farge = g_backg;
                makepoint(xx, yy);
                g_farge = g_ofarge;
            }
        }

        restoreparameters();
    }

    if (g_data[int('e')] == 1)
        g_data[int('e')] = 0;

    if (g_data[int('h')] == 1) {
        g_data[int('h')] = 0;
        g_bsize--;
        if (g_bsize < 0) g_bsize = 0;
        g_msgctr = -2;
        help(int('h'));
    }
    if (g_data[int('H')] == 1) {
        g_data[int('H')] = 0;
        g_bsize++;
        if (g_bsize > 10) g_bsize = 10;
        g_msgctr = -2;
        help(int('h'));
    }
    if (g_data[int('u')] == 1) {
        g_data[int('u')] = 0;
        message("Undo");
        restore_undo();
        refresh();
        g_boxreconstruct = 2;
    }
    if (g_data[int('U')] == 1) {
        g_data[int('U')] = 0;
        message("Redo");
        redo_undo();
        refresh();
    }

    if (g_machine == SPECTRUM) {
        if (g_data[int('i')] == 1)
        {
            g_data[int('i')] = 0;
            if (g_iconmode)
            {
                message("Icons|not loaded!");
            }
            else
            {
                message("Store|icons");
                mpSaveNativeImage("icons.bin");
            }
        }
        if (g_data[int('I')] == 1)
        {
            g_data[int('I')] = 0;
            message("Restore|icons");
            mpLoadNativeImage("icons.bin", true);
            refresh();

            for (int i = 0; i <= 80000; i++)
                g_icons[i] = g_map[i];

            g_iconmode = true;
        }
    }

    if (g_data[int('l')] == 1)
    {
        g_data[int('l')] = 0;

        mpLoadFileSelector("Multipaint image", ".mp",
        function (fh, fdata)
        {
            int err = mpSetNativeImage(fdata);
            if (err == 0)
            {
                mpSetTitle(fh.name);
                if (g_spare)
                    sfilename = fh.name;
                else
                    filename = fh.name;

                message("Image loaded");
                refresh();
            }
            else
            if (err == -2)
                message("Wrong|machine!");
            else
                message("ERROR!");
        });
    }

    if (g_data[int('s')] == 1)
    {
        g_data[int('s')] = 0;

        String fname = filename +"_"+ (g_spare ? "spare" : "main") +".mp";
        if (mpSaveBinaryFile(fname, mpGetNativeImage()))
            message("SAVED");
        else
            message("ERROR!");
    }

    if (g_data[int('E')] == 1)
    {
        g_data[int('E')] = 0;

//        message("Export SRC|is disabled");

        message("Source|export");
        String fname = (g_spare ? sfilename : filename) +"_"+ (g_spare ? "spare" : "main") +".asm";
        MPWriteCtx ctx = new MPWriteCtx();

        if (mpExportMachinePRG(ctx) && mpSaveBinaryFile(fname, ctx.getSource()))
            message("EXPORTED");
        else
            message("COULD NOT|EXPORT");
    }

    if (g_data[int('A')] == 1)
    {
        g_data[int('A')] = 0;
        message("Executable|export");

        String fname = (g_spare ? sfilename : filename) +"_"+ (g_spare ? "spare" : "main") +"."+ g_exportext;
        MPWriteCtx ctx = new MPWriteCtx();

        if (mpExportMachinePRG(ctx) && mpSaveBinaryFile(fname, ctx.getData()))
            message("EXPORTED");
        else
            message("COULD NOT|EXPORT");
    }

    if (g_data[int('w')] == 1)
    {
        g_data[int('w')] = 0;

        if (g_formatext != "") {
            message("Format|import");
            mpLoadFileSelector(g_formatname, "."+ g_formatext,
            function (fh, fdata)
            {
                store_undo();
                filename = fh.name;
                mpImportFormat(fdata);
                refresh();
            });
        }
        else
            message("None for|"+ g_name);
    }

    if (g_data[int('W')] == 1)
    {
        g_data[int('W')] = 0;

        if (g_alt)
        {
            message("PNG|export");

            String fname = filename +"_"+ (g_spare ? "spare" : "main") +".png";
            PImage simg = mpRenderImage(true, 64, 32, 1);

            if (simg !== null)
            {
                simg.sourceImg.toBlob(function(idata){ mpSaveBinaryBlob(fname, idata); }, "image/png", 0.95);
            }
        }
        else
        if (g_formatext != "")
        {
            message("Format|export");

            String fname = filename +"_"+ (g_spare ? "spare" : "main") +"."+ g_formatext;
            MPWriteCtx ctx = new MPWriteCtx();

            if (mpExportFormat(ctx, 0) && // XXX TODO
                mpSaveBinaryFile(fname, ctx.getData()))
                message("EXPORTED");
            else
                message("COULD NOT|EXPORT");
        }
        else
            message("None for|"+ g_name);
    }

    if (g_data[int('S')] == 1)
    {
        g_data[int('S')] = 0;
        g_data[int('s')] = 0;

        if (mpHaveLocalStorage())
        {
            try
            {
                var fdata = mpGetNativeImage();
                var fstr = JSON.stringify(fdata);
                localStorage.setItem("MPIMAGE_DATA"+ str(g_machine), fstr);
                message("Saved to lstorage");
            }
            catch (err)
            {
                message("ERROR");
            }
        }
        else
            message("Lstorage is not available");
    }

    if (g_data[int('L')] == 1)
    {
        g_data[int('L')] = 0;
        if (mpHaveLocalStorage())
        {
            try
            {
                var fstr = localStorage.getItem("MPIMAGE_DATA"+ str(g_machine));
                var fdata = JSON.parse(fstr);
                if (typeof(fdata) == "object" &&
                    Array.isArray(fdata))
                {
                    int res = mpSetNativeImage(fdata, false);
                    if (res != 0)
                        message("Wrong machine");
                    else
                        message("Loaded lstorage");
                }
                else
                    message("Invalid data in lstorage");
            }
            catch (err)
            {
                message("No data in lstorage");
            }
        }
        else
            message("Lstorage is not available");
    }
}