Skip to content

Commit

Permalink
(WIP) Implement a platform abstraction for windows.
Browse files Browse the repository at this point in the history
This commit removes a large amount of code partially duplicated
between the text and the graphics windows, and opens the path to
having more than one model window on screen at any given time,
as well as simplifies platform work.

This commit also adds proper support for High-DPI integral scale
factor (i.e. device pixel ratio). It does not add support for
fractional scale factor (i.e. font scaling, applied on top of
device pixel ratio).

It reinstates tooltip support and removes menu-related hacks.
  • Loading branch information
whitequark committed Jul 14, 2018
1 parent ff62147 commit 75d34b7
Show file tree
Hide file tree
Showing 57 changed files with 2,228 additions and 2,004 deletions.
5 changes: 4 additions & 1 deletion res/win32/manifest.xml
Expand Up @@ -6,12 +6,15 @@
name="JonathanWesthues.3dCAD.SolveSpace"
type="win32"
/>
<description>Parametric 3d CAD tool.</description>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
PerMonitorV2
</dpiAwareness>
</windowsSettings>
</application>
<description>Parametric 3d CAD tool.</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
Expand Down
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Expand Up @@ -329,7 +329,7 @@ if(ENABLE_GUI)

if(MSVC)
set_target_properties(solvespace PROPERTIES
LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /INCREMENTAL:NO /OPT:REF")
LINK_FLAGS "/MANIFEST:NO /SAFESEH:NO /INCREMENTAL:NO /OPT:REF /STACK:33554432")
endif()
endif()

Expand Down
2 changes: 1 addition & 1 deletion src/clipboard.cpp
Expand Up @@ -325,7 +325,7 @@ void GraphicsWindow::MenuClipboard(Command id) {
}
}

