Commit Graph

70 Commits (6b5db5897155ca9bdc5daa3e791c07723a6b7d9c)

Author SHA1 Message Date
whitequark 6b5db58971 Add a platform abstraction for file dialogs.
This commit merges all ad-hoc file dialog code, such as the feature
where dialogs remember last location and format, and exposes it
through a common interface.

This commit also significantly improves Gtk dialog handling code.
2018-07-17 22:33:45 +00:00
whitequark d7968978ad Add a platform abstraction for message dialogs.
This commit changes the awfully specific code for dialogs with
messages duplicated three times to go through a generic interface.
It also fixes some issues with the way translated messages
were parameterized.

This commit removes the custom message dialog box used on Windows,
for several reasons. First, it was the last element not respecting
HiDPI displays. Second, other OSes do not easily provide this much
control over rendering default message boxes, and both Gnome and
macOS frown upon non-standard renderings such as those; so the custom
rendering was already not used on the other OSes.
2018-07-17 22:33:45 +00:00
whitequark eb5501ecd6 Implement a platform abstraction for settings.
This commit mostly just changes the settings code to be in line with
the rest of the platform abstractions, although it also fixes some
settings names to be consistent with others, and uses native bool
types where applicable.

This commit also makes settings-related operations much less
wasteful, not that it should matter.
2018-07-17 15:01:58 +00:00
whitequark f324477dd0 Implement a platform abstraction for windows.
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 complete support for High-DPI device pixel
ratio. It adds support for font scale factor (a fractional factor
on top of integral device pixel ratio) on the platform side, but not
on the application side.

This commit also adds error checking to all Windows API calls
(within the abstracted code) and fixes a significant number of
misuses and non-future-proof uses of Windows API.

This commit also makes uses of Windows API idiomatic, e.g. using
the built-in vertical scroll bar, native tooltips, control
subclassing instead of hooks in the global dispatch loop, and so on.

It reinstates tooltip support and removes menu-related hacks.
2018-07-17 13:31:17 +00:00
whitequark 55baaf310f Implement a platform abstraction for menus.
This commit removes a large amount of redundant code that needed
to be kept in sync between platforms and also makes it much easier
to add new menu-related functionality since little to no platform
code needs to be altered anymore.

This commit also greatly improves code locality in context menu
handling by allowing context menu click handlers to be closures.

This commit temporarily introduces a SetMainMenu API, which is rather
hacky but only necessary until an abstraction for windows is added.
2018-07-16 11:21:30 +00:00
whitequark 7ab87caa88 Implement a platform abstraction for timers.
This commit temporarily disables tooltip functionality; it will
be handled natively in a platform abstraction for windows using
much simpler code.
2018-07-16 11:21:30 +00:00
EvilSpirit a16c204304 Allow using m (in addition to mm and inch) as base unit. 2018-07-12 12:01:46 +00:00
EvilSpirit 99f6ea34f1 Add an option to display areas of closed contours.
This is useful e.g. for architectural work.
2017-04-08 16:43:06 +00:00
EvilSpirit 5744d1d599 Implement an image request. 2017-03-12 00:13:56 +00:00
whitequark e2e74762f4 Rework path and file operations to be more robust.
This commit updates a *lot* of rather questionable path handling
logic to be robust. Specifically:
  * All path operations go through Platform::Path.
  * All ad-hoc path handling functions are removed, together with
    PATH_SEP. This removes code that was in platform-independent
    parts, but had platform-dependent behavior.
  * Group::linkFileRel is removed; only an absolute path is stored
    in Group::linkFile. However, only Group::linkFileRel is saved,
    with the relative path calculated on the fly, from the filename
    passed into SaveToFile. This eliminates dependence on global
    state, and makes it unnecessary to have separare code paths
    for saved and not yet saved files.
  * In a departure from previous practice, functions with
    platform-independent code but platform-dependent behavior
    are all grouped under platform/. This makes it easy to grep
    for functions with platform-dependent behavior.
  * Similarly, new (GUI-independent) code for all platforms is added
    in the same platform.cpp file, guarded with #ifs. It turns out
    that implementations for different platforms had a lot of shared
    code that tended to go out of sync.
