/*
 * mtsedit/sdl.c
 *
 * Copyright (C) 2019 bzt (bztsrc@gitlab)
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * @brief SDL specific UI code
 *
 */

#include "main.h"
#include "data.h"

uint32_t theme[] = { 0xFFF0F0F0, 0xFFF4F4F4, 0xFFBEBEBE, 0xFF808080, 0xFF5C5C5C, 0xFF4C4C4C, 0xFF454545, 0xFF383838, 0xFF303030,
    0xFFC00000, 0xFF800000, 0xFF7F7F7F, 0xFF3F0000 };

int quitting = 0, activetool = -1, overtool = -1, activeblock = 0, overblock = -1, palette[16], strmaxw, strsepar = 1;
int shift = 0, ctrl = 0, help = 0, systemcursor = 0;
char *status = NULL;
unsigned char *tmpblk = NULL;
SDL_Window *window = NULL;
SDL_Surface *icons = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *fg = NULL;
SDL_Surface *cl = NULL;
SDL_Surface *bg = NULL;
SDL_Surface *blk = NULL;
SDL_Cursor *working, *pointer;

psf_t *font = NULL;

/* help strings */
help_t helpkeys[] = {
    { ADDBLOCKS, " TAB \001 / \001 M " },
    { SELBLOCK, " 0 \001 .. \001 9 " },
    { FILL, " Enter " },
    { PAINT, "        " },
    { LOADFROM, " L " },
    { SAVE, " S " },
    { SAVEAS, " Shift \001 + \001 S " },
    { SAVEPREVIEW, " P " },
    { CHANGEORIENT, " R " },
    { MIRROR, " F " },
    { ADDY, " X " },
    { DELY, " Ctrl \001 + \001 X " },
    { ADDZ, " C " },
    { DELZ, " Ctrl \001 + \001 C " },
    { ADDX, " V " },
    { DELX, " Ctrl \001 + \001 V " },
    { UNDO, " Z " },
    { REDO, " Y " },
    { BRUSH, " B " },
    { GRID, " ; " },
    { GROUNDLEVEL, " G " },
    { LAYERUP, " PgUp " },
    { LAYERDOWN, " PgDn " },
    { ZOOMOUT, " , \001 / \001 < " },
    { ZOOMIN, " . \001 / \001 > " },
    { SCROLL, " Ctrl \001 + \001\033\001 \001\030\001 \001\031\001 \001\032" }
};

/**
 * Print string to screen
 */
void sdlprint(int x, int y, int fg, int bg, char *s)
{
    unsigned char *glyph;
    unsigned int c, offs, i, j, line, mask, bytesperline = (font->width + 7) / 8;

    for(; *s && x < strmaxw;) {
        if((*s & 128) != 0) {
            if(!(*s & 32)) { c = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); s++; } else
            if(!(*s & 16)) { c = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); s += 2; } else
            if(!(*s & 8)) { c = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); *s += 3; }
            else c = 0;
        } else c = *s;
        s++;
        if(c == 1) { fg += bg; bg = fg - bg; fg -= bg; continue; }
        glyph = (unsigned char*)font + font->headersize + (c < font->numglyph ? c : 0) * font->bytesperglyph;
        offs = (y * screen->pitch) + (x * 4);
        for(j = 0; j < font->height; j++){
            line = offs;
            mask = 1<<(font->width-1);
            for(i = 0; i < font->width && (int)(x + i) < strmaxw; i++){
                *((uint32_t*)((uint8_t*)screen->pixels + line)) = theme[(*glyph & mask)?fg:bg];
                mask >>= 1;
                line += 4;
            }
            glyph += bytesperline;
            offs += screen->pitch;
        }
        x += font->width + strsepar;
    }
}

/**
 * Draw help window
 */
