Commit b5591aae authored by bzt's avatar bzt

Kerning in editor

parent 426c93fc
......@@ -35,7 +35,7 @@ size | ....:XX..XX.:.... | | |
Glyphs must be aligned on `baseline`. When displaying, horizontal baseline must be
substracted from current pen y position, or when advance y is not zero, then vertical
baseline must be substracted from pen x.
baseline must be substracted from pen x (see Text Directions below).
The `advance` tells how much you should move your pen (cursor pointer) after the glyph is
drawn on screen (usually not the same as font width). It typically equals to width plus a
......@@ -52,6 +52,40 @@ I get totally different pixel sizes for different TTF fonts when I ask for the s
Passing `SSFN_STYLE_ABS_SIZE` will avoid this scheme, and will scale the glyph's height
to size as usual in other renderers.
Text Directions (Vertical and Right-to-Left Texts)
--------------------------------------------------
Depending on the text direction, you'll have to apply font metrics differently. Vertical
direction is stored within the font, but for right-to-left you'll have to implement
[bidirectional text algorithm](http://www.unicode.org/reports/tr9) as specified by UNICODE.
The BiDi state machine is not part of the SSFN renderer, because this is a low level font
rasterizer.
The logic is as follows:
1. you have to take `baseline` into consideration by substracting from Y or X
2. for right-to-left, you have to substract `glyph width` from X
3. draw the glyph at X, Y.
4. for right-to-left, subtract `advance x` from X, otherwise add to it.
5. add `advance y` to Y.
```c
if(glyph->adv_y) {
x = pen_x - glyph->baseline;
y = pen_y;
} else {
x = pen_x - (bidi_state_machine.rtl ? glyph->w : 0);
y = pen_y - glyph->baseline;
}
my_draw_glyph(x, y, ...);
if(bidi_state_machine.rtl)
pen_x -= glyph->adv_x;
else
pen_x += glyph->adv_x;
pen_y += glyph->adv_y;
```
Usage
-----
......@@ -79,7 +113,7 @@ As my favourite principle is K.I.S.S., there's only a few, clearly named functio
- draw the returned bitmap on your screen at cursor position.
- optionally alter the returned advance offsets with `ssfn_kern()`.
- move the cursor by the returned advance offsets.
- repeat the last 5 steps until you reach the end of the UTF-8 string.
- repeat the last 6 steps until you reach the end of the UTF-8 string.
- when not needed any more, free the rasterized glyphs
- when done with rendering, call `ssfn_free()`.
......
......@@ -177,6 +177,7 @@ the coordinates in font's grid resolution, X axis above, and Y below.
| --------------- | ----------- |
| <kbd>g</kbd> | Toggle grid |
| <kbd>l</kbd> | Toggle lines for control points |
| <kbd>r</kbd> | Toggle right-to-left flag on glyph. This does not influence the font, only the editor |
| <kbd>Shift</kbd> + left click and move | Select portion of the glyph |
| <kbd>Ctrl</kbd> + <kbd>c</kbd> | Copy the selected portion to clipboard |
| <kbd>Ctrl</kbd> + <kbd>x</kbd> | Cut out the selected portion and store it to clipboard |
......
......@@ -330,7 +330,10 @@ void cont_add(int type, int px, int py, int c1x, int c1y, int c2x, int c2y)
c->type = type;
if(type == SSFN_CONTOUR_COLOR) {
ssfn_hdr.features |= SSFN_FEAT_HASCMAP;
c->px = cpal_add(px, py, c1x, c1y);
c->px = px;
c->py = py;
c->c1x = c1x;
c->c1y = c1y;
} else {
c->px = px; if(px < frag_mx) frag_mx = px;
c->py = py; if(py < frag_my) frag_my = py;
......@@ -833,7 +836,11 @@ void bdf(char *ptr, int size)
c = gethex(ptr, 2);
for(k=1,j=0x80;j;j>>=1,k<<=1) if(c & j) bitmap[i] |= k;
}
char_add(0, SSFN_FRAG_BITMAP, w, h, w, 0, bitmap);
if(w != 16 || h != 16 || !(!bitmap[0] && !bitmap[1] && bitmap[2]==0xFE && bitmap[3]==0x7F &&
bitmap[(w+7)/8 * h/4]!=0xFE && bitmap[(w+7)/8 * h/4+1]!=0x7F &&
bitmap[(w+7)/8 * h/2]==0xFE && bitmap[(w+7)/8 * h/2+1]==0x7F &&
!bitmap[l-1] && !bitmap[l-2] && bitmap[l-3]==0x7F && bitmap[l-4]==0xFE))
char_add(0, SSFN_FRAG_BITMAP, w, h, w, 0, bitmap);
}
while(*ptr && *ptr!='\n') ptr++;
while(*ptr=='\n') ptr++;
......@@ -1120,11 +1127,10 @@ void asc(char *ptr, int size)
continue;
} else {
for(ptr+=2,p=0;*ptr && *ptr!='\n' && *ptr!='+' && p<6;ptr++) {
if(cmd=='c') {
par[p++] = gethex(ptr+2, 2);
par[p++] = gethex(ptr+4, 2);
par[p++] = gethex(ptr+6, 2);
par[p++] = gethex(ptr, 2);
if(cmd=='c' || cmd=='g') {
par[p++] = *ptr=='.' ? 240 : cpal_add(
gethex((char*)ptr+2, 2), gethex((char*)ptr+4, 2),
gethex((char*)ptr+6,2), gethex((char*)ptr,2));
} else
par[p++] = atoi(ptr);
while(*ptr!=' ' && *ptr!=',' && ptr[1] && ptr[1]!='\n' && ptr[1]!='+') ptr++;
......@@ -1166,8 +1172,13 @@ void asc(char *ptr, int size)
break;
case 'c':
if(p<3) { fprintf(stderr,"Too few color arguments for U+%06X\n",unicode); exit(3); }
cont_add(SSFN_CONTOUR_COLOR, par[0], par[1], par[2], par[3], par[4], par[5]);
if(p<1) { fprintf(stderr,"Too few color arguments for U+%06X\n",unicode); exit(3); }
cont_add(SSFN_CONTOUR_COLOR, par[0], par[0], par[0], par[0], 0, 0);
break;
case 'g':
if(p<4) { fprintf(stderr,"Too few gradient arguments for U+%06X\n",unicode); exit(3); }
cont_add(SSFN_CONTOUR_COLOR, par[0], par[1], par[2], par[3], 0, 0);
break;
}
}
......@@ -1649,6 +1660,9 @@ printf("arg_name '%s'\n",arg_name);
for(j=1;j<l;j++,contour++) {
frg = (unsigned char*)realloc(frg, fs+16);
if(!frg) { fprintf(stderr,"memory allocation error\n"); return 2; }
if(contour->type == SSFN_CONTOUR_COLOR) {
n = (contour->px == contour->py && contour->px == contour->c1x && contour->px == contour->c1y) ? 0 : 0x4;
}
switch(ssfn_hdr.quality) {
/* low quality */
case 0:
......@@ -1675,8 +1689,13 @@ printf("arg_name '%s'\n",arg_name);
frg[fs++] = contour->c2y & 0x7F;
break;
case SSFN_CONTOUR_COLOR:
frg[fs++] = contour->px >> 7;
frg[fs++] = n | (contour->px >> 7);
frg[fs++] = contour->px & 0x7F;
if(n) {
frg[fs++] = contour->py;
frg[fs++] = contour->c1x;
frg[fs++] = contour->c1y;
}
break;
}
break;
......@@ -1706,8 +1725,13 @@ printf("arg_name '%s'\n",arg_name);
frg[fs++] = contour->c2y & 0xFF;
break;
case SSFN_CONTOUR_COLOR:
frg[fs++] = 0;
frg[fs++] = n;
frg[fs++] = contour->px & 0xFF;
if(n) {
frg[fs++] = contour->py;
frg[fs++] = contour->c1x;
frg[fs++] = contour->c1y;
}
break;
}
break;
......@@ -1749,8 +1773,13 @@ printf("arg_name '%s'\n",arg_name);
frg[fs++] = contour->c2y & 0xFF;
break;
case SSFN_CONTOUR_COLOR:
frg[fs++] = 0;
frg[fs++] = n;
frg[fs++] = contour->px & 0xFF;
if(n) {
frg[fs++] = contour->py;
frg[fs++] = contour->c1x;
frg[fs++] = contour->c1y;
}
break;
}
break;
......@@ -1794,8 +1823,13 @@ printf("arg_name '%s'\n",arg_name);
frg[fs++] = contour->c2y & 0xFF;
break;
case SSFN_CONTOUR_COLOR:
frg[fs++] = 0;
frg[fs++] = n;
frg[fs++] = contour->px & 0xFF;
if(n) {
frg[fs++] = contour->py;
frg[fs++] = contour->c1x;
frg[fs++] = contour->c1y;
}
break;
}
break;
......
This diff is collapsed.
......@@ -173,7 +173,7 @@ int file_findchar(int v, uint32_t unicode)
*/
int file_addchar(int v, uint32_t unicode, int check)
{
int i;
int i, j;
if(v < 0 || v >= SSFN_NUMVARIANTS || unicode > UNICODE_LAST) return -1;
......@@ -191,6 +191,9 @@ int file_addchar(int v, uint32_t unicode, int check)
if(!chars[v]) error("file_addchar", ERR_MEM);
memset(&chars[v][i], 0, sizeof(char_t));
chars[v][i].unicode = unicode;
j = uniname(unicode);
if(!v && j != -1) chars[0][i].rtl = uninames[j].rtl;
chars[v][i].bear_t = chars[v][i].bear_l = 65536;
if(check) {
qsort(chars[v], numchars[v], sizeof(char_t), file_chrsort);
ui_updatewin(v, unicode, +1);
......@@ -234,7 +237,7 @@ void file_delchar(int v, int chr)
/**
* Add a contour fragment
*/
void file_contadd(int fragidx, int type, int px, int py, int c1x, int c1y, int c2x, int c2y)
void file_contadd(char_t *chr, int fragidx, int type, int px, int py, int c1x, int c1y, int c2x, int c2y)
{
int i;
frag_t *f = &frags[fragidx];
......@@ -252,6 +255,25 @@ void file_contadd(int fragidx, int type, int px, int py, int c1x, int c1y, int c
c->c1y = c1y;
c->c2x = c2x;
c->c2y = c2y;
if(type != SSFN_CONTOUR_COLOR && chr) {
if(px < chr->bear_l) chr->bear_l = px;
if(py < chr->bear_t) chr->bear_t = py;
if(px > chr->w) chr->w = px;
if(py > chr->h) chr->h = py;
if(type > 1) {
if(c1x < chr->bear_l) chr->bear_l = c1x;
if(c1y < chr->bear_t) chr->bear_t = c1y;
if(c1x > chr->w) chr->w = c1x;
if(c1y > chr->h) chr->h = c1y;
if(type > 2) {
if(c2x < chr->bear_l) chr->bear_l = c2x;
if(c2y < chr->bear_t) chr->bear_t = c2y;
if(c2x > chr->w) chr->w = c2x;
if(c2y > chr->h) chr->h = c2y;
}
}
}
}
/**
......@@ -322,10 +344,15 @@ bitmap: for(i=0,l=-1;i<chr->len;i++)
chr->frags[l] = file_fragadd(SSFN_FRAG_BITMAP);
}
data = (unsigned char*)frags[chr->frags[l]].data;
if((ox & ~7) < chr->bear_l) chr->bear_l = ox & ~7;
if(oy < chr->bear_t) chr->bear_t = oy;
if(oy+y > chr->h) chr->h = oy+y;
b = s >> 3;
for(j=0; j < y && oy + j < s; j++)
for(i=0; i < x && i < b; i++)
for(i=0; i < x && i < b; i++) {
if(*raw && (ox & ~7)+(x<<3) > chr->w) chr->w = (ox & ~7)+(x<<3);
data[(oy + j) * b + i] = *raw++;
}
break;
case SSFN_FRAG_PIXMAP:
......@@ -355,8 +382,15 @@ bitmap: for(i=0,l=-1;i<chr->len;i++)
data = (unsigned char*)frags[chr->frags[l]].data;
re = ra;
for(j=0; j < y && oy + j < s; j++)
for(i=0; i < x && ox + i < s; i++)
for(i=0; i < x && ox + i < s; i++) {
if(*re < 240) {
if(ox+i < chr->bear_l) chr->bear_l = ox+i;
if(oy+j < chr->bear_t) chr->bear_t = oy+j;
if((ox+i+1) > chr->w) chr->w = ox+i+1;
if(oy+j > chr->h) chr->h = oy+j;
}
data[(oy + j) * s + ox + i] = *re++;
}
free(ra);
break;
......@@ -395,7 +429,7 @@ bitmap: for(i=0,l=-1;i<chr->len;i++)
chr->frags = (int*)realloc(chr->frags, (chr->len)*sizeof(int));
if(!chr->frags) error("file_addrawfrag", ERR_MEM);
chr->frags[j] = file_fragadd(SSFN_FRAG_CONTOUR);
file_contadd(chr->frags[j], SSFN_CONTOUR_MOVE, ox+x, oy+y, 0,0, 0,0);
file_contadd(chr, chr->frags[j], SSFN_CONTOUR_MOVE, ox+x, oy+y, 0,0, 0,0);
for(i=0;i<l;i++) {
t = font->quality < 4 ? (raw[0] >> 7) | ((raw[1] >> 6) & 2) : raw[0] & 3;
x = y = a = b = c = d = 0;
......@@ -446,10 +480,10 @@ bitmap: for(i=0,l=-1;i<chr->len;i++)
break;
}
switch(t) {
case 0: file_contadd(chr->frags[j], SSFN_CONTOUR_COLOR, a,0, 0,0, 0,0); break;
case 1: file_contadd(chr->frags[j], SSFN_CONTOUR_LINE, ox+x, oy+y, 0,0, 0,0); break;
case 2: file_contadd(chr->frags[j], SSFN_CONTOUR_QUAD, ox+x,oy+y,ox+a,oy+b, 0,0); break;
case 3: file_contadd(chr->frags[j], SSFN_CONTOUR_CUBIC, ox+x,oy+y,ox+a,oy+b,ox+c,oy+d); break;
case 0: file_contadd(chr, chr->frags[j], SSFN_CONTOUR_COLOR, a,0, 0,0, 0,0); break;
case 1: file_contadd(chr, chr->frags[j], SSFN_CONTOUR_LINE, ox+x, oy+y, 0,0, 0,0); break;
case 2: file_contadd(chr, chr->frags[j], SSFN_CONTOUR_QUAD, ox+x,oy+y,ox+a,oy+b, 0,0); break;
case 3: file_contadd(chr, chr->frags[j], SSFN_CONTOUR_CUBIC, ox+x,oy+y,ox+a,oy+b,ox+c,oy+d); break;
}
} /* for numfrags */
}
......@@ -604,8 +638,8 @@ void file_load(char *filename)
continue;
} else {
for(ptr+=2,p=0;ptr < end && *ptr!='\n' && *ptr!='+' && p<6;ptr++) {
if(cmd=='c') {
par[p++] = cpal_add(
if(cmd=='c' || cmd=='g') {
par[p++] = *ptr=='.' ? 240 : cpal_add(
gethex((char*)ptr+2, 2), gethex((char*)ptr+4, 2),
gethex((char*)ptr+6,2), gethex((char*)ptr,2));
} else
......@@ -621,27 +655,32 @@ void file_load(char *filename)
c->frags = (int*)realloc(c->frags, (c->len)*sizeof(int));
if(!c->frags) error("file_load", ERR_MEM);
c->frags[i] = file_fragadd(SSFN_FRAG_CONTOUR);
file_contadd(c->frags[i], SSFN_CONTOUR_MOVE, par[0],par[1], 0,0, 0,0);
file_contadd(c, c->frags[i], SSFN_CONTOUR_MOVE, par[0],par[1], 0,0, 0,0);
break;
case 'l':
if(p<2) { fprintf(stderr,"Too few line arguments for U+%06X\n",j); exit(3); }
file_contadd(c->frags[i], SSFN_CONTOUR_LINE, par[0],par[1], 0,0, 0,0);
file_contadd(c, c->frags[i], SSFN_CONTOUR_LINE, par[0],par[1], 0,0, 0,0);
break;
case 'q':
if(p<4) { fprintf(stderr,"Too few quadratic curve arguments for U+%06X\n",j); exit(3); }
file_contadd(c->frags[i], SSFN_CONTOUR_QUAD, par[0],par[1], par[2],par[3], 0,0);
file_contadd(c, c->frags[i], SSFN_CONTOUR_QUAD, par[0],par[1], par[2],par[3], 0,0);
break;
case 'b':
if(p<6) { fprintf(stderr,"Too few bezier curve arguments for U+%06X\n",j); exit(3); }
file_contadd(c->frags[i], SSFN_CONTOUR_QUAD, par[0],par[1], par[2],par[3], par[4],par[5]);
file_contadd(c, c->frags[i], SSFN_CONTOUR_QUAD, par[0],par[1], par[2],par[3], par[4],par[5]);
break;
case 'c':
if(p<1) { fprintf(stderr,"Too few color arguments for U+%06X\n",j); exit(3); }
file_contadd(c->frags[i], SSFN_CONTOUR_COLOR, par[0],0, 0,0, 0,0);
file_contadd(c, c->frags[i], SSFN_CONTOUR_COLOR, par[0],par[0],par[0],par[0], 0,0);
break;
case 'g':
if(p<4) { fprintf(stderr,"Too few gradient arguments for U+%06X\n",j); exit(3); }
file_contadd(c, c->frags[i], SSFN_CONTOUR_COLOR, par[0],par[1],par[2],par[3], 0,0);
break;
}
}
......@@ -733,8 +772,8 @@ void file_load(char *filename)
n = (ptr[0] & 0x7F);
c->adv_x = ((ptr[2]&0x0F)<<8)|ptr[6];
c->adv_y = ((ptr[2]&0xF0)<<4)|ptr[7];
L = ((ptr[3]&0x0F)<<8)|ptr[8];
T = ((ptr[3]&0xF0)<<4)|ptr[9];
c->bear_l = L = ((ptr[3]&0x0F)<<8)|ptr[8];
c->bear_t = T = ((ptr[3]&0xF0)<<4)|ptr[9];
ptr += 10;
for(;n--;ptr += l) {
x = (((ptr[1] >> 4) & 3) << 8) | ptr[4];
......@@ -829,11 +868,16 @@ void file_saveasc(int idx)
/**
* Change quality of font
*/
void file_setquality(int idx, int q)
void file_setquality(int q)
{
if((q < 0 && font->quality == 0) || (q > 0 && font->quality == 6)) return;
int i, j, o, s, p, x, y;
uint8_t *data;
if((q != -1 && q != 1) || (q < 0 && font->quality == 0) || (q > 0 && font->quality == 6)) return;
modified = 1;
o = 16 << font->quality;
font->quality += q;
s = 16 << font->quality;
if(q<0) {
font->baseline >>= 1;
font->underline >>= 1;
......@@ -841,18 +885,105 @@ void file_setquality(int idx, int q)
font->baseline <<= 1;
font->underline <<= 1;
}
ui_saving(idx, 300000);
sleep(1);
for(i=0;i<numfrags;i++) {
switch(frags[i].type) {
case SSFN_FRAG_BITMAP:
data = (uint8_t*)malloc(s*s/8);
if(!data) error("file_setquality", ERR_MEM);
memset(data, 0, s*s/8);
if(q<0) {
for(y=p=0;y<s;y++)
for(x=0;x<s;x++,p++)
data[p>>3] |= ((uint8_t*)frags[i].data)[2*y*o/8+(x/4)] & (1 << ((2*x) & 7)) ? (1 << (p & 7)) : 0;
} else {
for(y=p=0;y<o;y++)
for(x=0;x<o;x++,p++)
if(((uint8_t*)frags[i].data)[p>>3] & (1 << (p & 7))) {
data[2*y*s/8+(x/4)] |= (3 << ((2*x) & 7));
data[(2*y+1)*s/8+(x/4)] |= (3 << ((2*x) & 7));
}
}
free(frags[i].data);
frags[i].data = (cont_t*)data;
break;
case SSFN_FRAG_PIXMAP:
data = (uint8_t*)malloc(s*s);
if(!data) error("file_setquality", ERR_MEM);
if(q<0) {
for(y=p=0;y<s;y++)
for(x=0;x<s;x++,p++) {
data[p] = ((uint8_t*)frags[i].data)[2*y*o+2*x];
}
} else {
for(y=p=0;y<o;y++)
for(x=0;x<o;x++,p++) {
data[2*y*s+2*x] = data[2*y*s+2*x+1] = data[(2*y+1)*s+2*x] = data[(2*y+1)*s+2*x+1] =
((uint8_t*)frags[i].data)[p];
}
}
free(frags[i].data);
frags[i].data = (cont_t*)data;
break;
case SSFN_FRAG_CONTOUR:
for(j=0;j<frags[i].len;j++) {
if(frags[i].data[j].type == SSFN_CONTOUR_COLOR) continue;
if(q<0) {
frags[i].data[j].px >>= 1;
frags[i].data[j].py >>= 1;
frags[i].data[j].c1x >>= 1;
frags[i].data[j].c1y >>= 1;
frags[i].data[j].c2x >>= 1;
frags[i].data[j].c2y >>= 1;
} else {
frags[i].data[j].px <<= 1;
frags[i].data[j].py <<= 1;
frags[i].data[j].c1x <<= 1;
frags[i].data[j].c1y <<= 1;
frags[i].data[j].c2x <<= 1;
frags[i].data[j].c2y <<= 1;
}
}
break;
}
}
for(j=0;j<SSFN_NUMVARIANTS;j++)
for(i=0;i<numchars[j];i++)
if(q<0) {
chars[j][i].bear_l >>= 1;
chars[j][i].bear_t >>= 1;
chars[j][i].w >>= 1;
chars[j][i].h >>= 1;
chars[j][i].adv_x >>= 1;
chars[j][i].adv_y >>= 1;
} else {
chars[j][i].bear_l <<= 1;
chars[j][i].bear_t <<= 1;
chars[j][i].w <<= 1;
chars[j][i].h <<= 1;
chars[j][i].adv_x <<= 1;
chars[j][i].adv_y <<= 1;
}
}
/**
* Autodetect baseline and bounding box
* Autodetect baseline
*/
void file_setbaseline(int idx)
void file_setbaseline()
{
modified = 1;
ui_saving(idx, 400000);
sleep(1);
int i,j,k,hs[4096], s=(16<<font->quality);
memset(hs, 0, sizeof(hs));
for(j=0;j<SSFN_NUMVARIANTS;j++)
for(i=0;i<numchars[j];i++)
hs[chars[j][i].h]++;
for(i=j=k=0;i<s;i++)
if(hs[i] > k) { k = hs[i]; j = i + 1; }
if(j < s && font->baseline != j) {
modified = 1;
font->underline += j-font->baseline;
font->baseline = j;
if(font->underline < font->baseline) font->underline = font->baseline;
}
}
/**
......
......@@ -42,6 +42,7 @@ typedef struct {
typedef struct {
uint32_t unicode;
int rtl;
int w;
int h;
int adv_x;
......@@ -70,10 +71,10 @@ void file_delchar(int v, int chr);
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_contadd(char_t *chr, 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);
void file_setquality(int idx, int q);
void file_setbaseline(int idx);
void file_setquality(int q);
void file_setbaseline();
void file_free();
......@@ -147,10 +147,9 @@ redraw:
ssfn_x = (win->w >> 1); ssfn_y = 44;
ui_scale(win, lang[LOCAL0 + win->v], (win->w >> 2)-32, glyphactive==0);
ssfn_x = (win->w >> 1) + 2 + (win->w >> 2) + (win->w & 1); ssfn_y = 44;
i = ui_textwidth(lang[SEARCH], 256);
w = ((win->w >> 1)-16-i-(win->w >> 2));
w = ((win->w >> 1)-16-8-(win->w >> 2));
ui_input(win, gsearch, w, 1, 0);
ui_button(win, lang[SEARCH], i, 2, glyphactive==1);
ui_button(win, "⚲", 8, 2, glyphactive==1);
ssfn_x = (win->w >> 1) + 2 + (win->w >> 2) + (win->w & 1); ssfn_y = 44;
if((i=ui_input(win, gsearch, w, 5, glyphactive==1 && glyphreent==1))) {
glyphactive += i;
......
......@@ -65,4 +65,6 @@ void view_help(ui_win_t *win)
ssfn_fg = theme[THEME_FG];
help_text(win, lang[ui_getwin(win->winid) ? HELP_GLYPHWIN : HELP_MAINWIN]);
help_text(win, lang[HELP_PROPS + t]);
if(t == 3)
help_text(win, lang[win->menu < 2 ? HELP_ADV : win->menu == 2 ? HELP_HINT : HELP_MODIFY]);
}
......@@ -42,7 +42,8 @@ extern int minx, miny, maxx, maxy, movex, movey;
*/
void hist_undo(ui_win_t *win)
{
int i;
int i,j,k;
frag_t *f;
char_t *chr = &chars[win->v][win->chr];
hist_t *his;
......@@ -50,18 +51,33 @@ void hist_undo(ui_win_t *win)
win->histmin--;
his = &win->hist[win->histmin];
switch(his->type) {
case HIST_DELLAYER: win->frag = file_addemptyfrag(chr, -1, his->frag); break;
case HIST_DELLAYER: win->frag = file_addemptyfrag(chr, -1, his->frag); win->tab = 0; win->menu = 5; 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;
win->tab = 0; win->menu = 5;
break;
case HIST_SETPIXEL: ((uint8_t*)frags[his->frag].data)[his->idx] = his->data.pixel.oldpix;
win->tab = 0; win->menu = 5; break;
case HIST_SETADV: chr->adv_x = his->data.adv.oldx; chr->adv_y = his->data.adv.oldy;
win->tab = 0; win->menu = chr-><