
that to try to find them if we can't find them by absolute path. This is intended to make everything still work if you copy an entire directory tree of files that import each other. Also add a mechanism to not paint the scene if we're not sure it's consistent; otherwise got some crashes on startup. And disable both text and graphic window when displaying a modal dialog, wasn't doing that always. [git-p4: depot-paths = "//depot/solvespace/": change = 1808]
693 lines
24 KiB
C++
693 lines
24 KiB
C++
#include "solvespace.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// A navigation bar that always appears at the top of the window.
|
|
//-----------------------------------------------------------------------------
|
|
void TextWindow::ScreenNavigation(int link, DWORD v) {
|
|
switch(link) {
|
|
default:
|
|
case 'h':
|
|
SS.TW.OneScreenForwardTo(SCREEN_LIST_OF_GROUPS);
|
|
break;
|
|
|
|
case 'b':
|
|
if(SS.TW.history > 0) {
|
|
SS.TW.shownIndex--;
|
|
if(SS.TW.shownIndex < 0) SS.TW.shownIndex = (HISTORY_LEN-1);
|
|
SS.TW.shown = &(SS.TW.showns[SS.TW.shownIndex]);
|
|
SS.TW.history--;
|
|
}
|
|
break;
|
|
|
|
case 'f':
|
|
SS.TW.OneScreenForwardTo(-1);
|
|
break;
|
|
}
|
|
}
|
|
void TextWindow::ShowHeader(bool withNav) {
|
|
ClearScreen();
|
|
|
|
char *cd = SS.GW.LockedInWorkplane() ?
|
|
SS.GetEntity(SS.GW.ActiveWorkplane())->DescriptionString() :
|
|
"free in 3d";
|
|
|
|
// Navigation buttons
|
|
if(withNav) {
|
|
Printf(false, " %Lb%f<<%E %Lh%fhome%E %Bt%Ft wrkpl:%Fd %s",
|
|
(&TextWindow::ScreenNavigation),
|
|
(&TextWindow::ScreenNavigation),
|
|
cd);
|
|
} else {
|
|
Printf(false, " %Bt%Ft wrkpl:%Fd %s", cd);
|
|
}
|
|
|
|
#define hs(b) ((b) ? 's' : 'h')
|
|
Printf(false, "%Bt%Ftshow: "
|
|
"%Fp%Ll%D%fwrkpls%E "
|
|
"%Fp%Ll%D%fnormals%E "
|
|
"%Fp%Ll%D%fpoints%E "
|
|
"%Fp%Ll%D%fconstraints%E ",
|
|
hs(SS.GW.showWorkplanes), (DWORD)&(SS.GW.showWorkplanes), &(SS.GW.ToggleBool),
|
|
hs(SS.GW.showNormals), (DWORD)&(SS.GW.showNormals), &(SS.GW.ToggleBool),
|
|
hs(SS.GW.showPoints), (DWORD)&(SS.GW.showPoints), &(SS.GW.ToggleBool),
|
|
hs(SS.GW.showConstraints), (DWORD)(&SS.GW.showConstraints), &(SS.GW.ToggleBool)
|
|
);
|
|
Printf(false, "%Bt%Ft "
|
|
"%Fp%Ll%D%fshaded%E "
|
|
"%Fp%Ll%D%ffaces%E "
|
|
"%Fp%Ll%D%fmesh%E "
|
|
"%Fp%Ll%D%fhidden-lines%E",
|
|
hs(SS.GW.showShaded), (DWORD)(&SS.GW.showShaded), &(SS.GW.ToggleBool),
|
|
hs(SS.GW.showFaces), (DWORD)(&SS.GW.showFaces), &(SS.GW.ToggleBool),
|
|
hs(SS.GW.showMesh), (DWORD)(&SS.GW.showMesh), &(SS.GW.ToggleBool),
|
|
hs(SS.GW.showHdnLines), (DWORD)(&SS.GW.showHdnLines), &(SS.GW.ToggleBool)
|
|
);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The screen that shows a list of every group in the sketch, with options
|
|
// to hide or show them, and to view them in detail. This is our home page.
|
|
//-----------------------------------------------------------------------------
|
|
void TextWindow::ScreenSelectGroup(int link, DWORD v) {
|
|
SS.TW.OneScreenForwardTo(SCREEN_GROUP_INFO);
|
|
SS.TW.shown->group.v = v;
|
|
}
|
|
void TextWindow::ScreenToggleGroupShown(int link, DWORD v) {
|
|
hGroup hg = { v };
|
|
Group *g = SS.GetGroup(hg);
|
|
g->visible = !(g->visible);
|
|
// If a group was just shown, then it might not have been generated
|
|
// previously, so regenerate.
|
|
SS.GenerateAll();
|
|
}
|
|
void TextWindow::ScreenShowGroupsSpecial(int link, DWORD v) {
|
|
int i;
|
|
for(i = 0; i < SS.group.n; i++) {
|
|
Group *g = &(SS.group.elem[i]);
|
|
|
|
if(link == 's') {
|
|
g->visible = true;
|
|
} else {
|
|
g->visible = false;
|
|
}
|
|
}
|
|
}
|
|
void TextWindow::ScreenActivateGroup(int link, DWORD v) {
|
|
hGroup hg = { v };
|
|
Group *g = SS.GetGroup(hg);
|
|
g->visible = true;
|
|
SS.GW.activeGroup.v = v;
|
|
SS.GetGroup(SS.GW.activeGroup)->Activate();
|
|
SS.GW.ClearSuper();
|
|
}
|
|
void TextWindow::ReportHowGroupSolved(hGroup hg) {
|
|
SS.GW.ClearSuper();
|
|
SS.TW.OneScreenForwardTo(SCREEN_GROUP_SOLVE_INFO);
|
|
SS.TW.shown->group.v = hg.v;
|
|
SS.later.showTW = true;
|
|
}
|
|
void TextWindow::ScreenHowGroupSolved(int link, DWORD v) {
|
|
if(SS.GW.activeGroup.v != v) {
|
|
ScreenActivateGroup(link, v);
|
|
}
|
|
SS.TW.OneScreenForwardTo(SCREEN_GROUP_SOLVE_INFO);
|
|
SS.TW.shown->group.v = v;
|
|
}
|
|
void TextWindow::ScreenShowConfiguration(int link, DWORD v) {
|
|
SS.TW.OneScreenForwardTo(SCREEN_CONFIGURATION);
|
|
}
|
|
void TextWindow::ShowListOfGroups(void) {
|
|
Printf(true, "%Ftactv show ok group-name%E");
|
|
int i;
|
|
bool afterActive = false;
|
|
for(i = 0; i < SS.group.n; i++) {
|
|
Group *g = &(SS.group.elem[i]);
|
|
char *s = g->DescriptionString();
|
|
bool active = (g->h.v == SS.GW.activeGroup.v);
|
|
bool shown = g->visible;
|
|
bool ok = (g->solved.how == Group::SOLVED_OKAY);
|
|
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%Fh%s%E "
|
|
"%Fp%D%f%s%Ll%s%E "
|
|
"%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),
|
|
afterActive ? "" : (shown ? "yes" : "no"),
|
|
afterActive ? " - " : (shown ? "" : " "),
|
|
// Link to the errors, if a problem occured while solving
|
|
ok ? 's' : 'x', g->h.v, (&TextWindow::ScreenHowGroupSolved),
|
|
ok ? "ok" : "",
|
|
ok ? "" : "NO",
|
|
// Link to a screen that gives more details on the group
|
|
g->h.v, (&TextWindow::ScreenSelectGroup), s);
|
|
|
|
if(active) afterActive = true;
|
|
}
|
|
|
|
Printf(true, " %Fl%Ls%fshow all%E / %Fl%Lh%fhide all%E",
|
|
&(TextWindow::ScreenShowGroupsSpecial),
|
|
&(TextWindow::ScreenShowGroupsSpecial));
|
|
Printf(false, " %Fl%Ls%fconfiguration%E",
|
|
&(TextWindow::ScreenShowConfiguration));
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The screen that shows information about a specific group, and allows the
|
|
// user to edit various things about it.
|
|
//-----------------------------------------------------------------------------
|
|
void TextWindow::ScreenHoverConstraint(int link, DWORD v) {
|
|
if(!SS.GW.showConstraints) return;
|
|
|
|
hConstraint hc = { v };
|
|
Constraint *c = SS.GetConstraint(hc);
|
|
if(c->group.v != SS.GW.activeGroup.v) {
|
|
// Only constraints in the active group are visible
|
|
return;
|
|
}
|
|
SS.GW.hover.Clear();
|
|
SS.GW.hover.constraint = hc;
|
|
SS.GW.hover.emphasized = true;
|
|
}
|
|
void TextWindow::ScreenHoverRequest(int link, DWORD v) {
|
|
SS.GW.hover.Clear();
|
|
hRequest hr = { v };
|
|
SS.GW.hover.entity = hr.entity(0);
|
|
SS.GW.hover.emphasized = true;
|
|
}
|
|
void TextWindow::ScreenSelectConstraint(int link, DWORD v) {
|
|
SS.GW.ClearSelection();
|
|
SS.GW.selection[0].constraint.v = v;
|
|
}
|
|
void TextWindow::ScreenSelectRequest(int link, DWORD v) {
|
|
hRequest hr = { v };
|
|
SS.GW.ClearSelection();
|
|
SS.GW.selection[0].entity = hr.entity(0);
|
|
}
|
|
void TextWindow::ScreenChangeOneOrTwoSides(int link, DWORD v) {
|
|
SS.UndoRemember();
|
|
|
|
Group *g = SS.GetGroup(SS.TW.shown->group);
|
|
if(g->subtype == Group::ONE_SIDED) {
|
|
g->subtype = Group::TWO_SIDED;
|
|
} else if(g->subtype == Group::TWO_SIDED) {
|
|
g->subtype = Group::ONE_SIDED;
|
|
} else oops();
|
|
SS.MarkGroupDirty(g->h);
|
|
SS.GenerateAll();
|
|
SS.GW.ClearSuper();
|
|
}
|
|
void TextWindow::ScreenChangeSkipFirst(int link, DWORD v) {
|
|
SS.UndoRemember();
|
|
|
|
Group *g = SS.GetGroup(SS.TW.shown->group);
|
|
(g->skipFirst) = !(g->skipFirst);
|
|
SS.MarkGroupDirty(g->h);
|
|
SS.GenerateAll();
|
|
SS.GW.ClearSuper();
|
|
}
|
|
void TextWindow::ScreenChangeMeshCombine(int link, DWORD v) {
|
|
SS.UndoRemember();
|
|
|
|
Group *g = SS.GetGroup(SS.TW.shown->group);
|
|
g->meshCombine = v;
|
|
SS.MarkGroupDirty(g->h);
|
|
SS.GenerateAll();
|
|
SS.GW.ClearSuper();
|
|
}
|
|
void TextWindow::ScreenChangeRightLeftHanded(int link, DWORD v) {
|
|
SS.UndoRemember();
|
|
|
|
Group *g = SS.GetGroup(SS.TW.shown->group);
|
|
if(g->subtype == Group::RIGHT_HANDED) {
|
|
g->subtype = Group::LEFT_HANDED;
|
|
} else {
|
|
g->subtype = Group::RIGHT_HANDED;
|
|
}
|
|
SS.MarkGroupDirty(g->h);
|
|
SS.GenerateAll();
|
|
SS.GW.ClearSuper();
|
|
}
|
|
void TextWindow::ScreenChangeHelixParameter(int link, DWORD v) {
|
|
Group *g = SS.GetGroup(SS.TW.shown->group);
|
|
char str[1024];
|
|
int r;
|
|
if(link == 't') {
|
|
sprintf(str, "%.3f", g->valA);
|
|
SS.TW.edit.meaning = EDIT_HELIX_TURNS;
|
|
r = 12;
|
|
} else if(link == 'p') {
|
|
strcpy(str, SS.MmToString(g->valB));
|
|
SS.TW.edit.meaning = EDIT_HELIX_PITCH;
|
|
r = 14;
|
|
} else if(link == 'r') {
|
|
strcpy(str, SS.MmToString(g->valC));
|
|
SS.TW.edit.meaning = EDIT_HELIX_DRADIUS;
|
|
r = 16;
|
|
} else oops();
|
|
SS.TW.edit.group.v = v;
|
|
ShowTextEditControl(r, 9, str);
|
|
}
|
|
void TextWindow::ScreenColor(int link, DWORD v) {
|
|
SS.UndoRemember();
|
|
|
|
Group *g = SS.GetGroup(SS.TW.shown->group);
|
|
if(v < 0 || v >= SS.MODEL_COLORS) return;
|
|
g->color = SS.modelColor[v];
|
|
SS.MarkGroupDirty(g->h);
|
|
SS.GenerateAll();
|
|
SS.GW.ClearSuper();
|
|
}
|
|
void TextWindow::ScreenChangeExprA(int link, DWORD v) {
|
|
Group *g = SS.GetGroup(SS.TW.shown->group);
|
|
|
|
// There's an extra line for the skipFirst parameter in one-sided groups.
|
|
int r = (g->subtype == Group::ONE_SIDED) ? 15 : 13;
|
|
|
|
char str[1024];
|
|
sprintf(str, "%d", (int)g->valA);
|
|
ShowTextEditControl(r, 9, str);
|
|
SS.TW.edit.meaning = EDIT_TIMES_REPEATED;
|
|
SS.TW.edit.group.v = v;
|
|
}
|
|
void TextWindow::ScreenChangeGroupName(int link, DWORD v) {
|
|
Group *g = SS.GetGroup(SS.TW.shown->group);
|
|
ShowTextEditControl(7, 14, g->DescriptionString()+5);
|
|
SS.TW.edit.meaning = EDIT_GROUP_NAME;
|
|
SS.TW.edit.group.v = v;
|
|
}
|
|
void TextWindow::ScreenDeleteGroup(int link, DWORD v) {
|
|
SS.UndoRemember();
|
|
|
|
hGroup hg = SS.TW.shown->group;
|
|
if(hg.v == SS.GW.activeGroup.v) {
|
|
Error("This group is currently active; activate a different group "
|
|
"before proceeding.");
|
|
return;
|
|
}
|
|
SS.group.RemoveById(SS.TW.shown->group);
|
|
// This is a major change, so let's re-solve everything.
|
|
SS.TW.ClearSuper();
|
|
SS.GW.ClearSuper();
|
|
SS.GenerateAll(0, INT_MAX);
|
|
}
|
|
void TextWindow::ShowGroupInfo(void) {
|
|
Group *g = SS.group.FindById(shown->group);
|
|
char *s, *s2, *s3;
|
|
|
|
if(shown->group.v == Group::HGROUP_REFERENCES.v) {
|
|
Printf(true, "%FtGROUP %E%s", g->DescriptionString());
|
|
} else {
|
|
Printf(true, "%FtGROUP %E%s "
|
|
"[%Fl%Ll%D%frename%E/%Fl%Ll%D%fdel%E]",
|
|
g->DescriptionString(),
|
|
g->h.v, &TextWindow::ScreenChangeGroupName,
|
|
g->h.v, &TextWindow::ScreenDeleteGroup);
|
|
}
|
|
|
|
if(g->type == Group::EXTRUDE) {
|
|
s = "EXTRUDE ";
|
|
} else if(g->type == Group::TRANSLATE) {
|
|
s = "TRANSLATE";
|
|
s2 ="REPEAT ";
|
|
s3 ="START ";
|
|
} else if(g->type == Group::ROTATE) {
|
|
s = "ROTATE ";
|
|
s2 ="REPEAT ";
|
|
s3 ="START ";
|
|
}
|
|
|
|
if(g->type == Group::EXTRUDE || g->type == Group::ROTATE ||
|
|
g->type == Group::TRANSLATE)
|
|
{
|
|
bool one = (g->subtype == Group::ONE_SIDED);
|
|
Printf(true, "%Ft%s%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E", s,
|
|
&TextWindow::ScreenChangeOneOrTwoSides,
|
|
(one ? "" : "one side"), (one ? "one side" : ""),
|
|
&TextWindow::ScreenChangeOneOrTwoSides,
|
|
(!one ? "" : "two sides"), (!one ? "two sides" : ""));
|
|
}
|
|
|
|
if(g->type == Group::LATHE) {
|
|
Printf(true, "%FtLATHE");
|
|
}
|
|
|
|
if(g->type == Group::SWEEP) {
|
|
Printf(true, "%FtSWEEP");
|
|
}
|
|
|
|
if(g->type == Group::HELICAL_SWEEP) {
|
|
bool rh = (g->subtype == Group::RIGHT_HANDED);
|
|
Printf(true,
|
|
"%FtHELICAL%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E",
|
|
&ScreenChangeRightLeftHanded,
|
|
(rh ? "" : "right-hand"), (rh ? "right-hand" : ""),
|
|
&ScreenChangeRightLeftHanded,
|
|
(!rh ? "" : "left-hand"), (!rh ? "left-hand" : ""));
|
|
Printf(false, "%FtTHROUGH%E %@ turns %Fl%Lt%D%f[change]%E",
|
|
g->valA, g->h.v, &ScreenChangeHelixParameter);
|
|
Printf(false, "%FtPITCH%E %s axially per turn %Fl%Lp%D%f[change]%E",
|
|
SS.MmToString(g->valB), g->h.v, &ScreenChangeHelixParameter);
|
|
Printf(false, "%FtdRADIUS%E %s radially per turn %Fl%Lr%D%f[change]%E",
|
|
SS.MmToString(g->valC), g->h.v, &ScreenChangeHelixParameter);
|
|
}
|
|
|
|
if(g->type == Group::ROTATE || g->type == Group::TRANSLATE) {
|
|
bool space;
|
|
if(g->subtype == Group::ONE_SIDED) {
|
|
bool skip = g->skipFirst;
|
|
Printf(true, "%Ft%s%E %Fh%f%Ll%s%E%Fs%s%E / %Fh%f%Ll%s%E%Fs%s%E",
|
|
s3,
|
|
&ScreenChangeSkipFirst,
|
|
(!skip ? "" : "with original"), (!skip ? "with original" : ""),
|
|
&ScreenChangeSkipFirst,
|
|
(skip ? "":"with copy #1"), (skip ? "with copy #1":""));
|
|
space = false;
|
|
} else {
|
|
space = true;
|
|
}
|
|
|
|
int times = (int)(g->valA);
|
|
Printf(space, "%Ft%s%E %d time%s %Fl%Ll%D%f[change]%E",
|
|
s2, times, times == 1 ? "" : "s",
|
|
g->h.v, &TextWindow::ScreenChangeExprA);
|
|
}
|
|
|
|
if(g->type == Group::IMPORTED) {
|
|
Printf(true, "%FtIMPORT%E '%s'", g->impFileRel);
|
|
}
|
|
|
|
if(g->type == Group::EXTRUDE ||
|
|
g->type == Group::LATHE ||
|
|
g->type == Group::SWEEP ||
|
|
g->type == Group::HELICAL_SWEEP ||
|
|
g->type == Group::IMPORTED)
|
|
{
|
|
bool un = (g->meshCombine == Group::COMBINE_AS_UNION);
|
|
bool diff = (g->meshCombine == Group::COMBINE_AS_DIFFERENCE);
|
|
bool asy = (g->meshCombine == Group::COMBINE_AS_ASSEMBLE);
|
|
bool asa = (g->type == Group::IMPORTED);
|
|
|
|
Printf((g->type == Group::HELICAL_SWEEP),
|
|
"%FtMERGE AS%E %Fh%f%D%Ll%s%E%Fs%s%E / %Fh%f%D%Ll%s%E%Fs%s%E %s "
|
|
"%Fh%f%D%Ll%s%E%Fs%s%E",
|
|
&TextWindow::ScreenChangeMeshCombine,
|
|
Group::COMBINE_AS_UNION,
|
|
(un ? "" : "union"), (un ? "union" : ""),
|
|
&TextWindow::ScreenChangeMeshCombine,
|
|
Group::COMBINE_AS_DIFFERENCE,
|
|
(diff ? "" : "difference"), (diff ? "difference" : ""),
|
|
asa ? "/" : "",
|
|
&TextWindow::ScreenChangeMeshCombine,
|
|
Group::COMBINE_AS_ASSEMBLE,
|
|
(asy || !asa ? "" : "assemble"), (asy && asa ? "assemble" : ""));
|
|
}
|
|
if(g->type == Group::IMPORTED && g->meshError.yes) {
|
|
Printf(false, "%Fx the parts interfere!");
|
|
}
|
|
|
|
if(g->type == Group::EXTRUDE ||
|
|
g->type == Group::LATHE ||
|
|
g->type == Group::SWEEP ||
|
|
g->type == Group::HELICAL_SWEEP)
|
|
{
|
|
#define TWOX(v) v v
|
|
Printf(true, "%FtM_COLOR%E " TWOX(TWOX(TWOX("%Bp%D%f%Ln %Bd%E "))),
|
|
0x80000000 | SS.modelColor[0], 0, &TextWindow::ScreenColor,
|
|
0x80000000 | SS.modelColor[1], 1, &TextWindow::ScreenColor,
|
|
0x80000000 | SS.modelColor[2], 2, &TextWindow::ScreenColor,
|
|
0x80000000 | SS.modelColor[3], 3, &TextWindow::ScreenColor,
|
|
0x80000000 | SS.modelColor[4], 4, &TextWindow::ScreenColor,
|
|
0x80000000 | SS.modelColor[5], 5, &TextWindow::ScreenColor,
|
|
0x80000000 | SS.modelColor[6], 6, &TextWindow::ScreenColor,
|
|
0x80000000 | SS.modelColor[7], 7, &TextWindow::ScreenColor);
|
|
}
|
|
|
|
// Leave more space if the group has configuration stuff above the req/
|
|
// constraint list (as all but the drawing groups do).
|
|
if(g->type == Group::DRAWING_3D || g->type == Group::DRAWING_WORKPLANE) {
|
|
Printf(true, "%Ftrequests in group");
|
|
} else {
|
|
Printf(false, "");
|
|
Printf(false, "%Ftrequests in group");
|
|
}
|
|
|
|
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(false, "%Bp %Fl%Ll%D%f%h%s%E",
|
|
(a & 1) ? 'd' : 'a',
|
|
r->h.v, (&TextWindow::ScreenSelectRequest),
|
|
&(TextWindow::ScreenHoverRequest), s);
|
|
a++;
|
|
}
|
|
}
|
|
if(a == 0) Printf(false, "%Ba (none)");
|
|
|
|
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(false, "%Bp %Fl%Ll%D%f%h%s%E",
|
|
(a & 1) ? 'd' : 'a',
|
|
c->h.v, (&TextWindow::ScreenSelectConstraint),
|
|
(&TextWindow::ScreenHoverConstraint), s);
|
|
a++;
|
|
}
|
|
}
|
|
if(a == 0) Printf(false, "%Ba (none)");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The screen that's displayed when the sketch fails to solve. A report of
|
|
// what failed, and (if the problem is a singular Jacobian) a list of
|
|
// constraints that could be removed to fix it.
|
|
//-----------------------------------------------------------------------------
|
|
void TextWindow::ShowGroupSolveInfo(void) {
|
|
Group *g = SS.group.FindById(shown->group);
|
|
if(g->solved.how == Group::SOLVED_OKAY) {
|
|
// Go back to the default group info screen
|
|
shown->screen = SCREEN_GROUP_INFO;
|
|
Show();
|
|
return;
|
|
}
|
|
|
|
Printf(true, "%FtGROUP %E%s", g->DescriptionString());
|
|
switch(g->solved.how) {
|
|
case Group::DIDNT_CONVERGE:
|
|
Printf(true, " %FxSOLVE FAILED!%Fd no convergence");
|
|
break;
|
|
|
|
case Group::SINGULAR_JACOBIAN: {
|
|
Printf(true, "%FxSOLVE FAILED!%Fd inconsistent system");
|
|
Printf(true, "remove any one of these to fix it");
|
|
for(int i = 0; i < g->solved.remove.n; i++) {
|
|
hConstraint hc = g->solved.remove.elem[i];
|
|
Constraint *c = SS.constraint.FindByIdNoOops(hc);
|
|
if(!c) continue;
|
|
|
|
Printf(false, "%Bp %Fl%Ll%D%f%h%s%E",
|
|
(i & 1) ? 'd' : 'a',
|
|
c->h.v, (&TextWindow::ScreenSelectConstraint),
|
|
(&TextWindow::ScreenHoverConstraint),
|
|
c->DescriptionString());
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// For the configuration screen, setup items that are not specific to the
|
|
// file being edited right now.
|
|
//-----------------------------------------------------------------------------
|
|
void TextWindow::ScreenChangeLightDirection(int link, DWORD v) {
|
|
char str[1024];
|
|
sprintf(str, "%.2f, %.2f, %.2f", CO(SS.lightDir[v]));
|
|
ShowTextEditControl(29+2*v, 8, str);
|
|
SS.TW.edit.meaning = EDIT_LIGHT_DIRECTION;
|
|
SS.TW.edit.i = v;
|
|
}
|
|
void TextWindow::ScreenChangeLightIntensity(int link, DWORD v) {
|
|
char str[1024];
|
|
sprintf(str, "%.2f", SS.lightIntensity[v]);
|
|
ShowTextEditControl(29+2*v, 30, str);
|
|
SS.TW.edit.meaning = EDIT_LIGHT_INTENSITY;
|
|
SS.TW.edit.i = v;
|
|
}
|
|
void TextWindow::ScreenChangeColor(int link, DWORD v) {
|
|
char str[1024];
|
|
sprintf(str, "%.2f, %.2f, %.2f",
|
|
REDf(SS.modelColor[v]),
|
|
GREENf(SS.modelColor[v]),
|
|
BLUEf(SS.modelColor[v]));
|
|
ShowTextEditControl(9+2*v, 12, str);
|
|
SS.TW.edit.meaning = EDIT_COLOR;
|
|
SS.TW.edit.i = v;
|
|
}
|
|
void TextWindow::ScreenChangeMeshTolerance(int link, DWORD v) {
|
|
char str[1024];
|
|
sprintf(str, "%.2f", SS.meshTol);
|
|
ShowTextEditControl(37, 3, str);
|
|
SS.TW.edit.meaning = EDIT_MESH_TOLERANCE;
|
|
}
|
|
void TextWindow::ScreenChangeCameraTangent(int link, DWORD v) {
|
|
char str[1024];
|
|
sprintf(str, "%.3f", 1000*SS.cameraTangent);
|
|
ShowTextEditControl(43, 3, str);
|
|
SS.TW.edit.meaning = EDIT_CAMERA_TANGENT;
|
|
}
|
|
void TextWindow::ShowConfiguration(void) {
|
|
int i;
|
|
Printf(true, "%Ft material color-(r, g, b)");
|
|
|
|
for(i = 0; i < SS.MODEL_COLORS; i++) {
|
|
Printf(false, "%Bp #%d: %Bp %Bp (%@, %@, %@) %f%D%Ll%Fl[change]%E",
|
|
(i & 1) ? 'd' : 'a',
|
|
i, 0x80000000 | SS.modelColor[i],
|
|
(i & 1) ? 'd' : 'a',
|
|
REDf(SS.modelColor[i]),
|
|
GREENf(SS.modelColor[i]),
|
|
BLUEf(SS.modelColor[i]),
|
|
&ScreenChangeColor, i);
|
|
}
|
|
|
|
Printf(false, "");
|
|
Printf(false, "%Ft light direction intensity");
|
|
for(i = 0; i < 2; i++) {
|
|
Printf(false, "%Bp #%d (%2,%2,%2)%Fl%D%f%Ll[c]%E "
|
|
"%2 %Fl%D%f%Ll[c]%E",
|
|
(i & 1) ? 'd' : 'a', i,
|
|
CO(SS.lightDir[i]), i, &ScreenChangeLightDirection,
|
|
SS.lightIntensity[i], i, &ScreenChangeLightIntensity);
|
|
}
|
|
|
|
Printf(false, "");
|
|
Printf(false, "%Ft mesh tolerance (smaller is finer)%E");
|
|
Printf(false, "%Ba %2 %Fl%Ll%f%D[change]%E; now %d triangles",
|
|
SS.meshTol,
|
|
&ScreenChangeMeshTolerance, 0,
|
|
SS.group.elem[SS.group.n-1].runningMesh.l.n);
|
|
|
|
Printf(false, "");
|
|
Printf(false, "%Ft perspective factor (0 for isometric)%E");
|
|
Printf(false, "%Ba %3 %Fl%Ll%f%D[change]%E",
|
|
SS.cameraTangent*1000,
|
|
&ScreenChangeCameraTangent, 0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The edit control is visible, and the user just pressed enter.
|
|
//-----------------------------------------------------------------------------
|
|
void TextWindow::EditControlDone(char *s) {
|
|
switch(edit.meaning) {
|
|
case EDIT_TIMES_REPEATED: {
|
|
Expr *e = Expr::From(s);
|
|
if(e) {
|
|
SS.UndoRemember();
|
|
|
|
Group *g = SS.GetGroup(edit.group);
|
|
g->valA = e->Eval();
|
|
|
|
SS.MarkGroupDirty(g->h);
|
|
SS.later.generateAll = true;
|
|
} else {
|
|
Error("Not a valid number or expression: '%s'", 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) {
|
|
Error("Invalid characters. Allowed are: A-Z a-z 0-9 _ -");
|
|
} else {
|
|
SS.UndoRemember();
|
|
|
|
Group *g = SS.GetGroup(edit.group);
|
|
g->name.strcpy(s);
|
|
}
|
|
SS.unsaved = true;
|
|
break;
|
|
}
|
|
case EDIT_LIGHT_INTENSITY:
|
|
SS.lightIntensity[edit.i] = min(1, max(0, atof(s)));
|
|
InvalidateGraphics();
|
|
break;
|
|
case EDIT_LIGHT_DIRECTION: {
|
|
double x, y, z;
|
|
if(sscanf(s, "%lf, %lf, %lf", &x, &y, &z)==3) {
|
|
SS.lightDir[edit.i] = Vector::From(x, y, z);
|
|
} else {
|
|
Error("Bad format: specify coordinates as x, y, z");
|
|
}
|
|
InvalidateGraphics();
|
|
break;
|
|
}
|
|
case EDIT_COLOR: {
|
|
double r, g, b;
|
|
if(sscanf(s, "%lf, %lf, %lf", &r, &g, &b)==3) {
|
|
SS.modelColor[edit.i] = RGB(r*255, g*255, b*255);
|
|
} else {
|
|
Error("Bad format: specify color as r, g, b");
|
|
}
|
|
break;
|
|
}
|
|
case EDIT_MESH_TOLERANCE: {
|
|
SS.meshTol = min(10, max(0.1, atof(s)));
|
|
SS.GenerateAll(0, INT_MAX);
|
|
break;
|
|
}
|
|
case EDIT_CAMERA_TANGENT: {
|
|
SS.cameraTangent = (min(2, max(0, atof(s))))/1000.0;
|
|
InvalidateGraphics();
|
|
break;
|
|
}
|
|
case EDIT_HELIX_TURNS:
|
|
case EDIT_HELIX_PITCH:
|
|
case EDIT_HELIX_DRADIUS: {
|
|
SS.UndoRemember();
|
|
Group *g = SS.GetGroup(edit.group);
|
|
Expr *e = Expr::From(s);
|
|
if(!e) {
|
|
Error("Not a valid number or expression: '%s'", s);
|
|
break;
|
|
}
|
|
if(edit.meaning == EDIT_HELIX_TURNS) {
|
|
g->valA = min(30, fabs(e->Eval()));
|
|
} else if(edit.meaning == EDIT_HELIX_PITCH) {
|
|
g->valB = SS.ExprToMm(e);
|
|
} else {
|
|
g->valC = SS.ExprToMm(e);
|
|
}
|
|
SS.MarkGroupDirty(g->h);
|
|
SS.later.generateAll = true;
|
|
break;
|
|
}
|
|
}
|
|
SS.later.showTW = true;
|
|
HideTextEditControl();
|
|
edit.meaning = EDIT_NOTHING;
|
|
}
|
|
|