void sdlhelp()
{
    int i;
    SDL_Rect rect;

    i = screen->w * 3 / 4;
    rect.w = mbstrlen(lang[HELP]) * (font->width+1) + 8;
    if(i > rect.w) rect.w = i;
    rect.h = ((int)(sizeof(helpkeys)/sizeof(helpkeys[0])) + 1) * (font->height + 4) + 8;
    rect.x = (screen->w - rect.w)/2;
    rect.y = (screen->h - rect.h)/2;
    if(rect.x < 0 || rect.y < 0) { help = 0; return; }
    SDL_FillRect(screen, &rect, theme[THEME_BG]);
    rect.x += 4; rect.y += 4; strmaxw = rect.x + rect.w - 8;

    for(i = 0; i < (int)(sizeof(helpkeys)/sizeof(helpkeys[0])); i++) {
        strsepar = 0; sdlprint(rect.x, rect.y, THEME_BG, THEME_FG, helpkeys[i].key); strsepar = 1;
        sdlprint(rect.x + 136, rect.y, THEME_FG, THEME_BG, lang[(int)helpkeys[i].text]);
        rect.y += font->height + 4;
    }
    sdlprint(rect.x + (rect.w - mbstrlen(lang[HELP]) * (font->width+1)) / 2, rect.y, THEME_INACT, THEME_BG, lang[HELP]);
}

/**
 * Redraw the toolbar
 */