2017-03-11 18:58:53 +00:00
EvilSpirit db75e06ecc Add a command to show center of mass, assuming uniform density. 2017-01-19 08:54:11 +00:00
whitequark 984f74d271 Internationalize all messages without substitutions. 2017-01-07 06:47:40 +00:00
whitequark 529e1bfd63 Internationalize the main menu. 2017-01-05 12:17:09 +00:00
Evil-Spirit d99a133982 Do ScheduleGenerateAll in MarkGroupDirty.
This generally simplifies code, and also fixes a bug where adding
a datum point would not regenerate the sketch.
2016-12-26 07:58:00 +00:00
EvilSpirit dbc567ed89 Reload linked files before upgrading legacy data.
Before this commit, if constraints with newly introduced params were
loaded from a file that linked other files, the upgrade code would
attempt to look up a non-existent entity.
2016-11-28 16:58:31 +00:00
whitequark 802d092b13 When exporting files, initially fill in the basename of the sketch.
This is a common and convenient behavior; the basename is
pre-selected, so exporting multiple views requires just one keystroke
to put the cursor after the basename.
2016-11-17 12:54:02 +00:00
Elvira Khabirova 489ae66e96 Fix crash when trying to import not .dxf or .dwg files 2016-11-17 06:52:12 +00:00
Evil-Spirit fdd08cbead Warn if exporting a non-watertight mesh.
If a generated mesh is non-watertight, and this is not noticed for
some reason (e.g. the markers are dismissed), and the mesh is
exported for further processing, it could cause problems down
the line.
2016-11-17 00:53:28 +00:00
EvilSpirit 600c39db91 Don't consider arc center point for bounding box calculation. 2016-11-02 02:40:26 +00:00
whitequark ea52fcbce1 Remove unnecessary GenerateAll/ZoomToFit calls in AfterNewFile.
These were useful before because chord tolerance depended on the zoom
level; and so the first generation produced a crude mesh used to
set the zoom level, and the second actually did useful work.
Chord tolerance is now independent of the zoom level, so this code
is no longer useful.
2016-10-12 23:34:02 +00:00
whitequark 476860acbb Normalize the string returned by Extension() to lowercase.
This would otherwise break code that branches on the extension,
such as that after 06a188cc.
2016-10-10 20:34:11 +00:00
whitequark a8e723381c Replace convenience #defines with const auto references.
These are nicer as they are scoped, and so it's clear where they
can be used.
2016-10-10 12:34:10 +00:00
whitequark ff23a4a471 Implement Analyze → Measure Perimeter. 2016-08-01 14:02:39 +00:00
whitequark 5e63d8301e Add a simple harness for automated, headless testing.
This commit alters the build system substantially; it adds another
platform, `headless`, that provides stubs in place of all GUI
functions, and provides a library `solvespace_headless` alongside
the main executable. To cut down build times, only the few files
that have #if defined(HEADLESS) are built twice for the executable
and the library; the rest is grouped into a new `solvespace_cad`
library. It is not usable on its own and just serves for grouping.

