e16/src/tclass.c

500 lines
12 KiB
C

/*
* Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
* Copyright (C) 2004-2023 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 "E.h"
#include "conf.h"
#include "emodule.h"
#include "iclass.h"
#include "list.h"
#include "tclass.h"
#include "xwin.h"
#define ENABLE_DESTROY 0 /* Broken */
static LIST_HEAD(tclass_list);
static TextClass *TextclassGetFallback(void);
static char *
TextstateFontLookup(const char *name)
{
const char *font;
if (*name == '*')
{
font = FontLookup(name + 1);
if (font)
name = font;
}
return Estrdup(name);
}
static TextState *
TextstateCreate(const char *font)
{
TextState *ts;
ts = ECALLOC(TextState, 1);
if (!ts)
return NULL;
ts->style.orientation = FONT_TO_RIGHT;
if (font)
ts->fontname = TextstateFontLookup(font);
return ts;
}
static void
TextstateDestroy(TextState *ts)
{
if (!ts)
return;
Efree(ts->fontname);
if (ts->ops)
ts->ops->Destroy(ts);
Efree(ts);
}
static TextState *
TextstateSet(TextState **tsp, const char *name)
{
TextState *ts;
ts = TextstateCreate(name);
if (*tsp)
TextstateDestroy(*tsp);
*tsp = ts;
return ts;
}
static TextClass *
TextclassCreate(const char *name)
{
TextClass *tc;
tc = ECALLOC(TextClass, 1);
if (!tc)
return NULL;
LIST_PREPEND(TextClass, &tclass_list, tc);
tc->name = Estrdup(name);
tc->justification = 512;
return tc;
}
#if ENABLE_DESTROY
static void
TextclassDestroy(TextClass *tc)
{
if (tc->ref_count > 0)
{
DialogOK("TextClass Error!", _("%u references remain"), tc->ref_count);
return;
}
Efree(tc->name);
TextStateDestroy(tc->norm.normal);
TextStateDestroy(tc->norm.hilited);
TextStateDestroy(tc->norm.clicked);
TextStateDestroy(tc->norm.disabled);
TextStateDestroy(tc->active.normal);
TextStateDestroy(tc->active.hilited);
TextStateDestroy(tc->active.clicked);
TextStateDestroy(tc->active.disabled);
TextStateDestroy(tc->sticky.normal);
TextStateDestroy(tc->sticky.hilited);
TextStateDestroy(tc->sticky.clicked);
TextStateDestroy(tc->sticky.disabled);
TextStateDestroy(tc->sticky_active.normal);
TextStateDestroy(tc->sticky_active.hilited);
TextStateDestroy(tc->sticky_active.clicked);
TextStateDestroy(tc->sticky_active.disabled);
Efree(tc);
}
#endif /* ENABLE_DESTROY */
TextClass *
TextclassAlloc(const char *name, int fallback)
{
TextClass *tc;
if (!name || !name[0])
return NULL;
tc = TextclassFind(name, fallback);
if (tc)
tc->ref_count++;
return tc;
}
void
TextclassFree(TextClass *tc)
{
if (tc)
tc->ref_count--;
}
int
TextclassGetJustification(TextClass *tc)
{
return tc->justification;
}
void
TextclassSetJustification(TextClass *tc, int just)
{
tc->justification = just;
}
#define TSTATE_SET_STATE(which, fallback) \
if (!tc->which) tc->which = tc->fallback;
static void
TextclassPopulate(TextClass *tc)
{
if (!tc || !tc->norm.normal)
return;
TSTATE_SET_STATE(norm.hilited, norm.normal);
TSTATE_SET_STATE(norm.clicked, norm.normal);
TSTATE_SET_STATE(norm.disabled, norm.normal);
TSTATE_SET_STATE(active.normal, norm.normal);
TSTATE_SET_STATE(active.hilited, active.normal);
TSTATE_SET_STATE(active.clicked, active.normal);
TSTATE_SET_STATE(active.disabled, active.normal);
TSTATE_SET_STATE(sticky.normal, norm.normal);
TSTATE_SET_STATE(sticky.hilited, sticky.normal);
TSTATE_SET_STATE(sticky.clicked, sticky.normal);
TSTATE_SET_STATE(sticky.disabled, sticky.normal);
TSTATE_SET_STATE(sticky_active.normal, norm.normal);
TSTATE_SET_STATE(sticky_active.hilited, sticky_active.normal);
TSTATE_SET_STATE(sticky_active.clicked, sticky_active.normal);
TSTATE_SET_STATE(sticky_active.disabled, sticky_active.normal);
}
static int
_TextclassMatchName(const void *data, const void *match)
{
return strcmp(((const TextClass *)data)->name, (const char *)match);
}
TextClass *
TextclassFind(const char *name, int fallback)
{
TextClass *tc = NULL;
if (name)
tc = LIST_FIND(TextClass, &tclass_list, _TextclassMatchName, name);
if (tc || !fallback)
return tc;
#if 0
Eprintf("%s: Get fallback (%s)\n", __func__, name);
#endif
return TextclassGetFallback();
}
int
TextclassConfigLoad(FILE *fs)
{
int err = 0;
char s[FILEPATH_LEN_MAX];
char s2[FILEPATH_LEN_MAX];
int i1, r, g, b;
TextClass *tc = NULL;
TextState *ts = NULL;
while (GetLine(s, sizeof(s), fs))
{
i1 = ConfigParseline1(s, s2, NULL, NULL);
/* tc not needed */
switch (i1)
{
case CONFIG_CLOSE:
TextclassPopulate(tc);
goto done;
case CONFIG_CLASSNAME:
if (TextclassFind(s2, 0))
{
SkipTillEnd(fs);
goto done;
}
tc = TextclassCreate(s2);
continue;
}
/* tc needed */
if (!tc)
break;
switch (i1)
{
case TEXT_JUSTIFICATION:
tc->justification = atoi(s2);
continue;
case ICLASS_NORMAL:
ts = TextstateSet(&tc->norm.normal, s2);
continue;
case ICLASS_CLICKED:
ts = TextstateSet(&tc->norm.clicked, s2);
continue;
case ICLASS_HILITED:
ts = TextstateSet(&tc->norm.hilited, s2);
continue;
case ICLASS_DISABLED:
ts = TextstateSet(&tc->norm.disabled, s2);
continue;
case ICLASS_STICKY_NORMAL:
ts = TextstateSet(&tc->sticky.normal, s2);
continue;
case ICLASS_STICKY_CLICKED:
ts = TextstateSet(&tc->sticky.clicked, s2);
continue;
case ICLASS_STICKY_HILITED:
ts = TextstateSet(&tc->sticky.hilited, s2);
continue;
case ICLASS_STICKY_DISABLED:
ts = TextstateSet(&tc->sticky.disabled, s2);
continue;
case ICLASS_ACTIVE_NORMAL:
ts = TextstateSet(&tc->active.normal, s2);
continue;
case ICLASS_ACTIVE_CLICKED:
ts = TextstateSet(&tc->active.clicked, s2);
continue;
case ICLASS_ACTIVE_HILITED:
ts = TextstateSet(&tc->active.hilited, s2);
continue;
case ICLASS_ACTIVE_DISABLED:
ts = TextstateSet(&tc->active.disabled, s2);
continue;
case ICLASS_STICKY_ACTIVE_NORMAL:
ts = TextstateSet(&tc->sticky_active.normal, s2);
continue;
case ICLASS_STICKY_ACTIVE_CLICKED:
ts = TextstateSet(&tc->sticky_active.clicked, s2);
continue;
case ICLASS_STICKY_ACTIVE_HILITED:
ts = TextstateSet(&tc->sticky_active.hilited, s2);
continue;
case ICLASS_STICKY_ACTIVE_DISABLED:
ts = TextstateSet(&tc->sticky_active.disabled, s2);
continue;
}
/* ts needed */
if (!ts)
break;
switch (i1)
{
case TEXT_ORIENTATION:
ts->style.orientation = atoi(s2);
continue;
case TEXT_EFFECT:
ts->style.effect = atoi(s2);
continue;
case TEXT_FG_COL:
r = g = b = 0;
sscanf(s, "%*s %i %i %i", &r, &g, &b);
COLOR32_FROM_RGB(ts->fg_col, r, g, b);
continue;
case TEXT_BG_COL:
r = g = b = 0;
sscanf(s, "%*s %i %i %i", &r, &g, &b);
COLOR32_FROM_RGB(ts->bg_col, r, g, b);
continue;
default:
ConfigParseError("TextClass", s);
continue;
}
}
err = -1;
done:
return err;
}
static TextClass *
TextclassGetFallback(void)
{
TextClass *tc;
tc = TextclassFind("__fb_tc", 0);
if (tc)
return tc;
/* Create fallback textclass */
tc = TextclassCreate("__fb_tc");
if (!tc)
return tc;
tc->norm.normal =
TextstateCreate("-*-helvetica-medium-r-*-*-12-*-*-*-*-*-*-*");
COLOR32_FROM_RGB(tc->norm.normal->fg_col, 0, 0, 0);
TextclassPopulate(tc);
return tc;
}
/*
* Textclass Module
*/
static void
TextclassIpc(const char *params)
{
char param1[1024];
char param2[1024];
int l;
const char *p;
TextClass *tc;
if (!params)
{
IpcPrintf("Please specify...\n");
return;
}
p = params;
l = 0;
param1[0] = param2[0] = '\0';
sscanf(p, "%1000s %1000s %n", param1, param2, &l);
p += l;
if (!strncmp(param1, "list", 2))
{
LIST_FOR_EACH(TextClass, &tclass_list, tc) IpcPrintf("%s\n", tc->name);
return;
}
if (!param1[0])
{
IpcPrintf("TextClass not specified\n");
return;
}
tc = TextclassFind(param1, 0);
if (!tc)
{
IpcPrintf("TextClass not found: %s\n", param1);
return;
}
if (!strcmp(param2, "apply"))
{
EX_Window xwin;
Win win;
char state[20];
int x, y, st;
/* 3:xwin 4:x 5:y 6:state 7-:txt */
xwin = NoXID;
x = y = 0;
state[0] = '\0';
l = 0;
sscanf(p, "%x %d %d %16s %n", &xwin, &x, &y, state, &l);
p += l;
if (!strcmp(state, "normal"))
st = STATE_NORMAL;
else if (!strcmp(state, "hilited"))
st = STATE_HILITED;
else if (!strcmp(state, "clicked"))
st = STATE_CLICKED;
else if (!strcmp(state, "disabled"))
st = STATE_DISABLED;
else
st = STATE_NORMAL;
if (l == 0)
return;
win = ECreateWinFromXwin(xwin);
if (!win)
return;
TextDraw(tc, win, NoXID, 0, 0, st, p, x, y, 99999, 99999, 0);
EDestroyWin(win);
}
else if (!strcmp(param2, "query_size"))
{
int w, h;
/* 3-:txt */
if (l == 0)
return;
w = h = 0;
TextSize(tc, 0, 0, STATE_NORMAL, p, &w, &h);
IpcPrintf("%i %i\n", w, h);
}
else if (!strcmp(param2, "query"))
{
IpcPrintf("TextClass %s found\n", tc->name);
}
else if (!strcmp(param2, "ref_count"))
{
IpcPrintf("%u references remain\n", tc->ref_count);
}
else
{
IpcPrintf("Error: unknown operation specified\n");
}
}
static const IpcItem TextclassIpcArray[] = {
{
TextclassIpc,
"textclass", "tc",
"List textclasses, apply a textclass",
NULL }
,
};
/*
* Module descriptor
*/
extern const EModule ModTextclass;
const EModule ModTextclass = {
"textclass", "tc",
NULL,
MOD_ITEMS(TextclassIpcArray),
{ 0, NULL }
};