void sdltoolbar()
{
    int i, m;
    char *s = status, str[16];
    SDL_Rect src, dst;

    strmaxw = screen->w - 5;
    dst.x = dst.y = 0; dst.w = 36; dst.h = screen->h;
    SDL_FillRect(screen, &dst, theme[THEME_BG]);
    dst.x = 2; dst.y = 4 + 5*36 + 84; dst.w = 32; dst.h = screen->h - 3*font->height - 4 - 2*37 - dst.y;
    SDL_FillRect(screen, &dst, theme[THEME_TABBG]);

    /* layer up and down */
    src.w = src.h = dst.w = dst.h = 32; src.x = 0; dst.x = 2;
    dst.y = screen->h - 3*font->height - 2*37;
    for(i = 0; i < 2; i++, dst.y += 36) {
        src.y = (i+14) * 32;
        dst.x--; dst.y--; dst.w += 2; dst.h += 2;
        SDL_FillRect(screen, &dst, theme[(i+17) == activetool ? THEME_FG : ((i+17) == overtool ? THEME_INACT : THEME_BG)]);
        dst.x++; dst.y++; dst.w -= 2; dst.h -= 2;
        SDL_BlitSurface(icons, &src, screen, &dst);
    }
    /* load, save, preview */
    dst.y = 2;
    for(i = 0; i < 3; i++) {
        src.y = (i+5) * 32;
        dst.y = 4 + (i * 36);
        dst.x--; dst.y--; dst.w += 2; dst.h += 2;
        SDL_FillRect(screen, &dst, theme[i == activetool ? THEME_FG : (i == overtool ? THEME_INACT : THEME_BG)]);
        dst.x++; dst.y++; dst.w -= 2; dst.h -= 2;
        SDL_BlitSurface(icons, &src, screen, &dst);
    }
    /* rotate, flip, insert, remove, undo, redo, zoom */
    dst.w = dst.h = 16;
    for(i = 0; i < 10; i++) {
        dst.x = 2 + (i & 1)*16;
        dst.y = 4 + (3 * 36) + (i >> 1) * 16;
        SDL_FillRect(screen, &dst, theme[(i+3) == activetool ? THEME_FG : ((i+3) == overtool ? THEME_INACT : THEME_BG)]);
    }
    src.y = 8 * 32; dst.x = 2; dst.y = 4 + (3 * 36); dst.w = 32; src.h = dst.h = 80;
    SDL_BlitSurface(icons, &src, screen, &dst);
    /* brush shape, all blocks (search blocks to add to palette) */
    dst.w = dst.h = src.h = 32;
    for(i = 0; i < 2; i++) {
        src.y = (i+11) * 32;
        dst.y = 88 + ((i+3) * 36);
        dst.x--; dst.y--; dst.w += 2; dst.h += 2;
        SDL_FillRect(screen, &dst, theme[(i + 15) == activetool ? THEME_FG : ((i + 15) == overtool ? THEME_INACT : THEME_BG)]);
        dst.x++; dst.y++; dst.w -= 2; dst.h -= 2;
        SDL_BlitSurface(icons, &src, screen, &dst);
    }
    /* blocks palette */
    src.y = 13 * 32; dst.x = 2; dst.y = 4 + 5*36 + 84;
    m = screen->h - 3*font->height - 2*37 - 4;
    SDL_FillRect(screen, &dst, theme[!activeblock ? THEME_INACT : (!overblock ? THEME_INPBG : THEME_TABBG)]);
    SDL_BlitSurface(icons, &src, screen, &dst);
    src.y = 0; dst.y += 32;
    for(i = 1; i < 16 && palette[i] && dst.y < m; dst.y += 32, i++) {
        if(dst.y + dst.h > m) dst.h = src.h = m - dst.y;
        SDL_FillRect(screen, &dst, theme[i == activeblock ? THEME_INACT : (i == overblock ? THEME_INPBG : THEME_TABBG)]);
        blk->pixels = blocks[palette[i]].img ? blocks[palette[i]].img : (uint8_t*)icons->pixels + 32 * icons->pitch;
        SDL_BlitSurface(blk, &src, screen, &dst);
    }
    dst.x = 36; dst.y = screen->h - font->height; dst.w = screen->w - 36; dst.h = font->height;
    SDL_FillRect(screen, &dst, theme[THEME_BG]);
    if(!status) {
        if((activetool == -1 && overtool < -1) || overtool >= 0) s = lang[LOAD + overtool];
        if(overblock != -1 && (!overblock || palette[overblock])) s = blocks[palette[overblock]].name;
    }
    /* ground layer */
    dst.x = 2; dst.y = screen->h - 3*font->height; dst.w = 32; dst.h = font->height;
    i = currlayer == gndlayer ? THEME_FG : THEME_TABBG;
    SDL_FillRect(screen, &dst, theme[i]);
    sdlprint(5, screen->h - 3*font->height, THEME_INACT, i, lang[GND]);
    /* current layer */
    dst.x = 2; dst.y = screen->h - 2*font->height; dst.w = 32; dst.h = font->height;
    SDL_FillRect(screen, &dst, theme[THEME_BG]);
    sprintf(str, "%4d", currlayer - gndlayer);
    /* probability */
    sdlprint(0, screen->h - 2*font->height, THEME_INACT, THEME_BG, str);
    sprintf(str, "%3d%%", layerprob[currlayer] * 100 / 127);
    sdlprint(2, screen->h - font->height, THEME_INACT, THEME_BG, str);
    /* status bar */
    src.x = 16; src.y = 8 * 32 + 80; dst.x = screen->w - 16 * font->width - 20 - 60; dst.y = screen->h - font->height / 2 - 8;
    if(nodes[currlayer][cz][cx].param0 && dst.x >= 0) {
        sprintf(str, "%02X %02X", nodes[currlayer][cz][cx].param1, nodes[currlayer][cz][cx].param2);
        sdlprint(dst.x, screen->h - font->height, THEME_FG, THEME_BG, str);
    } else if(overtool == -3) {
        sprintf(str, "%3d", layerprob[currlayer]);
        sdlprint(dst.x, screen->h - font->height, THEME_FG, THEME_BG, str);
    } else if(overtool == -4) {
        sprintf(str, "%3d", currlayer);
        sdlprint(dst.x, screen->h - font->height, THEME_FG, THEME_BG, str);
    }
    dst.x += 5*font->width + 15;
    if((nodes[currlayer][cz][cx].param1 & 0x80) && dst.x >= 0) {
        strsepar = 0;
        sdlprint(dst.x, screen->h - font->height, THEME_FG, THEME_BG, "\004\005");
        strsepar = 1;
    }
    dst.x += 2*font->width + 4;
    if(dst.x >= 0) {
        src.w = src.h = dst.w = dst.h = 16;
        SDL_BlitSurface(icons, &src, screen, &dst);
    }
    dst.x += 20;
    if(dst.x >= 0) {
        sprintf(str, "%3d%%", zoom * 100 / 128);
        sdlprint(dst.x, screen->h - font->height, THEME_FG, THEME_BG, str);
    }
    dst.x += 4 * (font->width+2);
    src.x = 0;
    if(dst.x >= 0)
        SDL_BlitSurface(icons, &src, screen, &dst);
    dst.x += 24;
    if(dst.x >= 0) {
        sprintf(str, "%3d", brush_height());
        sdlprint(dst.x, screen->h - font->height, THEME_FG, THEME_BG, str);
    }
    dst.x += 3 * (font->width+1);
    if(dst.x >= 0) {
        memcpy(str, "\xC2\x80\xC2\x80", 5);
        strsepar = 0;
        str[1] = 0x80 + (4*brush_type) + (2*brush_hollow);
        str[3] = 0x81 + (4*brush_type) + (2*brush_hollow);
        sdlprint(dst.x, screen->h - font->height, THEME_FG, THEME_BG, str);
        strsepar = 1;
    }
    if(s)
        sdlprint(42, screen->h - font->height, THEME_FG, THEME_BG, s);
}