This commit also gates the tests behind a -DENABLE_TESTS=ON CMake
option, ON by default (but suggested as OFF in the README so that
people don't ever have to install cairo to build the executable.)

The tests introduced in this commit are (so far) rudimentary,
although functional, and they serve as a stepping point towards
introducing coverage analysis.
2016-08-01 00:48:37 +00:00
whitequark 51f4f27b2b Do not remove autosave after successfully opening file.
If SolveSpace crashes after the open, or hangs and is forcibly
killed, data would be lost. (I lost my data.) Instead, remove
autosave only in two cases: right after a successful save, or right
after a save is declined. This should be completely safe.
2016-06-23 03:00:50 +00:00
EvilSpirit 5791310bb1 Annotate constants passed as boolean function arguments.
This is to ensure that:
  * it is clear, when looking at the point of usage, what is
    the purpose of "true" or "false";
  * when refactoring, a simple search will bring up any places that
    need to be changed.

Also, argument names were synchronized between declaration and
implementation.

As an exception, these are not annotated:
  * Printf(/*halfLine=*/), to avoid pointless churn.
2016-05-26 12:43:52 +00:00
whitequark 1249f8496e Enable exhaustive switch coverage warnings as an error, and use them.
Specifically, this enables -Wswitch=error on GCC/Clang and its MSVC
equivalent; the exact way it is handled varies slightly, but what
they all have in common is that in a switch statement over an
enumeration, any enumerand that is not explicitly (via case:) or
implicitly (via default:) handled in the switch triggers an error.

Moreover, we also change the switch statements in three ways:

  * Switch statements that ought to be extended every time a new
    enumerand is added (e.g. Entity::DrawOrGetDistance(), are changed
    to explicitly list every single enumerand, and not have a
    default: branch.

    Note that the assertions are kept because it is legal for
    a enumeration to have a value unlike any of its defined
    enumerands, and we can e.g. read garbage from a file, or
    an uninitialized variable. This requires some rearranging if
    a default: branch is undesired.

  * Switch statements that ought to only ever see a few select
    enumerands, are changed to always assert in the default: branch.

  * Switch statements that do something meaningful for a few
    enumerands, and ignore everything else, are changed to do nothing
    in a default: branch, under the assumption that changing them
    every time an enumerand is added or removed would just result
    in noise and catch no bugs.

This commit also removes the {Request,Entity,Constraint}::UNKNOWN and
Entity::DATUM_POINT enumerands, as those were just fancy names for
zeroes. They mess up switch exhaustiveness checks and most of the time
were not the best way to implement what they did anyway.
2016-05-26 12:43:52 +00:00
EvilSpirit f33ddc94fb Convert all enumerations to use `enum class`.
Specifically, take the old code that looks like this:

  class Foo {
    enum { X = 1, Y = 2 };
    int kind;
  }
  ... foo.kind = Foo::X; ...

and convert it to this:

  class Foo {
    enum class Kind : uint32_t { X = 1, Y = 2 };
    Kind kind;
  }
  ... foo.kind = Foo::Kind::X;

(In some cases the enumeration would not be in the class namespace,
such as when it is generally useful.)

The benefits are as follows:
  * The type of the field gives a clear indication of intent, both
    to humans and tools (such as binding generators).
  * The compiler is able to automatically warn when a switch is not
    exhaustive; but this is currently suppressed by the
      default: ssassert(false, ...)
    idiom.
  * Integers and plain enums are weakly type checked: they implicitly
    convert into each other. This can hide bugs where type conversion
    is performed but not intended. Enum classes are strongly type
    checked.
  * Plain enums pollute parent namespaces; enum classes do not.
    Almost every defined enum we have already has a kind of ad-hoc
    namespacing via `NAMESPACE_`, which is now explicit.
  * Plain enums do not have a well-defined ABI size, which is
    important for bindings. Enum classes can have it, if specified.
    We specify the base type for all enums as uint32_t, which is
    a safe choice and allows us to not change the numeric values
    of any variants.

This commit introduces absolutely no functional change to the code,
just renaming and change of types. It handles almost all cases,
except GraphicsWindow::pending.operation, which needs minor
functional change.
2016-05-25 07:17:14 +00:00
whitequark ddc0dd7194 Reimplement e129755d properly.
Before this commit, quitting through menu would bring up the dialog
twice when declining to save the file.
2016-05-25 03:22:54 +00:00
EvilSpirit bbca4cc224 Rewrite declarations of form f(void) as f().
In C++ there is no difference and newly added functions are all
declared as f(), so this brings back consistency.
2016-05-20 12:43:20 +00:00
whitequark ad4a204edf Replace all oops() checks with ssassert()s.
This includes explanation and context for non-obvious cases and
shortens debug cycles when just-in-time debugging is not available
(like on Linux) by immediately printing description of the assert
as well as symbolized backtrace.
2016-05-20 12:38:30 +00:00
whitequark f4c01f670c Implement a resource system.
Currently, icons, fonts, etc are converted to C structures at compile
time and are hardcoded to the binary. This presents several problems:

  * Cross-compilation is complicated. Right now, it is necessary
    to be able to run executables for the target platform; this
    happens to work with wine-binfmt installed, but is rather ugly.

  * Icons can only have one resolution. On OS X, modern software is
    expected to take advantage of high-DPI ("Retina") screens and
    use so-called @2x assets when ran in high-DPI mode.

  * Localization is complicated. Win32 and OS X provide built-in
    support for loading the resource appropriate for the user's
    locale.

  * Embedding strings can only be done as raw strings, using C++'s
    R"(...)" literals. This precludes embedding sizable strings,
    e.g. JavaScript libraries as used in Three.js export, and makes
    git history less useful. Not embedding the libraries means we
    have to rely on external CDNs, which requires an Internet
    connection and adds a glaring point of failure.

  * Linux distribution guidelines are violated. All architecture-
    independent data, especially large data such as fonts, is
    expected to be in /usr/share, not in the binary.

  * Customization is impossible without recompilation. Minor
    modifications like adding a few missing vector font characters
    or adjusting localization require a complete development
    environment, which is unreasonable to expect from users of
    a mechanical CAD.

As such, this commit adds a resource system that bundles (and
sometimes builds) resources with the executable. Where they go is
platform-dependent:

  * on Win32: into resources of the executable, which allows us to
    keep distributing one file;
  * on OS X: into the app bundle;
  * on other *nix: into /usr/share/solvespace/ or ../res/ (relative
    to the executable path), the latter allowing us to run freshly
    built executables without installation.

It also subsides the platform-specific resources that are in src/.

The resource system is not yet used for anything; this will be added
in later commits.
2016-05-18 11:24:23 +00:00
whitequark e129755d66 Offer to save file when closing if it is unsaved. 2016-05-11 07:43:04 +00:00
whitequark 4a8675c120 DXF: regenerate after importing.
Without this, some freshly imported entities appear with incorrect
styles.
2016-05-09 12:43:52 +00:00
whitequark febe0f5282 Rename the old "Import / Assemble" feature to "Link / Assemble".
This better reflects what it does and avoids clashes with the new
DXF import feature.
2016-05-07 05:27:54 +00:00
whitequark d05e9a938b DWG: implement import.
Before this commit, the file filter suggested that DWG was readable,
but it wasn't.

Also, report any failures while reading DWG and DXF files.
2016-05-07 05:17:23 +00:00
EvilSpirit 70d84b30e8 DXF: implement import. 2016-05-07 04:02:34 +00:00
whitequark e61bac2797 Refactor file filters to not use preprocessor magic.
The immediate reason for refactoring this was that the GTK port broke
after 52af7256 since config.h is not included anymore, but it was
a fragile piece of code I will shed no tears for.

While we're at it, get rid of the mutable std::string &file to be
consistent with our conventions.
2016-05-04 03:21:12 +00:00
whitequark 52af725606 Only #include "config.h" when we need something from it.
config.h now includes the git hash and so, as long as it's included
in solvespace.h, any change of git HEAD will trigger a complete
recompilation, which makes bisecting especially annoying.

While we're at it, remove HAVE_STDINT_H from it, since we require
C++11 and all MSVC versions that include C++11 also include stdint.h.
2016-04-23 23:06:31 +00:00
whitequark 2fed0587ea Embed git commit hash in the "About" dialog.
Also, remove usage of __DATE__ and __TIME__ to make the build fully
deterministic. They are redundant once we have the commit hash,
anyway.
2016-04-23 22:53:21 +00:00
whitequark 1098e598ae Quit export mode after new file. 2016-04-16 09:05:21 +00:00
whitequark 2d25bdb51f When choosing color for a new group, consider active, not last, group. 2016-04-15 06:11:03 +00:00
EvilSpirit 55e3162a05 When creating a new group, use the color of last requested solid. 2016-04-08 11:21:40 +00:00
whitequark c9648805ea Allow generating groups in arbitrary order. 2016-02-19 10:23:24 +00:00
whitequark bdd02ac3a8 Fix usage of uninitialized BBox. 2016-02-19 10:23:24 +00:00
whitequark 5c15cbf5f6 Remove extraneous instances of .c_str().
Most of these were just converting char* into std::string back and
forth; some more used ReadUTF8, which was converted to use nicer
STL-style iterators over UTF-8 text.

The remaining ones are:
  * arguments to Expr::From, which we'll change when refactoring
    the expression lexer;
  * arguments to varargs functions, which we'll change when adding
    localization (that requires custom printf-style functions to
    allow for changing argument order);
  * arguments where only string literals are ever passed, which
    are OK;
  * in platform-specific code, which is OK.
2016-02-19 10:22:53 +00:00
EvilSpirit 34a5d87011 Use relative chord tolerance instead of absolute.
Commit 89eb208 has improved the overall situation with chord
tolerance, but it changed the display chord tolerance to use
an absolute value in millimeters as a stopgap measure.

This commit changes the display chord tolerance to be specified
in percents of entity bounding box instead of millimeters.
As a result, the linearized curves are both zoom level and sketch
scale independent.

In order to compute the bounding box, all entities are generated
twice. However, this shouldn't result in a noticeable slowdown,
since the bounding box calculation does not need the expensive
triangle mesh generation and the solver will converge immediately
on the second run.

Since the meaning of the preference has changed, a new name is
used (ChordTolerancePct instead of ChordTolerance), so that it
would be reset to the default value after updating SolveSpace.

The default value, 0.5%, was selected using trial and error by
judging whether cylinders of moderate dimensions were looking
aesthetically pleasing enough.

After this change, the only real function of the spacebar
shortcut is to reload imported groups, since manual regeneration
should not change anything anymore unless there is a bug.
2016-02-13 16:16:56 +00:00
EvilSpirit fc68804f65 Add BBox class for calculating entity bounding boxes. 2016-02-13 16:16:47 +00:00
EvilSpirit 89eb208660 Use a separate value of chord tolerance for exporting.
Before this commit, a single chord tolerance was used for both
displaying and exporting geometry. Moreover, this chord tolerance
was specified in screen pixels, and as such depended on zoom level.
This was inconvenient: exporting geometry with a required level of
precision required awkward manipulations of viewport. Moreover,
since some operations, e.g. mesh watertightness checking, were done
on triangle meshes which are generated differently depending on
the zoom level, these operations could report wildly different
and quite confusing results depending on zoom level.

The chord tolerance for display and export pursue completely distinct
goals: display chord tolerance should be set high enough to achieve
both fast regeneration and legible rendering, whereas export chord
tolerance should be set to match the dimension tolerance of
the fabrication process.

This commit introduces two distinct chord tolerances: a display
and an export one. Both chord tolerances are absolute and expressed
in millimeters; this is inappropriate for display purposes but
will be fixed in the next commits.

After exporting, the geometry is redrawn with the chord tolerance
configured for the export and an overlay message is displayed;
pressing Esc clears the message and returns the display back to
normal.
2016-02-13 16:16:47 +00:00
EvilSpirit b28fa34e4a Use an enum to select the mode of operation for GenerateAll. 2016-01-27 09:19:37 +00:00