Add user interface to modify styles: change the color, line width,

line width units, on-screen and export visibility. So now we can
use that to modify the default styles, or to create custom styles.

Also add code to draw fat lines, with round endcaps, since gl
doesn't do that.

Next we need some user interface to assign styles to entities, and
to make all the export file formats support the style attributes.

[git-p4: depot-paths = "//depot/solvespace/": change = 2029]
This commit is contained in:
Jonathan Westhues 2009-09-18 00:14:15 -08:00
parent ce99217bbb
commit 517c5edbfa
14 changed files with 428 additions and 33 deletions

View File

@ -1018,7 +1018,9 @@ void GraphicsWindow::Paint(int w, int h) {
glDepthFunc(GL_LEQUAL);
if(SS.AllGroupsOkay()) {
glClearColor(0, 0, 0, 1.0f);
glClearColor(REDf(SS.backgroundColor),
GREENf(SS.backgroundColor),
BLUEf(SS.backgroundColor), 1.0f);
} else {
// Draw a different background whenever we're having solve problems.
DWORD rgb = Style::Color(Style::DRAW_ERROR);

View File

@ -10,14 +10,70 @@ char *Entity::DescriptionString(void) {
}
}
void Entity::LineDrawOrGetDistance(Vector a, Vector b) {
void Entity::FatLineEndcap(Vector p, Vector u, Vector v) {
// A table of cos and sin of (pi*i/10 + pi/2), as i goes from 0 to 10
static const double Circle[11][2] = {
{ 0.0000, 1.0000 },
{ -0.3090, 0.9511 },
{ -0.5878, 0.8090 },
{ -0.8090, 0.5878 },
{ -0.9511, 0.3090 },
{ -1.0000, 0.0000 },
{ -0.9511, -0.3090 },
{ -0.8090, -0.5878 },
{ -0.5878, -0.8090 },
{ -0.3090, -0.9511 },
{ 0.0000, -1.0000 },
};
glBegin(GL_TRIANGLE_FAN);
for(int i = 0; i <= 10; i++) {
double c = Circle[i][0], s = Circle[i][1];
glxVertex3v(p.Plus(u.ScaledBy(c)).Plus(v.ScaledBy(s)));
}
glEnd();
}
void Entity::FatLine(Vector a, Vector b) {
// The half-width of the line we're drawing.
double hw = (dogd.lineWidth/SS.GW.scale) / 2;
Vector ab = b.Minus(a);
Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp);
Vector abn = (ab.Cross(gn)).WithMagnitude(1);
abn = abn.Minus(gn.ScaledBy(gn.Dot(abn)));
// So now abn is normal to the projection of ab into the screen, so the
// line will always have constant thickness as the view is rotated.
abn = abn.WithMagnitude(hw);
ab = gn.Cross(abn);
ab = ab. WithMagnitude(hw);
// The body of a line is a quad
glBegin(GL_QUADS);
glxVertex3v(a.Minus(abn));
glxVertex3v(b.Minus(abn));
glxVertex3v(b.Plus (abn));
glxVertex3v(a.Plus (abn));
glEnd();
// And the line has two semi-circular end caps.
FatLineEndcap(a, ab, abn);
FatLineEndcap(b, ab.ScaledBy(-1), abn);
}
void Entity::LineDrawOrGetDistance(Vector a, Vector b, bool maybeFat) {
if(dogd.drawing) {
// Draw lines from active group in front of those from previous
glxDepthRangeOffset((group.v == SS.GW.activeGroup.v) ? 4 : 3);
// Narrow lines are drawn as lines, but fat lines must be drawn as
// filled polygons, to get the line join style right.
if(!maybeFat || dogd.lineWidth < 3) {
glBegin(GL_LINES);
glxVertex3v(a);
glxVertex3v(b);
glEnd();
} else {
FatLine(a, b);
}
glxDepthRangeOffset(0);
} else {
Point2d ap = SS.GW.ProjectPoint(a);
@ -100,7 +156,8 @@ void Entity::DrawAll(void) {
void Entity::Draw(void) {
hStyle hs = Style::ForEntity(h);
glLineWidth(Style::Width(hs));
dogd.lineWidth = Style::Width(hs);
glLineWidth((float)dogd.lineWidth);
glxColorRGB(Style::Color(hs));
dogd.drawing = true;
@ -479,7 +536,7 @@ void Entity::DrawOrGetDistance(void) {
int i;
for(i = 0; i < sel.l.n; i++) {
SEdge *se = &(sel.l.elem[i]);
LineDrawOrGetDistance(se->a, se->b);
LineDrawOrGetDistance(se->a, se->b, true);
}
sel.Clear();
}

9
dsc.h
View File

@ -219,15 +219,18 @@ public:
int n;
int elemsAllocated;
H AddAndAssignId(T *t) {
int i;
DWORD MaximumId(void) {
DWORD id = 0;
int i;
for(i = 0; i < n; i++) {
id = max(id, elem[i].h.v);
}
return id;
}
t->h.v = (id + 1);
H AddAndAssignId(T *t) {
t->h.v = (MaximumId() + 1);
Add(t);
return t->h;

View File

@ -152,6 +152,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
{ 'c', "Constraint.disp.style", 'x', &(SS.sv.c.disp.style) },
{ 's', "Style.h.v", 'x', &(SS.sv.s.h.v) },
{ 's', "Style.name", 'N', &(SS.sv.s.name) },
{ 's', "Style.width", 'f', &(SS.sv.s.width) },
{ 's', "Style.widthHow", 'd', &(SS.sv.s.widthHow) },
{ 's', "Style.color", 'x', &(SS.sv.s.color) },

View File

@ -585,11 +585,18 @@ void GraphicsWindow::MenuEdit(int id) {
switch(id) {
case MNU_UNSELECT_ALL:
SS.GW.GroupSelection();
// If there's nothing selected to de-select, and no operation
// to cancel, then perhaps they want to return to the home
// screen in the text window.
if(SS.GW.gs.n == 0 && SS.GW.pending.operation == 0) {
if(!TextEditControlIsVisible()) {
if(SS.TW.shown.screen == TextWindow::SCREEN_STYLE_INFO) {
SS.TW.GoToScreen(TextWindow::SCREEN_LIST_OF_STYLES);
} else {
SS.TW.ClearSuper();
}
}
}
SS.GW.ClearSuper();
HideTextEditControl();
SS.nakedEdges.Clear();

View File

@ -65,6 +65,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
// Generate the entity that's specific to this request.
e.type = et;
e.group = group;
e.style = style;
e.workplane = workplane;
e.construction = construction;
e.str.strcpy(str.str);
@ -79,6 +80,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
// points start from entity 1, except for datum point case
p.h = h.entity(i+(et ? 1 : 0));
p.group = group;
p.style = style;
if(workplane.v == Entity::FREE_IN_3D.v) {
p.type = Entity::POINT_IN_3D;
@ -101,6 +103,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
n.workplane = workplane;
n.h = h.entity(32);
n.group = group;
n.style = style;
if(workplane.v == Entity::FREE_IN_3D.v) {
n.type = Entity::NORMAL_IN_3D;
n.param[0] = AddParam(param, h.param(32+0));
@ -125,6 +128,7 @@ void Request::Generate(IdList<Entity,hEntity> *entity,
d.workplane = workplane;
d.h = h.entity(64);
d.group = group;
d.style = style;
d.type = Entity::DISTANCE;
d.param[0] = AddParam(param, h.param(64));
entity->Add(&d);

View File

@ -414,8 +414,11 @@ public:
Point2d mp;
double dmin;
Vector refp;
double lineWidth;
} dogd; // state for drawing or getting distance (for hit testing)
void LineDrawOrGetDistance(Vector a, Vector b);
void FatLine(Vector a, Vector b);
void FatLineEndcap(Vector p, Vector u, Vector v);
void LineDrawOrGetDistance(Vector a, Vector b, bool maybeFat=false);
void DrawOrGetDistance(void);
bool IsVisible(void);
@ -620,12 +623,12 @@ public:
static const int DRAW_ERROR = 12;
static const int DIM_SOLID = 13;
static const int FIRST_CUSTOM = 0x1000;
static const int FIRST_CUSTOM = 0x100;
NameStr name;
static const int WIDTH_MM = 0;
static const int WIDTH_PIXELS = 1;
static const int WIDTH_AS_MM = 0;
static const int WIDTH_AS_PIXELS = 1;
double width;
int widthHow;
DWORD color;
@ -645,6 +648,8 @@ public:
static char *CnfColor(char *prefix);
static char *CnfWidth(char *prefix);
static char *CnfPrefixToName(char *prefix);
static void CreateAllDefaultStyles(void);
static void CreateDefaultStyle(hStyle h);
static void FreezeDefaultStyles(void);
static void LoadFactoryDefaults(void);
@ -655,6 +660,8 @@ public:
static DWORD Color(int hs, bool forExport=false);
static float Width(int hs);
static hStyle ForEntity(hEntity he);
char *DescriptionString(void);
};

View File

@ -74,6 +74,8 @@ void SolveSpace::Init(char *cmdLine) {
exportShadedTriangles = CnfThawDWORD(1, "ExportShadedTriangles");
// Export pwl curves (instead of exact) always
exportPwlCurves = CnfThawDWORD(0, "ExportPwlCurves");
// Background color on-screen
backgroundColor = CnfThawDWORD(RGB(0, 0, 0), "BackgroundColor");
// Whether export canvas size is fixed or derived from bbox
exportCanvasSizeAuto = CnfThawDWORD(1, "ExportCanvasSizeAuto");
// Margins for automatic canvas size
@ -156,6 +158,8 @@ void SolveSpace::Exit(void) {
CnfFreezeDWORD(exportShadedTriangles, "ExportShadedTriangles");
// Export pwl curves (instead of exact) always
CnfFreezeDWORD(exportPwlCurves, "ExportPwlCurves");
// Background color on-screen
CnfFreezeDWORD(backgroundColor, "BackgroundColor");
// Whether export canvas size is fixed or derived from bbox
CnfFreezeDWORD(exportCanvasSizeAuto, "ExportCanvasSizeAuto");
// Margins for automatic canvas size
@ -274,6 +278,10 @@ void SolveSpace::AfterNewFile(void) {
// Then zoom to fit again, to fit the triangles
GW.ZoomToFit(false);
// Create all the default styles; they'll get created on the fly anyways,
// but can't hurt to do it now.
Style::CreateAllDefaultStyles();
UpdateWindowTitle();
}

View File

@ -207,6 +207,7 @@ void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
double a41, double a42, double a43, double a44);
void MakePathRelative(char *base, char *path);
void MakePathAbsolute(char *base, char *path);
bool StringAllPrintable(char *str);
class System {
public:
@ -531,6 +532,7 @@ public:
float exportOffset;
int drawBackFaces;
int showToolbar;
DWORD backgroundColor;
int exportShadedTriangles;
int exportPwlCurves;
int exportCanvasSizeAuto;

282
style.cpp
View File

@ -1,5 +1,7 @@
#include "solvespace.h"
#define clamp01(x) (max(0, min(1, (x))))
const Style::Default Style::Defaults[] = {
{ ACTIVE_GRP, "ActiveGrp", RGBf(1.0, 1.0, 1.0), 1.5, },
{ CONSTRUCTION, "Construction", RGBf(0.1, 0.7, 0.1), 1.5, },
@ -30,7 +32,9 @@ char *Style::CnfWidth(char *prefix) {
char *Style::CnfPrefixToName(char *prefix) {
static char name[100];
int i = 0, j = 0;
int i = 0, j;
strcpy(name, "def-");
j = 4;
while(prefix[i] && j < 90) {
if(isupper(prefix[i]) && i != 0) {
name[j++] = '-';
@ -42,7 +46,15 @@ char *Style::CnfPrefixToName(char *prefix) {
return name;
}
void Style::CreateAllDefaultStyles(void) {
const Default *d;
for(d = &(Defaults[0]); d->h.v; d++) {
(void)Get(d->h);
}
}
void Style::CreateDefaultStyle(hStyle h) {
bool isDefaultStyle = true;
const Default *d;
for(d = &(Defaults[0]); d->h.v; d++) {
if(d->h.v == h.v) break;
@ -51,17 +63,22 @@ void Style::CreateDefaultStyle(hStyle h) {
// Not a default style; so just create it the same as our default
// active group entity style.
d = &(Defaults[0]);
isDefaultStyle = false;
}
Style ns;
ZERO(&ns);
ns.color = CnfThawDWORD(d->color, CnfColor(d->cnfPrefix));
ns.width = CnfThawFloat((float)(d->width), CnfWidth(d->cnfPrefix));
ns.widthHow = WIDTH_PIXELS;
ns.widthHow = WIDTH_AS_PIXELS;
ns.visible = true;
ns.exportable = true;
ns.name.strcpy(CnfPrefixToName(d->cnfPrefix));
ns.h = h;
if(isDefaultStyle) {
ns.name.strcpy(CnfPrefixToName(d->cnfPrefix));
} else {
ns.name.strcpy("new-custom-style");
}
SK.style.Add(&ns);
}
@ -73,11 +90,12 @@ void Style::LoadFactoryDefaults(void) {
s->color = d->color;
s->width = d->width;
s->widthHow = WIDTH_PIXELS;
s->widthHow = WIDTH_AS_PIXELS;
s->visible = true;
s->exportable = true;
s->name.strcpy(CnfPrefixToName(d->cnfPrefix));
}
SS.backgroundColor = RGB(0, 0, 0);
}
void Style::FreezeDefaultStyles(void) {
@ -131,9 +149,9 @@ DWORD Style::Color(hStyle h, bool forExport) {
float Style::Width(hStyle h) {
double r = 1.0;
Style *s = Get(h);
if(s->widthHow == WIDTH_MM) {
if(s->widthHow == WIDTH_AS_MM) {
r = s->width * SS.GW.scale;
} else if(s->widthHow == WIDTH_PIXELS) {
} else if(s->widthHow == WIDTH_AS_PIXELS) {
r = s->width;
}
// This returns a float because glLineWidth expects a float, avoid casts.
@ -165,3 +183,255 @@ hStyle Style::ForEntity(hEntity he) {
return hs;
}
char *Style::DescriptionString(void) {
static char ret[100];
if(name.str[0]) {
sprintf(ret, "s%03x-%s", h.v, name.str);
} else {
sprintf(ret, "s%03x-(unnamed)", h.v);
}
return ret;
}
void TextWindow::ScreenShowListOfStyles(int link, DWORD v) {
SS.TW.GoToScreen(SCREEN_LIST_OF_STYLES);
}
void TextWindow::ScreenShowStyleInfo(int link, DWORD v) {
SS.TW.GoToScreen(SCREEN_STYLE_INFO);
SS.TW.shown.style.v = v;
}
void TextWindow::ScreenLoadFactoryDefaultStyles(int link, DWORD v) {
Style::LoadFactoryDefaults();
SS.TW.GoToScreen(SCREEN_LIST_OF_STYLES);
}
void TextWindow::ScreenCreateCustomStyle(int link, DWORD v) {
SS.UndoRemember();
DWORD vs = max(Style::FIRST_CUSTOM, SK.style.MaximumId() + 1);
hStyle hs = { vs };
(void)Style::Get(hs);
}
void TextWindow::ScreenChangeBackgroundColor(int link, DWORD v) {
DWORD rgb = SS.backgroundColor;
char str[300];
sprintf(str, "%.2f, %.2f, %.2f", REDf(rgb), GREENf(rgb), BLUEf(rgb));
ShowTextEditControl(v, 3, str);
SS.TW.edit.meaning = EDIT_BACKGROUND_COLOR;
}
void TextWindow::ShowListOfStyles(void) {
Printf(true, "%Ft color style-name");
bool darkbg = false;
Style *s;
for(s = SK.style.First(); s; s = SK.style.NextAfter(s)) {
Printf(false, "%Bp %Bp %Bp %Fl%Ll%f%D%s%E",
darkbg ? 'd' : 'a',
0x80000000 | s->color,
darkbg ? 'd' : 'a',
ScreenShowStyleInfo, s->h.v,
s->DescriptionString());
darkbg = !darkbg;
}
Printf(true, " %Fl%Ll%fcreate a new custom style%E",
&ScreenCreateCustomStyle);
Printf(false, "");
DWORD rgb = SS.backgroundColor;
Printf(false, "%Ft background color (r, g, b)%E");
Printf(false, "%Ba %@, %@, %@ %Fl%D%f%Ll[change]%E",
REDf(rgb), GREENf(rgb), BLUEf(rgb),
top[rows-1] + 2, &ScreenChangeBackgroundColor);
Printf(false, "");
Printf(false, " %Fl%Ll%fload factory defaults%E",
&ScreenLoadFactoryDefaultStyles);
}
void TextWindow::ScreenChangeStyleName(int link, DWORD v) {
hStyle hs = { v };
Style *s = Style::Get(hs);
ShowTextEditControl(10, 13, s->name.str);
SS.TW.edit.style = hs;
SS.TW.edit.meaning = EDIT_STYLE_NAME;
}
void TextWindow::ScreenDeleteStyle(int link, DWORD v) {
SS.UndoRemember();
hStyle hs = { v };
Style *s = SK.style.FindByIdNoOops(hs);
if(s) {
SK.style.RemoveById(hs);
// And it will get recreated automatically if something is still using
// the style, so no need to do anything else.
}
SS.TW.GoToScreen(SCREEN_LIST_OF_STYLES);
InvalidateGraphics();
}
void TextWindow::ScreenChangeStyleWidth(int link, DWORD v) {
hStyle hs = { v };
Style *s = Style::Get(hs);
char str[300];
if(s->widthHow == Style::WIDTH_AS_PIXELS) {
sprintf(str, "%.2f", s->width);
} else {
strcpy(str, SS.MmToString(s->width));
}
ShowTextEditControl(16, 8, str);
SS.TW.edit.style = hs;
SS.TW.edit.meaning = EDIT_STYLE_WIDTH;
}
void TextWindow::ScreenChangeStyleColor(int link, DWORD v) {
hStyle hs = { v };
Style *s = Style::Get(hs);
char str[300];
sprintf(str, "%.2f, %.2f, %.2f",
REDf(s->color), GREENf(s->color), BLUEf(s->color));
ShowTextEditControl(13, 12, str);
SS.TW.edit.style = hs;
SS.TW.edit.meaning = EDIT_STYLE_COLOR;
}
void TextWindow::ScreenChangeStyleYesNo(int link, DWORD v) {
SS.UndoRemember();
hStyle hs = { v };
Style *s = Style::Get(hs);
switch(link) {
case 'w':
if(s->widthHow == Style::WIDTH_AS_PIXELS) {
s->widthHow = Style::WIDTH_AS_MM;
} else {
s->widthHow = Style::WIDTH_AS_PIXELS;
}
break;
case 'e':
s->exportable = !(s->exportable);
break;
case 'v':
s->visible = !(s->visible);
break;
}
InvalidateGraphics();
}
bool TextWindow::EditControlDoneForStyles(char *str) {
Style *s;
switch(edit.meaning) {
case EDIT_STYLE_WIDTH:
SS.UndoRemember();
s = Style::Get(edit.style);
if(s->widthHow == Style::WIDTH_AS_MM) {
s->width = SS.StringToMm(str);
} else {
s->width = atof(str);
}
s->width = max(0, s->width);
return true;
case EDIT_BACKGROUND_COLOR:
case EDIT_STYLE_COLOR: {
double r, g, b;
if(sscanf(str, "%lf, %lf, %lf", &r, &g, &b)==3) {
r = clamp01(r);
g = clamp01(g);
b = clamp01(b);
if(edit.meaning == EDIT_STYLE_COLOR) {
SS.UndoRemember();
s = Style::Get(edit.style);
s->color = RGBf(r, g, b);
} else {
SS.backgroundColor = RGBf(r, g, b);
}
} else {
Error("Bad format: specify color as r, g, b");
}
return true;
}
case EDIT_STYLE_NAME:
if(!StringAllPrintable(str) || !*str) {
Error("Invalid characters. Allowed are: A-Z a-z 0-9 _ -");
} else {
SS.UndoRemember();
s = Style::Get(edit.style);
s->name.strcpy(str);
}
return true;
default: return false;
}
}
void TextWindow::ShowStyleInfo(void) {
Printf(true, "%Fl%f%Ll(back to list of styles)%E", &ScreenShowListOfStyles);
Style *s = Style::Get(shown.style);
if(s->h.v < Style::FIRST_CUSTOM) {
Printf(true, "%FtSTYLE %E%s ", s->DescriptionString());
} else {
Printf(true, "%FtSTYLE %E%s "
"[%Fl%Ll%D%frename%E/%Fl%Ll%D%fdel%E]",
s->DescriptionString(),
s->h.v, &ScreenChangeStyleName,
s->h.v, &ScreenDeleteStyle);
}
Printf(true, "%FtCOLOR %E%Bp %Bd (%@, %@, %@) %D%f%Ll%Fl[change]%E",
0x80000000 | s->color,
REDf(s->color), GREENf(s->color), BLUEf(s->color),
s->h.v, ScreenChangeStyleColor);
if(s->widthHow == Style::WIDTH_AS_PIXELS) {
Printf(true, "%FtWIDTH %E%@ %D%f%Ll%Fl[change]%E",
s->width,
s->h.v, &ScreenChangeStyleWidth);
} else {
Printf(true, "%FtWIDTH %E%s %D%f%Ll%Fl[change]%E",
SS.MmToString(s->width),
s->h.v, &ScreenChangeStyleWidth);
}
char *unit = (SS.viewUnits == SolveSpace::UNIT_INCHES) ? "inches" : "mm";
bool widthpx = (s->widthHow == Style::WIDTH_AS_PIXELS);
if(s->h.v < Style::FIRST_CUSTOM) {
Printf(false,"%FtUNITS %Fspixels%E");
} else {
Printf(false,"%FtUNITS %Fh%D%f%Lw%s%E%Fs%s%E / %Fh%D%f%Lw%s%E%Fs%s%E",
s->h.v, &ScreenChangeStyleYesNo,
( widthpx ? "" : "pixels"),
( widthpx ? "pixels" : ""),
s->h.v, &ScreenChangeStyleYesNo,
(!widthpx ? "" : unit),
(!widthpx ? unit : ""));
}
if(s->h.v >= Style::FIRST_CUSTOM) {
Printf(true, "%FtSHOW %Fh%D%f%Lv%s%E%Fs%s%E / %Fh%D%f%Lv%s%E%Fs%s%E",
s->h.v, &ScreenChangeStyleYesNo,
( s->visible ? "" : "yes"),
( s->visible ? "yes" : ""),
s->h.v, &ScreenChangeStyleYesNo,
(!s->visible ? "" : "no"),
(!s->visible ? "no" : ""));
Printf(false,"%FtEXPORT %Fh%D%f%Le%s%E%Fs%s%E / %Fh%D%f%Le%s%E%Fs%s%E",
s->h.v, &ScreenChangeStyleYesNo,
( s->exportable ? "" : "yes"),
( s->exportable ? "yes" : ""),
s->h.v, &ScreenChangeStyleYesNo,
(!s->exportable ? "" : "no"),
(!s->exportable ? "no" : ""));
}
}

View File

@ -143,7 +143,8 @@ void TextWindow::ShowListOfGroups(void) {
Printf(true, " %Fl%Ls%fshow all%E / %Fl%Lh%fhide all%E",
&(TextWindow::ScreenShowGroupsSpecial),
&(TextWindow::ScreenShowGroupsSpecial));
Printf(false, " %Fl%Ls%fconfiguration%E",
Printf(true, " %Fl%Ls%fline styles%E / %Fl%Ls%fconfiguration%E",
&(TextWindow::ScreenShowListOfStyles),
&(TextWindow::ScreenShowConfiguration));
// Show license info
@ -915,7 +916,8 @@ void TextWindow::EditControlDone(char *s) {
// already constrained, because that would break
// convergence.
if(c == 0) {
SK.GetParam(g->h.param(3))->val = PI/(2*ev);
double copies = (g->skipFirst) ? (ev + 1) : ev;
SK.GetParam(g->h.param(3))->val = PI/(2*copies);
}
}
@ -927,14 +929,7 @@ void TextWindow::EditControlDone(char *s) {
break;
}
case EDIT_GROUP_NAME: {
char *t;
bool invalid = false;
for(t = s; *t; t++) {
if(!(isalnum(*t) || *t == '-' || *t == '_')) {
invalid = true;
}
}
if(invalid || !*s) {
if(!StringAllPrintable(s) || !*s) {
Error("Invalid characters. Allowed are: A-Z a-z 0-9 _ -");
} else {
SS.UndoRemember();
@ -942,7 +937,6 @@ void TextWindow::EditControlDone(char *s) {
Group *g = SK.GetGroup(edit.group);
g->name.strcpy(s);
}
SS.unsaved = true;
break;
}
case EDIT_LIGHT_INTENSITY:
@ -1081,6 +1075,10 @@ void TextWindow::EditControlDone(char *s) {
}
break;
}
default:
EditControlDoneForStyles(s);
break;
}
InvalidateGraphics();
SS.later.showTW = true;

View File

@ -224,6 +224,8 @@ void TextWindow::Show(void) {
case SCREEN_CONFIGURATION: ShowConfiguration(); break;
case SCREEN_STEP_DIMENSION: ShowStepDimension(); break;
case SCREEN_MESH_VOLUME: ShowMeshVolume(); break;
case SCREEN_LIST_OF_STYLES: ShowListOfStyles(); break;
case SCREEN_STYLE_INFO: ShowStyleInfo(); break;
}
}
Printf(false, "");

23
ui.h
View File

@ -52,10 +52,13 @@ public:
static const int SCREEN_CONFIGURATION = 3;
static const int SCREEN_STEP_DIMENSION = 4;
static const int SCREEN_MESH_VOLUME = 5;
static const int SCREEN_LIST_OF_STYLES = 6;
static const int SCREEN_STYLE_INFO = 7;
typedef struct {
int screen;
hGroup group;
hStyle style;
hConstraint constraint;
bool dimIsDistance;
@ -89,11 +92,17 @@ public:
// For the step dimension screen
static const int EDIT_STEP_DIM_FINISH = 40;
static const int EDIT_STEP_DIM_STEPS = 41;
// For the styles stuff
static const int EDIT_STYLE_WIDTH = 50;
static const int EDIT_STYLE_COLOR = 51;
static const int EDIT_STYLE_NAME = 52;
static const int EDIT_BACKGROUND_COLOR = 53;
struct {
int meaning;
int i;
hGroup group;
hRequest request;
hStyle style;
} edit;
static void ReportHowGroupSolved(hGroup hg);
@ -107,6 +116,8 @@ public:
void ShowGroupInfo(void);
void ShowGroupSolveInfo(void);
void ShowConfiguration(void);
void ShowListOfStyles(void);
void ShowStyleInfo(void);
void ShowStepDimension(void);
void ShowMeshVolume(void);
// Special screen, based on selection
@ -142,6 +153,13 @@ public:
static void ScreenChangeHelixParameter(int link, DWORD v);
static void ScreenColor(int link, DWORD v);
static void ScreenShowListOfStyles(int link, DWORD v);
static void ScreenShowStyleInfo(int link, DWORD v);
static void ScreenDeleteStyle(int link, DWORD v);
static void ScreenChangeStyleYesNo(int link, DWORD v);
static void ScreenCreateCustomStyle(int link, DWORD v);
static void ScreenLoadFactoryDefaultStyles(int link, DWORD v);
static void ScreenShowConfiguration(int link, DWORD v);
static void ScreenGoToWebsite(int link, DWORD v);
@ -168,7 +186,12 @@ public:
static void ScreenChangeCameraTangent(int link, DWORD v);
static void ScreenChangeExportScale(int link, DWORD v);
static void ScreenChangeExportOffset(int link, DWORD v);
static void ScreenChangeStyleName(int link, DWORD v);
static void ScreenChangeStyleWidth(int link, DWORD v);
static void ScreenChangeStyleColor(int link, DWORD v);
static void ScreenChangeBackgroundColor(int link, DWORD v);
bool EditControlDoneForStyles(char *s);
void EditControlDone(char *s);
};

View File

@ -77,6 +77,17 @@ void MakePathAbsolute(char *basep, char *pathp) {
strcpy(pathp, out);
}
bool StringAllPrintable(char *str)
{
char *t;
for(t = str; *t; t++) {
if(!(isalnum(*t) || *t == '-' || *t == '_')) {
return false;
}
}
return true;
}
void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
double a21, double a22, double a23, double a24,
double a31, double a32, double a33, double a34,