Tear apart the text window, mostly to beautify things. The

foreground and background colours are now specified separately, and
it's possible to insert half-line spaces. So now I have a window
that lets me show/hide groups, and select the active one.

[git-p4: depot-paths = "//depot/solvespace/": change = 1695]
This commit is contained in:
Jonathan Westhues 2008-04-27 23:18:39 -08:00
parent 01cff278bd
commit 598d456d8d
8 changed files with 185 additions and 121 deletions

View File

@ -2,7 +2,7 @@
char *Constraint::DescriptionString(void) {
static char ret[1024];
sprintf(ret, "c%04x", h.v);
sprintf(ret, "c%03x", h.v);
return ret;
}

View File

@ -27,6 +27,10 @@ void Constraint::LineDrawOrGetDistance(Vector a, Vector b) {
void Constraint::DrawOrGetDistance(Vector *labelPos) {
if(!SS.GW.showConstraints) return;
Group *g = SS.GetGroup(group);
// If the group is hidden, then the constraints are hidden and not
// able to be selected.
if(!(g->visible)) return;
// Unit vectors that describe our current view of the scene.
Vector gr = SS.GW.projRight;

View File

@ -300,6 +300,11 @@ double Entity::GetDistance(Point2d mp) {
}
void Entity::DrawOrGetDistance(int order) {
Group *g = SS.GetGroup(group);
// If an entity is invisible, then it doesn't get shown, and it doesn't
// contribute a distance for the selection, but it still generates edges.
if(!(g->visible) && !dogd.edges) return;
glxColor3d(1, 1, 1);
switch(type) {

View File

@ -226,7 +226,6 @@ void GraphicsWindow::EnsureValidActives(void) {
activeWorkplane = Entity::FREE_IN_3D;
change = true;
}
if(change) SS.TW.Show();
bool in3d = (activeWorkplane.v == Entity::FREE_IN_3D.v);
CheckMenuById(MNU_FREE_IN_3D, in3d);

View File

@ -45,9 +45,9 @@ void Group::MenuGroup(int id) {
char *Group::DescriptionString(void) {
static char ret[100];
if(name.str[0]) {
sprintf(ret, "g%04x-%s", h.v, name.str);
sprintf(ret, "g%03x-%s", h.v, name.str);
} else {
sprintf(ret, "g%04x-(unnamed)", h.v);
sprintf(ret, "g%03x-(unnamed)", h.v);
}
return ret;
}
@ -135,6 +135,8 @@ void Group::CopyEntity(hEntity in, int a, hParam dx, hParam dy, hParam dz) {
}
void Group::Draw(void) {
if(!visible) return;
edges.l.Clear();
int i;
for(i = 0; i < SS.entity.n; i++) {

View File

@ -1,19 +1,22 @@
#include "solvespace.h"
#include <stdarg.h>
#define COLOR_BG_HEADER RGB(50, 20, 50)
const TextWindow::Color TextWindow::colors[] = {
{ 'd', RGB(255, 255, 255), COLOR_BG_DEFAULT, }, // default
{ 'l', RGB(100, 100, 255), COLOR_BG_DEFAULT, }, // link
// These are for the header
{ 'D', RGB(255, 255, 255), COLOR_BG_HEADER, }, // default
{ 'H', RGB(170, 0, 0), COLOR_BG_HEADER, }, // hidden
{ 'S', RGB( 40, 255, 40), COLOR_BG_HEADER, }, // shown
{ 'M', RGB(200, 200, 0), COLOR_BG_HEADER, }, // mixed h/s
{ 'T', RGB(255, 200, 40), COLOR_BG_HEADER, }, // title
{ 0, 0, 0 },
const TextWindow::Color TextWindow::fgColors[] = {
{ 'd', RGB(255, 255, 255) },
{ 'l', RGB(100, 100, 255) },
{ 't', RGB(255, 200, 0) },
{ 'h', RGB(170, 0, 0) },
{ 's', RGB( 40, 255, 40) },
{ 'm', RGB(200, 200, 0) },
{ 'r', RGB( 0, 0, 0) },
{ 0, 0 },
};
const TextWindow::Color TextWindow::bgColors[] = {
{ 'd', RGB( 0, 0, 0) },
{ 't', RGB( 30, 10, 30) },
{ 'a', RGB( 25, 25, 25) },
{ 'r', RGB(255, 255, 255) },
{ 0, 0 },
};
void TextWindow::Init(void) {
@ -28,14 +31,16 @@ void TextWindow::ClearScreen(void) {
for(i = 0; i < MAX_ROWS; i++) {
for(j = 0; j < MAX_COLS; j++) {
text[i][j] = ' ';
meta[i][j].color = 'd';
meta[i][j].fg = 'd';
meta[i][j].bg = 'd';
meta[i][j].link = NOT_A_LINK;
}
top[i] = i*2;
}
rows = 0;
}
void TextWindow::Printf(char *fmt, ...) {
void TextWindow::Printf(bool halfLine, char *fmt, ...) {
va_list vl;
va_start(vl, fmt);
@ -43,6 +48,7 @@ void TextWindow::Printf(char *fmt, ...) {
int r, c;
r = rows;
top[r] = (r == 0) ? 0 : (top[r-1] + (halfLine ? 3 : 2));
rows++;
for(c = 0; c < MAX_COLS; c++) {
@ -50,7 +56,7 @@ void TextWindow::Printf(char *fmt, ...) {
meta[r][c].link = NOT_A_LINK;
}
int color = 'd';
int fg = 'd', bg = 'd';
int link = NOT_A_LINK;
DWORD data = 0;
LinkFunction *f = NULL;
@ -80,23 +86,31 @@ void TextWindow::Printf(char *fmt, ...) {
break;
}
case 'E':
color = 'd';
fg = 'd';
// leave the background, though
link = NOT_A_LINK;
data = 0;
f = NULL;
break;
case 'C':
case 'F':
case 'B': {
int color;
if(fmt[1] == '\0') goto done;
fmt++;
if(*fmt == 'p') {
if(fmt[1] == 'p') {
color = va_arg(vl, int);
} else {
color = *fmt;
color = fmt[1];
}
if(color < 0 || color > 255) color = 0;
if(*fmt == 'F') {
fg = color;
} else {
bg = color;
}
fmt++;
break;
}
case 'L':
if(fmt[1] == '\0') goto done;
fmt++;
@ -123,7 +137,8 @@ void TextWindow::Printf(char *fmt, ...) {
for(unsigned i = 0; i < strlen(buf); i++) {
if(c >= MAX_COLS) goto done;
text[r][c] = buf[i];
meta[r][c].color = color;
meta[r][c].fg = fg;
meta[r][c].bg = bg;
meta[r][c].link = link;
meta[r][c].data = data;
meta[r][c].f = f;
@ -133,7 +148,8 @@ void TextWindow::Printf(char *fmt, ...) {
fmt++;
}
while(c < MAX_COLS) {
meta[r][c].color = color;
meta[r][c].fg = fg;
meta[r][c].bg = bg;
c++;
}
@ -149,8 +165,8 @@ void TextWindow::Show(void) {
if(SS.GW.pendingDescription) {
// A pending operation (that must be completed with the mouse in
// the graphics window) will preempt our usual display.
Printf("");
Printf("%s", SS.GW.pendingDescription);
Printf(false, "");
Printf(false, "%s", SS.GW.pendingDescription);
} else {
switch(shown->screen) {
default:
@ -201,7 +217,7 @@ void TextWindow::ShowHeader(void) {
SS.GW.EnsureValidActives();
if(SS.GW.pendingDescription) {
Printf(" %CT group:%s",
Printf(false, " %Bt%Ft group:%s",
SS.group.FindById(SS.GW.activeGroup)->DescriptionString());
} else {
// Navigation buttons
@ -211,35 +227,35 @@ void TextWindow::ShowHeader(void) {
} else {
cd = SS.GetEntity(SS.GW.activeWorkplane)->DescriptionString();
}
Printf(" %Lb%f<<%E %Lh%fhome%E %CT workplane:%CD %s",
(&TextWindow::ScreenNavigation),
(&TextWindow::ScreenNavigation),
cd);
Printf(false, " %Lb%f<<%E %Lh%fhome%E %Bt%Ft workplane:%Fd %s",
(&TextWindow::ScreenNavigation),
(&TextWindow::ScreenNavigation),
cd);
}
int datumColor;
if(SS.GW.showWorkplanes && SS.GW.showAxes && SS.GW.showPoints) {
datumColor = 'S'; // shown
datumColor = 's'; // shown
} else if(!(SS.GW.showWorkplanes || SS.GW.showAxes || SS.GW.showPoints)) {
datumColor = 'H'; // hidden
datumColor = 'h'; // hidden
} else {
datumColor = 'M'; // mixed
datumColor = 'm'; // mixed
}
#define hs(b) ((b) ? 'S' : 'H')
Printf("%CTshow: "
"%Cp%Ll%D%fworkplanes%E%CT "
"%Cp%Ll%D%faxes%E%CT "
"%Cp%Ll%D%fpoints%E%CT "
"%Cp%Ll%fany-datum%E%CT",
#define hs(b) ((b) ? 's' : 'h')
Printf(false, "%Bt%Ftshow: "
"%Fp%Ll%D%fworkplanes%E "
"%Fp%Ll%D%fvectors%E "
"%Fp%Ll%D%fpoints%E "
"%Fp%Ll%fany-datum%E",
hs(SS.GW.showWorkplanes), (DWORD)&(SS.GW.showWorkplanes), &(SS.GW.ToggleBool),
hs(SS.GW.showAxes), (DWORD)&(SS.GW.showAxes), &(SS.GW.ToggleBool),
hs(SS.GW.showPoints), (DWORD)&(SS.GW.showPoints), &(SS.GW.ToggleBool),
datumColor, &(SS.GW.ToggleAnyDatumShown)
);
Printf("%CT "
"%Cp%Ll%D%fall-groups%E%CT "
"%Cp%Ll%D%fconstraints%E%CT",
Printf(false, "%Bt%Ft "
"%Fp%Ll%D%fall-groups%E "
"%Fp%Ll%D%fconstraints%E",
hs(SS.GW.showAllGroups), (DWORD)(&SS.GW.showAllGroups), &(SS.GW.ToggleBool),
hs(SS.GW.showConstraints), (DWORD)(&SS.GW.showConstraints), &(SS.GW.ToggleBool)
);
@ -253,14 +269,48 @@ void TextWindow::ScreenSelectGroup(int link, DWORD v) {
SS.TW.Show();
}
void TextWindow::ScreenToggleGroupShown(int link, DWORD v) {
hGroup hg = { v };
Group *g = SS.GetGroup(hg);
g->visible = !(g->visible);
InvalidateGraphics();
SS.TW.Show();
}
void TextWindow::ScreenActivateGroup(int link, DWORD v) {
hGroup hg = { v };
Group *g = SS.GetGroup(hg);
g->visible = true;
SS.GW.activeGroup.v = v;
InvalidateGraphics();
SS.TW.Show();
}
void TextWindow::ShowListOfGroups(void) {
Printf("%Cd[[all groups in sketch follow]]%E");
Printf(true, "%Ftactive show group-name%E");
int i;
for(i = 0; i < SS.group.n; i++) {
char *s;
Group *g = &(SS.group.elem[i]);
s = g->DescriptionString();
Printf(" %Cl%Ll%D%f%s%E",
char *s = g->DescriptionString();
bool active = (g->h.v == SS.GW.activeGroup.v);
bool shown = g->visible;
bool ref = (g->h.v == Group::HGROUP_REFERENCES.v);
Printf(false, "%Bp%Fd "
"%Fp%D%f%s%Ll%s%E%s "
"%Fp%D%f%Ll%s%E%s "
"%Fl%Ll%D%f%s",
// Alternate between light and dark backgrounds, for readability
(i & 1) ? 'd' : 'a',
// Link that activates the group
active ? 's' : 'h', g->h.v, (&TextWindow::ScreenActivateGroup),
active ? "yes" : (ref ? " " : ""),
active ? "" : (ref ? "" : "no"),
active ? "" : " ",
// Link that hides or shows the group
shown ? 's' : 'h', g->h.v, (&TextWindow::ScreenToggleGroupShown),
shown ? "yes" : "no",
shown ? "" : " ",
// Link to a screen that gives more details on the group
g->h.v, (&TextWindow::ScreenSelectGroup), s);
}
}
@ -274,10 +324,6 @@ void TextWindow::ScreenSelectConstraint(int link, DWORD v) {
SS.TW.Show();
}
void TextWindow::ScreenActivateGroup(int link, DWORD v) {
SS.GW.activeGroup.v = v;
SS.TW.Show();
}
void TextWindow::ScreenSelectRequest(int link, DWORD v) {
SS.TW.OneScreenForward();
@ -288,40 +334,45 @@ void TextWindow::ScreenSelectRequest(int link, DWORD v) {
}
void TextWindow::ShowGroupInfo(void) {
Group *g = SS.group.FindById(shown->group);
Printf("%Cd[[group %s]]", g->DescriptionString());
char *s;
if(SS.GW.activeGroup.v == shown->group.v) {
Printf("%Cd[[this is the active group]]");
s = "active ";
} else if(shown->group.v == Group::HGROUP_REFERENCES.v) {
Printf("%Cd[[this group contains the references]]");
s = "special ";
} else {
Printf("%Cd[[not active; %Cl%Ll%D%factivate group%E%Cd]]",
g->h.v, (&TextWindow::ScreenActivateGroup));
s = "";
}
Printf("%Cd[[requests in group]]%E");
Printf(true, "%Ft%sgroup %E%s", s, g->DescriptionString());
Printf(true, "%Ftrequests in group");
int i;
int i, a = 0;
for(i = 0; i < SS.request.n; i++) {
Request *r = &(SS.request.elem[i]);
if(r->group.v == shown->group.v) {
char *s = r->DescriptionString();
Printf(" %Cl%Ll%D%f%s%E",
Printf(false, "%Bp %Fl%Ll%D%f%s%E",
(a & 1) ? 'd' : 'a',
r->h.v, (&TextWindow::ScreenSelectRequest), s);
a++;
}
}
if(SS.request.n == 0) Printf(" (none)");
if(a == 0) Printf(false, "%Ba (none)");
Printf("");
Printf("[[constraints in group]]");
a = 0;
Printf(true, "%Ftconstraints in group");
for(i = 0; i < SS.constraint.n; i++) {
Constraint *c = &(SS.constraint.elem[i]);
if(c->group.v == shown->group.v) {
char *s = c->DescriptionString();
Printf(" %Cl%Ll%D%f%s%E",
Printf(false, "%Bp %Fl%Ll%D%f%s%E",
(a & 1) ? 'd' : 'a',
c->h.v, (&TextWindow::ScreenSelectConstraint), s);
a++;
}
}
if(a == 0) Printf(false, "%Ba (none)");
}
void TextWindow::ShowRequestInfo(void) {
@ -334,13 +385,13 @@ void TextWindow::ShowRequestInfo(void) {
case Request::LINE_SEGMENT: s = "line segment"; break;
default: oops();
}
Printf("%Cd[[request for %s]]%E", s);
Printf(false, "[[request for %s]]", s);
}
void TextWindow::ShowConstraintInfo(void) {
Constraint *c = SS.GetConstraint(shown->constraint);
Printf("[[constraint]]");
Printf(false, "[[constraint]]");
}

21
ui.h
View File

@ -10,33 +10,30 @@ public:
#ifndef RGB
#define RGB(r, g, b) ((r) | ((g) << 8) | ((b) << 16))
#endif
static const int COLOR_BG_DEFAULT = RGB( 15, 15, 0);
typedef struct {
char c;
int fg;
int bg;
int color;
} Color;
static const Color colors[];
static const Color fgColors[];
static const Color bgColors[];
// The rest of the window, text displayed in response to typed commands;
// some of this might do something if you click on it.
static const int NOT_A_LINK = 0;
BYTE text[MAX_ROWS][MAX_COLS];
typedef void LinkFunction(int link, DWORD v);
static const int NOT_A_LINK = 0;
struct {
int color;
char fg;
char bg;
int link;
DWORD data;
LinkFunction *f;
} meta[MAX_ROWS][MAX_COLS];
int top[MAX_ROWS]; // in half-line units, or -1 for unused
int rows;
void Init(void);
void Printf(char *fmt, ...);
void Printf(bool half, char *fmt, ...);
void ClearScreen(void);
void Show(void);
@ -71,6 +68,8 @@ public:
void OneScreenForward(void);
static void ScreenSelectGroup(int link, DWORD v);
static void ScreenActivateGroup(int link, DWORD v);
static void ScreenToggleGroupShown(int link, DWORD v);
static void ScreenSelectRequest(int link, DWORD v);
static void ScreenSelectConstraint(int link, DWORD v);
static void ScreenNavigation(int link, DWORD v);

View File

@ -13,19 +13,15 @@
#include "freeze.h"
#define MIN_COLS 45
#define TEXT_HEIGHT 18
#define TEXT_HEIGHT 20
#define TEXT_WIDTH 9
// There's a half-line offset between the header and the rest of the window
#define OFFSET_LINE 3
#define OFFSET_HEIGHT 9
HINSTANCE Instance;
HWND TextWnd;
HWND TextWndScrollBar;
int TextWndScrollPos;
int TextWndRows;
int TextWndScrollPos; // The scrollbar position, in half-row units
int TextWndHalfRows; // The height of our window, in half-row units
HWND GraphicsWnd;
HWND GraphicsEditControl;
@ -95,14 +91,18 @@ static void PaintTextWnd(HDC hdc)
static HBRUSH FillBrush;
if(!MadeBrushes) {
// Generate the color table.
for(i = 0; SS.TW.colors[i].c != 0; i++) {
int c = SS.TW.colors[i].c;
for(i = 0; SS.TW.fgColors[i].c != 0; i++) {
int c = SS.TW.fgColors[i].c;
if(c < 0 || c > 255) oops();
BgColor[c] = SS.TW.colors[i].bg;
FgColor[c] = SS.TW.colors[i].fg;
FgColor[c] = SS.TW.fgColors[i].color;
}
for(i = 0; SS.TW.bgColors[i].c != 0; i++) {
int c = SS.TW.bgColors[i].c;
if(c < 0 || c > 255) oops();
BgColor[c] = SS.TW.bgColors[i].color;
BgBrush[c] = CreateSolidBrush(BgColor[c]);
}
FillBrush = CreateSolidBrush(SS.TW.COLOR_BG_DEFAULT);
FillBrush = CreateSolidBrush(RGB(0, 0, 0));
MadeBrushes = TRUE;
}
@ -118,12 +118,13 @@ static void PaintTextWnd(HDC hdc)
FillRect(backDc, &rect, FillBrush);
SelectObject(backDc, FixedFont);
SetBkColor(backDc, SS.TW.COLOR_BG_DEFAULT);
SetBkColor(backDc, RGB(0, 0, 0));
int rows = height / TEXT_HEIGHT;
TextWndRows = rows;
int halfRows = height / (TEXT_HEIGHT/2);
TextWndHalfRows = halfRows;
TextWndScrollPos = min(TextWndScrollPos, SS.TW.rows - rows);
int bottom = SS.TW.top[SS.TW.rows-1] + 2;
TextWndScrollPos = min(TextWndScrollPos, bottom - halfRows);
TextWndScrollPos = max(TextWndScrollPos, 0);
// Let's set up the scroll bar first
@ -132,20 +133,22 @@ static void PaintTextWnd(HDC hdc)
si.cbSize = sizeof(si);
si.fMask = SIF_DISABLENOSCROLL | SIF_ALL;
si.nMin = 0;
si.nMax = SS.TW.rows - 1;
si.nMax = SS.TW.top[SS.TW.rows - 1] + 1;
si.nPos = TextWndScrollPos;
si.nPage = rows;
si.nPage = halfRows;
SetScrollInfo(TextWndScrollBar, SB_CTL, &si, TRUE);
int r, c;
for(r = TextWndScrollPos; r < (TextWndScrollPos+rows); r++) {
if(r < 0) continue;
if(r >= SS.TW.MAX_ROWS) continue;
for(r = 0; r < SS.TW.rows; r++) {
int top = SS.TW.top[r];
if(top < (TextWndScrollPos-1)) continue;
if(top > TextWndScrollPos+halfRows) break;
for(c = 0; c < min((width/TEXT_WIDTH)+1, SS.TW.MAX_COLS); c++) {
int color = SS.TW.meta[r][c].color;
SetTextColor(backDc, FgColor[color]);
SetBkColor(backDc, BgColor[color]);
int fg = SS.TW.meta[r][c].fg;
int bg = SS.TW.meta[r][c].bg;
SetTextColor(backDc, FgColor[fg]);
SetBkColor(backDc, BgColor[bg]);
if(SS.TW.meta[r][c].link) {
SelectObject(backDc, LinkFont);
@ -154,15 +157,14 @@ static void PaintTextWnd(HDC hdc)
}
int x = 4 + c*TEXT_WIDTH;
int y = (r-TextWndScrollPos)*TEXT_HEIGHT + 1 +
(r >= OFFSET_LINE ? OFFSET_HEIGHT : 0);
int y = (top-TextWndScrollPos)*(TEXT_HEIGHT/2);
RECT a;
a.left = x; a.right = x+TEXT_WIDTH;
a.top = y; a.bottom = y+TEXT_HEIGHT;
FillRect(backDc, &a, BgBrush[color]);
FillRect(backDc, &a, BgBrush[bg]);
TextOut(backDc, x, y, (char *)&(SS.TW.text[r][c]), 1);
TextOut(backDc, x, y+2, (char *)&(SS.TW.text[r][c]), 1);
}
}
@ -189,8 +191,9 @@ void HandleTextWindowScrollBar(WPARAM wParam, LPARAM lParam)
case SB_THUMBTRACK:
case SB_THUMBPOSITION: TextWndScrollPos = HIWORD(wParam); break;
}
TextWndScrollPos = max(0, TextWndScrollPos);
TextWndScrollPos = min(SS.TW.rows - TextWndRows, TextWndScrollPos);
int bottom = SS.TW.top[SS.TW.rows-1] + 2;
TextWndScrollPos = min(TextWndScrollPos, bottom - TextWndHalfRows);
TextWndScrollPos = max(TextWndScrollPos, 0);
if(prevPos != TextWndScrollPos) {
SCROLLINFO si;
si.cbSize = sizeof(si);
@ -224,8 +227,7 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_SIZING: {
RECT *r = (RECT *)lParam;
int hc = (r->bottom - r->top) - ClientIsSmallerBy;
hc += TEXT_HEIGHT/2;
int extra = hc % TEXT_HEIGHT;
int extra = hc % (TEXT_HEIGHT/2);
switch(wParam) {
case WMSZ_BOTTOM:
case WMSZ_BOTTOMLEFT:
@ -263,18 +265,20 @@ LRESULT CALLBACK TextWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
int x = LOWORD(lParam);
int y = HIWORD(lParam);
if(y >= TEXT_HEIGHT*OFFSET_LINE) {
y -= OFFSET_HEIGHT;
}
// Find the corresponding character in the text buffer
int r = (y / TEXT_HEIGHT);
int c = (x / TEXT_WIDTH);
if(msg == WM_MOUSEMOVE && r >= TextWndRows) {
int hh = (TEXT_HEIGHT)/2;
y += TextWndScrollPos*hh;
int r;
for(r = 0; r < SS.TW.rows; r++) {
if(y >= SS.TW.top[r]*hh && y <= (SS.TW.top[r]+2)*hh) {
break;
}
}
if(r >= SS.TW.rows) {
SetCursor(LoadCursor(NULL, IDC_ARROW));
break;
}
r += TextWndScrollPos;
if(msg == WM_MOUSEMOVE) {
if(SS.TW.meta[r][c].link) {
@ -728,10 +732,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
InitCommonControls();
// A monospaced font
FixedFont = CreateFont(TEXT_HEIGHT-2, TEXT_WIDTH, 0, 0, FW_REGULAR, FALSE,
FixedFont = CreateFont(TEXT_HEIGHT-4, TEXT_WIDTH, 0, 0, FW_REGULAR, FALSE,
FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, FF_DONTCARE, "Lucida Console");
LinkFont = CreateFont(TEXT_HEIGHT-2, TEXT_WIDTH, 0, 0, FW_REGULAR, FALSE,
LinkFont = CreateFont(TEXT_HEIGHT-4, TEXT_WIDTH, 0, 0, FW_REGULAR, FALSE,
TRUE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, FF_DONTCARE, "Lucida Console");
if(!FixedFont)