diff --git a/BUILDING.md b/BUILDING.md index 5359268f..109ad97a 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1,11 +1,14 @@ Requirements ------------ -- [Qt 5.4](http://www.qt.io/) +- [Qt 5.4 or later](http://www.qt.io/) - [Python 3](https://www.python.org/) - [Boost.Python](http://www.boost.org/doc/libs/1_57_0/libs/python/doc/index.html) (linked against Python 3) - [`libpng`](http://www.libpng.org/pub/png/libpng.html) - [Lemon](http://www.hwaci.com/sw/lemon/) - [Flex](http://flex.sourceforge.net) +- [ninja](https://ninja-build.org/) (recommended) + +-------------------------------------------------------------------------------- Mac OS X -------- @@ -17,32 +20,22 @@ brew install --with-python3 boost-python brew install qt5 brew install lemon brew install flex +brew install ninja +brew install cmake git clone https://github.com/mkeeter/antimony cd antimony mkdir build cd build -/usr/local/Cellar/qt5/5.*/bin/qmake ../sb.pro -make -j8 -open app/Antimony.app -``` -### Troubleshooting -If you have installed Homebrew in a non-standard directory like `~/.homebrew` -(the default is `/usr/local`), you'll need to provide a path to your Homebrew -files: -``` -export BREW_HOME=/Users/yourusername/.homebrew +cmake -DCMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.6.1 -GNinja .. +ninja -$BREW_HOME/Cellar/qt5/5.*/bin/qmake ../qt/antimony.pro -make -j8 +open app/Antimony.app ``` -If you need to further adjust your library paths, Mac specific settings -can be found in `qt/libpng.pri` and `qt/python.pri` - -Note: If `make -j8` exits with an "Error 2" just run `make -j8` again to succeed. +-------------------------------------------------------------------------------- Linux ----- @@ -50,7 +43,7 @@ Tested on a clean Xubuntu 16.04 virtual machine: ``` # Install dependencies -sudo apt install git build-essential libpng-dev python3-dev libboost-all-dev libgl1-mesa-dev lemon flex qt5-default +sudo apt install git build-essential libpng-dev python3-dev libboost-all-dev libgl1-mesa-dev lemon flex qt5-default ninja-build cmake # Clone the repo git clone https://github.com/mkeeter/antimony @@ -61,32 +54,23 @@ mkdir build cd build # Build and launch the application -qmake ../sb.pro -make -j8 -./app/Antimony -``` - -You can use `make install`, or set up a symlink to run `antimony` from outside the build directory: -``` -ln -s ~/antimony/build/app/antimony /usr/local/bin/antimony +cmake -GNinja .. +ninja +./app/antimony ``` -### Caveats - -The path to `qmake` may vary depending on how Qt 5 was installed; if the instructions don't work, try -``` -~/Qt/5.4/gcc_64/bin/qmake ../sb.pro -``` - --------------------------------------------------------------------------------- +To put Antimony on your path, call `sudo ninja install`. This does two things: +- The `antimony` executable is copied to `/usr/local/bin` +- Antimony's Python libraries are copied to `/usr/local/share/antimony` +## Debugging +### `cannot find -lGL` If running `make` gives the `/usr/bin/ld: cannot find -lGL`, create a symlink to the `libGL` file: ``` ln -s /usr/lib/x86_64-linux-gnu/mesa/libGL.so.1.2.0 /usr/lib/libGL.so ``` --------------------------------------------------------------------------------- - +### Missing top menu If the top menu bar is not appearing in Ubuntu with a non-Unity desktop environment (e.g. `gnome-session-flashback`), run ``` diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..4aada8d7 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 2.6) +project(Antimony) +set(CMAKE_BUILD_TYPE RELEASE) + +set(CMAKE_CXX_FLAGS "-Wall -Wextra -g -Werror=switch") +set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DRELEASE") +set(CMAKE_CXX_FLAGS_DEBUG "-O0") + +################################################################################ + +find_package(PythonLibs 3.3 REQUIRED) + +if (APPLE) + find_package(Boost REQUIRED COMPONENTS python3) +elseif (UNIX) + foreach (PYTHON_NAME python3 python-py35 python-py34) + find_package(Boost QUIET COMPONENTS ${PYTHON_NAME}) + if (${Boost_FOUND}) + break() + endif() + endforeach() + if (NOT ${Boost_FOUND}) + message(FATAL_ERROR "Could not find boost::python3") + endif() +endif() + +################################################################################ + +add_subdirectory(lib/graph) +add_subdirectory(lib/fab) + +add_subdirectory(app) diff --git a/README.md b/README.md index 51010e20..ab8c7242 100644 --- a/README.md +++ b/README.md @@ -11,15 +11,15 @@ For more details and screenshots, look at [this writeup](http://mattkeeter.com/p *Antimony* is under active development. It's at a beta level of stability: solid, but not recommended for mission-critical use. -If you're on a Mac, you can download a [pre-built application](https://github.com/mkeeter/antimony/releases) -and get started immediately. +To get started, there are two suggested options: +- Download a [pre-built application](https://github.com/mkeeter/antimony/releases) (Mac only) +- [Build from source](https://github.com/mkeeter/antimony/blob/develop/BUILDING.md) (Mac and Linux) -Antimony has also been [packaged for Fedora 22/23](https://admin.fedoraproject.org/pkgdb/package/antimony/): +There is also a community-supported package for [Fedora 22 or later](https://admin.fedoraproject.org/pkgdb/package/antimony/): ``` -dnf install antimony --enablerepo=updates-testing +dnf install antimony ``` - -Otherwise, please refer to the [build instructions](https://github.com/mkeeter/antimony/blob/develop/BUILDING.md). +(or `dnf install antimony --enablerepo=updates-testing` to get testing builds) ## Support diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt new file mode 100644 index 00000000..ddc5c9b4 --- /dev/null +++ b/app/CMakeLists.txt @@ -0,0 +1,186 @@ +# Instruct CMake to run moc, uic, and rrc automatically when needed. +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) + +# Make the build directory an include target (for generated moc_ files) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +# Find the Qt libraries +find_package(Qt5Core REQUIRED) +find_package(Qt5Widgets REQUIRED) +find_package(Qt5OpenGL REQUIRED) +find_package(Qt5Network REQUIRED) +find_package(Qt5Concurrent REQUIRED) + +set(SRC_FILES + app/main.cpp + app/app.cpp + app/update.cpp + app/colors.cpp + canvas/scene.cpp + canvas/canvas_view.cpp + canvas/info.cpp + canvas/inspector/frame.cpp + canvas/inspector/export.cpp + canvas/inspector/title.cpp + canvas/inspector/buttons.cpp + canvas/inspector/util.cpp + canvas/datum_row.cpp + canvas/datum_editor.cpp + canvas/datum_port.cpp + canvas/subdatum/subdatum_frame.cpp + canvas/subdatum/subdatum_editor.cpp + canvas/subdatum/subdatum_row.cpp + canvas/connection/base.cpp + canvas/connection/connection.cpp + canvas/connection/dummy.cpp + window/base.cpp + window/canvas.cpp + window/viewport.cpp + window/quad.cpp + window/base_viewport_window.cpp + window/script_window.cpp + graph/constructor/populate.cpp + graph/proxy/graph.cpp + graph/proxy/node.cpp + graph/proxy/script.cpp + graph/proxy/datum.cpp + graph/proxy/subdatum.cpp + graph/proxy/base_datum.cpp + graph/hooks/hooks.cpp + graph/hooks/export.cpp + graph/hooks/ui.cpp + graph/hooks/title.cpp + graph/serialize/serializer.cpp + graph/serialize/deserializer.cpp + script/syntax.cpp + script/editor.cpp + script/frame.cpp + undo/undo_command.cpp + undo/undo_add_node.cpp + undo/undo_add_datum.cpp + undo/undo_delete_datum.cpp + undo/undo_delete_multi.cpp + undo/undo_delete_node.cpp + undo/undo_delete_link.cpp + undo/undo_move_node.cpp + undo/undo_move_datum.cpp + undo/undo_change_script.cpp + undo/undo_change_expr.cpp + undo/undo_stack.cpp + dialog/exporting.cpp + dialog/resolution.cpp + export/export_mesh.cpp + export/export_heightmap.cpp + export/export_worker.cpp + viewport/scene.cpp + viewport/gl.cpp + viewport/view.cpp + viewport/image.cpp + viewport/control/control.cpp + viewport/control/control_instance.cpp + viewport/control/point.cpp + viewport/control/wireframe.cpp + viewport/render/instance.cpp + viewport/render/task.cpp + + gl/gl.qrc +) + +set(PY_FAB_FILES + ../py/fab/__init__.py + ../py/fab/shapes.py + ../py/fab/types.py +) + +if (APPLE) + set(ANTIMONY_APP Antimony) + set(CMAKE_MACOSX_RPATH ON) + + # Add the icon file and deploy it to Resources + set(SB_ICON ../deploy/mac/sb.icns) + set_source_files_properties(${SB_ICON} + PROPERTIES MACOSX_PACKAGE_LOCATION "Resources" + ) + + # Deploy fab module's files into Resources/fab + set_source_files_properties(${PY_FAB_FILES} + PROPERTIES MACOSX_PACKAGE_LOCATION "Resources/fab" + ) + + add_executable(${ANTIMONY_APP} MACOSX_BUNDLE + ${SRC_FILES} + ${SB_ICON} + ${PY_FAB_FILES} + ) + + # Set application Info.plist file + set_target_properties(${ANTIMONY_APP} PROPERTIES + MACOSX_BUNDLE_INFO_PLIST ../deploy/mac/Info.plist + ) + + # Copy node directory into application bundle + add_custom_command(TARGET ${ANTIMONY_APP} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/py/nodes + ${CMAKE_CURRENT_BINARY_DIR}/${ANTIMONY_APP}.app/Contents/Resources/nodes) +else() + set(ANTIMONY_APP antimony) + add_executable(${ANTIMONY_APP} ${SRC_FILES}) + + # Copy node and fab directory into build directory + add_custom_command(TARGET ${ANTIMONY_APP} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/py/nodes + ${CMAKE_CURRENT_BINARY_DIR}/sb/nodes) + add_custom_command(TARGET ${ANTIMONY_APP} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/py/fab + ${CMAKE_CURRENT_BINARY_DIR}/sb/fab) + + install(TARGETS antimony + DESTINATION /usr/local/bin) + install(DIRECTORY ../py/nodes + DESTINATION /usr/local/share/antimony) + install(DIRECTORY ../py/fab + DESTINATION /usr/local/share/antimony) +endif() + +target_link_libraries(${ANTIMONY_APP} + Qt5::Widgets + Qt5::Gui + Qt5::OpenGL + Qt5::Network + Qt5::Concurrent + SbGraph + SbFab) + +################################################################################ + +execute_process(COMMAND git log --pretty=format:'%h' -n 1 + OUTPUT_VARIABLE GITREV) +execute_process(COMMAND bash -c "git diff --quiet --exit-code || echo +" + OUTPUT_VARIABLE GITDIFF) +execute_process(COMMAND git describe --exact-match --tags + OUTPUT_VARIABLE GITTAG + ERROR_QUIET) +execute_process(COMMAND git rev-parse --abbrev-ref HEAD + OUTPUT_VARIABLE GITBRANCH) + +add_definitions(-D'GITREV="${GITREV}${GITDIFF}"' + -D'GITTAG="${GITTAG}"' + -D'GITBRANCH="${GITBRANCH}"') + +################################################################################ + +target_include_directories(${ANTIMONY_APP} SYSTEM PRIVATE + ${PYTHON_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${AUTOGEN_TARGETS_FOLDER} +) + +################################################################################ + +set_property(TARGET ${ANTIMONY_APP} PROPERTY CXX_STANDARD 11) + diff --git a/app/app.pro b/app/app.pro deleted file mode 100644 index b5f928ba..00000000 --- a/app/app.pro +++ /dev/null @@ -1,221 +0,0 @@ -QT += core gui widgets opengl network concurrent - -CONFIG += object_parallel_to_source - -TARGET = Antimony -TEMPLATE = app - -LIBS += -L../lib/fab -lSbFab -L../lib/graph -lSbGraph -INCLUDEPATH += ../lib/fab/inc -INCLUDEPATH += ../lib/graph/inc - -PRE_TARGETDEPS += ../lib/graph/libSbGraph.a -PRE_TARGETDEPS += ../lib/fab/libSbFab.a - -include(../qt/common.pri) -include(../qt/python.pri) -include(../qt/libpng.pri) - -################################################################################ - -# Copy the py/fab and py/nodes directory when building the application -make_sb.commands = $(MKDIR) $$OUT_PWD/sb -copy_nodes.commands = $(COPY_DIR) $$PWD/../py/nodes $$OUT_PWD/sb -copy_fab.commands = $(COPY_DIR) $$PWD/../py/fab $$OUT_PWD/sb -first.depends = $(first) make_sb copy_nodes copy_fab -QMAKE_EXTRA_TARGETS += first make_sb copy_nodes copy_fab - -################################################################################ - -# Extract the git revision, tag, and branch, then populate them -# into various preprocessor macros to populate the About box. -GITREV = $$system(git log --pretty=format:'%h' -n 1) -GITDIFF = $$system(git diff --quiet --exit-code || echo "+") -GITTAG = $$system(git describe --exact-match --tags 2> /dev/null) -GITBRANCH = $$system(git rev-parse --abbrev-ref HEAD) - -QMAKE_CXXFLAGS += "-D'GITREV=\"$${GITREV}$${GITDIFF}\"'" -QMAKE_CXXFLAGS += "-D'GITTAG=\"$${GITTAG}\"'" -QMAKE_CXXFLAGS += "-D'GITBRANCH=\"$${GITBRANCH}\"'" - -QMAKE_CXXFLAGS += "-g -O0" - -################################################################################ - -# Details for Mac applications -macx { - # Normally you would deploy an icon and a .plist file by setting - # QMAKE_INFO_PLIST and ICON, but qmake doesn't work properly when - # the build directory and .pro file are at different levels (QTBUG-46133). - QMAKE_POST_LINK += $(COPY) $$PWD/../deploy/mac/Info.plist $$OUT_PWD/$${TARGET}.app/Contents; - QMAKE_POST_LINK += $(COPY) $$PWD/../deploy/mac/sb.icns $$OUT_PWD/$${TARGET}.app/Contents/Resources; -} - -################################################################################ - -# Installation details for Linux systems -linux { - # Rename file from "Antimony" to "antimony" - QMAKE_POST_LINK += $(MOVE) $$OUT_PWD/$${TARGET} $$OUT_PWD/$$lower($${TARGET}) - - executable.path = /usr/local/bin - executable.files = antimony - nodes_folder.path = /usr/local/bin/sb/nodes - nodes_folder.files = ../py/nodes/* - fab_folder.path = /usr/local/bin/sb/fab - fab_folder.files = ../py/fab/* - INSTALLS += executable nodes_folder fab_folder -} - -################################################################################ - -SOURCES += \ - app/main.cpp \ - app/app.cpp \ - app/update.cpp \ - app/colors.cpp \ - canvas/scene.cpp \ - canvas/canvas_view.cpp \ - canvas/info.cpp \ - canvas/inspector/frame.cpp \ - canvas/inspector/export.cpp \ - canvas/inspector/title.cpp \ - canvas/inspector/buttons.cpp \ - canvas/inspector/util.cpp \ - canvas/datum_row.cpp \ - canvas/datum_editor.cpp \ - canvas/datum_port.cpp \ - canvas/subdatum/subdatum_frame.cpp \ - canvas/subdatum/subdatum_editor.cpp \ - canvas/subdatum/subdatum_row.cpp \ - canvas/connection/base.cpp \ - canvas/connection/connection.cpp \ - canvas/connection/dummy.cpp \ - window/base.cpp \ - window/canvas.cpp \ - window/viewport.cpp \ - window/quad.cpp \ - window/base_viewport_window.cpp \ - window/script_window.cpp \ - graph/constructor/populate.cpp \ - graph/proxy/graph.cpp \ - graph/proxy/node.cpp \ - graph/proxy/script.cpp \ - graph/proxy/datum.cpp \ - graph/proxy/subdatum.cpp \ - graph/proxy/base_datum.cpp \ - graph/hooks/hooks.cpp \ - graph/hooks/export.cpp \ - graph/hooks/ui.cpp \ - graph/hooks/title.cpp \ - graph/serialize/serializer.cpp \ - graph/serialize/deserializer.cpp \ - script/syntax.cpp \ - script/editor.cpp \ - script/frame.cpp \ - undo/undo_command.cpp \ - undo/undo_add_node.cpp \ - undo/undo_add_datum.cpp \ - undo/undo_delete_datum.cpp \ - undo/undo_delete_multi.cpp \ - undo/undo_delete_node.cpp \ - undo/undo_delete_link.cpp \ - undo/undo_move_node.cpp \ - undo/undo_move_datum.cpp \ - undo/undo_change_script.cpp \ - undo/undo_change_expr.cpp \ - undo/undo_stack.cpp \ - dialog/exporting.cpp \ - dialog/resolution.cpp \ - export/export_mesh.cpp \ - export/export_heightmap.cpp \ - export/export_worker.cpp \ - viewport/scene.cpp \ - viewport/gl.cpp \ - viewport/view.cpp \ - viewport/image.cpp \ - viewport/control/control.cpp \ - viewport/control/control_instance.cpp \ - viewport/control/point.cpp \ - viewport/control/wireframe.cpp \ - viewport/render/instance.cpp \ - viewport/render/task.cpp \ - -HEADERS += \ - app/app.h \ - app/update.h \ - app/colors.h \ - canvas/scene.h \ - canvas/canvas_view.h \ - canvas/info.h \ - window/base.h \ - window/canvas.h \ - window/viewport.h \ - window/quad.h \ - window/base_viewport_window.h \ - window/script_window.h \ - canvas/inspector/frame.h \ - canvas/inspector/export.h \ - canvas/inspector/title.h \ - canvas/inspector/buttons.h \ - canvas/inspector/util.h \ - canvas/datum_row.h \ - canvas/datum_editor.h \ - canvas/datum_port.h \ - canvas/subdatum/subdatum_frame.h \ - canvas/subdatum/subdatum_editor.h \ - canvas/subdatum/subdatum_row.h \ - canvas/connection/base.h \ - canvas/connection/connection.h \ - canvas/connection/dummy.h \ - graph/constructor/populate.h \ - graph/proxy/graph.h \ - graph/proxy/node.h \ - graph/proxy/script.h \ - graph/proxy/datum.h \ - graph/proxy/subdatum.h \ - graph/proxy/base_datum.h \ - graph/hooks/hooks.h \ - graph/hooks/export.h \ - graph/hooks/title.h \ - graph/hooks/ui.cpp \ - graph/serialize/serializer.h \ - graph/serialize/deserializer.h \ - script/syntax.h \ - script/editor.h \ - script/frame.h \ - undo/undo_command.h \ - undo/undo_add_node.h \ - undo/undo_add_datum.h \ - undo/undo_delete_datum.h \ - undo/undo_delete_multi.h \ - undo/undo_delete_node.h \ - undo/undo_delete_link.h \ - undo/undo_move_node.h \ - undo/undo_move_datum.h \ - undo/undo_change_script.h \ - undo/undo_change_expr.h \ - undo/undo_stack.h \ - dialog/exporting.h \ - dialog/resolution.h \ - export/export_mesh.h \ - export/export_heightmap.h \ - export/export_worker.h \ - viewport/scene.h \ - viewport/view.h \ - viewport/image.h \ - viewport/gl.h \ - viewport/control/control.h \ - viewport/control/control_instance.h \ - viewport/control/point.h \ - viewport/control/wireframe.h \ - viewport/render/instance.h \ - viewport/render/task.h \ - -FORMS += \ - forms/base_window.ui \ - forms/resolution_dialog.ui \ - forms/exporting_dialog.ui \ - -RESOURCES += \ - gl/gl.qrc \ diff --git a/app/app/app.cpp b/app/app/app.cpp index 1da29f5b..7183adf5 100644 --- a/app/app/app.cpp +++ b/app/app/app.cpp @@ -48,31 +48,30 @@ void App::makeDefaultWindows() QString App::bundledNodePath() const { - auto path = applicationDirPath().split("/"); #if defined Q_OS_MAC - // On Mac, the 'nodes' folder should be either in - // Antimony.app/Contents/Resources/nodes (when deployed) - // or Antimony.app/../sb/nodes (when running from the build directory) + // On Mac, the 'nodes' folder must be at + // Antimony.app/Contents/Resources/nodes + auto path = applicationDirPath().split("/"); path.removeLast(); // Trim the MacOS folder from the path - - // When deployed, the nodes folder is in Resources/sb - if (QDir(path.join("/") + "/Resources/nodes").exists()) + return path.join("/") + "/Resources/nodes"; +#elif defined Q_OS_LINUX + // If we're running Antimony from the build folder, use sb/nodes + auto path = applicationDirPath() + "/sb/nodes"; + if (QDir(path).exists()) { - path << "Resources" << "nodes"; + return path; } - // Otherwise, assume it's at the same level as antimony.app + // Otherwise, assume nodes have been installed into + // /usr/local/share/antimony/nodes else { - for (int i=0; i < 2; ++i) - path.removeLast(); - path << "sb" << "nodes"; + return "/usr/local/share/antimony/nodes"; } #else - path << "sb" << "nodes"; +#error "Unknown OS!" #endif - return path.join("/"); } QString App::userNodePath() const diff --git a/app/app/app.h b/app/app/app.h index ceb7dfee..4352d603 100644 --- a/app/app/app.h +++ b/app/app/app.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include diff --git a/app/app/main.cpp b/app/app/main.cpp index c0542b5d..7295424e 100644 --- a/app/app/main.cpp +++ b/app/app/main.cpp @@ -30,16 +30,6 @@ int main(int argc, char *argv[]) // Create the Application object App app(argc, argv); -#if defined Q_OS_MAC - if (QCoreApplication::applicationDirPath().startsWith("/Volumes/")) - { - QMessageBox::critical(NULL, "Cannot run from disk image", - "Antimony cannot run from a disk image.\n" - "Please copy it out of the disk image and relaunch."); - exit(1); - } -#endif - // Initialize various Python modules and the interpreter itself fab::preInit(); Graph::preInit(); @@ -51,15 +41,19 @@ int main(int argc, char *argv[]) { // Modify Python's default search path to include the application's // directory (as this doesn't happen on Linux by default) - QString d = QCoreApplication::applicationDirPath(); #if defined Q_OS_MAC - QStringList path = d.split("/"); - for (int i=0; i < 3; ++i) - path.removeLast(); - d = path.join("/"); + QStringList path = QCoreApplication::applicationDirPath().split("/"); + path.removeLast(); + path << "Resources"; + fab::postInit({path.join("/").toStdString()}); +#elif defined Q_OS_LINUX + QCoreApplication::applicationDirPath() + "/sb"; + fab::postInit( + {(QCoreApplication::applicationDirPath() + "/sb").toStdString(), + "/usr/local/share/antimony"}); +#else +#error "Unknown OS!" #endif - d += "/sb"; - fab::postInit(d.toStdString().c_str()); } { // Install operator.or_ as a reducer for shapes diff --git a/app/canvas/canvas_view.h b/app/canvas/canvas_view.h index 769a4a44..ebea08d6 100644 --- a/app/canvas/canvas_view.h +++ b/app/canvas/canvas_view.h @@ -87,10 +87,10 @@ public slots: /* Properties used to animate zooming to a particular node */ QPointF getCenter() const; void setCenter(QPointF p); - Q_PROPERTY(QPointF _center READ getCenter WRITE setCenter); + Q_PROPERTY(QPointF _center READ getCenter WRITE setCenter) void setZoom(float z); float getZoom() const; - Q_PROPERTY(float _zoom READ getZoom WRITE setZoom); + Q_PROPERTY(float _zoom READ getZoom WRITE setZoom) QPointF click_pos; QPointF drag_pos; diff --git a/app/dialog/exporting.cpp b/app/dialog/exporting.cpp index b72c7a9f..5253ea5b 100644 --- a/app/dialog/exporting.cpp +++ b/app/dialog/exporting.cpp @@ -1,3 +1,4 @@ +// cmake doesn't find ui_exporting_dialog without this dummy line #include "ui_exporting_dialog.h" #include "dialog/exporting.h" diff --git a/app/forms/exporting_dialog.ui b/app/dialog/exporting_dialog.ui similarity index 100% rename from app/forms/exporting_dialog.ui rename to app/dialog/exporting_dialog.ui diff --git a/app/forms/resolution_dialog.ui b/app/dialog/resolution_dialog.ui similarity index 100% rename from app/forms/resolution_dialog.ui rename to app/dialog/resolution_dialog.ui diff --git a/app/graph/hooks/ui.cpp b/app/graph/hooks/ui.cpp index 896cf0d8..41f23f2f 100644 --- a/app/graph/hooks/ui.cpp +++ b/app/graph/hooks/ui.cpp @@ -271,30 +271,62 @@ QString ScriptUIHooks::getDatum(PyObject* obj) //////////////////////////////////////////////////////////////////////////////// -long ScriptUIHooks::getInstruction() +Py_hash_t ScriptUIHooks::getKey(dict kwargs, std::string type) { - // Get the current bytecode instruction - // (used to uniquely identify calls to this function) - auto inspect_module = PyImport_ImportModule("inspect"); - auto frame = PyObject_CallMethod(inspect_module, "currentframe", NULL); - auto f_lineno = PyObject_GetAttrString(frame, "f_lineno"); - long lineno = PyLong_AsLong(f_lineno); - Q_ASSERT(!PyErr_Occurred()); + Py_hash_t key = -1; - // Clean up these objects immediately - for (auto o : {inspect_module, frame, f_lineno}) + if (kwargs.has_key("key")) { - Py_DECREF(o); - } + auto key_str = PyObject_Str(extract(kwargs["key"])().ptr()); + if (!key_str) + { + throw AppHooks::Exception("Key must be convertable to a string."); + } + Py_XDECREF(key_str); + + auto prefix = PyUnicode_FromString(("__KEY__" + type).c_str()); + auto target = PyUnicode_Concat(prefix, key_str); - if (instructions.contains(lineno)) + key = PyObject_Hash(target); + Py_DECREF(prefix); + Py_DECREF(target); + + if (keys.contains(key)) + { + throw AppHooks::Exception( + "Collision with user-defined keys"); + } + } + else { - throw AppHooks::Exception( - "Cannot declare multiple UI elements on same line."); + // Get the current line and hash it + // (used to uniquely identify calls to this function) + auto inspect_module = PyImport_ImportModule("inspect"); + auto frame = PyObject_CallMethod(inspect_module, "currentframe", NULL); + auto f_lineno = PyObject_GetAttrString(frame, "f_lineno"); + auto f_lineno_str = PyObject_Str(f_lineno); + auto prefix = PyUnicode_FromString(("__LINE__" + type).c_str()); + auto target = PyUnicode_Concat(prefix, f_lineno_str); + key = PyObject_Hash(target); + Q_ASSERT(!PyErr_Occurred()); + + // Clean up PyObjects immediately + for (auto o : {inspect_module, frame, f_lineno, + f_lineno_str, prefix, target}) + { + Py_DECREF(o); + } + + if (keys.contains(key)) + { + throw AppHooks::Exception( + "Cannot declare multiple UI elements on same line " + "(without unique keys)"); + } } - instructions.insert(lineno); - return lineno; + keys.insert(key); + return key; } //////////////////////////////////////////////////////////////////////////////// @@ -305,7 +337,7 @@ object ScriptUIHooks::wireframe(tuple args, dict kwargs) // Find the instruction at which this callback happened // (used as a unique identifier for the Control). - long lineno = self.getInstruction(); + Py_hash_t key = self.getKey(kwargs, "wireframe"); if (len(args) != 2) { @@ -319,12 +351,12 @@ object ScriptUIHooks::wireframe(tuple args, dict kwargs) } WireframeControl* w = dynamic_cast( - self.proxy->getControl(lineno)); + self.proxy->getControl(key)); if (!w) { w = new WireframeControl(self.proxy); - self.proxy->registerControl(lineno, w); + self.proxy->registerControl(key, w); } PyObject* drag_func = self.getDragFunction(kwargs); @@ -352,7 +384,7 @@ object ScriptUIHooks::point(tuple args, dict kwargs) // Find the instruction at which this callback happened // (used as a unique identifier for the Control). - long lineno = self.getInstruction(); + Py_hash_t key = self.getKey(kwargs, "point"); if (len(args) != 4 && len(args) != 3) { @@ -386,11 +418,11 @@ object ScriptUIHooks::point(tuple args, dict kwargs) } PointControl* p = dynamic_cast( - self.proxy->getControl(lineno)); + self.proxy->getControl(key)); if (!p) { p = new PointControl(self.proxy); - self.proxy->registerControl(lineno, p); + self.proxy->registerControl(key, p); } const float r = getFloat(p->r, kwargs, "r"); diff --git a/app/graph/hooks/ui.h b/app/graph/hooks/ui.h index b4505f05..c758c7f3 100644 --- a/app/graph/hooks/ui.h +++ b/app/graph/hooks/ui.h @@ -11,10 +11,12 @@ class NodeProxy; struct ScriptUIHooks { /* - * Returns the line number at which this function was called. - * Throws HookException if the line number has been seen already. + * If kwargs['key'] is a value, hash it + type and return that result + * Otherwise, return a hash based on the line number + type + * + * Throws HookException if the key has been seen already */ - long getInstruction(); + Py_hash_t getKey(boost::python::dict kwargs, std::string type); /* * Returns a drag function from a kwargs dictionary @@ -44,8 +46,8 @@ struct ScriptUIHooks */ QString getDatum(PyObject* obj); - /* Set of instructions used to uniquely identify Controls */ - QSet instructions; + /* Set of keys used to uniquely identify Controls */ + QSet keys; /* Pointer to proxy node */ NodeProxy* proxy=nullptr; diff --git a/app/viewport/control/control.h b/app/viewport/control/control.h index 40f1050f..154b3cdb 100644 --- a/app/viewport/control/control.h +++ b/app/viewport/control/control.h @@ -55,6 +55,11 @@ Q_OBJECT */ void setDragFunc(PyObject* new_drag_func); + /* + * Returns true if the given control has a drag function + */ + bool hasDragFunc() const { return drag_func; } + /* * Drags the node around using the Python drag_func */ diff --git a/app/viewport/control/control_instance.cpp b/app/viewport/control/control_instance.cpp index f08f1e8f..03f24f81 100644 --- a/app/viewport/control/control_instance.cpp +++ b/app/viewport/control/control_instance.cpp @@ -12,10 +12,11 @@ ControlInstance::ControlInstance(Control* c, ViewportView* v) : control(c), view(v) { - setFlags(QGraphicsItem::ItemIsSelectable | - QGraphicsItem::ItemIsFocusable); + // To enable dragging, the item needs to be selectable + setFlags(QGraphicsItem::ItemIsSelectable); setAcceptHoverEvents(true); + connect(v, &ViewportView::changed, this, &ControlInstance::onViewChanged); v->scene()->addItem(this); } @@ -60,7 +61,7 @@ void ControlInstance::paint(QPainter* painter, if (control) { - control->paint(getMatrix(), isSelected() || hover, painter); + control->paint(getMatrix(), hover && control->hasDragFunc(), painter); } } @@ -84,10 +85,12 @@ void ControlInstance::mouseMoveEvent(QGraphicsSceneMouseEvent* event) QGraphicsObject::mouseMoveEvent(event); QMatrix4x4 mi = getMatrix().inverted(); + QVector3D p0 = mi * QVector3D(click_pos); QVector3D p1 = mi * QVector3D(event->pos()); - QVector3D eye = (mi*QVector3D(0, 0, -1)).normalized(); + QVector3D eye = -view->getMatrix(ViewportView::ROT).inverted() + .column(2).toVector3D().normalized(); control->drag(p1 + eye * QVector3D::dotProduct(eye, control->pos() - p1), p1 - p0); @@ -95,9 +98,8 @@ void ControlInstance::mouseMoveEvent(QGraphicsSceneMouseEvent* event) click_pos = event->pos(); } -void ControlInstance::contextMenuEvent(QGraphicsSceneContextMenuEvent* e) +void ControlInstance::openContextMenu() { - Q_UNUSED(e); QString desc = control->getName(); QScopedPointer menu(new QMenu()); @@ -106,6 +108,11 @@ void ControlInstance::contextMenuEvent(QGraphicsSceneContextMenuEvent* e) menu->addAction(jump_to); connect(jump_to, &QAction::triggered, this, &ControlInstance::onZoomTo); + auto delete_node = new QAction("Delete node " + desc, menu.data()); + menu->addAction(delete_node); + connect(delete_node, &QAction::triggered, + this, &ControlInstance::onDeleteNode); + menu->exec(QCursor::pos()); } @@ -131,17 +138,15 @@ void ControlInstance::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) emit(onFocus(false)); } -void ControlInstance::keyPressEvent(QKeyEvent* event) +void ControlInstance::onDeleteNode() { - if (event->key() == Qt::Key_Delete || - event->key() == Qt::Key_Backspace) - { - control->deleteNode(); - } - else - { - event->ignore(); - } + control->deleteNode(); +} + +void ControlInstance::onViewChanged(QMatrix4x4 M) +{ + Q_UNUSED(M); + redraw(); } void ControlInstance::redraw() diff --git a/app/viewport/control/control_instance.h b/app/viewport/control/control_instance.h index 146d26f3..58f18db9 100644 --- a/app/viewport/control/control_instance.h +++ b/app/viewport/control/control_instance.h @@ -2,6 +2,7 @@ #include #include +#include #include class Control; @@ -47,6 +48,11 @@ Q_OBJECT void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override; + /* + * On mouse press, open a 'jump to node' menu + */ + void openContextMenu(); + /* * Handle mouse clicks by preparing to drag. */ @@ -62,28 +68,25 @@ Q_OBJECT */ void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; - /* - * On mouse press, open a 'jump to node' menu - */ - void contextMenuEvent(QGraphicsSceneContextMenuEvent* event) override; - /* * On hover enter and exit, set hover flag and call update */ void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; - /* - * On backspace or delete, pass a deletion request up to the proxy - */ - void keyPressEvent(QKeyEvent* event) override; - public slots: /* * Indicate that the control should be redrawn + * M is unused, present just for ease of connection. */ + void onViewChanged(QMatrix4x4 M=QMatrix4x4()); void redraw(); + /* + * Deletes the associated node + */ + void onDeleteNode(); + signals: /* * Emitted when hover changes diff --git a/app/viewport/view.cpp b/app/viewport/view.cpp index 828372a6..a53a8de6 100644 --- a/app/viewport/view.cpp +++ b/app/viewport/view.cpp @@ -35,15 +35,26 @@ ViewportView::ViewportView(QWidget* parent, ViewportScene* scene) //////////////////////////////////////////////////////////////////////////////// -QMatrix4x4 ViewportView::getMatrix() const +QMatrix4x4 ViewportView::getMatrix(int params) const { QMatrix4x4 M; // Remember that these operations are applied in reverse order. - M.scale(scale, -scale, scale); - M.rotate(pitch * 180 / M_PI, QVector3D(1, 0, 0)); - M.rotate(yaw * 180 / M_PI, QVector3D(0, 0, 1)); - M.translate(-center.x(), -center.y(), -center.z()); + if (params & SCALE) + { + M.scale(scale, -scale, scale); + } + + if (params & ROT) + { + M.rotate(pitch * 180 / M_PI, QVector3D(1, 0, 0)); + M.rotate(yaw * 180 / M_PI, QVector3D(0, 0, 1)); + } + + if (params & MOVE) + { + M.translate(-center.x(), -center.y(), -center.z()); + } return M; } @@ -77,6 +88,11 @@ void ViewportView::drawBackground(QPainter* painter, const QRectF& rect) QGraphicsView::drawBackground(painter, rect); painter->beginNativePainting(); + if (!gl_initialized) + { + initializeOpenGLFunctions(); + gl_initialized = true; + } glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -127,9 +143,7 @@ void ViewportView::drawCoords(QPainter* painter) const } // Get rotate-only transform matrix - QMatrix4x4 M; - M.rotate(pitch * 180 / M_PI, QVector3D(1, 0, 0)); - M.rotate(yaw * 180 / M_PI, QVector3D(0, 0, 1)); + QMatrix4x4 M = getMatrix(ROT); const float threshold = 0.98; const auto a = M.inverted() * QVector3D(0, 0, 1); @@ -281,15 +295,26 @@ void ViewportView::mouseReleaseEvent(QMouseEvent* event) if (event->button() == Qt::RightButton && !dragged) { auto is = items(event->pos()); - if (is.size()) + if (is.size() > 1) { openRaiseMenu(is); } + else if (is.size()) + { + if (auto c = dynamic_cast(is.front())) + { + c->openContextMenu(); + } + } else { openAddMenu(true); } } + else + { + QGraphicsView::mouseReleaseEvent(event); + } } void ViewportView::wheelEvent(QWheelEvent* event) diff --git a/app/viewport/view.h b/app/viewport/view.h index 4671275e..88b9e9da 100644 --- a/app/viewport/view.h +++ b/app/viewport/view.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include "viewport/gl.h" @@ -11,16 +12,18 @@ class Node; class BaseDatumProxy; class ViewportScene; -class ViewportView : public QGraphicsView +class ViewportView : public QGraphicsView, protected QOpenGLFunctions { Q_OBJECT public: ViewportView(QWidget* parent, ViewportScene* scene); + enum MatrixParams { ROT=1, SCALE=2, MOVE=4 }; + /* * Returns a generic matrix transform from the view */ - QMatrix4x4 getMatrix() const; + QMatrix4x4 getMatrix(int params=ROT|SCALE|MOVE) const; /* * Draw depth images in the background @@ -195,4 +198,7 @@ public slots: /* Pointer to raised ControlInstance */ QGraphicsItem* raised=nullptr; + + /* Records whether initializeOpenGLFunctions has been called */ + bool gl_initialized=false; }; diff --git a/app/window/base.cpp b/app/window/base.cpp index c7c97100..0f4a4453 100644 --- a/app/window/base.cpp +++ b/app/window/base.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include diff --git a/app/window/base_viewport_window.cpp b/app/window/base_viewport_window.cpp index 2429fa32..971068e4 100644 --- a/app/window/base_viewport_window.cpp +++ b/app/window/base_viewport_window.cpp @@ -5,8 +5,6 @@ #include "window/base_viewport_window.h" -#include "ui_base_window.h" - BaseViewportWindow::BaseViewportWindow(QList views) : BaseWindow("Viewport") { diff --git a/app/forms/base_window.ui b/app/window/base_window.ui similarity index 100% rename from app/forms/base_window.ui rename to app/window/base_window.ui diff --git a/app/window/canvas.cpp b/app/window/canvas.cpp index f602ef29..74d1695e 100644 --- a/app/window/canvas.cpp +++ b/app/window/canvas.cpp @@ -2,8 +2,6 @@ #include "canvas/scene.h" #include "canvas/canvas_view.h" -#include "ui_base_window.h" - CanvasWindow::CanvasWindow(CanvasView* view) : BaseWindow("Graph") { diff --git a/deploy/mac/Info.plist b/deploy/mac/Info.plist index dae2a654..1b5c6981 100644 --- a/deploy/mac/Info.plist +++ b/deploy/mac/Info.plist @@ -11,7 +11,7 @@ CFBundleGetInfoString It's CAD, Jim, but not as we know it. CFBundleExecutable - antimony + Antimony CFBundleIdentifier com.impraxical.antimony CFBundleVersion diff --git a/deploy/mac/deploy.sh b/deploy/mac/deploy.sh index 8f365238..0f089d39 100755 --- a/deploy/mac/deploy.sh +++ b/deploy/mac/deploy.sh @@ -9,44 +9,73 @@ fi RELEASE=`git describe --exact-match --tags || echo "($(git rev-parse --abbrev-ref HEAD))"` cd ../../build-$1 -make clean -make qmake -rm -rf app lib +ninja clean +ninja -make -j8 -macdeployqt app/Antimony.app +# Pull out framework paths info with otool +MACDEPLOYQT=`otool -L app/Antimony.app/Contents/MacOS/Antimony | sed -n -e "s:\(.*\)lib/QtCore.*:\1/bin/macdeployqt:gp"` +PY3_VERSION=`otool -L app/Antimony.app/Contents/MacOS/Antimony | sed -n -e "s:.*Python.framework/Versions/\(3\..\).*:\1:gp"` +PY3_FRAMEWORK=`otool -L app/Antimony.app/Contents/MacOS/Antimony | sed -n -e "s:\(.*Python.framework\)/Versions.*:\1:gp"` +BOOST_DYLIB=`otool -L app/Antimony.app/Contents/MacOS/Antimony | sed -n -e "s:.*\(libboost.*python.*\.dylib\).*:\1:gp"` +$MACDEPLOYQT app/Antimony.app + +# Delete unused Qt plugins cd app/Antimony.app/Contents/PlugIns -rm -rf accessible audio imageformats mediaservice playlistformats position printsupport qml1tooling sensorgestures sensors +rm -rf accessible audio imageformats mediaservice playlistformats position printsupport qml1tooling sensorgestures sensors bearer + +fix_qt () { + echo "Fixing Qt for $1" + for LIB in $( otool -L $1 | sed -n -e "s:\(.*Qt.*.framework[^ ]*\).*:\1:gp" ) + do + RENAMED=`echo $LIB | sed -n -e "s:.*\(Qt.*\)\.framework.*:@executable_path/../Frameworks/\1.framework/Versions/5/\1:gp"` + install_name_tool -change $LIB $RENAMED $1 + done +} -cd ../Frameworks +# Remap platform links +cd platforms +fix_qt libqcocoa.dylib + +# Delete unused Qt frameworks +cd ../../Frameworks rm -rf QtDeclarative.framework QtMultimedia.framework QtMultimediaWidgets.framework QtPositioning.framework QtQml.framework QtQuick.framework QtScript.framework QtSensors.framework QtSql.framework QtXmlPatterns.framework Qt3DCore.framework Qt3DRender.framework QtLocation.framework QtSerialBus.framework QtSerialPort.framework -PY_VERSION=3.5 -cp -r /usr/local/Frameworks/Python.framework . -rm -rf Python.framework/Versions/2.7 Python.framework/Versions/Current -rm -rf Python.framework/Versions/$PY_VERSION/lib/python$PY_VERSION/site-packages/* -chmod a+w libboost_python3.dylib +# Clean up remaining Qt frameworks +for LIB in $( ls|sed -n -e "s:\(Qt.*\)\.framework:\1:gp" ) +do + fix_qt $LIB.framework/Versions/Current/$LIB +done -cd ../Resources -rm empty.lproj +# Deploy the Python framework, cleaning out older versions and site-packages +rm -rf Python.framework +cp -R $PY3_FRAMEWORK . +rm -rf Python.framework/Versions/2.7 +rm -r Python.framework/Versions/Current +rm -rf Python.framework/Versions/$PY3_VERSION/lib/python$PY3_VERSION/site-packages/* +rm -r Python.framework/Versions/$PY3_VERSION/lib/python$PY3_VERSION/test +rm -r Python.framework/Versions/$PY3_VERSION/lib/python$PY3_VERSION/__pycache__ +rm -rf Python.framework/Versions/$PY3_VERSION/lib/python$PY3_VERSION/*/__pycache__ +rm -r Python.framework/Versions/$PY3_VERSION/Resources/English.lproj +rm -r Python.framework/Versions/$PY3_VERSION/share/doc +chmod a+w $BOOST_DYLIB +# Rewire Python framework to point into the application bundle cd ../MacOS -install_name_tool -change /usr/local/opt/python3/Frameworks/Python.framework/Versions/$PY_VERSION/Python \ - @executable_path/../Frameworks/Python.framework/Versions/$PY_VERSION/Python \ - Antimony +install_name_tool -change $PY3_FRAMEWORK/Versions/$PY3_VERSION/Python \ + @executable_path/../Frameworks/Python.framework/Versions/$PY3_VERSION/Python \ + Antimony +# Update release number in Info.plist cd ../../.. -cp -r sb/fab Antimony.app/Contents/Frameworks/Python.framework/Versions/$PY_VERSION/lib/python$PY_VERSION/fab -cp -r sb/nodes Antimony.app/Contents/Resources - sed -i "" "s:0\.0\.0:$RELEASE:g" Antimony.app/Contents/Info.plist +# Create the disk image mkdir Antimony cp ../../README.md ./Antimony/README.txt cp ../../doc/USAGE.md ./Antimony/USAGE.txt cp ../../doc/SCRIPTING.md ./Antimony/SCRIPTING.txt -mv Antimony.app ./Antimony +cp -R Antimony.app ./Antimony hdiutil create Antimony.dmg -volname "Antimony $RELEASE" -srcfolder Antimony rm -rf Antimony mv Antimony.dmg .. diff --git a/doc/release-notes/0.9.2.md b/doc/release-notes/0.9.2.md new file mode 100644 index 00000000..456fbd04 --- /dev/null +++ b/doc/release-notes/0.9.2.md @@ -0,0 +1,17 @@ +Antimony 0.9.2 +-------------- + +This release has relatively few user-facing features, but should make the +lives of our Linux packaging volunteers easier. + +There are also a host of bugfixes in `sb.ui` (which contains a set of +immediate-mode UI calls that can be placed in `Node` scripts). + +## Features +- Building now uses `cmake` instead of `qmake`, which is much simpler +- `sb.ui` functions now take an optional `key` argument to disambiguate + +### Bugfixes: +- Dragging `sb.ui` shapes was not undoable; now, it is. +- Correct positions are passed into controls with absolute drag callbacks +- Fixed a bug where you could end up with unparented control instances diff --git a/lib/fab/CMakeLists.txt b/lib/fab/CMakeLists.txt new file mode 100644 index 00000000..7661c061 --- /dev/null +++ b/lib/fab/CMakeLists.txt @@ -0,0 +1,95 @@ +find_package(PNG REQUIRED) +find_package(FLEX REQUIRED) + +################################################################################ + +# Custom command to generate the parser sources with lemon +find_program(LEMON_EXECUTABLE lemon DOC "path to the lemon executable") +mark_as_advanced(LEMON_EXECUTABLE) +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/v2syntax.lemon.hpp + ${CMAKE_CURRENT_BINARY_DIR}/v2syntax.lemon.cpp + COMMAND ${LEMON_EXECUTABLE} -q -c -s ${CMAKE_CURRENT_SOURCE_DIR}/src/tree/v2syntax.y + COMMAND mv ${CMAKE_CURRENT_SOURCE_DIR}/src/tree/v2syntax.c ${CMAKE_CURRENT_BINARY_DIR}/v2syntax.lemon.cpp + COMMAND mv ${CMAKE_CURRENT_SOURCE_DIR}/src/tree/v2syntax.h ${CMAKE_CURRENT_BINARY_DIR}/v2syntax.lemon.hpp) + +# Custom command to generate the lexer sources with flex +find_program(FLEX_EXECUTABLE flex DOC "path to the flex executable") +mark_as_advanced(FLEX_EXECUTABLE) +add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/v2syntax.yy.hpp + ${CMAKE_CURRENT_BINARY_DIR}/v2syntax.yy.cpp + COMMAND ${FLEX_EXECUTABLE} --outfile=${CMAKE_CURRENT_BINARY_DIR}/v2syntax.yy.cpp + --header-file=${CMAKE_CURRENT_BINARY_DIR}/v2syntax.yy.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/tree/v2syntax.l) + +add_library(SbFab STATIC + src/fab.cpp + src/formats/png.c + src/formats/stl.c + src/tree/eval.c + src/tree/math/math_f.c + src/tree/math/math_g.c + src/tree/math/math_i.c + src/tree/math/math_r.c + src/tree/node/node_c.c + src/tree/node/opcodes.c + src/tree/node/printers.c + src/tree/node/printers_ss.cpp + src/tree/node/results.c + src/tree/parser.c + src/tree/render.c + src/tree/tree.c + src/tree/v2parser.cpp + src/tree/triangulate/mesher.cpp + src/tree/triangulate/triangle.cpp + src/tree/triangulate.cpp + src/types/bounds.cpp + src/types/shape.cpp + src/types/transform.cpp + src/util/region.c + src/util/ustack.c + + # Generated files + ${CMAKE_CURRENT_BINARY_DIR}/v2syntax.lemon.cpp + ${CMAKE_CURRENT_BINARY_DIR}/v2syntax.yy.cpp +) + +target_include_directories(SbFab SYSTEM PRIVATE + ${PYTHON_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} + ${PNG_INCLUDE_DIR} +) + +# Add the binary dir to include generated files +target_include_directories(SbFab PRIVATE + ${CMAKE_CURRENT_BINARY_DIR} +) + +target_link_libraries(SbFab + ${PYTHON_LIBRARY} + ${Boost_LIBRARIES} + ${PNG_LIBRARIES} +) +target_include_directories(SbFab PUBLIC inc) +target_include_directories(SbFab SYSTEM PRIVATE + vendor) + +################################################################################ + +add_executable(SbFabTest + tests/main.cpp + tests/parser.cpp + tests/shape.cpp +) +target_link_libraries(SbFabTest SbFab) + +target_include_directories(SbFabTest SYSTEM PRIVATE + ../../vendor + ${PYTHON_INCLUDE_DIRS} +) + +################################################################################ + +set_property(TARGET SbFab PROPERTY CXX_STANDARD 11) +set_property(TARGET SbFabTest PROPERTY CXX_STANDARD 11) diff --git a/lib/fab/fab-tests.pro b/lib/fab/fab-tests.pro deleted file mode 100644 index b75956f3..00000000 --- a/lib/fab/fab-tests.pro +++ /dev/null @@ -1,9 +0,0 @@ -TARGET = SbFabTests -TEMPLATE = app -VERSION = 0.8 -CONFIG -= core - -INCLUDEPATH += ../../vendor - -include(fab.pri) -SOURCES += tests/main.cpp tests/parser.cpp tests/shape.cpp diff --git a/lib/fab/fab.pri b/lib/fab/fab.pri deleted file mode 100644 index c00dbe6c..00000000 --- a/lib/fab/fab.pri +++ /dev/null @@ -1,35 +0,0 @@ -INCLUDEPATH += inc vendor - -include(../../qt/common.pri) -include(../../qt/python.pri) -include(../../qt/libpng.pri) - -include(flex.pri) -include(lemon.pri) - -SOURCES += \ - src/fab.cpp \ - src/formats/png.c \ - src/formats/stl.c \ - src/tree/eval.c \ - src/tree/math/math_f.c \ - src/tree/math/math_g.c \ - src/tree/math/math_i.c \ - src/tree/math/math_r.c \ - src/tree/node/node_c.c \ - src/tree/node/opcodes.c \ - src/tree/node/printers.c \ - src/tree/node/printers_ss.cpp \ - src/tree/node/results.c \ - src/tree/parser.c \ - src/tree/render.c \ - src/tree/tree.c \ - src/tree/v2parser.cpp \ - src/tree/triangulate/mesher.cpp \ - src/tree/triangulate/triangle.cpp \ - src/tree/triangulate.cpp \ - src/types/bounds.cpp \ - src/types/shape.cpp \ - src/types/transform.cpp \ - src/util/region.c \ - src/util/ustack.c \ diff --git a/lib/fab/fab.pro b/lib/fab/fab.pro deleted file mode 100644 index 94cdbd7a..00000000 --- a/lib/fab/fab.pro +++ /dev/null @@ -1,7 +0,0 @@ -TARGET = SbFab -TEMPLATE = lib -VERSION = 0.8 -CONFIG -= core -CONFIG += staticlib - -include(fab.pri) diff --git a/lib/fab/inc/fab/fab.h b/lib/fab/inc/fab/fab.h index 1968865e..1f7ae7bc 100644 --- a/lib/fab/inc/fab/fab.h +++ b/lib/fab/inc/fab/fab.h @@ -3,6 +3,9 @@ #include +#include +#include + namespace fab { struct ParseError {}; @@ -22,9 +25,9 @@ namespace fab /** Loads the fab module in Python's namespace. * - * path_dir is added to Python's search path. + * fab_paths are added to Python's search path. */ - void postInit(const char* path_dir); + void postInit(std::vector fab_paths); extern PyTypeObject* ShapeType; } diff --git a/lib/fab/src/fab.cpp b/lib/fab/src/fab.cpp index 1a2e8faa..4e5e0e95 100644 --- a/lib/fab/src/fab.cpp +++ b/lib/fab/src/fab.cpp @@ -74,12 +74,15 @@ void fab::preInit() PyImport_AppendInittab("_fabtypes", PyInit__fabtypes); } -void fab::postInit(const char* path_dir) +void fab::postInit(std::vector fab_paths) { PyObject* fabtypes = PyImport_ImportModule("_fabtypes"); ShapeType = (PyTypeObject*)PyObject_GetAttrString(fabtypes, "Shape"); // Modify the default search path to include the application's directory // (as this doesn't happen on Linux by default) - PyList_Insert(PySys_GetObject("path"), 0, PyUnicode_FromString(path_dir)); + for (auto p : fab_paths) + { + PyList_Insert(PySys_GetObject("path"), 0, PyUnicode_FromString(p.c_str())); + } } diff --git a/lib/graph/CMakeLists.txt b/lib/graph/CMakeLists.txt new file mode 100644 index 00000000..0cb6b3bd --- /dev/null +++ b/lib/graph/CMakeLists.txt @@ -0,0 +1,48 @@ +add_library(SbGraph STATIC + src/datum.cpp + src/graph.cpp + src/node.cpp + src/script_node.cpp + src/graph_node.cpp + src/proxy.cpp + src/script.cpp + src/util.cpp + src/types/downstream.cpp + src/types/root.cpp + src/hooks/hooks.cpp + src/hooks/input.cpp + src/hooks/output.cpp +) + +target_include_directories(SbGraph SYSTEM PRIVATE + ${PYTHON_INCLUDE_DIRS} + ${Boost_INCLUDE_DIRS} +) +target_link_libraries(SbGraph + ${PYTHON_LIBRARY} + ${Boost_LIBRARIES} +) +target_include_directories(SbGraph PUBLIC inc) + +################################################################################ + +add_executable(SbGraphTest + tests/datum.cpp + tests/graph.cpp + tests/link.cpp + tests/main.cpp + tests/node.cpp + tests/script.cpp + tests/subgraph.cpp +) +target_link_libraries(SbGraphTest SbGraph) + +target_include_directories(SbGraphTest SYSTEM PRIVATE + ${PYTHON_INCLUDE_DIRS} + ../../vendor +) + +################################################################################ + +set_property(TARGET SbGraph PROPERTY CXX_STANDARD 11) +set_property(TARGET SbGraphTest PROPERTY CXX_STANDARD 11) diff --git a/lib/graph/graph-tests.pro b/lib/graph/graph-tests.pro deleted file mode 100644 index 270cdd5b..00000000 --- a/lib/graph/graph-tests.pro +++ /dev/null @@ -1,10 +0,0 @@ -TARGET = SbGraphTests -TEMPLATE = app -VERSION = 0.8 -CONFIG -= core - -INCLUDEPATH += ../../vendor - -include(graph.pri) -SOURCES += tests/main.cpp tests/datum.cpp tests/script.cpp tests/node.cpp \ - tests/link.cpp tests/graph.cpp tests/subgraph.cpp diff --git a/lib/graph/graph.pri b/lib/graph/graph.pri deleted file mode 100644 index 592d3a15..00000000 --- a/lib/graph/graph.pri +++ /dev/null @@ -1,19 +0,0 @@ -INCLUDEPATH += inc - -include(../../qt/common.pri) -include(../../qt/python.pri) - -SOURCES += \ - src/datum.cpp \ - src/graph.cpp \ - src/node.cpp \ - src/script_node.cpp \ - src/graph_node.cpp \ - src/proxy.cpp \ - src/script.cpp \ - src/util.cpp \ - src/types/downstream.cpp \ - src/types/root.cpp \ - src/hooks/hooks.cpp \ - src/hooks/input.cpp \ - src/hooks/output.cpp \ diff --git a/lib/graph/graph.pro b/lib/graph/graph.pro deleted file mode 100644 index 494a72b0..00000000 --- a/lib/graph/graph.pro +++ /dev/null @@ -1,7 +0,0 @@ -TARGET = SbGraph -TEMPLATE = lib -VERSION = 0.8 -CONFIG -= core -CONFIG += staticlib - -include(graph.pri) diff --git a/qt/brew.pri b/qt/brew.pri deleted file mode 100644 index 7f1cb7cc..00000000 --- a/qt/brew.pri +++ /dev/null @@ -1,6 +0,0 @@ -macx { - BREW_HOME = $$(BREW_HOME) - isEmpty(BREW_HOME){ - BREW_HOME = /usr/local - } -} diff --git a/qt/common.pri b/qt/common.pri deleted file mode 100644 index 74f5cca8..00000000 --- a/qt/common.pri +++ /dev/null @@ -1,11 +0,0 @@ -# Configuration that is common to Antimony and supporting libraries -CONFIG += c++11 object_parallel_to_source - -# Bump optimization up to -O3 in release builds -QMAKE_CXXFLAGS_RELEASE -= -O2 -QMAKE_CXXFLAGS_RELEASE += -O3 -QMAKE_CFLAGS_RELEASE -= -O2 -QMAKE_CFLAGS_RELEASE += -O3 - -QMAKE_CXXFLAGS += -Werror=switch -QMAKE_CFLAGS += -std=c11 diff --git a/qt/libpng.pri b/qt/libpng.pri deleted file mode 100644 index efabc292..00000000 --- a/qt/libpng.pri +++ /dev/null @@ -1,16 +0,0 @@ -# Link against libpng for image export - -cygwin { - LIBS += $$system(libpng-config --libs) -} - -macx { - include(brew.pri) - LIBS += -L$${BREW_HOME}/lib -lpng - INCLUDEPATH += $${BREW_HOME}/include/libpng15/ - INCLUDEPATH += $${BREW_HOME}/include/libpng16/ -} - -linux { - LIBS += -lpng -} diff --git a/qt/python.pri b/qt/python.pri deleted file mode 100644 index 1334f6b2..00000000 --- a/qt/python.pri +++ /dev/null @@ -1,55 +0,0 @@ -# Platform-specific configuration common to Antimony and supporting libraries -cygwin { - QMAKE_CXXFLAGS += $$system(python3-config --includes) - QMAKE_CFLAGS += $$system(python3-config --includes) - LIBS += $$system(python3-config --libs) - LIBS += -lboost_python3 -} - -macx { - include(brew.pri) - QMAKE_CXXFLAGS += $$system($${BREW_HOME}/bin/python3-config --includes) - QMAKE_LFLAGS += $$system($${BREW_HOME}/bin/python3-config --ldflags) - LIBS += -L$${BREW_HOME}/lib -lboost_python3 - QMAKE_CXXFLAGS += -isystem$${BREW_HOME}/include -} - -linux { - QMAKE_CXXFLAGS += $$system(/usr/bin/python3-config --includes) - QMAKE_LFLAGS += $$system(/usr/bin/python3-config --ldflags) - - # Even though this is in QMAKE_LFLAGS, the linker is picky about - # library ordering (so it needs to be here too). - LIBS += $$system(/usr/bin/python3-config --ldflags | grep -o -- '-lpython3.[0-9]m') - - # ldconfig is being used to find libboost_python, but it's in a different - # place in different distros (and is not in the default $PATH on Debian). - # First, check to see if it's on the default $PATH. - system(which ldconfig > /dev/null) { - LDCONFIG_BIN = "ldconfig" - } - # If that failed, then search for it in its usual places. - isEmpty(LDCONFIG_BIN) { - for(p, $$list(/sbin/ldconfig /usr/bin/ldconfig)) { - exists($$p): LDCONFIG_BIN = $$p - } - } - # If that search failed too, then exit with an error. - isEmpty(LDCONFIG_BIN) { - error("Could not find ldconfig!") - } - - # Check for different boost::python naming schemes - LDCONFIG_OUT = $$system($$LDCONFIG_BIN -p|grep python) - for (b, $$list(boost_python-py34 boost_python-py35 boost_python3)) { - contains(LDCONFIG_OUT, "lib$${b}.so") { - LIBS += "-l$$b" - GOT_BOOST_PYTHON = True - } - } - - # If we couldn't find boost::python, exit with an error. - isEmpty(GOT_BOOST_PYTHON) { - error("Could not find boost::python3") - } -} diff --git a/sb.pro b/sb.pro deleted file mode 100644 index 9f5a5070..00000000 --- a/sb.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs -CONFIG += ordered -SUBDIRS = lib/fab lib/graph app