e16/src/text.c

1005 lines
23 KiB
C

/*
* Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
* Copyright (C) 2004-2021 Kim Woelders
*
* 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 of the Software, its documentation and marketing & publicity
* materials, and acknowledgment shall be given in the documentation, materials
* and software packages that this Software was used.
*
* 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 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.
*/
#include "config.h"
#include <X11/Xlib.h>
#include "E.h"
#include "eimage.h"
#include "tclass.h"
#include "xwin.h"
static GC
_get_gc(Win win)
{
static GC gc = NULL;
static Visual *last_vis = NULL;
Visual *vis;
vis = WinGetVisual(win);
if (vis != last_vis)
{
if (gc)
EXFreeGC(gc);
gc = NULL;
last_vis = vis;
}
if (!gc)
gc = EXCreateGC(WinGetXwin(win), 0, NULL);
return gc;
}
static void
TextDrawRotTo(Win win, EX_Drawable src, EX_Drawable dst, int x, int y,
int w, int h, TextState * ts)
{
EImage *im;
int win_w;
switch (ts->style.orientation)
{
case FONT_TO_UP:
im = EImageGrabDrawable(src, 0, y, x, h, w, 0);
EImageOrientate(im, 1);
EImageRenderOnDrawable(im, win, dst, 0, 0, 0, w, h);
EImageFree(im);
break;
case FONT_TO_DOWN:
EXGetSize(src, &win_w, NULL);
im = EImageGrabDrawable(src, NoXID, win_w - y - h, x, h, w, 0);
EImageOrientate(im, 3);
EImageRenderOnDrawable(im, win, dst, 0, 0, 0, w, h);
EImageFree(im);
break;
case FONT_TO_LEFT: /* Holy carumba! That's for yoga addicts, maybe .... */
im = EImageGrabDrawable(src, NoXID, x, y, w, h, 0);
EImageOrientate(im, 2);
EImageRenderOnDrawable(im, win, dst, 0, 0, 0, w, h);
EImageFree(im);
break;
default:
break;
}
}
static void
TextDrawRotBack(Win win, EX_Drawable dst, EX_Drawable src, int x, int y,
int w, int h, TextState * ts)
{
EImage *im;
int win_w;
switch (ts->style.orientation)
{
case FONT_TO_UP:
im = EImageGrabDrawable(src, NoXID, 0, 0, w, h, 0);
EImageOrientate(im, 3);
EImageRenderOnDrawable(im, win, dst, 0, y, x, h, w);
EImageFree(im);
break;
case FONT_TO_DOWN:
EXGetSize(dst, &win_w, NULL);
im = EImageGrabDrawable(src, NoXID, 0, 0, w, h, 0);
EImageOrientate(im, 1);
EImageRenderOnDrawable(im, win, dst, 0, win_w - y - h, x, h, w);
EImageFree(im);
break;
case FONT_TO_LEFT: /* Holy carumba! That's for yoga addicts, maybe .... */
im = EImageGrabDrawable(src, NoXID, 0, 0, w, h, 0);
EImageOrientate(im, 2);
EImageRenderOnDrawable(im, win, dst, 0, x, y, w, h);
EImageFree(im);
break;
default:
break;
}
}
#if FONT_TYPE_IFT
static EImage *
TextImageGet(Win win __UNUSED__, EX_Drawable src, int x, int y, int w, int h,
TextState * ts)
{
EImage *im;
int win_w;
switch (ts->style.orientation)
{
default:
case FONT_TO_RIGHT:
im = EImageGrabDrawable(src, NoXID, x, y, w, h, 0);
break;
case FONT_TO_LEFT:
im = EImageGrabDrawable(src, NoXID, x, y, w, h, 0);
EImageOrientate(im, 2);
break;
case FONT_TO_UP:
im = EImageGrabDrawable(src, 0, y, x, h, w, 0);
EImageOrientate(im, 1);
break;
case FONT_TO_DOWN:
EXGetSize(src, &win_w, NULL);
im = EImageGrabDrawable(src, NoXID, win_w - y - h, x, h, w, 0);
EImageOrientate(im, 3);
break;
}
return im;
}
static void
TextImagePut(EImage * im, Win win, EX_Drawable dst, int x, int y,
int w, int h, TextState * ts)
{
int win_w;
switch (ts->style.orientation)
{
default:
case FONT_TO_RIGHT:
EImageRenderOnDrawable(im, win, dst, 0, x, y, w, h);
break;
case FONT_TO_LEFT:
EImageOrientate(im, 2);
EImageRenderOnDrawable(im, win, dst, 0, x, y, w, h);
break;
case FONT_TO_UP:
EImageOrientate(im, 3);
EImageRenderOnDrawable(im, win, dst, 0, y, x, h, w);
break;
case FONT_TO_DOWN:
EXGetSize(dst, &win_w, NULL);
EImageOrientate(im, 1);
EImageRenderOnDrawable(im, win, dst, 0, win_w - y - h, x, h, w);
break;
}
EImageFree(im);
}
#endif /* FONT_TYPE_IFT */
TextState *
TextclassGetTextState(TextClass * tclass, int state, int active, int sticky)
{
if (!tclass)
return NULL;
if (active)
{
if (!sticky)
{
switch (state)
{
case STATE_NORMAL:
return tclass->active.normal;
case STATE_HILITED:
return tclass->active.hilited;
case STATE_CLICKED:
return tclass->active.clicked;
case STATE_DISABLED:
return tclass->active.disabled;
default:
break;
}
}
else
{
switch (state)
{
case STATE_NORMAL:
return tclass->sticky_active.normal;
case STATE_HILITED:
return tclass->sticky_active.hilited;
case STATE_CLICKED:
return tclass->sticky_active.clicked;
case STATE_DISABLED:
return tclass->sticky_active.disabled;
default:
break;
}
}
}
else if (sticky)
{
switch (state)
{
case STATE_NORMAL:
return tclass->sticky.normal;
case STATE_HILITED:
return tclass->sticky.hilited;
case STATE_CLICKED:
return tclass->sticky.clicked;
case STATE_DISABLED:
return tclass->sticky.disabled;
default:
break;
}
}
else
{
switch (state)
{
case STATE_NORMAL:
return tclass->norm.normal;
case STATE_HILITED:
return tclass->norm.hilited;
case STATE_CLICKED:
return tclass->norm.clicked;
case STATE_DISABLED:
return tclass->norm.disabled;
default:
break;
}
}
return NULL;
}
static void
TextstateTextFit1(TextState * ts, char **ptext, int *pw, int textwidth_limit)
{
char *text = *ptext;
int hh, ascent;
char *new_line;
int nuke_count = 0, nc2;
int len;
len = strlen(text);
if (len <= 1)
return;
new_line = EMALLOC(char, len + 10);
if (!new_line)
return;
while (*pw > textwidth_limit)
{
nuke_count++;
if (nuke_count >= len - 1)
{
new_line[0] = text[0];
memcpy(new_line + 1, "...", 4);
break;
}
nc2 = (len - nuke_count) / 2;
memcpy(new_line, text, nc2);
memcpy(new_line + nc2, "...", 3);
strcpy(new_line + nc2 + 3, text + nc2 + nuke_count);
ts->ops->TextSize(ts, new_line, 0, pw, &hh, &ascent);
}
Efree(text);
*ptext = new_line;
}
#if FONT_TYPE_XFONT
static void
TextstateTextFit2(TextState * ts, char **ptext, int *pw, int textwidth_limit)
{
char *text = *ptext;
int hh, ascent;
char *new_line;
int nuke_count = 0;
int len;
len = strlen(text);
new_line = EMALLOC(char, len + 20);
if (!new_line)
return;
while (*pw > textwidth_limit)
{
nuke_count += 2;
if (nuke_count > len)
{
memcpy(new_line, text, 2);
memcpy(new_line + 2, ". . . ", 7);
break;
}
new_line[0] = 0;
strncat(new_line, text, (len - nuke_count) / 4);
strcat(new_line, ". . . ");
strcat(new_line, text + ((len - nuke_count) / 4) + nuke_count);
ts->ops->TextSize(ts, new_line, 0, pw, &hh, &ascent);
}
Efree(text);
*ptext = new_line;
}
#endif /* FONT_TYPE_XFONT */
static void
TextstateTextFitMB(TextState * ts, char **ptext, int *pw, int textwidth_limit)
{
char *text = *ptext;
int hh, ascent;
char *new_line;
int nuke_count = 0, nc2;
int len;
wchar_t *wc_line = NULL;
int wc_len;
if (EwcOpen(ts->need_utf8 || Mode.locale.utf8_int))
return;
len = strlen(text);
wc_len = EwcStrToWcs(text, len, NULL, 0);
if (wc_len <= 1)
goto done;
wc_line = EMALLOC(wchar_t, wc_len + 1);
if (!wc_line)
goto done;
if (EwcStrToWcs(text, len, wc_line, wc_len) <= 0)
goto done;
new_line = EMALLOC(char, len + 10);
if (!new_line)
goto done;
while (*pw > textwidth_limit)
{
int len_mb;
nuke_count++;
if (nuke_count >= wc_len - 1)
{
int mlen;
mlen = EwcWcsToStr(wc_line, 1, new_line, MB_CUR_MAX);
if (mlen < 0)
mlen = 1;
strcpy(new_line + mlen, "...");
break;
}
nc2 = (wc_len - nuke_count) / 2;
len_mb = EwcWcsToStr(wc_line, nc2, new_line, len + 10);
memcpy(new_line + len_mb, "...", 3);
len_mb += 3;
len_mb += EwcWcsToStr(wc_line + nc2 + nuke_count,
wc_len - nc2 - nuke_count,
new_line + len_mb, len + 10 - len_mb);
new_line[len_mb] = '\0';
ts->ops->TextSize(ts, new_line, 0, pw, &hh, &ascent);
}
Efree(text);
*ptext = new_line;
done:
Efree(wc_line);
EwcClose();
}
#if FONT_TYPE_XFS
/*
* XFontSet - XCreateFontSet
*/
extern const FontOps FontOpsXfs;
typedef struct {
XFontSet font;
int ascent;
Win win;
EX_Drawable draw;
GC gc;
} FontCtxXfs;
static int
_xfs_Load(TextState * ts, const char *name)
{
XFontSet font;
FontCtxXfs *fdc;
int i, missing_cnt, font_cnt;
char **missing_list, *def_str, **fnlr;
XFontStruct **fs;
font = XCreateFontSet(disp, name, &missing_list, &missing_cnt, &def_str);
if (missing_cnt)
XFreeStringList(missing_list);
if (!font)
return -1;
if (EDebug(EDBUG_TYPE_FONTS) >= 2)
{
Eprintf("- XBaseFontNameListOfFontSet %s\n",
XBaseFontNameListOfFontSet(font));
font_cnt = XFontsOfFontSet(font, &fs, &fnlr);
for (i = 0; i < font_cnt; i++)
Eprintf("- XFontsOfFontSet %d: %s\n", i, fnlr[i]);
}
fdc = EMALLOC(FontCtxXfs, 1);
if (!fdc)
return -1;
fdc->font = font;
ts->fdc = fdc;
fdc->ascent = 0;
font_cnt = XFontsOfFontSet(font, &fs, &fnlr);
for (i = 0; i < font_cnt; i++)
fdc->ascent = MAX(fs[i]->ascent, fdc->ascent);
ts->type = FONT_TYPE_XFS;
ts->ops = &FontOpsXfs;
return 0;
}
static void
_xfs_Unload(TextState * ts)
{
FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
XFreeFontSet(disp, fdc->font);
}
static void
_xfs_TextSize(TextState * ts, const char *text, int len,
int *width, int *height, int *ascent)
{
FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
XRectangle ret2;
if (len == 0)
len = strlen(text);
XmbTextExtents(fdc->font, text, len, NULL, &ret2);
*height = ret2.height;
*width = ret2.width;
*ascent = fdc->ascent;
}
static void
_xfs_TextDraw(TextState * ts, int x, int y, const char *text, int len)
{
FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
XmbDrawString(disp, fdc->draw, fdc->font, fdc->gc, x, y, text, len);
}
static int
_xfs_FdcInit(TextState * ts, Win win, EX_Drawable draw)
{
FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
fdc->win = win;
fdc->draw = draw;
fdc->gc = _get_gc(win);
return 0;
}
static void
_xfs_FdcSetDrawable(TextState * ts, unsigned long draw)
{
FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
fdc->draw = draw;
}
static void
_xfs_FdcSetColor(TextState * ts, unsigned int color)
{
FontCtxXfs *fdc = (FontCtxXfs *) ts->fdc;
unsigned int pixel;
pixel = EAllocColor(WinGetCmap(fdc->win), color);
XSetForeground(disp, fdc->gc, pixel);
}
const FontOps FontOpsXfs = {
_xfs_Load, _xfs_Unload, _xfs_TextSize, TextstateTextFit, _xfs_TextDraw,
_xfs_FdcInit, NULL, _xfs_FdcSetDrawable, _xfs_FdcSetColor
};
#endif /* FONT_TYPE_XFS */
#if FONT_TYPE_XFONT
/*
* XFontStruct - XLoadQueryFont
*/
extern const FontOps FontOpsXfont;
typedef struct {
XFontStruct *font;
Win win;
EX_Drawable draw;
GC gc;
} FontCtxXfont;
static int
_xfont_Load(TextState * ts, const char *name)
{
XFontStruct *font;
FontCtxXfont *fdc;
font = XLoadQueryFont(disp, name);
if (!font)
return -1;
fdc = EMALLOC(FontCtxXfont, 1);
if (!fdc)
return -1;
fdc->font = font;
ts->fdc = fdc;
ts->type = FONT_TYPE_XFONT;
ts->ops = &FontOpsXfont;
return 0;
}
static void
_xfont_Unload(TextState * ts __UNUSED__)
{
FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
XFreeFont(disp, fdc->font);
}
static void
_xfont_TextSize(TextState * ts, const char *text, int len,
int *width, int *height, int *ascent)
{
FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
if (len == 0)
len = strlen(text);
if (fdc->font->min_byte1 == 0 && fdc->font->max_byte1 == 0)
*width = XTextWidth(fdc->font, text, len);
else
*width = XTextWidth16(fdc->font, (XChar2b *) text, len / 2);
*height = fdc->font->ascent + fdc->font->descent;
*ascent = fdc->font->ascent;
}
static void
_xfont_TextDraw(TextState * ts, int x, int y, const char *text, int len)
{
FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
if (fdc->font->min_byte1 == 0 && fdc->font->max_byte1 == 0)
XDrawString(disp, fdc->draw, fdc->gc, x, y, text, len);
else
XDrawString16(disp, fdc->draw, fdc->gc, x, y, (XChar2b *) text, len);
}
static int
_xfont_FdcInit(TextState * ts, Win win, EX_Drawable draw)
{
FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
fdc->win = win;
fdc->draw = draw;
fdc->gc = _get_gc(win);
XSetFont(disp, fdc->gc, fdc->font->fid);
return 0;
}
static void
_xfont_FdcSetDrawable(TextState * ts, unsigned long draw)
{
FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
fdc->draw = draw;
}
static void
_xfont_FdcSetColor(TextState * ts, unsigned int color)
{
FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
unsigned int pixel;
pixel = EAllocColor(WinGetCmap(fdc->win), color);
XSetForeground(disp, fdc->gc, pixel);
}
static void
_xfont_TextFit(TextState * ts, char **ptext, int *pw, int textwidth_limit)
{
FontCtxXfont *fdc = (FontCtxXfont *) ts->fdc;
if (fdc->font->min_byte1 == 0 && fdc->font->max_byte1 == 0)
TextstateTextFit1(ts, ptext, pw, textwidth_limit);
else
TextstateTextFit2(ts, ptext, pw, textwidth_limit);
}
const FontOps FontOpsXfont = {
_xfont_Load, _xfont_Unload, _xfont_TextSize, _xfont_TextFit, _xfont_TextDraw,
_xfont_FdcInit, NULL, _xfont_FdcSetDrawable, _xfont_FdcSetColor
};
#endif /* FONT_TYPE_XFONT */
static void
TsTextDraw(TextState * ts, int x, int y, const char *text, int len)
{
if (ts->style.effect == 1)
{
ts->ops->FdcSetColor(ts, ts->bg_col);
ts->ops->TextDraw(ts, x + 1, y + 1, text, len);
}
else if (ts->style.effect == 2)
{
ts->ops->FdcSetColor(ts, ts->bg_col);
ts->ops->TextDraw(ts, x - 1, y, text, len);
ts->ops->TextDraw(ts, x + 1, y, text, len);
ts->ops->TextDraw(ts, x, y - 1, text, len);
ts->ops->TextDraw(ts, x, y + 1, text, len);
}
ts->ops->FdcSetColor(ts, ts->fg_col);
ts->ops->TextDraw(ts, x, y, text, len);
}
typedef struct {
const char *type;
const FontOps *ops;
#if USE_MODULES
char checked;
#endif
} FontHandler;
#if USE_MODULES
#define FONT(type, ops, opsm) { type, opsm, 0 }
#else
#define FONT(type, ops, opsm) { type, ops }
#if FONT_TYPE_IFT
extern const FontOps FontOps_ift;
#endif
#if FONT_TYPE_XFT
extern const FontOps FontOps_xft;
#endif
#if FONT_TYPE_PANGO_XFT
extern const FontOps FontOps_pango;
#endif
#endif /* USE_MODULES */
static FontHandler fhs[] = {
#if FONT_TYPE_XFONT
FONT("xfont", &FontOpsXfont, &FontOpsXfont), /* XFontStruct - XLoadQueryFont */
#endif
#if FONT_TYPE_XFS
FONT("xfs", &FontOpsXfs, &FontOpsXfs), /* XFontSet - XCreateFontSet */
#endif
#if FONT_TYPE_IFT
FONT("ift", &FontOps_ift, NULL), /* Imlib2/FreeType */
#endif
#if FONT_TYPE_XFT
FONT("xft", &FontOps_xft, NULL), /* Xft */
#endif
#if FONT_TYPE_PANGO_XFT
FONT("pango", &FontOps_pango, NULL), /* Pango-Xft */
#endif
FONT(NULL, NULL, NULL)
};
static void
TextStateLoadFont(TextState * ts)
{
const char *s, *type, *name;
char buf[1024];
FontHandler *fhp = fhs;
if (!ts->fontname)
return;
/* Quit if already done */
if (ts->type)
return;
ts->need_utf8 = Mode.locale.utf8_int;
type = NULL;
name = ts->fontname;
#if FONT_TYPE_IFT
if (strchr(ts->fontname, '/'))
{
type = "ift";
goto check;
}
#endif
#if FONT_TYPE_XFS
if (ts->fontname[0] == '-')
{
type = "xfs";
goto check;
}
#endif
s = strchr(ts->fontname, ':');
if (!s || s == ts->fontname)
goto fallback;
if (s - ts->fontname > 16)
goto fallback;
memcpy(buf, ts->fontname, s - ts->fontname);
buf[s - ts->fontname] = '\0';
type = buf;
name = s + 1;
check:
for (fhp = fhs; fhp->type; fhp++)
{
if (strcmp(fhp->type, type))
continue;
#if USE_MODULES
if (!fhp->ops)
{
if (fhp->checked)
goto fallback;
fhp->checked = 1;
fhp->ops = ModLoadSym("font", "FontOps", type);
if (!fhp->ops)
goto fallback;
}
#endif
if (fhp->ops->Load(ts, name) == 0)
goto done;
}
fallback:
#if FONT_TYPE_XFS
if (!FontOpsXfs.Load(ts, "fixed")) /* XFontSet - XCreateFontSet */
goto done;
#endif
#if FONT_TYPE_XFONT
if (!FontOpsXfont.Load(ts, "fixed")) /* XFontStruct - XLoadQueryFont */
goto done;
#endif
done:
if (!ts->ops)
Eprintf("*** Unable to load font \"%s\"\n", ts->fontname);
else if (EDebug(EDBUG_TYPE_FONTS))
Eprintf("%s: %s: type=%d\n", __func__, ts->fontname, ts->type);
return;
}
void
TextSize(TextClass * tclass, int active, int sticky, int state,
const char *text, int *width, int *height, int fsize __UNUSED__)
{
const char *str;
char **lines;
int i, num_lines, ww, hh, asc;
TextState *ts;
*width = 0;
*height = 0;
if (!text)
return;
ts = TextclassGetTextState(tclass, state, active, sticky);
if (!ts)
return;
TextStateLoadFont(ts);
if (!ts->ops)
return;
/* Do encoding conversion, if necessary */
str = EstrInt2Enc(text, ts->need_utf8);
lines = StrlistFromString(str, '\n', &num_lines);
EstrInt2EncFree(str, ts->need_utf8);
if (!lines)
return;
for (i = 0; i < num_lines; i++)
{
ts->ops->TextSize(ts, lines[i], strlen(lines[i]), &ww, &hh, &asc);
*height += hh;
if (ww > *width)
*width = ww;
}
StrlistFree(lines, num_lines);
}
__EXPORT__ void
TextstateTextFit(TextState * ts, char **ptext, int *pw, int textwidth_limit)
{
if (ts->need_utf8 || MB_CUR_MAX > 1)
TextstateTextFitMB(ts, ptext, pw, textwidth_limit);
else
TextstateTextFit1(ts, ptext, pw, textwidth_limit);
}
void
TextstateTextDraw(TextState * ts, Win win, EX_Drawable draw,
const char *text, int x, int y, int w, int h,
const EImageBorder * pad, int fsize __UNUSED__, int justh,
int justv)
{
const char *str;
char **lines;
int i, num_lines;
int textwidth_limit, textheight_limit, offset_x, offset_y;
int xx, yy, ww, hh, ascent;
EX_Pixmap drawable;
if (w <= 0 || h <= 0)
return;
TextStateLoadFont(ts);
if (!ts->ops)
return;
/* Do encoding conversion, if necessary */
str = EstrInt2Enc(text, ts->need_utf8);
lines = StrlistFromString(str, '\n', &num_lines);
EstrInt2EncFree(str, ts->need_utf8);
if (!lines)
return;
if (draw == NoXID)
draw = WinGetXwin(win);
if (ts->style.orientation == FONT_TO_RIGHT ||
ts->style.orientation == FONT_TO_LEFT)
{
if (pad)
{
x += pad->left;
w -= pad->left + pad->right;
y += pad->top;
h -= pad->top + pad->bottom;
}
textwidth_limit = w;
textheight_limit = h;
}
else
{
if (pad)
{
x += pad->left;
h -= pad->left + pad->right;
y += pad->top;
w -= pad->top + pad->bottom;
}
textwidth_limit = h;
textheight_limit = w;
}
#if 0
Eprintf("%s: %d,%d %dx%d(%dx%d): %s\n", __func__, x, y, w, h,
textwidth_limit, textheight_limit, text);
#endif
yy = y;
if (ts->ops->FdcInit(ts, win, draw))
return;
#if FONT_TYPE_IFT
if (ts->type == FONT_TYPE_IFT)
{
for (i = 0; i < num_lines; i++)
{
EImage *im;
ts->ops->TextSize(ts, lines[i], 0, &ww, &hh, &ascent);
if (ww > textwidth_limit)
ts->ops->TextFit(ts, &lines[i], &ww, textwidth_limit);
if (justv && num_lines == 1 && textheight_limit > 0)
yy += (textheight_limit - hh) / 2;
if (i == 0)
yy += ascent;
xx = x + (((textwidth_limit - ww) * justh) >> 10);
im = TextImageGet(win, draw, xx - 1, yy - 1 - ascent,
ww + 2, hh + 2, ts);
if (!im)
break;
offset_x = 1;
offset_y = ascent + 1;
ts->ops->FdcSetDrawable(ts, (unsigned long)im);
TsTextDraw(ts, offset_x, offset_y, lines[i], strlen(lines[i]));
TextImagePut(im, win, draw, xx - 1, yy - 1 - ascent,
ww + 2, hh + 2, ts);
yy += hh;
}
}
else
#endif /* FONT_TYPE_IFT */
{
for (i = 0; i < num_lines; i++)
{
ts->ops->TextSize(ts, lines[i], 0, &ww, &hh, &ascent);
if (ww > textwidth_limit)
ts->ops->TextFit(ts, &lines[i], &ww, textwidth_limit);
if (justv && num_lines == 1 && textheight_limit > 0)
yy += (textheight_limit - hh) / 2;
if (i == 0)
yy += ascent;
xx = x + (((textwidth_limit - ww) * justh) >> 10);
if (ts->style.orientation != FONT_TO_RIGHT)
drawable = ECreatePixmap(win, ww + 2, hh + 2, 0);
else
drawable = draw;
TextDrawRotTo(win, draw, drawable, xx - 1, yy - 1 - ascent,
ww + 2, hh + 2, ts);
if (ts->style.orientation == FONT_TO_RIGHT)
{
offset_x = xx;
offset_y = yy;
}
else
{
offset_x = 1;
offset_y = ascent + 1;
}
if (drawable != draw)
ts->ops->FdcSetDrawable(ts, drawable);
TsTextDraw(ts, offset_x, offset_y, lines[i], strlen(lines[i]));
TextDrawRotBack(win, draw, drawable, xx - 1, yy - 1 - ascent,
ww + 2, hh + 2, ts);
if (drawable != draw)
EFreePixmap(drawable);
yy += hh;
}
}
if (ts->ops->FdcFini)
ts->ops->FdcFini(ts);
StrlistFree(lines, num_lines);
}
void
TextDraw(TextClass * tclass, Win win, EX_Drawable draw, int active,
int sticky, int state, const char *text, int x, int y, int w, int h,
int fsize, int justh)
{
TextState *ts;
if (!tclass || !text)
return;
ts = TextclassGetTextState(tclass, state, active, sticky);
if (!ts)
return;
TextstateTextDraw(ts, win, draw, text, x, y, w, h, NULL, fsize, justh, 0);
}