/**
 * Redraw the SDL window
 */
void sdlredraw()
{
    SDL_Rect dst;

    /* main window area */
    if(!activetool) load_redraw(); else
    if(!dx || !dz)  {
        dst.x = 36; dst.y = 0; dst.w = screen->w - 36; dst.h = screen->h - font->height;
        SDL_FillRect(screen, &dst, theme[THEME_TABBG]);
    } else {
        switch(activetool) {
            case 1: save_redraw(); break;
            case 15: brush_redraw(); break;
            case 16: search_redraw(); break;
            default: edit_redraw(1); break;
        }
    }

    /* toolbar and status bar */
    sdltoolbar();

    if(help) sdlhelp();

    /* flush the window */
    SDL_UpdateWindowSurface(window);
}

/**
 * Set window title
 */
void sdltitle()
{
    char *fn, *title;
    fn = strrchr(mtsfile, DIRSEP);
    if(fn) fn++; else fn = mtsfile;
    title = (char*)malloc(strlen(fn) + 10);
    sprintf(title, "MTSEdit: %s", fn);
    SDL_SetWindowTitle(window, title);
    free(title);
}

/**
 * UI for various MTS operations
 */
void sdldo(int opt)
{
    int i;

    SDL_ShowCursor(1); systemcursor = 1;
    SDL_SetCursor(working);
    switch(opt) {
        case -1: activetool = -1; break;
        case -2: readschem(); if(mts_x && mts_y && mts_z) { sdltitle(); activetool = -1; activeblock = 0; } break;
        case 0: activetool = 0; break;
        case 1: mts_save(); activetool = -1; activeblock = 0; break;
        case 2: mts_view(shift); break;
        case 3:
        case 4:
            hist_prepare(opt == 4 ? HIST_ROTCCW : HIST_ROTCW, 0);
            mts_rotate(4-opt); i = cx; if(opt == 3) { cx = cz; cz = 255 - i; } else { cx = 255 - cz; cz = i; }
            hist_commit();
        break;
        case 5: hist_prepare(HIST_FLIP, 0); mts_flip(); hist_commit(); break;
        case 6: hist_prepare(HIST_ADDY, currlayer); mts_addy(currlayer, shift); hist_commit(); break;
        case 7: hist_prepare(HIST_DELY, currlayer); mts_dely(currlayer); hist_commit(); break;
        case 8: hist_prepare(HIST_ADDZ, cz); mts_addz(cz, shift); hist_commit(); break;
        case 9: hist_prepare(HIST_DELZ, cz); mts_delz(cz); hist_commit(); break;
        case 10: hist_prepare(HIST_ADDX, cx); mts_addx(cx, shift); hist_commit(); break;
        case 11: hist_prepare(HIST_DELX, cx); mts_delx(cx); hist_commit(); break;
        case 12: mts_blueprint(shift); break;
    }
    SDL_SetCursor(pointer);
    SDL_ShowCursor(0); systemcursor = 0;
    sdlredraw();
}

/**
 * The main SDL loop
 */