bool TextWindow::EditControlDoneForPaste(const char *s) {
bool TextWindow::EditControlDoneForPaste(const std::string &s) {
Expr *e;
switch(edit.meaning) {
case Edit::PASTE_TIMES_REPEATED: {
Expand Down
47 changes: 23 additions & 24 deletions src/confscreen.cpp
Expand Up @@ -80,28 +80,27 @@ void TextWindow::ScreenChangeFixExportColors(int link, uint32_t v) {

void TextWindow::ScreenChangeBackFaces(int link, uint32_t v) {
SS.drawBackFaces = !SS.drawBackFaces;
SS.GW.persistentDirty = true;
InvalidateGraphics();
SS.GW.Invalidate(/*clearPersistent=*/true);
}

void TextWindow::ScreenChangeShowContourAreas(int link, uint32_t v) {
SS.showContourAreas = !SS.showContourAreas;
InvalidateGraphics();
SS.GW.Invalidate();
}

void TextWindow::ScreenChangeCheckClosedContour(int link, uint32_t v) {
SS.checkClosedContour = !SS.checkClosedContour;
InvalidateGraphics();
SS.GW.Invalidate();
}

void TextWindow::ScreenChangeShadedTriangles(int link, uint32_t v) {
SS.exportShadedTriangles = !SS.exportShadedTriangles;
InvalidateGraphics();
SS.GW.Invalidate();
}

void TextWindow::ScreenChangePwlCurves(int link, uint32_t v) {
SS.exportPwlCurves = !SS.exportPwlCurves;
InvalidateGraphics();
SS.GW.Invalidate();
}

void TextWindow::ScreenChangeCanvasSizeAuto(int link, uint32_t v) {
Expand All @@ -110,7 +109,7 @@ void TextWindow::ScreenChangeCanvasSizeAuto(int link, uint32_t v) {
} else {
SS.exportCanvasSizeAuto = false;
}
InvalidateGraphics();
SS.GW.Invalidate();
}

void TextWindow::ScreenChangeCanvasSize(int link, uint32_t v) {
Expand Down Expand Up @@ -321,26 +320,26 @@ void TextWindow::ShowConfiguration() {
}
}

bool TextWindow::EditControlDoneForConfiguration(const char *s) {
bool TextWindow::EditControlDoneForConfiguration(const std::string &s) {
switch(edit.meaning) {
case Edit::LIGHT_INTENSITY:
SS.lightIntensity[edit.i] = min(1.0, max(0.0, atof(s)));
InvalidateGraphics();
SS.lightIntensity[edit.i] = min(1.0, max(0.0, atof(s.c_str())));
SS.GW.Invalidate();
break;

case Edit::LIGHT_DIRECTION: {
double x, y, z;
if(sscanf(s, "%lf, %lf, %lf", &x, &y, &z)==3) {
if(sscanf(s.c_str(), "%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();
SS.GW.Invalidate();
break;
}
case Edit::COLOR: {
Vector rgb;
if(sscanf(s, "%lf, %lf, %lf", &rgb.x, &rgb.y, &rgb.z)==3) {
if(sscanf(s.c_str(), "%lf, %lf, %lf", &rgb.x, &rgb.y, &rgb.z)==3) {
rgb = rgb.ClampWithin(0, 1);
SS.modelColor[edit.i] = RGBf(rgb.x, rgb.y, rgb.z);
} else {
Expand All @@ -350,44 +349,44 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) {
}
case Edit::CHORD_TOLERANCE: {
if(edit.i == 0) {
SS.chordTol = max(0.0, atof(s));
SS.chordTol = max(0.0, atof(s.c_str()));
SS.GenerateAll(SolveSpaceUI::Generate::ALL);
} else {
SS.exportChordTol = max(0.0, atof(s));
SS.exportChordTol = max(0.0, atof(s.c_str()));
}
break;
}
case Edit::MAX_SEGMENTS: {
if(edit.i == 0) {
SS.maxSegments = min(1000, max(7, atoi(s)));
SS.maxSegments = min(1000, max(7, atoi(s.c_str())));
SS.GenerateAll(SolveSpaceUI::Generate::ALL);
} else {
SS.exportMaxSegments = min(1000, max(7, atoi(s)));
SS.exportMaxSegments = min(1000, max(7, atoi(s.c_str())));
}
break;
}
case Edit::CAMERA_TANGENT: {
SS.cameraTangent = (min(2.0, max(0.0, atof(s))))/1000.0;
SS.cameraTangent = (min(2.0, max(0.0, atof(s.c_str()))))/1000.0;
if(!SS.usePerspectiveProj) {
Message(_("The perspective factor will have no effect until you "
"enable View -> Use Perspective Projection."));
}
InvalidateGraphics();
SS.GW.Invalidate();
break;
}
case Edit::GRID_SPACING: {
SS.gridSpacing = (float)min(1e4, max(1e-3, SS.StringToMm(s)));
InvalidateGraphics();
SS.GW.Invalidate();
break;
}
case Edit::DIGITS_AFTER_DECIMAL: {
int v = atoi(s);
int v = atoi(s.c_str());
if(v < 0 || v > 8) {
Error(_("Specify between 0 and 8 digits after the decimal."));
} else {
SS.SetUnitDigitsAfterDecimal(v);
}
InvalidateGraphics();
SS.GW.Invalidate();
break;
}
case Edit::EXPORT_SCALE: {
Expand Down Expand Up @@ -455,8 +454,8 @@ bool TextWindow::EditControlDoneForConfiguration(const char *s) {
break;
}
case Edit::AUTOSAVE_INTERVAL: {
int interval;
if(sscanf(s, "%d", &interval)==1) {
int interval = atoi(s.c_str());
if(interval) {
if(interval >= 1) {
SS.autosaveInterval = interval;
SS.ScheduleAutosave();
Expand Down
2 changes: 1 addition & 1 deletion src/constraint.cpp
Expand Up @@ -744,7 +744,7 @@ void Constraint::MenuConstrain(Command id) {
}

SS.GW.ClearSelection();
InvalidateGraphics();
SS.GW.Invalidate();
}

#endif /* ! LIBRARY */
43 changes: 26 additions & 17 deletions src/draw.cpp
Expand Up @@ -80,7 +80,7 @@ void GraphicsWindow::Selection::Draw(bool isHovered, Canvas *canvas) {
void GraphicsWindow::ClearSelection() {
selection.Clear();
SS.ScheduleShowTW();
InvalidateGraphics();
Invalidate();
}

void GraphicsWindow::ClearNonexistentSelectionItems() {
Expand All @@ -98,7 +98,7 @@ void GraphicsWindow::ClearNonexistentSelectionItems() {
}
}
selection.RemoveTagged();
if(change) InvalidateGraphics();
if(change) Invalidate();
}

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -304,14 +304,14 @@ void GraphicsWindow::GroupSelection() {

Camera GraphicsWindow::GetCamera() const {
Camera camera = {};
camera.width = (int)width;
camera.height = (int)height;
camera.offset = offset;
camera.projUp = projUp;
camera.projRight = projRight;
camera.scale = scale;
camera.tangent = SS.CameraTangent();
camera.hasPixels = true;
window->GetContentSize(&camera.width, &camera.height);
camera.pixelRatio = window->GetIntegralScaleFactor();
camera.gridFit = (window->GetIntegralScaleFactor() == 1);
camera.offset = offset;
camera.projUp = projUp;
camera.projRight = projRight;
camera.scale = scale;
camera.tangent = SS.CameraTangent();
return camera;
}

Expand Down Expand Up @@ -457,7 +457,7 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) {

if(!sel.Equals(&hover)) {
hover = sel;
InvalidateGraphics();
Invalidate();
}
}

Expand Down Expand Up @@ -545,6 +545,10 @@ void GraphicsWindow::NormalizeProjectionVectors() {
void GraphicsWindow::DrawSnapGrid(Canvas *canvas) {
if(!LockedInWorkplane()) return;

const Camera &camera = canvas->GetCamera();
double width = camera.width,
height = camera.height;

hEntity he = ActiveWorkplane();
EntityBase *wrkpl = SK.GetEntity(he),
*norm = wrkpl->Normal();
Expand Down Expand Up @@ -816,15 +820,11 @@ void GraphicsWindow::Draw(Canvas *canvas) {
}

void GraphicsWindow::Paint() {
if(!canvas) return;
ssassert(window != NULL && canvas != NULL,
"Cannot paint without window and canvas");

havePainted = true;

int w, h;
GetGraphicsWindowSize(&w, &h);
width = w;
height = h;

Camera camera = GetCamera();
Lighting lighting = GetLighting();

Expand Down Expand Up @@ -902,3 +902,12 @@ void GraphicsWindow::Paint() {
canvas->FlushFrame();
canvas->Clear();
}

void GraphicsWindow::Invalidate(bool clearPersistent) {
if(window) {
if(clearPersistent) {
persistentDirty = true;
}
window->Invalidate();
}
}
6 changes: 3 additions & 3 deletions src/export.cpp
Expand Up @@ -263,7 +263,7 @@ void SolveSpaceUI::ExportViewOrWireframeTo(const Platform::Path &filename, bool
}

SS.justExportedInfo.draw = true;
InvalidateGraphics();
GW.Invalidate();
}

edges.Clear();
Expand Down Expand Up @@ -839,7 +839,7 @@ void SolveSpaceUI::ExportMeshTo(const Platform::Path &filename) {

SS.justExportedInfo.showOrigin = false;
SS.justExportedInfo.draw = true;
InvalidateGraphics();
GW.Invalidate();
}

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -1108,5 +1108,5 @@ void SolveSpaceUI::ExportMeshAsThreeJsTo(FILE *f, const Platform::Path &filename
void SolveSpaceUI::ExportAsPngTo(const Platform::Path &filename) {
screenshotFile = filename;
// The rest of the work is done in the next redraw.
InvalidateGraphics();
GW.Invalidate();
}
23 changes: 13 additions & 10 deletions src/expr.cpp
Expand Up @@ -605,8 +605,7 @@ class ExprParser {
bool IsError() const { return type == TokenType::ERROR; }
};

const char *input;
unsigned inputPos;
std::string::const_iterator it, end;
std::vector<Token> stack;

char ReadChar();
Expand All @@ -624,7 +623,7 @@ class ExprParser {
bool Reduce(std::string *error);
bool Parse(std::string *error, size_t reduceUntil = 0);

static Expr *Parse(const char *input, std::string *error);
static Expr *Parse(const std::string &input, std::string *error);
};

ExprParser::Token ExprParser::Token::From(TokenType type, Expr *expr) {
Expand All @@ -643,11 +642,15 @@ ExprParser::Token ExprParser::Token::From(TokenType type, Expr::Op op) {
}

char ExprParser::ReadChar() {
return input[inputPos++];
return *it++;
}

char ExprParser::PeekChar() {
return input[inputPos];
if(it == end) {
return '\0';
} else {
return *it;
}
}

std::string ExprParser::ReadWord() {
Expand Down Expand Up @@ -889,22 +892,22 @@ bool ExprParser::Parse(std::string *error, size_t reduceUntil) {
return true;
}

Expr *ExprParser::Parse(const char *input, std::string *error) {
Expr *ExprParser::Parse(const std::string &input, std::string *error) {
ExprParser parser;
parser.input = input;
parser.inputPos = 0;
parser.it = input.cbegin();
parser.end = input.cend();
if(!parser.Parse(error)) return NULL;

Token r = parser.PopOperand(error);
if(r.IsError()) return NULL;
return r.expr;
}

Expr *Expr::Parse(const char *input, std::string *error) {
Expr *Expr::Parse(const std::string &input, std::string *error) {
return ExprParser::Parse(input, error);
}

Expr *Expr::From(const char *input, bool popUpError) {
Expr *Expr::From(const std::string &input, bool popUpError) {
std::string error;
Expr *e = ExprParser::Parse(input, &error);
if(!e) {
Expand Down
4 changes: 2 additions & 2 deletions src/expr.h
Expand Up @@ -96,8 +96,8 @@ class Expr {
Expr *DeepCopyWithParamsAsPointers(IdList<Param,hParam> *firstTry,
IdList<Param,hParam> *thenTry) const;

static Expr *Parse(const char *input, std::string *error);
static Expr *From(const char *in, bool popUpError);
static Expr *Parse(const std::string &input, std::string *error);
static Expr *From(const std::string &input, bool popUpError);
};

class ExprVector {
Expand Down
2 changes: 1 addition & 1 deletion src/generate.cpp
Expand Up @@ -313,7 +313,7 @@ void SolveSpaceUI::GenerateAll(Generate type, bool andFindFree, bool genForBBox)
}

prev.Clear();
InvalidateGraphics();
GW.Invalidate();

// Remove nonexistent selection items, for same reason we waited till
// the end to put up a dialog box.
Expand Down

0 comments on commit 75d34b7

Please sign in to comment.