Commit ccf3c585 authored by bzt's avatar bzt

More sfnedit

parent e5378bb1
docs/sfnedit4.png

10.2 KB | W: | H:

docs/sfnedit4.png

11.6 KB | W: | H:

docs/sfnedit4.png
docs/sfnedit4.png
docs/sfnedit4.png
docs/sfnedit4.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -34,11 +34,12 @@
#include "lang.h"
#include "util.h"
#include "file.h"
#include "hist.h"
#include "render.h"
#include "unicode.h"
extern int selcolor, clickx, clicky;
int overmenu=0, showgrid=0, mousex=0, mousey=0, inmove=0, prevx = 0, prevy = 0;
int overmenu=0, showgrid=0, showlines=0, mousex=0, mousey=0, mousebtn = 0, inmove=0, prevx = 0, prevy = 0;
int zooms[] = { 16,24,32,40,48,56,64,80,96,128,160,192,224,256,320,384,448,512,768,1024,1536,2048,3072,4096,5120,6144,7168,8192 };
/**
......@@ -174,21 +175,21 @@ void view_editarea(ui_win_t *win)
if(win->zx < 0)
ui_number(win, 0, 38 - win->zx, 24, theme[THEME_INACT]);
else
ui_number(win, (win->zx * b + q) / win->zoom, 38, 24, theme[THEME_INACT]);
ui_number(win, (win->zx * b) / win->zoom, 38, 24, theme[THEME_INACT]);
if(win->zy < 0)
ui_number(win, 0, 36, 32 - win->zy, theme[THEME_INACT]);
else
ui_number(win, (win->zy * b + q) / win->zoom, 36, 32, theme[THEME_INACT]);
ui_number(win, (win->zy * b) / win->zoom, 36, 32, theme[THEME_INACT]);
a = 36 - win->zx + win->zoom;
if(a <= win->w - 16)
ui_number(win, b, a, 24, theme[THEME_INACT]);
else
ui_number(win, ((win->zoom - (a - win->w +16)) * b + q) / win->zoom, win->w -16, 24, theme[THEME_INACT]);
ui_number(win, ((win->zoom - (a - win->w +16)) * b) / win->zoom, win->w -16, 24, theme[THEME_INACT]);
a = 26 - win->zy + win->zoom;
if(a <= win->h - 6)
ui_number(win, b, 36, a, theme[THEME_INACT]);
else
ui_number(win, ((win->zoom - (a - win->h + 6)) * b + q) / win->zoom, 36, win->h - 6, theme[THEME_INACT]);
ui_number(win, ((win->zoom - (a - win->h + 6)) * b) / win->zoom, 36, win->h - 6, theme[THEME_INACT]);
a = win->zoom-win->zx;
b = win->zoom-win->zy;
if(showgrid && s > 2) {
......@@ -231,7 +232,7 @@ void view_editarea(ui_win_t *win)
for(j=0,p=32*win->p; j < h && 32 + j < win->h; j++, p += win->p)
for(i=0;i<w && 52+i < win->w;i++)
win->data[p + 52 + i] = win->bg[j*w+i];
if(chars[win->v][win->chr].len) {
if(chars[win->v][win->chr].len && win->frag < chars[win->v][win->chr].len) {
switch(frags[chars[win->v][win->chr].frags[win->frag]].type) {
case SSFN_FRAG_BITMAP:
render_bitmap(&frags[chars[win->v][win->chr].frags[win->frag]], win->data, win->w, win->h, win->p,
......@@ -243,7 +244,7 @@ void view_editarea(ui_win_t *win)
break;
case SSFN_FRAG_CONTOUR:
render_contour(&frags[chars[win->v][win->chr].frags[win->frag]], win->data, win->w, win->h, win->p,
win->zx, win->zy, 52, 32, win->zoom, win->zoom, theme[THEME_INPUT], theme[THEME_TABBG], 0);
win->zx, win->zy, 52, 32, win->zoom, win->zoom, theme[THEME_INPUT], theme[THEME_TABBG], 2);
break;
}
}
......@@ -307,6 +308,8 @@ void view_edit(ui_win_t *win)
*/
int ctrl_edit(ui_win_t *win, ui_event_t *evt)
{
int i, j;
switch(evt->type) {
case E_KEY:
switch(evt->x) {
......@@ -315,6 +318,21 @@ int ctrl_edit(ui_win_t *win, ui_event_t *evt)
if(win->bg) free(win->bg);
win->bg = NULL;
break;
case 'l':
showlines ^= 1;
break;
case 'z':
hist_undo(win);
if(win->bg) free(win->bg);
win->bg = NULL;
ui_refreshwin(evt->win, 0, 0, win->w, win->h);
break;
case 'y':
hist_redo(win);
if(win->bg) free(win->bg);
win->bg = NULL;
ui_refreshwin(evt->win, 0, 0, win->w, win->h);
break;
default: break;
}
return 1;
......@@ -328,8 +346,8 @@ int ctrl_edit(ui_win_t *win, ui_event_t *evt)
win->bg = NULL;
return 1;
}
mousex = ((evt->x - 52 + win->zx) * (16 << font->quality) + (win->zoom >> 1)) / win->zoom;
mousey = ((evt->y - 32 + win->zy) * (16 << font->quality) + (win->zoom >> 1)) / win->zoom;
mousex = ((evt->x - 52 + win->zx) * (16 << font->quality)) / win->zoom;
mousey = ((evt->y - 32 + win->zy) * (16 << font->quality)) / win->zoom;
view_coords(win);
ui_flushwin(win, 0, win->h - 34, 36, 32);
} else {
......@@ -350,6 +368,18 @@ int ctrl_edit(ui_win_t *win, ui_event_t *evt)
}
return 0;
case E_BTNPRESS:
if(chars[win->v][win->chr].len && (evt->w & 32 || (evt->h & 1 && evt->w & 8))) {
if(frags[chars[win->v][win->chr].frags[win->frag]].color[0])
frags[chars[win->v][win->chr].frags[win->frag]].color[0]--;
view_coords(win);
return 1;
}
if(evt->w & 64 || (evt->h & 1 && evt->w & 16)) {
if(frags[chars[win->v][win->chr].frags[win->frag]].color[0] < 241)
frags[chars[win->v][win->chr].frags[win->frag]].color[0]++;
view_coords(win);
return 1;
}
if(evt->x < 36) {
if(win->menu == 3 || win->menu > 8) {
win->menu = 5;
......@@ -392,13 +422,16 @@ int ctrl_edit(ui_win_t *win, ui_event_t *evt)
} else
if(evt->y >= 32 && evt->x >= 52) {
if(win->menu < 9) {
clickx = evt->x;
clicky = evt->y;
mousebtn = evt->w;
if(evt->w & 1) {
clickx = evt->x;
clicky = evt->y;
prevx = win->zx;
prevy = win->zy;
inmove = 1;
if(chars[win->v][win->chr].len && frags[chars[win->v][win->chr].frags[win->frag]].type == SSFN_FRAG_CONTOUR) {
mousex = ((evt->x - 52 + win->zx) * (16 << font->quality)) / win->zoom;
mousey = ((evt->y - 32 + win->zy) * (16 << font->quality)) / win->zoom;
ui_cursorwin(win, CURSOR_MOVE);
}
}
......@@ -444,32 +477,52 @@ int ctrl_edit(ui_win_t *win, ui_event_t *evt)
case 0: /* set advance x */ break;
case 1: /* set advance y */ break;
case 2: /* set hinting grid */ break;
case 4:
file_removefrag(&chars[win->v][win->chr], win->frag);
if(win->frag > 0 && win->frag >= chars[win->v][win->chr].len)
win->frag--;
break;
case 6: win->frag = file_addemptyfrag(&chars[win->v][win->chr], SSFN_FRAG_CONTOUR); break;
case 7: win->frag = file_addemptyfrag(&chars[win->v][win->chr], SSFN_FRAG_BITMAP); break;
case 8: win->frag = file_addemptyfrag(&chars[win->v][win->chr], SSFN_FRAG_PIXMAP); break;
case 4: hist_dellayer(win); break;
case 6: hist_addlayer(win, SSFN_FRAG_CONTOUR); break;
case 7: hist_addlayer(win, SSFN_FRAG_BITMAP); break;
case 8: hist_addlayer(win, SSFN_FRAG_PIXMAP); break;
}
if(win->menu == 4 || win->menu > 5) win->menu = 5;
if(win->bg) free(win->bg);
win->bg = NULL;
ui_resizewin(win, win->w, win->h);
return 1;
} else
if(evt->x < 36 && evt->y > 276) {
} else
if(chars[win->v][win->chr].len && win->menu >= 9)
ctrl_color(win, evt, &frags[chars[win->v][win->chr].frags[win->frag]].color[win->menu-9]);
else
if(evt->y > 32 && evt->x > 52) {
if(clickx == evt->x && clicky == evt->y && chars[win->v][win->chr].len &&
frags[chars[win->v][win->chr].frags[win->frag]].type != SSFN_FRAG_CONTOUR) {
printf("plot pixel\n");
if(clickx == evt->x && clicky == evt->y && chars[win->v][win->chr].len) {
switch(frags[chars[win->v][win->chr].frags[win->frag]].type) {
case SSFN_FRAG_BITMAP:
i = mousey * ((16 << font->quality)>>3) + (mousex >> 3);
j = ((uint8_t*)frags[chars[win->v][win->chr].frags[win->frag]].data)[i];
if((mousebtn & 1) || (mousebtn & 6))
hist_setpixel(win, i, mousebtn & 1 ? j | (1<<(mousex&7)) : j & ~(1<<(mousex&7)));
break;
case SSFN_FRAG_PIXMAP:
i = mousey * (16 << font->quality) + mousex;
if((mousebtn & 1) || (mousebtn & 6))
hist_setpixel(win, i, mousebtn & 1? frags[chars[win->v][win->chr].frags[win->frag]].color[0]:240);
break;
default:
if(mousebtn & 1) {
if(evt->h) {
hist_addcont(win, (evt->h & 4) || (evt->h & 3) == 3 ? SSFN_CONTOUR_QUAD :
(evt->h & 2 ? SSFN_CONTOUR_CUBIC : SSFN_CONTOUR_LINE), mousex, mousey);
}
} else
if(mousebtn & 6) {
hist_delcont(win);
}
break;
}
clickx = clicky = -1;
return 1;
}
}
clickx = clicky = -1;
return 0;
break;
}
return 0;
}
......@@ -240,10 +240,10 @@ void file_contadd(int fragidx, int type, int px, int py, int c1x, int c1y, int c
cont_t *c;
i = f->len++;
f->data = (cont_t*)realloc(f->data, f->len*sizeof(char_t));
f->data = (cont_t*)realloc(f->data, f->len*sizeof(cont_t));
if(!f->data) error("file_contadd", ERR_MEM);
c = &f->data[i];
memset(c, 0, sizeof(char_t));
memset(c, 0, sizeof(cont_t));
c->type = type;
c->px = px;
c->py = py;
......@@ -256,18 +256,18 @@ void file_contadd(int fragidx, int type, int px, int py, int c1x, int c1y, int c
/**
* Add a new and empty fragment to character
*/
int file_addemptyfrag(char_t *chr, int type)
int file_addemptyfrag(char_t *chr, int type, int fragidx)
{
int i;
if(type != SSFN_FRAG_CONTOUR) {
for(i=0;i<chr->len;i++)
if(frags[chr->frags[i]].type == type) return i;
}
for(i=0;i<chr->len;i++)
if(chr->frags[i] == fragidx || (type != SSFN_FRAG_CONTOUR && frags[chr->frags[i]].type == type))
return i;
i = chr->len; chr->len++;
chr->frags = (int*)realloc(chr->frags, (chr->len)*sizeof(int));
if(!chr->frags) error("file_addemptyfrag", ERR_MEM);
chr->frags[i] = file_fragadd(type);
chr->frags[i] = fragidx >= 0 ? fragidx : file_fragadd(type);
return i;
}
......@@ -280,9 +280,7 @@ void file_removefrag(char_t *chr, int idx)
if(idx < 0 || idx >= chr->len || chr->len == 0) return;
file_delfrag(chr->frags[idx]);
for(i = idx; i +1 < chr->len; i++)
for(i = idx; i + 1 < chr->len; i++)
chr->frags[i] = chr->frags[i+1];
chr->len--;
if(!chr->len) {
......
......@@ -77,8 +77,10 @@ extern char *strtable[];
int file_findchar(int v, uint32_t unicode);
int file_addchar(int v, uint32_t unicode, int check);
void file_delchar(int v, int chr);
int file_addemptyfrag(char_t *chr, int type);
void file_delfrag(int idx);
int file_addemptyfrag(char_t *chr, int type, int fragidx);
void file_removefrag(char_t *chr, int idx);
void file_contadd(int fragidx, int type, int px, int py, int c1x, int c1y, int c2x, int c2y);
void file_load(char *filename);
void file_savesfn(int idx);
void file_saveasc(int idx);
......
......@@ -202,7 +202,7 @@ down: if(!glyphactive) { glyphactive = 1; return 1; }
}
return 0;
case K_LEFT:
if(win->v > 0) {
left: if(win->v > 0) {
win->v--;
gmax = 0;
lastover = selrs = selre = -1;
......@@ -212,7 +212,7 @@ down: if(!glyphactive) { glyphactive = 1; return 1; }
}
return 0;
case K_RIGHT:
if(win->v + 1 < SSFN_NUMVARIANTS) {
right: if(win->v + 1 < SSFN_NUMVARIANTS) {
win->v++;
gmax = 0;
lastover = selrs = selre = -1;
......@@ -245,9 +245,11 @@ down: if(!glyphactive) { glyphactive = 1; return 1; }
if(evt->y >= 44 && evt->y < 44+24 && evt->x > win->w >> 1 && evt->x < (win->w >> 1) + (win->w >> 2)) glyphactive = 0;
else if(evt->y >= 44 && evt->y < 44+24 && evt->x > (win->w >> 1) + (win->w >> 2)) glyphactive = 1;
else glyphactive = 2;
if(evt->w & 32 || (evt->h & 1 && evt->w & 8)) goto left;
if(evt->w & 64 || (evt->h & 1 && evt->w & 16)) goto right;
if(evt->w & 8) goto up;
if(evt->w & 16) goto down;
if(evt->y > 68 && evt->x > goff && evt->x < goff + (gsiz+1)*16) {
if(evt->w & 8) goto up;
if(evt->w & 16) goto down;
if(evt->w & 1) {
a = ((evt->y - 68) / (gsiz+1) *16) + ((evt->x - goff) / (gsiz+1)) + scroll;
if(a < gmax && glist[a] != -1) {
......
/*
* sfnedit/hist.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 Edit history
*
*/
#include <string.h>
#include <stdlib.h>
#include "ui.h"
#include "hist.h"
#include "file.h"
#include "lang.h"
#include "util.h"
/**
* Undo
*/
void hist_undo(ui_win_t *win)
{
int i;
char_t *chr = &chars[win->v][win->chr];
hist_t *his;
if(win->hist && win->histmin) {
win->histmin--;
his = &win->hist[win->histmin];
switch(his->type) {
case HIST_DELLAYER: win->frag = file_addemptyfrag(chr, -1, his->frag); break;
case HIST_ADDLAYER:
for(i=0;i<chr->len;i++) if(chr->frags[i] == his->frag) break;
file_removefrag(chr, i);
win->frag = 0;
break;
case HIST_SETPIXEL: ((uint8_t*)frags[his->frag].data)[his->idx] = his->data.pixel.oldpix; break;
case HIST_DELCONT: file_contadd(his->frag, his->data.cont.type, his->data.cont.px, his->data.cont.py,
his->data.cont.c1x, his->data.cont.c1y, his->data.cont.c2x, his->data.cont.c2y); break;
case HIST_ADDCONT: if(frags[his->frag].len) frags[his->frag].len--; break;
}
}
}
/**
* Redo
*/
void hist_redo(ui_win_t *win)
{
int i;
char_t *chr = &chars[win->v][win->chr];
hist_t *his = win->hist ? &win->hist[win->histmin] : NULL;
if(win->histmin < win->histmax && his) {
switch(his->type) {
case HIST_ADDLAYER: win->frag = file_addemptyfrag(chr, -1, his->frag); break;
case HIST_DELLAYER:
for(i=0;i<chr->len;i++) if(chr->frags[i] == his->frag) break;
file_removefrag(chr, i); if(win->frag > chr->len) { win->frag--; }
break;
case HIST_SETPIXEL: ((uint8_t*)frags[his->frag].data)[his->idx] = his->data.pixel.newpix; break;
case HIST_DELCONT: if(frags[his->frag].len) frags[his->frag].len--; break;
case HIST_ADDCONT: file_contadd(his->frag, his->data.cont.type, his->data.cont.px, his->data.cont.py,
his->data.cont.c1x, his->data.cont.c1y, his->data.cont.c2x, his->data.cont.c2y); break;
}
win->histmin++;
}
}
/**
* Cleanup things stuck in history
*/
void hist_cleanup(ui_win_t *win, int idx)
{
int i;
if(win->hist && win->histmax) {
for(i=idx;i<win->histmax;i++)
switch(win->hist[i].type) {
case HIST_DELLAYER: file_delfrag(win->hist[i].frag); break;
}
}
}
/**
* Allocate memory for a new history element
*/
int hist_add(ui_win_t *win)
{
hist_cleanup(win, win->histmin);
win->histmax = win->histmin + 1;
win->hist = (hist_t*)realloc(win->hist, win->histmax*sizeof(ui_win_t));
if(!win->hist) error("hist_add", ERR_MEM);
return win->histmin;
}
/**
* Add a new layer
*/
void hist_addlayer(ui_win_t *win, int type)
{
int i;
char_t *chr = &chars[win->v][win->chr];
if(type != SSFN_FRAG_CONTOUR) {
for(i=0;i<chr->len;i++)
if(frags[chr->frags[i]].type == type) { win->frag = i; return; }
}
i = hist_add(win);
win->histmin++;
win->hist[i].type = HIST_ADDLAYER;
win->frag = file_addemptyfrag(&chars[win->v][win->chr], type, -1);
win->hist[i].frag = chars[win->v][win->chr].frags[win->frag];
}
/**
* Delete a layer
*/
void hist_dellayer(ui_win_t *win)
{
int i = hist_add(win);
char_t *chr = &chars[win->v][win->chr];
win->hist[i].type = HIST_DELLAYER;
win->hist[i].frag = chr->frags[win->frag];
hist_redo(win);
modified = 1;
}
/**
* Change a pixel on a bitmap or pixmap glyph
*/
void hist_setpixel(ui_win_t *win, int idx, uint8_t pixel)
{
int i = hist_add(win);
char_t *chr = &chars[win->v][win->chr];
win->histmin++;
win->hist[i].type = HIST_SETPIXEL;
win->hist[i].frag = chr->frags[win->frag];
win->hist[i].idx = idx;
win->hist[i].data.pixel.oldpix = ((uint8_t*)frags[chr->frags[win->frag]].data)[idx];
win->hist[i].data.pixel.newpix = ((uint8_t*)frags[chr->frags[win->frag]].data)[idx] = pixel;
modified = 1;
}
/**
* Delete the last contour command
*/
void hist_delcont(ui_win_t *win)
{
int i, j;
char_t *chr = &chars[win->v][win->chr];
if(!frags[chr->frags[win->frag]].len) return;
j = --frags[chr->frags[win->frag]].len;
i = hist_add(win);
win->histmin++;
win->hist[i].type = HIST_DELCONT;
win->hist[i].frag = chr->frags[win->frag];
win->hist[i].idx = j;
memcpy(&win->hist[i].data.cont, &frags[chr->frags[win->frag]].data[j], sizeof(cont_t));
modified = 1;
}
/**
* Add a contour command to contour
*/
void hist_addcont(ui_win_t *win, int type, int px, int py)
{
int i = hist_add(win), j, dx, dy;
char_t *chr = &chars[win->v][win->chr];
cont_t *c;
if(!frags[chr->frags[win->frag]].len) type = SSFN_CONTOUR_MOVE;
j = frags[chr->frags[win->frag]].len;
win->hist[i].type = HIST_ADDCONT;
win->hist[i].frag = chr->frags[win->frag];
win->hist[i].idx = j;
win->hist[i].data.cont.type = type;
win->hist[i].data.cont.px = px;
win->hist[i].data.cont.py = py;
if(type == SSFN_CONTOUR_QUAD) {
c = &frags[chr->frags[win->frag]].data[j-1];
win->hist[i].data.cont.c1x = (px + c->px) >> 1;
win->hist[i].data.cont.c1y = (py + c->py) >> 1;
} else
if(type == SSFN_CONTOUR_CUBIC) {
c = &frags[chr->frags[win->frag]].data[j-1];
dx = px > c->px ? px - c->px : c->px - px;
dy = py > c->py ? py - c->py : c->py - py;
win->hist[i].data.cont.c1x = (px > c->px ? c->px + dx/3 : px + 2*dx/3);
win->hist[i].data.cont.c1y = (py > c->py ? c->py + dy/3 : py + 2*dy/3);
win->hist[i].data.cont.c2x = (px > c->px ? c->px + 2*dx/3 : px + dx/3);
win->hist[i].data.cont.c2y = (py > c->py ? c->py + 2*dy/3 : py + dy/3);
} else {
win->hist[i].data.cont.c1x = win->hist[i].data.cont.c1y = win->hist[i].data.cont.c2x = win->hist[i].data.cont.c2y = 0;
}
hist_redo(win);
modified = 1;
}
/*
* sfnedit/hist.h
*
* 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 Edit history
*
*/
enum {
HIST_ADDLAYER,
HIST_DELLAYER,
HIST_SETPIXEL,
HIST_DELCONT,
HIST_ADDCONT,
HOST_MOVEPT
};
void hist_cleanup(ui_win_t *win, int idx);
void hist_undo(ui_win_t *win);
void hist_redo(ui_win_t *win);
void hist_addlayer(ui_win_t *win, int type);
void hist_dellayer(ui_win_t *win);
void hist_setpixel(ui_win_t *win, int idx, uint8_t pixel);
void hist_delcont(ui_win_t *win);
void hist_addcont(ui_win_t *win, int type, int px, int py);