int sdlmain(int opt)
{
    stbi__context s;
    stbi__result_info ri;
    unsigned char *icondata;
    char *fn, *title;
    int iw = 0, ih = 0, len, i, j, k, l;
    SDL_Event event, lookahead;

    /* this is tricky, because extern wouldn't know sizeof() */
    if(opt == 7) return instmod(binary_mtsedit, sizeof(binary_mtsedit));

    /* get our font */
    font = (psf_t*)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)binary_font_psf_gz + 10,
        sizeof(binary_font_psf_gz) - 10, 32768, &len, 0);
    if(!font) error(lang[ERR_MEM]);

    /* as an additional dependency, blueprint needs the font */
    if(opt) return mts_blueprint(shift);

    /* initialize SDL */
    SDL_Init(SDL_INIT_VIDEO);
    fn = strrchr(mtsfile, DIRSEP);
    if(fn) fn++; else fn = mtsfile;
    title = (char*)malloc(strlen(fn) + 10);
    sprintf(title, "MTSEdit: %s", fn);
    window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600,  SDL_WINDOW_RESIZABLE);
    free(title);
    screen = SDL_GetWindowSurface(window);

    working = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAITARROW);
    pointer = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);

    /* get icons and surfaces */
    s.read_from_callbacks = 0;
    s.img_buffer = s.img_buffer_original = binary_icons_png;
    s.img_buffer_end = s.img_buffer_original_end = binary_icons_png + sizeof(binary_icons_png);
    ri.bits_per_channel = 8;
    icondata = (uint8_t*)stbi__png_load(&s, &iw, &ih, &len, 0, &ri);
    icons = SDL_CreateRGBSurfaceFrom((uint32_t*)icondata, iw, iw, 32, iw*4, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
    SDL_SetWindowIcon(window, icons);
    SDL_FreeSurface(icons);
    icons = SDL_CreateRGBSurfaceFrom((uint32_t*)icondata, iw, ih, 32, iw*4, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
    blk = SDL_CreateRGBSurfaceFrom(NULL, 32, 32, 32, 32*4, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
    fg = SDL_CreateRGBSurface(0, screen->w - 36 + 64, screen->h - font->height + 64, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
    cl = SDL_CreateRGBSurface(0, screen->w - 36 + 64, screen->h - font->height + 64, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
    bg = SDL_CreateRGBSurface(0, screen->w - 36 + 64, screen->h - font->height + 64, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000);
    memset(&histcurr, 0, sizeof(histlist_t));
    dx = dz = 0;

    /* draw window and loading message */
    memset(palette, 0, sizeof(palette));
    status = lang[LOADING];
    SDL_SetCursor(working);
    sdlredraw();

    /* parse blocks.csv */
    blocks_parse();
    /* load schematics from file */
    readschem();
    if(!mts_y || !mts_y || !mts_x)
        activetool = 0;

    /* populate search window with default results (may include unknown blocks from the MTS) */
    numresults = numblocks - 1;
    results = (int*)malloc(numresults * sizeof(int));
    for(i = 0; (int)i < numresults; i++) results[i] = i + 1;
    /* clear block probability for air */
    for(i = 0; i < 256; i++)
        for(j = 0; j < 256; j++)
            for(k = 0; k < 256; k++)
                if(!nodes[i][j][k].param0) nodes[i][j][k].param1 = 0;

    /* repaint window with the loaded MTS */
    sdlredraw();
    SDL_SetCursor(pointer);
    SDL_ShowCursor(0);
    SDL_StartTextInput();

    /* main loop */
    while (!quitting) {
        if (SDL_WaitEvent(&event)) {
            /* check if we have multiple mouse motion events in the queue, only serve the last */
            if(event.type == SDL_MOUSEMOTION) {
                lookahead.type = 0;
                while(SDL_PollEvent(&lookahead) && lookahead.type == SDL_MOUSEMOTION)
                    memcpy(&event, &lookahead, sizeof(SDL_Event));
                if(lookahead.type && lookahead.type != SDL_MOUSEMOTION)
                    SDL_PushEvent(&lookahead);
            }
            switch (event.type) {
                /* window events */
                case SDL_QUIT: quitting = 1; break;
                case SDL_WINDOWEVENT:
                    switch(event.window.event) {
                        case SDL_WINDOWEVENT_CLOSE: quitting = 1; break;
                        case SDL_WINDOWEVENT_RESIZED:
                        case SDL_WINDOWEVENT_SIZE_CHANGED:
                            SDL_FreeSurface(screen);
                            SDL_FreeSurface(fg);
                            SDL_FreeSurface(bg);
                            screen = SDL_GetWindowSurface(window);
                            fg = SDL_CreateRGBSurface(0, screen->w - 36 + 64, screen->h - font->height + 64, 32,
                                0xFF, 0xFF00, 0xFF0000, 0xFF000000);
                            cl = SDL_CreateRGBSurface(0, screen->w - 36 + 64, screen->h - font->height + 64, 32,
                                0xFF, 0xFF00, 0xFF0000, 0xFF000000);
                            bg = SDL_CreateRGBSurface(0, screen->w - 36 + 64, screen->h - font->height + 64, 32,
                                0xFF, 0xFF00, 0xFF0000, 0xFF000000);
                            sdlredraw();
                        break;
                        default: sdlredraw(); break;
                    }
                break;

                /* mouse events */
                case SDL_MOUSEMOTION:
                    i = j = -1; status = NULL; help = 0;
                    if(event.motion.x >= 36 && event.motion.y < screen->h - (int)font->height &&
                        activetool == -1 && SDL_GetCursor() != working) {
                        if(systemcursor) SDL_ShowCursor(0);
                        systemcursor = 0;
                    } else {
                        if(!systemcursor) SDL_ShowCursor(1);
                        systemcursor = 1;
                    }
                    if(event.motion.x < 36) {
                        /* toolbar */
                        if(event.motion.y < 4 + 3 * 36) {
                            i = (event.motion.y > 3 ? event.motion.y - 4 : event.motion.y) / 36;
                        } else
                        if(event.motion.y < 4 + 3 * 36 + 80) {
                            i = 3 + ((((event.motion.y - 4 - 3 * 36) / 16) << 1) | (event.motion.x >= 18 ? 1 : 0));
                        } else
                        if(event.motion.y < 4 + 5 * 36 + 84) {
                            i = 15 + ((event.motion.y - 4 - 3 * 36 - 84) / 36);
                        } else
                        if(event.motion.y >= (int)(screen->h - font->height))           i = -3; else
                        if(event.motion.y >= (int)(screen->h - 2*font->height))         i = -4; else
                        if(event.motion.y >= (int)(screen->h - 3*font->height))         i = -2; else
                        if(event.motion.y >= (int)(screen->h - 3*font->height - 36))    i = 18; else
                        if(event.motion.y >= (int)(screen->h - 3*font->height - 2*36))  i = 17; else
                        if(event.motion.y < (int)(screen->h - 3*font->height - 2*36))
                            j = (event.motion.y - 4 - 5 * 36 - 88) / 32;
                    } else
                    if(event.motion.y > screen->h - (int)font->height) {
                        if(event.motion.x > screen->w - 9 * (int)font->width - 9 - 52 &&
                            event.motion.x < screen->w - 7 * (int)font->width - 2 - 32) i = 14;
                        if(event.motion.x > screen->w - 7 * (int)font->width - 7 - 32 &&
                            event.motion.x < screen->w - 5 * (int)font->width - 5 - 12) i = 13;
                    } else
                    if(activetool == 16) search_mouseover(&event); else
                    if(activetool == -1) {
                        if(event.motion.x > screen->w - 32 && event.motion.y >= (int)(screen->h - font->height - 32)) i = -5;
                        k = cx; l = cz;
                        edit_mouseover(&event);
                        if(k != cx || l != cz) {
                            edit_redraw(0);
                            sdltoolbar();
                            SDL_UpdateWindowSurface(window);
                        }
                    }
                    if(i != overtool || j != overblock) {
                        overtool = i;
                        overblock = j;
                        sdltoolbar();
                        SDL_UpdateWindowSurface(window);
                    }
                break;
                case SDL_MOUSEBUTTONDOWN:
                    if(activetool == -1 && overtool == -1 && event.motion.x > 36) {
                        edit_mousedown(&event);
                        sdltoolbar();
                        SDL_UpdateWindowSurface(window);
                    } else
                    if(overtool == -3) mts_layerprob(event.button.button == 1 ? +1 : -1); else
                    if(overtool == -2) gndlayer = currlayer; else
                    if(overtool >= 0 || overblock != -1) {
                        if(overtool >= 0 && activetool != overtool) activetool = overtool;
                        else { activetool = -1; if(overblock != -1) activeblock = overblock; }
                        sdltoolbar();
                        SDL_UpdateWindowSurface(window);
                    }
                    switch(activetool) {
                        case 0: load_mousedown(&event); break;
                        case 1: save_mousedown(&event); break;
                        case 15:
                            if(event.motion.x > 36) {
                                if(!brush_mousedown(&event)) {
                                    edit_mouseover(&event);
                                    edit_redraw(0);
                                    SDL_ShowCursor(0); systemcursor = 0; activetool = -1;
                                }
                                SDL_UpdateWindowSurface(window);
                            }
                        break;
                        case 16: search_mousedown(&event); break;
                    }
                break;
                case SDL_MOUSEBUTTONUP:
                    i = 1;
                    if(activetool != -1 && activetool == overtool) {
                        switch(activetool) {
                            case 2: sdldo(2); break;
                            case 3: sdldo(shift || event.button.button != 1 ? 4 : 3); break;
                            case 4: sdldo(5); break;
                            case 5: sdldo(6); break;
                            case 6: sdldo(7); break;
                            case 7: sdldo(8); break;
                            case 8: sdldo(9); break;
                            case 9: sdldo(10); break;
                            case 10: sdldo(11); break;
                            case 11: i = hist_undo(); break;
                            case 12: i = hist_redo(); break;
                            case 13: i = edit_zoomin(); break;
                            case 14: i = edit_zoomout(); break;
                            case 17: if(currlayer < 255) currlayer++; break;
                            case 18: if(currlayer > 0) currlayer--; break;
                        }
                        if(activetool != 0 && activetool != 1 && activetool != 15 && activetool != 16) activetool = -1;
                    }
                    if(i) sdlredraw();
                break;
                case SDL_MOUSEWHEEL:
                    i = 1;
                    if(overtool == -3) mts_layerprob(event.wheel.y); else
                    switch(activetool) {
                        case 0: load_scroll(&event); break;
                        case 1: save_scroll(&event); break;
                        case 16: search_scroll(&event); break;
                        case -1: i = edit_scroll(&event); break;
                    }
                    if(i) sdlredraw();
                break;

                /* handle the keyboard */
                case SDL_KEYDOWN:
                    status = NULL;
                    if(event.key.keysym.sym == SDLK_LSHIFT || event.key.keysym.sym == SDLK_RSHIFT) shift = 1;
                    if(event.key.keysym.sym == SDLK_LCTRL || event.key.keysym.sym == SDLK_RCTRL) ctrl = 1;
                    if(!help) {
                        if(activetool != -1 && event.key.keysym.sym == SDLK_ESCAPE) {
                            if(activetool == 15) brush_setmask(1);
                            SDL_ShowCursor(0);
                            systemcursor = 0;
                            activetool = -1;
                        } else
                        if(activetool != 0 && activetool != 1 && activetool != 15 && activetool != 16) edit_key(&event);
                    }
                break;
                case SDL_TEXTINPUT:
                case SDL_KEYUP:
                    if(event.key.keysym.sym == SDLK_LSHIFT || event.key.keysym.sym == SDLK_RSHIFT) shift = 0;
                    if(event.key.keysym.sym == SDLK_LCTRL || event.key.keysym.sym == SDLK_RCTRL) ctrl = 0;
                    if(event.key.keysym.sym == SDLK_F1) { help ^= 1; sdlredraw(); break; }
                    if(!help) {
                        i = 0;
                        switch(activetool) {
                            case 0: load_key(&event); break;
                            case 1: save_key(&event); break;
                            case 15: brush_key(&event); break;
                            case 16: search_key(&event); break;
                            default:
                                if(event.key.keysym.sym == SDLK_f) sdldo(5); else
                                if(event.key.keysym.sym == SDLK_m || event.key.keysym.sym == SDLK_TAB) activetool = 16;
                                if(event.key.keysym.sym == SDLK_b) activetool = 15;
                                if(shift && event.key.keysym.sym == SDLK_s) activetool = 1;
                            break;
                        }
                        if(!i) sdlredraw();
                        else {
                            edit_redraw(0);
                            sdltoolbar();
                            SDL_UpdateWindowSurface(window);
                        }
                    } else {
                        help = 0;
                        sdlredraw();
                    }
                break;
            }
            if(activetool != -1 || overtool != -1 || SDL_GetCursor() == working) {
                if(!systemcursor) SDL_ShowCursor(1);
                systemcursor = 1;
            }
        }
    }

    /* cleanup SDL */
    SDL_StopTextInput();
    SDL_FreeCursor(working);
    SDL_FreeCursor(pointer);
    SDL_FreeSurface(icons);
    SDL_FreeSurface(blk);
    SDL_FreeSurface(fg);
    SDL_FreeSurface(cl);
    SDL_FreeSurface(bg);
    SDL_Quit();
    hist_free(-1, -1);
    free(icondata);
    free(font);
    blocks_free();
    return 0;
}
