diff options
-rw-r--r-- | .gitignore (renamed from waflib/.gitignore) | 0 | ||||
-rw-r--r-- | AUTHORS | 4 | ||||
-rw-r--r-- | Build.py (renamed from waflib/Build.py) | 0 | ||||
-rw-r--r-- | COPYING | 699 | ||||
-rw-r--r-- | ConfigSet.py (renamed from waflib/ConfigSet.py) | 0 | ||||
-rw-r--r-- | Configure.py (renamed from waflib/Configure.py) | 0 | ||||
-rw-r--r-- | Context.py (renamed from waflib/Context.py) | 0 | ||||
-rw-r--r-- | Errors.py (renamed from waflib/Errors.py) | 0 | ||||
-rw-r--r-- | INSTALL | 59 | ||||
-rw-r--r-- | Logs.py (renamed from waflib/Logs.py) | 0 | ||||
-rw-r--r-- | NEWS | 58 | ||||
-rw-r--r-- | Node.py (renamed from waflib/Node.py) | 0 | ||||
-rw-r--r-- | Options.py (renamed from waflib/Options.py) | 0 | ||||
-rw-r--r-- | README | 14 | ||||
-rw-r--r-- | README.md (renamed from waflib/README.md) | 0 | ||||
-rw-r--r-- | Runner.py (renamed from waflib/Runner.py) | 0 | ||||
-rw-r--r-- | Scripting.py (renamed from waflib/Scripting.py) | 0 | ||||
-rw-r--r-- | Task.py (renamed from waflib/Task.py) | 0 | ||||
-rw-r--r-- | TaskGen.py (renamed from waflib/TaskGen.py) | 0 | ||||
-rw-r--r-- | Tools/__init__.py (renamed from waflib/Tools/__init__.py) | 0 | ||||
-rw-r--r-- | Tools/ar.py (renamed from waflib/Tools/ar.py) | 0 | ||||
-rw-r--r-- | Tools/asm.py (renamed from waflib/Tools/asm.py) | 0 | ||||
-rw-r--r-- | Tools/bison.py (renamed from waflib/Tools/bison.py) | 0 | ||||
-rw-r--r-- | Tools/c.py (renamed from waflib/Tools/c.py) | 0 | ||||
-rw-r--r-- | Tools/c_aliases.py (renamed from waflib/Tools/c_aliases.py) | 0 | ||||
-rw-r--r-- | Tools/c_config.py (renamed from waflib/Tools/c_config.py) | 0 | ||||
-rw-r--r-- | Tools/c_osx.py (renamed from waflib/Tools/c_osx.py) | 0 | ||||
-rw-r--r-- | Tools/c_preproc.py (renamed from waflib/Tools/c_preproc.py) | 0 | ||||
-rw-r--r-- | Tools/c_tests.py (renamed from waflib/Tools/c_tests.py) | 0 | ||||
-rw-r--r-- | Tools/ccroot.py (renamed from waflib/Tools/ccroot.py) | 0 | ||||
-rw-r--r-- | Tools/clang.py (renamed from waflib/Tools/clang.py) | 0 | ||||
-rw-r--r-- | Tools/clangxx.py (renamed from waflib/Tools/clangxx.py) | 0 | ||||
-rw-r--r-- | Tools/compiler_c.py (renamed from waflib/Tools/compiler_c.py) | 0 | ||||
-rw-r--r-- | Tools/compiler_cxx.py (renamed from waflib/Tools/compiler_cxx.py) | 0 | ||||
-rw-r--r-- | Tools/compiler_d.py (renamed from waflib/Tools/compiler_d.py) | 0 | ||||
-rw-r--r-- | Tools/compiler_fc.py (renamed from waflib/Tools/compiler_fc.py) | 0 | ||||
-rw-r--r-- | Tools/cs.py (renamed from waflib/Tools/cs.py) | 0 | ||||
-rw-r--r-- | Tools/cxx.py (renamed from waflib/Tools/cxx.py) | 0 | ||||
-rw-r--r-- | Tools/d.py (renamed from waflib/Tools/d.py) | 0 | ||||
-rw-r--r-- | Tools/d_config.py (renamed from waflib/Tools/d_config.py) | 0 | ||||
-rw-r--r-- | Tools/d_scan.py (renamed from waflib/Tools/d_scan.py) | 0 | ||||
-rw-r--r-- | Tools/dbus.py (renamed from waflib/Tools/dbus.py) | 0 | ||||
-rw-r--r-- | Tools/dmd.py (renamed from waflib/Tools/dmd.py) | 0 | ||||
-rw-r--r-- | Tools/errcheck.py (renamed from waflib/Tools/errcheck.py) | 0 | ||||
-rw-r--r-- | Tools/fc.py (renamed from waflib/Tools/fc.py) | 0 | ||||
-rw-r--r-- | Tools/fc_config.py (renamed from waflib/Tools/fc_config.py) | 0 | ||||
-rw-r--r-- | Tools/fc_scan.py (renamed from waflib/Tools/fc_scan.py) | 0 | ||||
-rw-r--r-- | Tools/flex.py (renamed from waflib/Tools/flex.py) | 0 | ||||
-rw-r--r-- | Tools/g95.py (renamed from waflib/Tools/g95.py) | 0 | ||||
-rw-r--r-- | Tools/gas.py (renamed from waflib/Tools/gas.py) | 0 | ||||
-rw-r--r-- | Tools/gcc.py (renamed from waflib/Tools/gcc.py) | 0 | ||||
-rw-r--r-- | Tools/gdc.py (renamed from waflib/Tools/gdc.py) | 0 | ||||
-rw-r--r-- | Tools/gfortran.py (renamed from waflib/Tools/gfortran.py) | 0 | ||||
-rw-r--r-- | Tools/glib2.py (renamed from waflib/Tools/glib2.py) | 0 | ||||
-rw-r--r-- | Tools/gnu_dirs.py (renamed from waflib/Tools/gnu_dirs.py) | 0 | ||||
-rw-r--r-- | Tools/gxx.py (renamed from waflib/Tools/gxx.py) | 0 | ||||
-rw-r--r-- | Tools/icc.py (renamed from waflib/Tools/icc.py) | 0 | ||||
-rw-r--r-- | Tools/icpc.py (renamed from waflib/Tools/icpc.py) | 0 | ||||
-rw-r--r-- | Tools/ifort.py (renamed from waflib/Tools/ifort.py) | 0 | ||||
-rw-r--r-- | Tools/intltool.py (renamed from waflib/Tools/intltool.py) | 0 | ||||
-rw-r--r-- | Tools/irixcc.py (renamed from waflib/Tools/irixcc.py) | 0 | ||||
-rw-r--r-- | Tools/javaw.py (renamed from waflib/Tools/javaw.py) | 0 | ||||
-rw-r--r-- | Tools/ldc2.py (renamed from waflib/Tools/ldc2.py) | 0 | ||||
-rw-r--r-- | Tools/lua.py (renamed from waflib/Tools/lua.py) | 0 | ||||
-rw-r--r-- | Tools/md5_tstamp.py (renamed from waflib/Tools/md5_tstamp.py) | 0 | ||||
-rw-r--r-- | Tools/msvc.py (renamed from waflib/Tools/msvc.py) | 0 | ||||
-rw-r--r-- | Tools/nasm.py (renamed from waflib/Tools/nasm.py) | 0 | ||||
-rw-r--r-- | Tools/nobuild.py (renamed from waflib/Tools/nobuild.py) | 0 | ||||
-rw-r--r-- | Tools/perl.py (renamed from waflib/Tools/perl.py) | 0 | ||||
-rw-r--r-- | Tools/python.py (renamed from waflib/Tools/python.py) | 0 | ||||
-rw-r--r-- | Tools/qt5.py (renamed from waflib/Tools/qt5.py) | 0 | ||||
-rw-r--r-- | Tools/ruby.py (renamed from waflib/Tools/ruby.py) | 0 | ||||
-rw-r--r-- | Tools/suncc.py (renamed from waflib/Tools/suncc.py) | 0 | ||||
-rw-r--r-- | Tools/suncxx.py (renamed from waflib/Tools/suncxx.py) | 0 | ||||
-rw-r--r-- | Tools/tex.py (renamed from waflib/Tools/tex.py) | 0 | ||||
-rw-r--r-- | Tools/vala.py (renamed from waflib/Tools/vala.py) | 0 | ||||
-rw-r--r-- | Tools/waf_unit_test.py (renamed from waflib/Tools/waf_unit_test.py) | 0 | ||||
-rw-r--r-- | Tools/winres.py (renamed from waflib/Tools/winres.py) | 0 | ||||
-rw-r--r-- | Tools/xlc.py (renamed from waflib/Tools/xlc.py) | 0 | ||||
-rw-r--r-- | Tools/xlcxx.py (renamed from waflib/Tools/xlcxx.py) | 0 | ||||
-rw-r--r-- | Utils.py (renamed from waflib/Utils.py) | 0 | ||||
-rw-r--r-- | __init__.py (renamed from waflib/__init__.py) | 0 | ||||
-rw-r--r-- | ansiterm.py (renamed from waflib/ansiterm.py) | 0 | ||||
-rw-r--r-- | extras/__init__.py (renamed from waflib/extras/__init__.py) | 0 | ||||
-rw-r--r-- | extras/autowaf.py (renamed from waflib/extras/autowaf.py) | 60 | ||||
-rw-r--r-- | extras/batched_cc.py (renamed from waflib/extras/batched_cc.py) | 0 | ||||
-rw-r--r-- | extras/biber.py (renamed from waflib/extras/biber.py) | 0 | ||||
-rw-r--r-- | extras/bjam.py (renamed from waflib/extras/bjam.py) | 0 | ||||
-rw-r--r-- | extras/blender.py (renamed from waflib/extras/blender.py) | 0 | ||||
-rw-r--r-- | extras/boo.py (renamed from waflib/extras/boo.py) | 0 | ||||
-rw-r--r-- | extras/boost.py (renamed from waflib/extras/boost.py) | 0 | ||||
-rw-r--r-- | extras/build_file_tracker.py (renamed from waflib/extras/build_file_tracker.py) | 0 | ||||
-rw-r--r-- | extras/build_logs.py (renamed from waflib/extras/build_logs.py) | 0 | ||||
-rw-r--r-- | extras/buildcopy.py (renamed from waflib/extras/buildcopy.py) | 0 | ||||
-rw-r--r-- | extras/c_bgxlc.py (renamed from waflib/extras/c_bgxlc.py) | 0 | ||||
-rw-r--r-- | extras/c_dumbpreproc.py (renamed from waflib/extras/c_dumbpreproc.py) | 0 | ||||
-rw-r--r-- | extras/c_emscripten.py (renamed from waflib/extras/c_emscripten.py) | 0 | ||||
-rw-r--r-- | extras/c_nec.py (renamed from waflib/extras/c_nec.py) | 0 | ||||
-rw-r--r-- | extras/cabal.py (renamed from waflib/extras/cabal.py) | 0 | ||||
-rw-r--r-- | extras/cfg_altoptions.py (renamed from waflib/extras/cfg_altoptions.py) | 0 | ||||
-rw-r--r-- | extras/clang_compilation_database.py (renamed from waflib/extras/clang_compilation_database.py) | 0 | ||||
-rw-r--r-- | extras/codelite.py (renamed from waflib/extras/codelite.py) | 0 | ||||
-rw-r--r-- | extras/color_gcc.py (renamed from waflib/extras/color_gcc.py) | 0 | ||||
-rw-r--r-- | extras/color_rvct.py (renamed from waflib/extras/color_rvct.py) | 0 | ||||
-rw-r--r-- | extras/compat15.py (renamed from waflib/extras/compat15.py) | 0 | ||||
-rw-r--r-- | extras/cppcheck.py (renamed from waflib/extras/cppcheck.py) | 0 | ||||
-rw-r--r-- | extras/cpplint.py (renamed from waflib/extras/cpplint.py) | 0 | ||||
-rw-r--r-- | extras/cross_gnu.py (renamed from waflib/extras/cross_gnu.py) | 0 | ||||
-rw-r--r-- | extras/cython.py (renamed from waflib/extras/cython.py) | 0 | ||||
-rw-r--r-- | extras/dcc.py (renamed from waflib/extras/dcc.py) | 0 | ||||
-rw-r--r-- | extras/distnet.py (renamed from waflib/extras/distnet.py) | 0 | ||||
-rw-r--r-- | extras/doxygen.py (renamed from waflib/extras/doxygen.py) | 0 | ||||
-rw-r--r-- | extras/dpapi.py (renamed from waflib/extras/dpapi.py) | 0 | ||||
-rw-r--r-- | extras/eclipse.py (renamed from waflib/extras/eclipse.py) | 0 | ||||
-rw-r--r-- | extras/erlang.py (renamed from waflib/extras/erlang.py) | 0 | ||||
-rw-r--r-- | extras/fast_partial.py (renamed from waflib/extras/fast_partial.py) | 0 | ||||
-rw-r--r-- | extras/fc_bgxlf.py (renamed from waflib/extras/fc_bgxlf.py) | 0 | ||||
-rw-r--r-- | extras/fc_cray.py (renamed from waflib/extras/fc_cray.py) | 0 | ||||
-rw-r--r-- | extras/fc_nag.py (renamed from waflib/extras/fc_nag.py) | 0 | ||||
-rw-r--r-- | extras/fc_nec.py (renamed from waflib/extras/fc_nec.py) | 0 | ||||
-rw-r--r-- | extras/fc_open64.py (renamed from waflib/extras/fc_open64.py) | 0 | ||||
-rw-r--r-- | extras/fc_pgfortran.py (renamed from waflib/extras/fc_pgfortran.py) | 0 | ||||
-rw-r--r-- | extras/fc_solstudio.py (renamed from waflib/extras/fc_solstudio.py) | 0 | ||||
-rw-r--r-- | extras/fc_xlf.py (renamed from waflib/extras/fc_xlf.py) | 0 | ||||
-rw-r--r-- | extras/file_to_object.py (renamed from waflib/extras/file_to_object.py) | 0 | ||||
-rw-r--r-- | extras/fluid.py (renamed from waflib/extras/fluid.py) | 0 | ||||
-rw-r--r-- | extras/freeimage.py (renamed from waflib/extras/freeimage.py) | 0 | ||||
-rw-r--r-- | extras/fsb.py (renamed from waflib/extras/fsb.py) | 0 | ||||
-rw-r--r-- | extras/fsc.py (renamed from waflib/extras/fsc.py) | 0 | ||||
-rw-r--r-- | extras/gccdeps.py (renamed from waflib/extras/gccdeps.py) | 0 | ||||
-rw-r--r-- | extras/gdbus.py (renamed from waflib/extras/gdbus.py) | 0 | ||||
-rw-r--r-- | extras/gob2.py (renamed from waflib/extras/gob2.py) | 0 | ||||
-rw-r--r-- | extras/halide.py (renamed from waflib/extras/halide.py) | 0 | ||||
-rwxr-xr-x | extras/javatest.py (renamed from waflib/extras/javatest.py) | 0 | ||||
-rw-r--r-- | extras/kde4.py (renamed from waflib/extras/kde4.py) | 0 | ||||
-rw-r--r-- | extras/local_rpath.py (renamed from waflib/extras/local_rpath.py) | 0 | ||||
-rw-r--r-- | extras/lv2.py (renamed from waflib/extras/lv2.py) | 0 | ||||
-rw-r--r-- | extras/make.py (renamed from waflib/extras/make.py) | 0 | ||||
-rw-r--r-- | extras/midl.py (renamed from waflib/extras/midl.py) | 0 | ||||
-rw-r--r-- | extras/msvcdeps.py (renamed from waflib/extras/msvcdeps.py) | 0 | ||||
-rw-r--r-- | extras/msvs.py (renamed from waflib/extras/msvs.py) | 0 | ||||
-rw-r--r-- | extras/netcache_client.py (renamed from waflib/extras/netcache_client.py) | 0 | ||||
-rw-r--r-- | extras/objcopy.py (renamed from waflib/extras/objcopy.py) | 0 | ||||
-rw-r--r-- | extras/ocaml.py (renamed from waflib/extras/ocaml.py) | 0 | ||||
-rw-r--r-- | extras/package.py (renamed from waflib/extras/package.py) | 0 | ||||
-rw-r--r-- | extras/parallel_debug.py (renamed from waflib/extras/parallel_debug.py) | 0 | ||||
-rw-r--r-- | extras/pch.py (renamed from waflib/extras/pch.py) | 0 | ||||
-rw-r--r-- | extras/pep8.py (renamed from waflib/extras/pep8.py) | 0 | ||||
-rw-r--r-- | extras/pgicc.py (renamed from waflib/extras/pgicc.py) | 0 | ||||
-rw-r--r-- | extras/pgicxx.py (renamed from waflib/extras/pgicxx.py) | 0 | ||||
-rw-r--r-- | extras/proc.py (renamed from waflib/extras/proc.py) | 0 | ||||
-rw-r--r-- | extras/protoc.py (renamed from waflib/extras/protoc.py) | 0 | ||||
-rw-r--r-- | extras/pyqt5.py (renamed from waflib/extras/pyqt5.py) | 0 | ||||
-rw-r--r-- | extras/pytest.py (renamed from waflib/extras/pytest.py) | 0 | ||||
-rw-r--r-- | extras/qnxnto.py (renamed from waflib/extras/qnxnto.py) | 0 | ||||
-rw-r--r-- | extras/qt4.py (renamed from waflib/extras/qt4.py) | 0 | ||||
-rw-r--r-- | extras/relocation.py (renamed from waflib/extras/relocation.py) | 0 | ||||
-rw-r--r-- | extras/remote.py (renamed from waflib/extras/remote.py) | 0 | ||||
-rw-r--r-- | extras/resx.py (renamed from waflib/extras/resx.py) | 0 | ||||
-rw-r--r-- | extras/review.py (renamed from waflib/extras/review.py) | 0 | ||||
-rw-r--r-- | extras/rst.py (renamed from waflib/extras/rst.py) | 0 | ||||
-rw-r--r-- | extras/run_do_script.py (renamed from waflib/extras/run_do_script.py) | 0 | ||||
-rw-r--r-- | extras/run_m_script.py (renamed from waflib/extras/run_m_script.py) | 0 | ||||
-rw-r--r-- | extras/run_py_script.py (renamed from waflib/extras/run_py_script.py) | 0 | ||||
-rw-r--r-- | extras/run_r_script.py (renamed from waflib/extras/run_r_script.py) | 0 | ||||
-rw-r--r-- | extras/sas.py (renamed from waflib/extras/sas.py) | 0 | ||||
-rw-r--r-- | extras/satellite_assembly.py (renamed from waflib/extras/satellite_assembly.py) | 0 | ||||
-rw-r--r-- | extras/scala.py (renamed from waflib/extras/scala.py) | 0 | ||||
-rw-r--r-- | extras/slow_qt4.py (renamed from waflib/extras/slow_qt4.py) | 0 | ||||
-rw-r--r-- | extras/softlink_libs.py (renamed from waflib/extras/softlink_libs.py) | 0 | ||||
-rw-r--r-- | extras/stale.py (renamed from waflib/extras/stale.py) | 0 | ||||
-rw-r--r-- | extras/stracedeps.py (renamed from waflib/extras/stracedeps.py) | 0 | ||||
-rw-r--r-- | extras/swig.py (renamed from waflib/extras/swig.py) | 0 | ||||
-rw-r--r-- | extras/syms.py (renamed from waflib/extras/syms.py) | 0 | ||||
-rw-r--r-- | extras/ticgt.py (renamed from waflib/extras/ticgt.py) | 0 | ||||
-rw-r--r-- | extras/unity.py (renamed from waflib/extras/unity.py) | 0 | ||||
-rw-r--r-- | extras/use_config.py (renamed from waflib/extras/use_config.py) | 0 | ||||
-rw-r--r-- | extras/valadoc.py (renamed from waflib/extras/valadoc.py) | 0 | ||||
-rw-r--r-- | extras/waf_xattr.py (renamed from waflib/extras/waf_xattr.py) | 0 | ||||
-rw-r--r-- | extras/why.py (renamed from waflib/extras/why.py) | 0 | ||||
-rw-r--r-- | extras/win32_opts.py (renamed from waflib/extras/win32_opts.py) | 0 | ||||
-rw-r--r-- | extras/wix.py (renamed from waflib/extras/wix.py) | 0 | ||||
-rw-r--r-- | extras/xcode6.py (renamed from waflib/extras/xcode6.py) | 0 | ||||
-rw-r--r-- | fixpy2.py (renamed from waflib/fixpy2.py) | 0 | ||||
-rw-r--r-- | ganv.pc.in | 11 | ||||
-rw-r--r-- | ganv/Box.hpp | 50 | ||||
-rw-r--r-- | ganv/Canvas.hpp | 158 | ||||
-rw-r--r-- | ganv/Circle.hpp | 79 | ||||
-rw-r--r-- | ganv/Edge.hpp | 90 | ||||
-rw-r--r-- | ganv/Item.hpp | 90 | ||||
-rw-r--r-- | ganv/Module.hpp | 130 | ||||
-rw-r--r-- | ganv/Node.hpp | 106 | ||||
-rw-r--r-- | ganv/Port.hpp | 76 | ||||
-rw-r--r-- | ganv/box.h | 78 | ||||
-rw-r--r-- | ganv/canvas.h | 630 | ||||
-rw-r--r-- | ganv/circle.h | 78 | ||||
-rw-r--r-- | ganv/edge.h | 129 | ||||
-rw-r--r-- | ganv/ganv.h | 31 | ||||
-rw-r--r-- | ganv/ganv.hpp | 26 | ||||
-rw-r--r-- | ganv/group.h | 55 | ||||
-rw-r--r-- | ganv/item.h | 184 | ||||
-rw-r--r-- | ganv/module.h | 95 | ||||
-rw-r--r-- | ganv/node.h | 179 | ||||
-rw-r--r-- | ganv/port.h | 103 | ||||
-rw-r--r-- | ganv/text.h | 52 | ||||
-rw-r--r-- | ganv/types.h | 26 | ||||
-rw-r--r-- | ganv/types.hpp | 30 | ||||
-rw-r--r-- | ganv/widget.h | 54 | ||||
-rw-r--r-- | ganv/wrap.hpp | 131 | ||||
-rwxr-xr-x | gtkdoc.sh | 26 | ||||
-rwxr-xr-x | processor.py (renamed from waflib/processor.py) | 0 | ||||
-rw-r--r-- | src/Canvas.cpp | 4184 | ||||
-rw-r--r-- | src/Port.cpp | 57 | ||||
-rw-r--r-- | src/boilerplate.h | 43 | ||||
-rw-r--r-- | src/box.c | 561 | ||||
-rw-r--r-- | src/circle.c | 467 | ||||
-rw-r--r-- | src/color.h | 63 | ||||
-rw-r--r-- | src/edge.c | 786 | ||||
-rw-r--r-- | src/fdgl.hpp | 166 | ||||
-rw-r--r-- | src/ganv-marshal.list | 4 | ||||
-rw-r--r-- | src/ganv-private.h | 403 | ||||
-rw-r--r-- | src/ganv_bench.cpp | 178 | ||||
-rw-r--r-- | src/ganv_test.c | 119 | ||||
-rwxr-xr-x | src/ganv_test.py | 22 | ||||
-rw-r--r-- | src/gettext.h | 26 | ||||
-rw-r--r-- | src/group.c | 446 | ||||
-rw-r--r-- | src/item.c | 707 | ||||
-rw-r--r-- | src/module.c | 859 | ||||
-rw-r--r-- | src/node.c | 897 | ||||
-rw-r--r-- | src/port.c | 735 | ||||
-rw-r--r-- | src/text.c | 381 | ||||
-rw-r--r-- | src/widget.c | 503 | ||||
-rw-r--r-- | waflib/COPYING | 25 | ||||
-rwxr-xr-x | waflib/waf | 16 | ||||
-rw-r--r-- | wscript | 247 |
235 files changed, 60 insertions, 15426 deletions
diff --git a/waflib/.gitignore b/.gitignore index 8d35cb3..8d35cb3 100644 --- a/waflib/.gitignore +++ b/.gitignore diff --git a/AUTHORS b/AUTHORS deleted file mode 100644 index f1bb6b3..0000000 --- a/AUTHORS +++ /dev/null @@ -1,4 +0,0 @@ -Author: - -David Robillard <d@drobilla.net> - diff --git a/waflib/Build.py b/Build.py index 1afcba6..1afcba6 100644 --- a/waflib/Build.py +++ b/Build.py @@ -1,674 +1,25 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - <program> Copyright (C) <year> <name of author> - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -<http://www.gnu.org/licenses/>. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -<http://www.gnu.org/philosophy/why-not-lgpl.html>. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/waflib/ConfigSet.py b/ConfigSet.py index b300bb5..b300bb5 100644 --- a/waflib/ConfigSet.py +++ b/ConfigSet.py diff --git a/waflib/Configure.py b/Configure.py index d0a4793..d0a4793 100644 --- a/waflib/Configure.py +++ b/Configure.py diff --git a/waflib/Context.py b/Context.py index bb47c92..bb47c92 100644 --- a/waflib/Context.py +++ b/Context.py diff --git a/waflib/Errors.py b/Errors.py index bf75c1b..bf75c1b 100644 --- a/waflib/Errors.py +++ b/Errors.py diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 623cddd..0000000 --- a/INSTALL +++ /dev/null @@ -1,59 +0,0 @@ -Installation Instructions -========================= - -Basic Installation ------------------- - -Building this software requires only Python. To install with default options: - - ./waf configure - ./waf - ./waf install - -You may need to become root for the install stage, for example: - - sudo ./waf install - -Configuration Options ---------------------- - -All supported options can be viewed using the command: - - ./waf --help - -Most options only need to be passed during the configure stage, for example: - - ./waf configure --prefix=/usr - ./waf - ./waf install - -Compiler Configuration ----------------------- - -Several standard environment variables can be used to control how compilers are -invoked: - - * CC: Path to C compiler - * CFLAGS: C compiler options - * CXX: Path to C++ compiler - * CXXFLAGS: C++ compiler options - * CPPFLAGS: C preprocessor options - * LINKFLAGS: Linker options - -Installation Directories ------------------------- - -The --prefix option (or the PREFIX environment variable) can be used to change -the prefix which all files are installed under. There are also several options -allowing for more fine-tuned control, see the --help output for details. - -Packaging ---------- - -Everything can be installed to a specific root directory by passing a --destdir -option to the install stage (or setting the DESTDIR environment variable), -which adds a prefix to all install paths. For example: - - ./waf configure --prefix=/usr - ./waf - ./waf install --destdir=/tmp/package @@ -1,58 +0,0 @@ -ganv (1.4.3) unstable; - - * Fix positioning of embedded widgets when changing layout. - * Fix port position on modules with embedded widgets. - * Fix unexpected node jumping when dragging new connections. - * Preserve selection for quickly making several connections. - * Dampen sprung layout energy over time to prevent oscillation. - * Add support for edges that do not constrain the layout. - * Distinguish edge color from port color slighly. - * Highlight connected edges on port hover. - * Add support for PDF and PS export. - * Improve text rendering at high zoom. - * Improve appearance of graphs with circle nodes. - * Improve update performance. - * Add API to specify module port order. - * Add support for beveled box corners. - * Fix various minor visual alignment/sizing issues. - * Fix size of vertical flow modules. - * Fix compilation with --no-fdgl (patch from Vlad Glagolev). - * Fix crash when destroying canvas. - * Upgrade to waf 1.8.14 - - -- David Robillard <d@drobilla.net> Fri, 14 Oct 2016 18:55:26 -0400 - -ganv (1.4.2) stable; - - * Fix bug where edges would not update when nodes are moved after the canvas - is cleared (fix stuck connections in Patchage after refresh). - * Upgrade to waf 1.7.16 - - -- David Robillard <d@drobilla.net> Fri, 08 Aug 2014 18:24:33 -0400 - -ganv (1.4.0) stable; - - * Begin using library and pkg-config names suitable for parallel - installation. This version of flowcanvas is flowcanvas-1 and is - NOT compatible with previous versions - * Clean up API and improve documentation. - * Add font size API - * Use system theme font size by default - * Size empty ports in font based units so they look right when zoomed - * Adjust padding and placement to precisely fit text - * Add ability to select connections directly - * Add Connection::set_curved() - * Fix lingering handle when deleting connections - * Dramatically increase performance by rendering text manually - rather than using the truly awful Gnome::Canvas::Text. - * Remove use of boost smart pointers. Adding and removing from containers - (e.g. Canvas, Module) is now done automatically. - * Clean up API/ABI by hiding private implementations. - * Add ability to select connections by their handles, either individually - or in groups with rect select. - * Further slight improvements in memory consumption and alignment. - * Improve scalability to graphs with many connections (eliminate linear - connection searches and redundant connection collections). - * Switch to GPLv3+ - - -- David Robillard <d@drobilla.net> Sun, 27 Apr 2014 23:44:29 -0400 diff --git a/waflib/Options.py b/Options.py index ad802d4..ad802d4 100644 --- a/waflib/Options.py +++ b/Options.py @@ -1,14 +0,0 @@ -Ganv -==== - -Ganv is an interactive Gtk canvas widget for graph-based interfaces (patchers, -modular synthesizers, finite state automata, interactive graphs, etc). -For more information, see <http://drobilla.net/software/ganv>. - -Ganv provides classes for "Modules" (boxes with "Ports"), Circles, and -Edges (lines that connect either Ports or Circles). The user can rearrange -items, or Ganv can automatically arrange items using GraphViz. Edges can -be made by the user one at a time with the mouse, or in groups using the mouse -and keyboard. - - -- David Robillard <d@drobilla.net> diff --git a/waflib/README.md b/README.md index c5361b9..c5361b9 100644 --- a/waflib/README.md +++ b/README.md diff --git a/waflib/Runner.py b/Runner.py index 261084d..261084d 100644 --- a/waflib/Runner.py +++ b/Runner.py diff --git a/waflib/Scripting.py b/Scripting.py index 749d4f2..749d4f2 100644 --- a/waflib/Scripting.py +++ b/Scripting.py diff --git a/waflib/TaskGen.py b/TaskGen.py index a74e643..a74e643 100644 --- a/waflib/TaskGen.py +++ b/TaskGen.py diff --git a/waflib/Tools/__init__.py b/Tools/__init__.py index 079df35..079df35 100644 --- a/waflib/Tools/__init__.py +++ b/Tools/__init__.py diff --git a/waflib/Tools/ar.py b/Tools/ar.py index b39b645..b39b645 100644 --- a/waflib/Tools/ar.py +++ b/Tools/ar.py diff --git a/waflib/Tools/asm.py b/Tools/asm.py index b6f26fb..b6f26fb 100644 --- a/waflib/Tools/asm.py +++ b/Tools/asm.py diff --git a/waflib/Tools/bison.py b/Tools/bison.py index eef56dc..eef56dc 100644 --- a/waflib/Tools/bison.py +++ b/Tools/bison.py diff --git a/waflib/Tools/c.py b/Tools/c.py index effd6b6..effd6b6 100644 --- a/waflib/Tools/c.py +++ b/Tools/c.py diff --git a/waflib/Tools/c_aliases.py b/Tools/c_aliases.py index c9d5369..c9d5369 100644 --- a/waflib/Tools/c_aliases.py +++ b/Tools/c_aliases.py diff --git a/waflib/Tools/c_config.py b/Tools/c_config.py index d2b3c0d..d2b3c0d 100644 --- a/waflib/Tools/c_config.py +++ b/Tools/c_config.py diff --git a/waflib/Tools/c_osx.py b/Tools/c_osx.py index f70b128..f70b128 100644 --- a/waflib/Tools/c_osx.py +++ b/Tools/c_osx.py diff --git a/waflib/Tools/c_preproc.py b/Tools/c_preproc.py index 7e04b4a..7e04b4a 100644 --- a/waflib/Tools/c_preproc.py +++ b/Tools/c_preproc.py diff --git a/waflib/Tools/c_tests.py b/Tools/c_tests.py index f858df5..f858df5 100644 --- a/waflib/Tools/c_tests.py +++ b/Tools/c_tests.py diff --git a/waflib/Tools/ccroot.py b/Tools/ccroot.py index cfef8bf..cfef8bf 100644 --- a/waflib/Tools/ccroot.py +++ b/Tools/ccroot.py diff --git a/waflib/Tools/clang.py b/Tools/clang.py index 3828e39..3828e39 100644 --- a/waflib/Tools/clang.py +++ b/Tools/clang.py diff --git a/waflib/Tools/clangxx.py b/Tools/clangxx.py index 152013c..152013c 100644 --- a/waflib/Tools/clangxx.py +++ b/Tools/clangxx.py diff --git a/waflib/Tools/compiler_c.py b/Tools/compiler_c.py index 2dba3f8..2dba3f8 100644 --- a/waflib/Tools/compiler_c.py +++ b/Tools/compiler_c.py diff --git a/waflib/Tools/compiler_cxx.py b/Tools/compiler_cxx.py index 1af65a2..1af65a2 100644 --- a/waflib/Tools/compiler_cxx.py +++ b/Tools/compiler_cxx.py diff --git a/waflib/Tools/compiler_d.py b/Tools/compiler_d.py index 43bb1f6..43bb1f6 100644 --- a/waflib/Tools/compiler_d.py +++ b/Tools/compiler_d.py diff --git a/waflib/Tools/compiler_fc.py b/Tools/compiler_fc.py index 96b58e7..96b58e7 100644 --- a/waflib/Tools/compiler_fc.py +++ b/Tools/compiler_fc.py diff --git a/waflib/Tools/cs.py b/Tools/cs.py index aecca6d..aecca6d 100644 --- a/waflib/Tools/cs.py +++ b/Tools/cs.py diff --git a/waflib/Tools/cxx.py b/Tools/cxx.py index 194fad7..194fad7 100644 --- a/waflib/Tools/cxx.py +++ b/Tools/cxx.py diff --git a/waflib/Tools/d.py b/Tools/d.py index e4cf73b..e4cf73b 100644 --- a/waflib/Tools/d.py +++ b/Tools/d.py diff --git a/waflib/Tools/d_config.py b/Tools/d_config.py index 6637556..6637556 100644 --- a/waflib/Tools/d_config.py +++ b/Tools/d_config.py diff --git a/waflib/Tools/d_scan.py b/Tools/d_scan.py index 14c6c31..14c6c31 100644 --- a/waflib/Tools/d_scan.py +++ b/Tools/d_scan.py diff --git a/waflib/Tools/dbus.py b/Tools/dbus.py index d520f1c..d520f1c 100644 --- a/waflib/Tools/dbus.py +++ b/Tools/dbus.py diff --git a/waflib/Tools/dmd.py b/Tools/dmd.py index 8917ca1..8917ca1 100644 --- a/waflib/Tools/dmd.py +++ b/Tools/dmd.py diff --git a/waflib/Tools/errcheck.py b/Tools/errcheck.py index de8d75a..de8d75a 100644 --- a/waflib/Tools/errcheck.py +++ b/Tools/errcheck.py diff --git a/waflib/Tools/fc.py b/Tools/fc.py index d9e8d8c..d9e8d8c 100644 --- a/waflib/Tools/fc.py +++ b/Tools/fc.py diff --git a/waflib/Tools/fc_config.py b/Tools/fc_config.py index 222f3a5..222f3a5 100644 --- a/waflib/Tools/fc_config.py +++ b/Tools/fc_config.py diff --git a/waflib/Tools/fc_scan.py b/Tools/fc_scan.py index 12cb0fc..12cb0fc 100644 --- a/waflib/Tools/fc_scan.py +++ b/Tools/fc_scan.py diff --git a/waflib/Tools/flex.py b/Tools/flex.py index 2256657..2256657 100644 --- a/waflib/Tools/flex.py +++ b/Tools/flex.py diff --git a/waflib/Tools/g95.py b/Tools/g95.py index f69ba4f..f69ba4f 100644 --- a/waflib/Tools/g95.py +++ b/Tools/g95.py diff --git a/waflib/Tools/gas.py b/Tools/gas.py index 77afed7..77afed7 100644 --- a/waflib/Tools/gas.py +++ b/Tools/gas.py diff --git a/waflib/Tools/gcc.py b/Tools/gcc.py index acdd473..acdd473 100644 --- a/waflib/Tools/gcc.py +++ b/Tools/gcc.py diff --git a/waflib/Tools/gdc.py b/Tools/gdc.py index d89a66d..d89a66d 100644 --- a/waflib/Tools/gdc.py +++ b/Tools/gdc.py diff --git a/waflib/Tools/gfortran.py b/Tools/gfortran.py index 1050667..1050667 100644 --- a/waflib/Tools/gfortran.py +++ b/Tools/gfortran.py diff --git a/waflib/Tools/glib2.py b/Tools/glib2.py index 949fe37..949fe37 100644 --- a/waflib/Tools/glib2.py +++ b/Tools/glib2.py diff --git a/waflib/Tools/gnu_dirs.py b/Tools/gnu_dirs.py index 2847071..2847071 100644 --- a/waflib/Tools/gnu_dirs.py +++ b/Tools/gnu_dirs.py diff --git a/waflib/Tools/gxx.py b/Tools/gxx.py index 22c5d26..22c5d26 100644 --- a/waflib/Tools/gxx.py +++ b/Tools/gxx.py diff --git a/waflib/Tools/icc.py b/Tools/icc.py index b6492c8..b6492c8 100644 --- a/waflib/Tools/icc.py +++ b/Tools/icc.py diff --git a/waflib/Tools/icpc.py b/Tools/icpc.py index 8a6cc6c..8a6cc6c 100644 --- a/waflib/Tools/icpc.py +++ b/Tools/icpc.py diff --git a/waflib/Tools/ifort.py b/Tools/ifort.py index 74934f3..74934f3 100644 --- a/waflib/Tools/ifort.py +++ b/Tools/ifort.py diff --git a/waflib/Tools/intltool.py b/Tools/intltool.py index af95ba8..af95ba8 100644 --- a/waflib/Tools/intltool.py +++ b/Tools/intltool.py diff --git a/waflib/Tools/irixcc.py b/Tools/irixcc.py index c3ae1ac..c3ae1ac 100644 --- a/waflib/Tools/irixcc.py +++ b/Tools/irixcc.py diff --git a/waflib/Tools/javaw.py b/Tools/javaw.py index f6fd20c..f6fd20c 100644 --- a/waflib/Tools/javaw.py +++ b/Tools/javaw.py diff --git a/waflib/Tools/ldc2.py b/Tools/ldc2.py index a51c344..a51c344 100644 --- a/waflib/Tools/ldc2.py +++ b/Tools/ldc2.py diff --git a/waflib/Tools/lua.py b/Tools/lua.py index 15a333a..15a333a 100644 --- a/waflib/Tools/lua.py +++ b/Tools/lua.py diff --git a/waflib/Tools/md5_tstamp.py b/Tools/md5_tstamp.py index 6428e46..6428e46 100644 --- a/waflib/Tools/md5_tstamp.py +++ b/Tools/md5_tstamp.py diff --git a/waflib/Tools/msvc.py b/Tools/msvc.py index 17b347d..17b347d 100644 --- a/waflib/Tools/msvc.py +++ b/Tools/msvc.py diff --git a/waflib/Tools/nasm.py b/Tools/nasm.py index 411d582..411d582 100644 --- a/waflib/Tools/nasm.py +++ b/Tools/nasm.py diff --git a/waflib/Tools/nobuild.py b/Tools/nobuild.py index 2e4b055..2e4b055 100644 --- a/waflib/Tools/nobuild.py +++ b/Tools/nobuild.py diff --git a/waflib/Tools/perl.py b/Tools/perl.py index 32b03fb..32b03fb 100644 --- a/waflib/Tools/perl.py +++ b/Tools/perl.py diff --git a/waflib/Tools/python.py b/Tools/python.py index 25841d0..25841d0 100644 --- a/waflib/Tools/python.py +++ b/Tools/python.py diff --git a/waflib/Tools/qt5.py b/Tools/qt5.py index 4f9c690..4f9c690 100644 --- a/waflib/Tools/qt5.py +++ b/Tools/qt5.py diff --git a/waflib/Tools/ruby.py b/Tools/ruby.py index 8d92a79..8d92a79 100644 --- a/waflib/Tools/ruby.py +++ b/Tools/ruby.py diff --git a/waflib/Tools/suncc.py b/Tools/suncc.py index 33d34fc..33d34fc 100644 --- a/waflib/Tools/suncc.py +++ b/Tools/suncc.py diff --git a/waflib/Tools/suncxx.py b/Tools/suncxx.py index 3b384f6..3b384f6 100644 --- a/waflib/Tools/suncxx.py +++ b/Tools/suncxx.py diff --git a/waflib/Tools/tex.py b/Tools/tex.py index eaf9fdb..eaf9fdb 100644 --- a/waflib/Tools/tex.py +++ b/Tools/tex.py diff --git a/waflib/Tools/vala.py b/Tools/vala.py index 822ec50..822ec50 100644 --- a/waflib/Tools/vala.py +++ b/Tools/vala.py diff --git a/waflib/Tools/waf_unit_test.py b/Tools/waf_unit_test.py index a71ed1c..a71ed1c 100644 --- a/waflib/Tools/waf_unit_test.py +++ b/Tools/waf_unit_test.py diff --git a/waflib/Tools/winres.py b/Tools/winres.py index 586c596..586c596 100644 --- a/waflib/Tools/winres.py +++ b/Tools/winres.py diff --git a/waflib/Tools/xlc.py b/Tools/xlc.py index 134dd41..134dd41 100644 --- a/waflib/Tools/xlc.py +++ b/Tools/xlc.py diff --git a/waflib/Tools/xlcxx.py b/Tools/xlcxx.py index 76aa59b..76aa59b 100644 --- a/waflib/Tools/xlcxx.py +++ b/Tools/xlcxx.py diff --git a/waflib/Utils.py b/Utils.py index b4665c4..b4665c4 100644 --- a/waflib/Utils.py +++ b/Utils.py diff --git a/waflib/__init__.py b/__init__.py index 079df35..079df35 100644 --- a/waflib/__init__.py +++ b/__init__.py diff --git a/waflib/ansiterm.py b/ansiterm.py index 0d20c63..0d20c63 100644 --- a/waflib/ansiterm.py +++ b/ansiterm.py diff --git a/waflib/extras/__init__.py b/extras/__init__.py index c8a3c34..c8a3c34 100644 --- a/waflib/extras/__init__.py +++ b/extras/__init__.py diff --git a/waflib/extras/autowaf.py b/extras/autowaf.py index 8f9c633..feaae3c 100644 --- a/waflib/extras/autowaf.py +++ b/extras/autowaf.py @@ -2,6 +2,7 @@ import glob import os import subprocess import sys +import time from waflib import Build, Context, Logs, Options, Utils from waflib.TaskGen import feature, before, after @@ -69,7 +70,7 @@ def set_options(opt, debug_by_default=False, test=False): opts.add_option('-s', '--strict', action='store_true', default=False, dest='strict', help="use strict compiler flags and show all warnings") - opts.add_option('--ultra-strict', action='store_true', default=False, + opts.add_option('-S', '--ultra-strict', action='store_true', default=False, dest='ultra_strict', help="use extremely strict compiler flags (likely noisy)") opts.add_option('--docs', action='store_true', default=False, dest='docs', @@ -731,8 +732,6 @@ def cd_to_build_dir(ctx, appname): os.chdir(os.path.join('build', appname)) else: os.chdir('build') - Logs.pprint('GREEN', ("Waf: Entering directory `%s'" % - os.path.abspath(os.getcwd()))) def cd_to_orig_dir(ctx, child): if child: @@ -741,7 +740,10 @@ def cd_to_orig_dir(ctx, child): os.chdir('..') def pre_test(ctx, appname, dirs=['src']): + Logs.pprint('GREEN', '\n[==========] Running %s tests' % appname) + if not hasattr(ctx, 'autowaf_tests_total'): + ctx.autowaf_tests_start_time = time.clock() ctx.autowaf_tests_total = 0 ctx.autowaf_tests_failed = 0 ctx.autowaf_local_tests_total = 0 @@ -766,6 +768,9 @@ def pre_test(ctx, appname, dirs=['src']): finally: clear_log.close() +class TestFailed(Exception): + pass + def post_test(ctx, appname, dirs=['src'], remove=['*boost*', 'c++*']): if not ctx.env.NO_COVERAGE: diropts = '' @@ -806,21 +811,22 @@ def post_test(ctx, appname, dirs=['src'], remove=['*boost*', 'c++*']): coverage_lcov.close() coverage_log.close() - if ctx.autowaf_tests[appname]['failed'] > 0: - Logs.pprint('RED', '\nSummary: %d / %d %s tests failed' % ( - ctx.autowaf_tests[appname]['failed'], - ctx.autowaf_tests[appname]['total'], - appname)) - else: - Logs.pprint('GREEN', '\nSummary: All %d %s tests passed' % ( - ctx.autowaf_tests[appname]['total'], appname)) - + duration = (time.clock() - ctx.autowaf_tests_start_time) * 1000.0 + total_tests = ctx.autowaf_tests[appname]['total'] + failed_tests = ctx.autowaf_tests[appname]['failed'] + passed_tests = total_tests - failed_tests + Logs.pprint('GREEN', '\n[==========] %d tests from %s ran (%d ms total)' % ( + total_tests, appname, duration)) if not ctx.env.NO_COVERAGE: - Logs.pprint('GREEN', 'Coverage: <file://%s>\n' + Logs.pprint('GREEN', '[----------] Coverage: <file://%s>' % os.path.abspath('coverage/index.html')) - Logs.pprint('GREEN', ("Waf: Leaving directory `%s'" % - os.path.abspath(os.getcwd()))) + Logs.pprint('GREEN', '[ PASSED ] %d tests' % passed_tests) + if failed_tests > 0: + Logs.pprint('RED', '[ FAILED ] %d tests' % failed_tests) + raise TestFailed('Tests from %s failed' % appname) + Logs.pprint('', '') + top_level = (len(ctx.stack_path) > 1) if top_level: cd_to_orig_dir(ctx, top_level) @@ -854,7 +860,7 @@ def run_test(ctx, if isinstance(test, type([])): s = ' '.join(test) if header and not quiet: - Logs.pprint('Green', '\n** Test %s' % s) + Logs.pprint('Green', '\n[ RUN ] %s' % s) cmd = test if Options.options.test_wrapper: cmd = Options.options.test_wrapper + ' ' + test @@ -869,17 +875,18 @@ def run_test(ctx, success = desired_status is None or returncode == desired_status if success: if not quiet: - Logs.pprint('GREEN', '** Pass %s' % name) + Logs.pprint('GREEN', '[ OK ] %s' % name) else: - Logs.pprint('RED', '** FAIL %s' % name) + Logs.pprint('RED', '[ FAILED ] %s' % name) ctx.autowaf_tests_failed += 1 + ctx.autowaf_local_tests_failed += 1 ctx.autowaf_tests[appname]['failed'] += 1 if type(test) != list and not callable(test): Logs.pprint('RED', test) if Options.options.verbose_tests and type(test) != list and not callable(test): - sys.stdout.write(out[0]) - sys.stderr.write(out[1]) + sys.stdout.write(out[0].decode('utf-8')) + sys.stderr.write(out[1].decode('utf-8')) return (success, out) @@ -892,7 +899,8 @@ def tests_name(ctx, appname, name='*'): def begin_tests(ctx, appname, name='*'): ctx.autowaf_local_tests_failed = 0 ctx.autowaf_local_tests_total = 0 - Logs.pprint('GREEN', '\n** Begin %s tests' % ( + ctx.autowaf_local_tests_start_time = time.clock() + Logs.pprint('GREEN', '\n[----------] %s' % ( tests_name(ctx, appname, name))) class Handle: @@ -905,13 +913,15 @@ def begin_tests(ctx, appname, name='*'): return Handle() def end_tests(ctx, appname, name='*'): + duration = (time.clock() - ctx.autowaf_local_tests_start_time) * 1000.0 + total = ctx.autowaf_local_tests_total failures = ctx.autowaf_local_tests_failed if failures == 0: - Logs.pprint('GREEN', '** Passed all %d %s tests' % ( - ctx.autowaf_local_tests_total, tests_name(ctx, appname, name))) + Logs.pprint('GREEN', '[----------] %d tests from %s (%d ms total)' % ( + ctx.autowaf_local_tests_total, tests_name(ctx, appname, name), duration)) else: - Logs.pprint('RED', '** Failed %d / %d %s tests' % ( - failures, ctx.autowaf_local_tests_total, tests_name(ctx, appname, name))) + Logs.pprint('RED', '[----------] %d/%d tests from %s (%d ms total)' % ( + total - failures, total, tests_name(ctx, appname, name), duration)) def run_tests(ctx, appname, diff --git a/waflib/extras/batched_cc.py b/extras/batched_cc.py index aad2872..aad2872 100644 --- a/waflib/extras/batched_cc.py +++ b/extras/batched_cc.py diff --git a/waflib/extras/biber.py b/extras/biber.py index fd9db4e..fd9db4e 100644 --- a/waflib/extras/biber.py +++ b/extras/biber.py diff --git a/waflib/extras/bjam.py b/extras/bjam.py index 8e04d3a..8e04d3a 100644 --- a/waflib/extras/bjam.py +++ b/extras/bjam.py diff --git a/waflib/extras/blender.py b/extras/blender.py index e5efc28..e5efc28 100644 --- a/waflib/extras/blender.py +++ b/extras/blender.py diff --git a/waflib/extras/boo.py b/extras/boo.py index 06623d4..06623d4 100644 --- a/waflib/extras/boo.py +++ b/extras/boo.py diff --git a/waflib/extras/boost.py b/extras/boost.py index c2aaaa9..c2aaaa9 100644 --- a/waflib/extras/boost.py +++ b/extras/boost.py diff --git a/waflib/extras/build_file_tracker.py b/extras/build_file_tracker.py index c4f26fd..c4f26fd 100644 --- a/waflib/extras/build_file_tracker.py +++ b/extras/build_file_tracker.py diff --git a/waflib/extras/build_logs.py b/extras/build_logs.py index cdf8ed0..cdf8ed0 100644 --- a/waflib/extras/build_logs.py +++ b/extras/build_logs.py diff --git a/waflib/extras/buildcopy.py b/extras/buildcopy.py index a6d9ac8..a6d9ac8 100644 --- a/waflib/extras/buildcopy.py +++ b/extras/buildcopy.py diff --git a/waflib/extras/c_bgxlc.py b/extras/c_bgxlc.py index 6e3eaf7..6e3eaf7 100644 --- a/waflib/extras/c_bgxlc.py +++ b/extras/c_bgxlc.py diff --git a/waflib/extras/c_dumbpreproc.py b/extras/c_dumbpreproc.py index ce9e1a4..ce9e1a4 100644 --- a/waflib/extras/c_dumbpreproc.py +++ b/extras/c_dumbpreproc.py diff --git a/waflib/extras/c_emscripten.py b/extras/c_emscripten.py index e1ac494..e1ac494 100644 --- a/waflib/extras/c_emscripten.py +++ b/extras/c_emscripten.py diff --git a/waflib/extras/c_nec.py b/extras/c_nec.py index 96bfae4..96bfae4 100644 --- a/waflib/extras/c_nec.py +++ b/extras/c_nec.py diff --git a/waflib/extras/cabal.py b/extras/cabal.py index e10a0d1..e10a0d1 100644 --- a/waflib/extras/cabal.py +++ b/extras/cabal.py diff --git a/waflib/extras/cfg_altoptions.py b/extras/cfg_altoptions.py index 47b1189..47b1189 100644 --- a/waflib/extras/cfg_altoptions.py +++ b/extras/cfg_altoptions.py diff --git a/waflib/extras/clang_compilation_database.py b/extras/clang_compilation_database.py index 4d9b5e2..4d9b5e2 100644 --- a/waflib/extras/clang_compilation_database.py +++ b/extras/clang_compilation_database.py diff --git a/waflib/extras/codelite.py b/extras/codelite.py index 523302c..523302c 100644 --- a/waflib/extras/codelite.py +++ b/extras/codelite.py diff --git a/waflib/extras/color_gcc.py b/extras/color_gcc.py index b68c5eb..b68c5eb 100644 --- a/waflib/extras/color_gcc.py +++ b/extras/color_gcc.py diff --git a/waflib/extras/color_rvct.py b/extras/color_rvct.py index f89ccbd..f89ccbd 100644 --- a/waflib/extras/color_rvct.py +++ b/extras/color_rvct.py diff --git a/waflib/extras/compat15.py b/extras/compat15.py index 0e74df8..0e74df8 100644 --- a/waflib/extras/compat15.py +++ b/extras/compat15.py diff --git a/waflib/extras/cppcheck.py b/extras/cppcheck.py index 13ff424..13ff424 100644 --- a/waflib/extras/cppcheck.py +++ b/extras/cppcheck.py diff --git a/waflib/extras/cpplint.py b/extras/cpplint.py index e3302e5..e3302e5 100644 --- a/waflib/extras/cpplint.py +++ b/extras/cpplint.py diff --git a/waflib/extras/cross_gnu.py b/extras/cross_gnu.py index 309f53b..309f53b 100644 --- a/waflib/extras/cross_gnu.py +++ b/extras/cross_gnu.py diff --git a/waflib/extras/cython.py b/extras/cython.py index 481d6f4..481d6f4 100644 --- a/waflib/extras/cython.py +++ b/extras/cython.py diff --git a/waflib/extras/dcc.py b/extras/dcc.py index c1a57c0..c1a57c0 100644 --- a/waflib/extras/dcc.py +++ b/extras/dcc.py diff --git a/waflib/extras/distnet.py b/extras/distnet.py index 09a31a6..09a31a6 100644 --- a/waflib/extras/distnet.py +++ b/extras/distnet.py diff --git a/waflib/extras/doxygen.py b/extras/doxygen.py index 28f56e9..28f56e9 100644 --- a/waflib/extras/doxygen.py +++ b/extras/doxygen.py diff --git a/waflib/extras/dpapi.py b/extras/dpapi.py index b94d482..b94d482 100644 --- a/waflib/extras/dpapi.py +++ b/extras/dpapi.py diff --git a/waflib/extras/eclipse.py b/extras/eclipse.py index bb78741..bb78741 100644 --- a/waflib/extras/eclipse.py +++ b/extras/eclipse.py diff --git a/waflib/extras/erlang.py b/extras/erlang.py index 49f6d5b..49f6d5b 100644 --- a/waflib/extras/erlang.py +++ b/extras/erlang.py diff --git a/waflib/extras/fast_partial.py b/extras/fast_partial.py index b3af513..b3af513 100644 --- a/waflib/extras/fast_partial.py +++ b/extras/fast_partial.py diff --git a/waflib/extras/fc_bgxlf.py b/extras/fc_bgxlf.py index cca1810..cca1810 100644 --- a/waflib/extras/fc_bgxlf.py +++ b/extras/fc_bgxlf.py diff --git a/waflib/extras/fc_cray.py b/extras/fc_cray.py index da733fa..da733fa 100644 --- a/waflib/extras/fc_cray.py +++ b/extras/fc_cray.py diff --git a/waflib/extras/fc_nag.py b/extras/fc_nag.py index edcb218..edcb218 100644 --- a/waflib/extras/fc_nag.py +++ b/extras/fc_nag.py diff --git a/waflib/extras/fc_nec.py b/extras/fc_nec.py index 67c8680..67c8680 100644 --- a/waflib/extras/fc_nec.py +++ b/extras/fc_nec.py diff --git a/waflib/extras/fc_open64.py b/extras/fc_open64.py index 413719f..413719f 100644 --- a/waflib/extras/fc_open64.py +++ b/extras/fc_open64.py diff --git a/waflib/extras/fc_pgfortran.py b/extras/fc_pgfortran.py index afb2817..afb2817 100644 --- a/waflib/extras/fc_pgfortran.py +++ b/extras/fc_pgfortran.py diff --git a/waflib/extras/fc_solstudio.py b/extras/fc_solstudio.py index 53766df..53766df 100644 --- a/waflib/extras/fc_solstudio.py +++ b/extras/fc_solstudio.py diff --git a/waflib/extras/fc_xlf.py b/extras/fc_xlf.py index 5a3da03..5a3da03 100644 --- a/waflib/extras/fc_xlf.py +++ b/extras/fc_xlf.py diff --git a/waflib/extras/file_to_object.py b/extras/file_to_object.py index 1393b51..1393b51 100644 --- a/waflib/extras/file_to_object.py +++ b/extras/file_to_object.py diff --git a/waflib/extras/fluid.py b/extras/fluid.py index 4814a35..4814a35 100644 --- a/waflib/extras/fluid.py +++ b/extras/fluid.py diff --git a/waflib/extras/freeimage.py b/extras/freeimage.py index f27e525..f27e525 100644 --- a/waflib/extras/freeimage.py +++ b/extras/freeimage.py diff --git a/waflib/extras/fsb.py b/extras/fsb.py index 1b8f398..1b8f398 100644 --- a/waflib/extras/fsb.py +++ b/extras/fsb.py diff --git a/waflib/extras/fsc.py b/extras/fsc.py index c67e70b..c67e70b 100644 --- a/waflib/extras/fsc.py +++ b/extras/fsc.py diff --git a/waflib/extras/gccdeps.py b/extras/gccdeps.py index d9758ab..d9758ab 100644 --- a/waflib/extras/gccdeps.py +++ b/extras/gccdeps.py diff --git a/waflib/extras/gdbus.py b/extras/gdbus.py index 0e0476e..0e0476e 100644 --- a/waflib/extras/gdbus.py +++ b/extras/gdbus.py diff --git a/waflib/extras/gob2.py b/extras/gob2.py index b4fa3b9..b4fa3b9 100644 --- a/waflib/extras/gob2.py +++ b/extras/gob2.py diff --git a/waflib/extras/halide.py b/extras/halide.py index 6078e38..6078e38 100644 --- a/waflib/extras/halide.py +++ b/extras/halide.py diff --git a/waflib/extras/javatest.py b/extras/javatest.py index 979b8d8..979b8d8 100755 --- a/waflib/extras/javatest.py +++ b/extras/javatest.py diff --git a/waflib/extras/kde4.py b/extras/kde4.py index e49a9ec..e49a9ec 100644 --- a/waflib/extras/kde4.py +++ b/extras/kde4.py diff --git a/waflib/extras/local_rpath.py b/extras/local_rpath.py index b2507e1..b2507e1 100644 --- a/waflib/extras/local_rpath.py +++ b/extras/local_rpath.py diff --git a/waflib/extras/lv2.py b/extras/lv2.py index 815987f..815987f 100644 --- a/waflib/extras/lv2.py +++ b/extras/lv2.py diff --git a/waflib/extras/make.py b/extras/make.py index 933d9ca..933d9ca 100644 --- a/waflib/extras/make.py +++ b/extras/make.py diff --git a/waflib/extras/midl.py b/extras/midl.py index 43e6cf9..43e6cf9 100644 --- a/waflib/extras/midl.py +++ b/extras/midl.py diff --git a/waflib/extras/msvcdeps.py b/extras/msvcdeps.py index fc1ecd4..fc1ecd4 100644 --- a/waflib/extras/msvcdeps.py +++ b/extras/msvcdeps.py diff --git a/waflib/extras/msvs.py b/extras/msvs.py index 8aa2db0..8aa2db0 100644 --- a/waflib/extras/msvs.py +++ b/extras/msvs.py diff --git a/waflib/extras/netcache_client.py b/extras/netcache_client.py index dc49048..dc49048 100644 --- a/waflib/extras/netcache_client.py +++ b/extras/netcache_client.py diff --git a/waflib/extras/objcopy.py b/extras/objcopy.py index 82d8359..82d8359 100644 --- a/waflib/extras/objcopy.py +++ b/extras/objcopy.py diff --git a/waflib/extras/ocaml.py b/extras/ocaml.py index afe73c0..afe73c0 100644 --- a/waflib/extras/ocaml.py +++ b/extras/ocaml.py diff --git a/waflib/extras/package.py b/extras/package.py index c06498e..c06498e 100644 --- a/waflib/extras/package.py +++ b/extras/package.py diff --git a/waflib/extras/parallel_debug.py b/extras/parallel_debug.py index 35883a3..35883a3 100644 --- a/waflib/extras/parallel_debug.py +++ b/extras/parallel_debug.py diff --git a/waflib/extras/pch.py b/extras/pch.py index 103e752..103e752 100644 --- a/waflib/extras/pch.py +++ b/extras/pch.py diff --git a/waflib/extras/pep8.py b/extras/pep8.py index 676beed..676beed 100644 --- a/waflib/extras/pep8.py +++ b/extras/pep8.py diff --git a/waflib/extras/pgicc.py b/extras/pgicc.py index 9790b9c..9790b9c 100644 --- a/waflib/extras/pgicc.py +++ b/extras/pgicc.py diff --git a/waflib/extras/pgicxx.py b/extras/pgicxx.py index eae121c..eae121c 100644 --- a/waflib/extras/pgicxx.py +++ b/extras/pgicxx.py diff --git a/waflib/extras/proc.py b/extras/proc.py index 764abec..764abec 100644 --- a/waflib/extras/proc.py +++ b/extras/proc.py diff --git a/waflib/extras/protoc.py b/extras/protoc.py index f3cb4d8..f3cb4d8 100644 --- a/waflib/extras/protoc.py +++ b/extras/protoc.py diff --git a/waflib/extras/pyqt5.py b/extras/pyqt5.py index c21dfa7..c21dfa7 100644 --- a/waflib/extras/pyqt5.py +++ b/extras/pyqt5.py diff --git a/waflib/extras/pytest.py b/extras/pytest.py index 7dd5a1a..7dd5a1a 100644 --- a/waflib/extras/pytest.py +++ b/extras/pytest.py diff --git a/waflib/extras/qnxnto.py b/extras/qnxnto.py index 1158124..1158124 100644 --- a/waflib/extras/qnxnto.py +++ b/extras/qnxnto.py diff --git a/waflib/extras/qt4.py b/extras/qt4.py index 90cae7e..90cae7e 100644 --- a/waflib/extras/qt4.py +++ b/extras/qt4.py diff --git a/waflib/extras/relocation.py b/extras/relocation.py index 7e821f4..7e821f4 100644 --- a/waflib/extras/relocation.py +++ b/extras/relocation.py diff --git a/waflib/extras/remote.py b/extras/remote.py index 3b038f7..3b038f7 100644 --- a/waflib/extras/remote.py +++ b/extras/remote.py diff --git a/waflib/extras/resx.py b/extras/resx.py index caf4d31..caf4d31 100644 --- a/waflib/extras/resx.py +++ b/extras/resx.py diff --git a/waflib/extras/review.py b/extras/review.py index 561e062..561e062 100644 --- a/waflib/extras/review.py +++ b/extras/review.py diff --git a/waflib/extras/rst.py b/extras/rst.py index f3c3a5e..f3c3a5e 100644 --- a/waflib/extras/rst.py +++ b/extras/rst.py diff --git a/waflib/extras/run_do_script.py b/extras/run_do_script.py index f3c5812..f3c5812 100644 --- a/waflib/extras/run_do_script.py +++ b/extras/run_do_script.py diff --git a/waflib/extras/run_m_script.py b/extras/run_m_script.py index b5f27eb..b5f27eb 100644 --- a/waflib/extras/run_m_script.py +++ b/extras/run_m_script.py diff --git a/waflib/extras/run_py_script.py b/extras/run_py_script.py index 3670381..3670381 100644 --- a/waflib/extras/run_py_script.py +++ b/extras/run_py_script.py diff --git a/waflib/extras/run_r_script.py b/extras/run_r_script.py index b0d8f2b..b0d8f2b 100644 --- a/waflib/extras/run_r_script.py +++ b/extras/run_r_script.py diff --git a/waflib/extras/sas.py b/extras/sas.py index 754c614..754c614 100644 --- a/waflib/extras/sas.py +++ b/extras/sas.py diff --git a/waflib/extras/satellite_assembly.py b/extras/satellite_assembly.py index 005eb07..005eb07 100644 --- a/waflib/extras/satellite_assembly.py +++ b/extras/satellite_assembly.py diff --git a/waflib/extras/scala.py b/extras/scala.py index a9880f0..a9880f0 100644 --- a/waflib/extras/scala.py +++ b/extras/scala.py diff --git a/waflib/extras/slow_qt4.py b/extras/slow_qt4.py index ec7880b..ec7880b 100644 --- a/waflib/extras/slow_qt4.py +++ b/extras/slow_qt4.py diff --git a/waflib/extras/softlink_libs.py b/extras/softlink_libs.py index 50c777f..50c777f 100644 --- a/waflib/extras/softlink_libs.py +++ b/extras/softlink_libs.py diff --git a/waflib/extras/stale.py b/extras/stale.py index cac3f46..cac3f46 100644 --- a/waflib/extras/stale.py +++ b/extras/stale.py diff --git a/waflib/extras/stracedeps.py b/extras/stracedeps.py index 37d82cb..37d82cb 100644 --- a/waflib/extras/stracedeps.py +++ b/extras/stracedeps.py diff --git a/waflib/extras/swig.py b/extras/swig.py index fd3d6d2..fd3d6d2 100644 --- a/waflib/extras/swig.py +++ b/extras/swig.py diff --git a/waflib/extras/syms.py b/extras/syms.py index dfa0059..dfa0059 100644 --- a/waflib/extras/syms.py +++ b/extras/syms.py diff --git a/waflib/extras/ticgt.py b/extras/ticgt.py index f43a7ea..f43a7ea 100644 --- a/waflib/extras/ticgt.py +++ b/extras/ticgt.py diff --git a/waflib/extras/unity.py b/extras/unity.py index 78128ed..78128ed 100644 --- a/waflib/extras/unity.py +++ b/extras/unity.py diff --git a/waflib/extras/use_config.py b/extras/use_config.py index ef5129f..ef5129f 100644 --- a/waflib/extras/use_config.py +++ b/extras/use_config.py diff --git a/waflib/extras/valadoc.py b/extras/valadoc.py index c50f69e..c50f69e 100644 --- a/waflib/extras/valadoc.py +++ b/extras/valadoc.py diff --git a/waflib/extras/waf_xattr.py b/extras/waf_xattr.py index 351dd63..351dd63 100644 --- a/waflib/extras/waf_xattr.py +++ b/extras/waf_xattr.py diff --git a/waflib/extras/why.py b/extras/why.py index 1bb941f..1bb941f 100644 --- a/waflib/extras/why.py +++ b/extras/why.py diff --git a/waflib/extras/win32_opts.py b/extras/win32_opts.py index 9f7443c..9f7443c 100644 --- a/waflib/extras/win32_opts.py +++ b/extras/win32_opts.py diff --git a/waflib/extras/wix.py b/extras/wix.py index d87bfbb..d87bfbb 100644 --- a/waflib/extras/wix.py +++ b/extras/wix.py diff --git a/waflib/extras/xcode6.py b/extras/xcode6.py index 91bbff1..91bbff1 100644 --- a/waflib/extras/xcode6.py +++ b/extras/xcode6.py diff --git a/waflib/fixpy2.py b/fixpy2.py index 24176e0..24176e0 100644 --- a/waflib/fixpy2.py +++ b/fixpy2.py diff --git a/ganv.pc.in b/ganv.pc.in deleted file mode 100644 index 3edf190..0000000 --- a/ganv.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@PREFIX@ -exec_prefix=@EXEC_PREFIX@ -libdir=@LIBDIR@ -includedir=@INCLUDEDIR@ - -Name: ganv -Version: @GANV_VERSION@ -Description: A Gtk canvas widget for graph based interfaces -Requires: gtk+-2.0 -Libs: -L${libdir} -l@LIB_GANV@ -Cflags: -I${includedir}/ganv-@GANV_MAJOR_VERSION@ diff --git a/ganv/Box.hpp b/ganv/Box.hpp deleted file mode 100644 index 1b95859..0000000 --- a/ganv/Box.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_BOX_HPP -#define GANV_BOX_HPP - -#include "ganv/Node.hpp" -#include "ganv/box.h" - -namespace Ganv { - -class Box : public Node -{ -public: - Box(Canvas* canvas, GanvBox* gobj) - : Node(canvas, GANV_NODE(gobj)) - {} - - RW_PROPERTY(const char*, label) - RW_PROPERTY(gboolean, beveled) - - METHODRET0(ganv_box, double, get_x1) - METHODRET0(ganv_box, double, get_y1) - METHODRET0(ganv_box, double, get_x2) - METHODRET0(ganv_box, double, get_y2) - METHODRET0(ganv_box, double, get_width) - METHOD1(ganv_box, set_width, double, width) - METHODRET0(ganv_box, double, get_height) - METHOD1(ganv_box, set_height, double, height) - METHODRET0(ganv_box, double, get_border_width) - - GanvBox* gobj() { return GANV_BOX(_gobj); } - const GanvBox* gobj() const { return GANV_BOX(_gobj); } -}; - -} // namespace Ganv - -#endif // GANV_BOX_HPP diff --git a/ganv/Canvas.hpp b/ganv/Canvas.hpp deleted file mode 100644 index 8db1f66..0000000 --- a/ganv/Canvas.hpp +++ /dev/null @@ -1,158 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_CANVAS_HPP -#define GANV_CANVAS_HPP - -#include <string> - -#include <glib.h> -#include <glibmm.h> -#include <gtkmm/layout.h> - -#include "ganv/canvas.h" -#include "ganv/wrap.hpp" - -/** Ganv namespace, everything is defined under this. - * - * @ingroup Ganv - */ -namespace Ganv { - -class Edge; -class Item; -class Node; -class Port; - -/** @defgroup Ganv Ganv - * - * A canvas widget for graph-like UIs. - */ - -/** The 'master' canvas widget which contains all other objects. - * - * Applications must override some virtual methods to make the widget actually - * do anything (e.g. connect). - * - * @ingroup Ganv - */ -class Canvas -{ -public: - Canvas(double width, double height); - virtual ~Canvas(); - - GanvItem* root() { return ganv_canvas_root(gobj()); } - - METHOD0(ganv_canvas, clear); - METHODRET0(ganv_canvas, gboolean, empty) - METHOD2(ganv_canvas, resize, double, width, double, height); - METHOD4(ganv_canvas, set_scroll_region, double, x1, double, y1, double, x2, double, y2); - METHOD4(ganv_canvas, get_scroll_region, double*, x1, double*, y1, double*, x2, double*, y2); - METHOD1(ganv_canvas, set_center_scroll_region, gboolean, c); - METHODRET0(ganv_canvas, gboolean, get_center_scroll_region); - METHOD2(ganv_canvas, scroll_to, int, x, int, y); - - void get_scroll_offsets(int& cx, int& cy) const { - ganv_canvas_get_scroll_offsets(gobj(), &cx, &cy); - } - - METHOD1(ganv_canvas, w2c_affine, cairo_matrix_t*, matrix); - METHOD4(ganv_canvas, w2c, double, wx, double, wy, int*, cx, int*, cy); - METHOD4(ganv_canvas, w2c_d, double, wx, double, wy, double*, cx, double*, cy); - METHOD4(ganv_canvas, c2w, int, cx, int, cy, double*, wx, double*, wy); - METHOD4(ganv_canvas, window_to_world, double, winx, double, winy, double*, worldx, double*, worldy); - METHOD4(ganv_canvas, world_to_window, double, worldx, double, worldy, double*, winx, double*, winy); - - Item* get_item_at(double x, double y) const; - Edge* get_edge(Node* tail, Node* head) const; - void remove_edge_between(Node* tail, Node* head); - void remove_edge(Edge* edge); - - METHOD0(ganv_canvas, arrange); - METHODRET2(ganv_canvas, int, export_image, const char*, filename, bool, draw_background); - METHOD1(ganv_canvas, export_dot, const char*, filename); - METHODRET0(ganv_canvas, gboolean, supports_sprung_layout); - METHODRET1(ganv_canvas, gboolean, set_sprung_layout, gboolean, sprung_layout); - METHOD2(ganv_canvas, for_each_node, GanvNodeFunc, f, void*, data) - METHOD2(ganv_canvas, for_each_selected_node, GanvNodeFunc, f, void*, data) - METHOD2(ganv_canvas, for_each_edge, GanvEdgeFunc, f, void*, data) - METHOD3(ganv_canvas, for_each_edge_from, - const GanvNode*, tail, - GanvEdgeFunc, f, - void*, data); - METHOD3(ganv_canvas, for_each_edge_to, - const GanvNode*, head, - GanvEdgeFunc, f, - void*, data); - METHOD3(ganv_canvas, for_each_edge_on, - const GanvNode*, node, - GanvEdgeFunc, f, - void*, data); - METHOD2(ganv_canvas, for_each_selected_edge, GanvEdgeFunc, f, void*, data) - - METHOD0(ganv_canvas, select_all); - METHOD0(ganv_canvas, clear_selection); - METHODRET0(ganv_canvas, double, get_zoom); - METHOD1(ganv_canvas, set_zoom, double, pix_per_unit); - METHOD0(ganv_canvas, zoom_full); - METHODRET0(ganv_canvas, double, get_default_font_size) - METHODRET0(ganv_canvas, double, get_font_size) - METHOD1(ganv_canvas, set_font_size, double, points); - METHOD0(ganv_canvas, get_move_cursor); - METHOD2(ganv_canvas, move_contents_to, double, x, double, y); - - RW_PROPERTY(gboolean, locked) - RW_PROPERTY(double, width) - RW_PROPERTY(double, height) - RW_PROPERTY(GanvDirection, direction) - - void set_port_order(GanvPortOrderFunc port_cmp, void* data) { - ganv_canvas_set_port_order(gobj(), port_cmp, data); - } - - Gtk::Layout& widget() { - return *Glib::wrap(&_gobj->layout); - } - - GQuark wrapper_key(); - - GanvCanvas* gobj() { return GANV_CANVAS(_gobj); } - const GanvCanvas* gobj() const { return GANV_CANVAS(_gobj); } - - sigc::signal<bool, GdkEvent*> signal_event; - sigc::signal<void, Node*, Node*> signal_connect; - sigc::signal<void, Node*, Node*> signal_disconnect; - -private: - Canvas(const Canvas&); ///< Noncopyable - const Canvas& operator=(const Canvas&); ///< Noncopyable - - GanvCanvas* const _gobj; -}; - -} // namespace Ganv - -namespace Glib { - -static inline Ganv::Canvas* -wrap(GanvCanvas* canvas) -{ - return (Ganv::Canvas*)ganv_canvas_get_wrapper(canvas); -} - -} // namespace Glib - -#endif // GANV_CANVAS_HPP diff --git a/ganv/Circle.hpp b/ganv/Circle.hpp deleted file mode 100644 index ab47669..0000000 --- a/ganv/Circle.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2013 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_CIRCLE_HPP -#define GANV_CIRCLE_HPP - -#include <algorithm> -#include <map> -#include <string> -#include <stdint.h> - -#include <gdkmm/types.h> - -#include "ganv/types.hpp" -#include "ganv/Node.hpp" -#include "ganv/circle.h" - -GANV_GLIB_WRAP(Circle) - -namespace Ganv { - -class Canvas; - -/** An elliptical Item which is Node. - * - * Unlike a Module, this doesn't contain ports, but is directly joinable itself - * (think your classic circles 'n' lines diagram, ala FSM). - * - * @ingroup Ganv - */ -class Circle : public Node -{ -public: - static const uint32_t FILL_COLOUR = 0x1E2224FF; - static const uint32_t BORDER_COLOUR = 0xD3D7CFFF; - - Circle(Canvas& canvas, - const std::string& name, - double x, - double y) - : Node(&canvas, - GANV_NODE( - ganv_item_new( - GANV_ITEM(canvas.root()), - ganv_circle_get_type(), - "x", x, - "y", y, - "can-tail", TRUE, - "can-head", TRUE, - "fill-color", FILL_COLOUR, - "border-color", BORDER_COLOUR, - "label", name.c_str(), - "draggable", TRUE, - NULL))) - {} - - RW_PROPERTY(double, radius) - RW_PROPERTY(double, radius_ems) - RW_PROPERTY(gboolean, fit_label) - - GanvCircle* gobj() { return GANV_CIRCLE(_gobj); } - const GanvCircle* gobj() const { return GANV_CIRCLE(_gobj); } -}; - -} // namespace Ganv - -#endif // GANV_CIRCLE_HPP diff --git a/ganv/Edge.hpp b/ganv/Edge.hpp deleted file mode 100644 index a01de44..0000000 --- a/ganv/Edge.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_EDGE_HPP -#define GANV_EDGE_HPP - -#include <stdint.h> - -#include <gdk/gdkevents.h> - -#include "ganv/Canvas.hpp" -#include "ganv/Item.hpp" -#include "ganv/Node.hpp" -#include "ganv/edge.h" - -GANV_GLIB_WRAP(Edge) - -namespace Ganv { - -class Canvas; - -/** A edge (line) between two Node objects. - * - * @ingroup Ganv - */ -class Edge : public Item -{ -public: - Edge(Canvas& canvas, - Node* tail, - Node* head, - uint32_t color = 0, - bool show_arrowhead = false, - bool curved = true) - : Item(GANV_ITEM(ganv_edge_new(canvas.gobj(), - tail->gobj(), - head->gobj(), - "color", color, - "curved", (gboolean)curved, - "arrowhead", (gboolean)show_arrowhead, - NULL))) - {} - - Edge(GanvEdge* gobj) - : Item(GANV_ITEM(gobj)) - {} - - virtual ~Edge() { - if (_gobj && ganv_item_get_parent(_gobj)) { - g_object_unref(_gobj); - } - } - - gboolean is_within(double x1, double y1, double x2, double y2) const { - return ganv_edge_is_within(gobj(), x1, y1, x2, y2); - } - - RW_PROPERTY(gboolean, constraining) - RW_PROPERTY(gboolean, curved) - RW_PROPERTY(gboolean, selected) - RW_PROPERTY(gboolean, highlighted) - RW_PROPERTY(guint, color) - RW_PROPERTY(gdouble, handle_radius) - - METHODRETWRAP0(ganv_edge, Node*, get_tail); - METHODRETWRAP0(ganv_edge, Node*, get_head); - - GanvEdge* gobj() { return (GanvEdge*)_gobj; } - const GanvEdge* gobj() const { return (GanvEdge*)_gobj; } - -private: - Edge(const Edge& copy); - Edge& operator=(const Edge& other); -}; - -} // namespace Ganv - -#endif // GANV_EDGE_HPP diff --git a/ganv/Item.hpp b/ganv/Item.hpp deleted file mode 100644 index 680b991..0000000 --- a/ganv/Item.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_ITEM_HPP -#define GANV_ITEM_HPP - -#include <assert.h> - -#include <glib.h> - -#include <sigc++/signal.h> -#include <sigc++/trackable.h> - -#include "ganv/Canvas.hpp" -#include "ganv/item.h" -#include "ganv/wrap.hpp" - -GANV_GLIB_WRAP(Item) - -namespace Ganv { - -class Canvas; - -/** An item on the canvas. - */ -class Item : public sigc::trackable { -public: - Item(GanvItem* gobj) - : _gobj(gobj) - { - ganv_item_set_wrapper(gobj, this); - if (gobj && ganv_item_get_parent(gobj)) { - g_signal_connect( - G_OBJECT(_gobj), "event", G_CALLBACK(on_item_event), this); - } - } - - virtual ~Item() { - gtk_object_destroy(GTK_OBJECT(_gobj)); - } - - RW_PROPERTY(double, x) - RW_PROPERTY(double, y) - - METHOD0(ganv_item, raise); - METHOD0(ganv_item, lower); - METHOD2(ganv_item, move, double, dx, double, dy); - METHOD0(ganv_item, show); - METHOD0(ganv_item, hide); - METHOD2(ganv_item, i2w, double*, x, double*, y); - METHOD2(ganv_item, w2i, double*, x, double*, y); - METHOD0(ganv_item, grab_focus); - - Canvas* canvas() const { - return Glib::wrap(ganv_item_get_canvas(_gobj)); - } - - GanvItem* gobj() const { return _gobj; } - - SIGNAL1(event, GdkEvent*) - SIGNAL1(click, GdkEventButton*) - -protected: - GanvItem* const _gobj; - -private: - static gboolean - on_item_event(GanvItem* canvasitem, - GdkEvent* ev, - void* item) - { - return ((Item*)item)->signal_event().emit(ev); - } -}; - -} // namespace Ganv - -#endif // GANV_ITEM_HPP diff --git a/ganv/Module.hpp b/ganv/Module.hpp deleted file mode 100644 index 8ca4393..0000000 --- a/ganv/Module.hpp +++ /dev/null @@ -1,130 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_MODULE_HPP -#define GANV_MODULE_HPP - -#include <string> -#include <vector> - -#include <gtkmm/container.h> - -#include "ganv/Canvas.hpp" -#include "ganv/Node.hpp" -#include "ganv/Port.hpp" -#include "ganv/module.h" - -GANV_GLIB_WRAP(Module) - -namespace Ganv { - -class Canvas; - -/** A rectangular Item which can hold a Port. - * - * @ingroup Ganv - */ -class Module : public Box -{ -public: - Module(Canvas& canvas, - const std::string& name, - double x = 0, - double y = 0, - bool show_title = true) - : Box(&canvas, - GANV_BOX(ganv_item_new(GANV_ITEM(canvas.root()), - ganv_module_get_type(), - "x", x, - "y", y, - "can-tail", FALSE, - "can-head", FALSE, - "radius-tl", 4.0, - "radius-tr", 4.0, - "radius-br", 4.0, - "radius-bl", 4.0, - "border-width", 2.0, - "label", name.c_str(), - "draggable", TRUE, - NULL))) - {} - - template<typename P, typename C> - class iterator_base { - public: - iterator_base(GanvModule* m, guint i) : _module(m), _index(i) {} - template<typename T, typename U> - iterator_base(const iterator_base<T, U>& i) - : _module(i._module) - , _index(i._index) - {} - P* operator*() const { - return Glib::wrap(ganv_module_get_port(_module, _index)); - } - P* operator->() const { - return Glib::wrap(ganv_module_get_port(_module, _index)); - } - iterator_base operator++(int) const { - return iterator_base<P, C>(_index + 1); - } - iterator_base& operator++() { - ++_index; return *this; - } - bool operator==(const iterator_base<P, C>& i) const { - return _index == i._index; - } - bool operator!=(const iterator_base<P, C>& i) const { - return _index != i._index; - } - private: - template<typename T, typename U> friend class iterator_base; - GanvModule* _module; - guint _index; - }; - - typedef iterator_base<Port, GanvPort> iterator; - typedef iterator_base<const Port, const GanvPort> const_iterator; - - iterator begin() { return iterator(gobj(), 0); } - iterator end() { return iterator(gobj(), num_ports()); } - iterator back() { return iterator(gobj(), num_ports() - 1); } - const_iterator begin() const { return iterator(const_cast<GanvModule*>(gobj()), 0); } - const_iterator end() const { return iterator(const_cast<GanvModule*>(gobj()), num_ports()); } - const_iterator back() const { return iterator(const_cast<GanvModule*>(gobj()), num_ports() - 1); } - - void embed(Gtk::Widget* widget) { - ganv_module_embed(gobj(), widget ? widget->gobj() : NULL); - } - - Port* get_port(guint index) { - return Glib::wrap(ganv_module_get_port(gobj(), index)); - } - - METHOD2(ganv_module, for_each_port, GanvPortFunc, f, void*, data); - - METHODRET0(ganv_module, guint, num_ports); - - RW_PROPERTY(gboolean, stacked) - - METHODRET0(ganv_module, double, get_empty_port_breadth) - METHODRET0(ganv_module, double, get_empty_port_depth) - - GanvModule* gobj() { return GANV_MODULE(_gobj); } - const GanvModule* gobj() const { return GANV_MODULE(_gobj); } -}; - -} // namespace Ganv - -#endif // GANV_MODULE_HPP diff --git a/ganv/Node.hpp b/ganv/Node.hpp deleted file mode 100644 index 2fef74c..0000000 --- a/ganv/Node.hpp +++ /dev/null @@ -1,106 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_NODE_HPP -#define GANV_NODE_HPP - -#include <glib.h> -#include <assert.h> - -#include "ganv/node.h" -#include "ganv/Item.hpp" - -GANV_GLIB_WRAP(Node) - -namespace Ganv { - -class Canvas; -class Node; - -/** An object a Edge can connect to. - */ -class Node : public Item { -public: - Node(Canvas* canvas, GanvNode* gobj) - : Item(GANV_ITEM(g_object_ref(gobj))) - { - g_signal_connect(gobj, "moved", G_CALLBACK(on_moved), this); - CONNECT_PROP_SIGNAL(gobj, selected, on_notify_bool, &Node::on_selected) - } - - ~Node() { - g_object_unref(_gobj); - } - - RW_PROPERTY(gboolean, can_tail) - RW_PROPERTY(gboolean, can_head) - RW_PROPERTY(gboolean, is_source) - - gboolean is_within(double x1, double y1, double x2, double y2) const { - return ganv_node_is_within(gobj(), x1, y1, x2, y2); - } - - RW_PROPERTY(const char*, label) - RW_PROPERTY(double, border_width) - RW_PROPERTY(double, dash_length) - RW_PROPERTY(double, dash_offset) - RW_PROPERTY(guint, fill_color) - RW_PROPERTY(guint, border_color) - RW_PROPERTY(gboolean, selected) - RW_PROPERTY(gboolean, highlighted) - RW_PROPERTY(gboolean, draggable) - RW_PROPERTY(gboolean, grabbed) - - RW_OBJECT_PROPERTY(Node*, partner); - - GanvNode* gobj() { return GANV_NODE(_gobj); } - const GanvNode* gobj() const { return GANV_NODE(_gobj); } - - METHOD2(ganv_node, move, double, dx, double, dy) - METHOD2(ganv_node, move_to, double, x, double, y) - - METHOD0(ganv_node, disconnect); - - sigc::signal<void, double, double>& signal_moved() { - return _signal_moved; - } - -private: - sigc::signal<void, double, double> _signal_moved; - - static void on_moved(GanvNode* node, double x, double y) { - Glib::wrap(node)->_signal_moved.emit(x, y); - } - - /* GCC 4.6 can't handle this - template<typename T> - static void on_notify(GObject* gobj, GParamSpec* pspec, gpointer signal) { - T value; - g_object_get(gobj, g_param_spec_get_name(pspec), &value, NULL); - ((sigc::signal<bool, T>*)signal)->emit(value); - } - */ - static void on_notify_bool(GObject* gobj, - GParamSpec* pspec, - gpointer signal) { - gboolean value; - g_object_get(gobj, g_param_spec_get_name(pspec), &value, NULL); - ((sigc::signal<bool, gboolean>*)signal)->emit(value); - } -}; - -} // namespace Ganv - -#endif // GANV_NODE_HPP diff --git a/ganv/Port.hpp b/ganv/Port.hpp deleted file mode 100644 index 94fb760..0000000 --- a/ganv/Port.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2014 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_PORT_HPP -#define GANV_PORT_HPP - -#include <stdint.h> - -#include <string> - -#include <gdkmm/types.h> - -#include "ganv/Box.hpp" -#include "ganv/port.h" - -GANV_GLIB_WRAP(Port) - -namespace Ganv { - -class Module; - -/** A port on a Module. - * - * This is a group that contains both the label and rectangle for a port. - * - * @ingroup Ganv - */ -class Port : public Box -{ -public: - Port(Module& module, - const std::string& name, - bool is_input, - uint32_t color); - - RW_PROPERTY(gboolean, is_controllable) - - METHODRET0(ganv_port, gboolean, is_input) - METHODRET0(ganv_port, gboolean, is_output) - - METHODRET0(ganv_port, double, get_natural_width); - METHODRET0(ganv_port, float, get_control_value) - METHODRET0(ganv_port, float, get_control_min) - METHODRET0(ganv_port, float, get_control_max) - METHOD0(ganv_port, show_control) - METHOD0(ganv_port, hide_control) - METHOD1(ganv_port, set_control_is_toggle, gboolean, is_toggle) - METHOD1(ganv_port, set_control_is_integer, gboolean, is_integer) - METHOD1(ganv_port, set_control_value, float, value) - METHOD1(ganv_port, set_control_min, float, min) - METHOD1(ganv_port, set_control_max, float, max) - METHOD1(ganv_port, set_value_label, const char*, str); - - sigc::signal<void, double> signal_value_changed; - - Module* get_module() const; - - GanvPort* gobj() { return GANV_PORT(_gobj); } - const GanvPort* gobj() const { return GANV_PORT(_gobj); } -}; - -} // namespace Ganv - -#endif // GANV_PORT_HPP diff --git a/ganv/box.h b/ganv/box.h deleted file mode 100644 index ab166bf..0000000 --- a/ganv/box.h +++ /dev/null @@ -1,78 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2014 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_BOX_H -#define GANV_BOX_H - -#include "ganv/node.h" - -G_BEGIN_DECLS - -#define GANV_TYPE_BOX (ganv_box_get_type()) -#define GANV_BOX(obj) (GTK_CHECK_CAST((obj), GANV_TYPE_BOX, GanvBox)) -#define GANV_BOX_CLASS(klass) (GTK_CHECK_CLASS_CAST((klass), GANV_TYPE_BOX, GanvBoxClass)) -#define GANV_IS_BOX(obj) (GTK_CHECK_TYPE((obj), GANV_TYPE_BOX)) -#define GANV_IS_BOX_CLASS(klass) (GTK_CHECK_CLASS_TYPE((klass), GANV_TYPE_BOX)) -#define GANV_BOX_GET_CLASS(obj) (GTK_CHECK_GET_CLASS((obj), GANV_TYPE_BOX, GanvBoxClass)) - -typedef struct _GanvBoxClass GanvBoxClass; -typedef struct _GanvBoxPrivate GanvBoxPrivate; - -struct _GanvBox { - GanvNode node; - GanvBoxPrivate* impl; -}; - -/** - * GanvBoxClass: - * @parent_class: Node superclass. - * @set_width: Set the width of the box. - * @set_height: Set the height of the box. - */ -struct _GanvBoxClass { - GanvNodeClass parent_class; - - void (*set_width)(GanvBox* box, - double width); - - void (*set_height)(GanvBox* box, - double height); - - /* Reserved for future expansion */ - gpointer spare_vmethods[4]; -}; - -GType ganv_box_get_type(void) G_GNUC_CONST; -double ganv_box_get_x1(const GanvBox* box); -double ganv_box_get_y1(const GanvBox* box); -double ganv_box_get_x2(const GanvBox* box); -double ganv_box_get_y2(const GanvBox* box); -double ganv_box_get_width(const GanvBox* box); -void ganv_box_set_width(GanvBox* box, double width); -double ganv_box_get_height(const GanvBox* box); -void ganv_box_set_height(GanvBox* box, double height); -double ganv_box_get_border_width(const GanvBox* box); - -/** - * ganv_box_normalize: - * @box: The box to normalize. - * - * Normalize the box coordinates such that x1 < x2 and y1 < y2. - */ -void ganv_box_normalize(GanvBox* box); - -G_END_DECLS - -#endif /* GANV_BOX_H */ diff --git a/ganv/canvas.h b/ganv/canvas.h deleted file mode 100644 index 3ffb55c..0000000 --- a/ganv/canvas.h +++ /dev/null @@ -1,630 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_CANVAS_H -#define GANV_CANVAS_H - -#include <stdarg.h> - -#include <cairo.h> -#include <gtk/gtk.h> - -#include "ganv/canvas.h" -#include "ganv/types.h" -#include "ganv/edge.h" -#include "ganv/item.h" - -G_BEGIN_DECLS - -#define GANV_TYPE_CANVAS (ganv_canvas_get_type()) -#define GANV_CANVAS(obj) (GTK_CHECK_CAST((obj), GANV_TYPE_CANVAS, GanvCanvas)) -#define GANV_CANVAS_CLASS(klass) (GTK_CHECK_CLASS_CAST((klass), GANV_TYPE_CANVAS, GanvCanvasClass)) -#define GANV_IS_CANVAS(obj) (GTK_CHECK_TYPE((obj), GANV_TYPE_CANVAS)) -#define GANV_IS_CANVAS_CLASS(klass) (GTK_CHECK_CLASS_TYPE((klass), GANV_TYPE_CANVAS)) -#define GANV_CANVAS_GET_CLASS(obj) (GTK_CHECK_GET_CLASS((obj), GANV_TYPE_CANVAS, GanvCanvasClass)) - -typedef struct GanvCanvasImpl GanvCanvasPrivate; -typedef struct _GanvCanvasClass GanvCanvasClass; - -/** - * GanvDirection: - * @GANV_DIRECTION_DOWN: Signal flows from top to bottom. - * @GANV_DIRECTION_RIGHT: Signal flows from left to right. - * - * Specifies the direction of signal flow on the canvas, which affects the - * appearance of modules and how the canvas is auto-arranged. - */ -typedef enum { - GANV_DIRECTION_DOWN, - GANV_DIRECTION_RIGHT -} GanvDirection; - -struct _GanvCanvas { - GtkLayout layout; - GanvCanvasPrivate* impl; -}; - -struct _GanvCanvasClass { - GtkLayoutClass parent_class; - - /* Reserved for future expansion */ - gpointer spare_vmethods[4]; -}; - -GType ganv_canvas_get_type(void) G_GNUC_CONST; - -/** - * GanvEdgeFunc: - * @edge: Canvas edge. - * @data: User callback data. - * - * A node function that takes a user data argument (for callbacks). - * - * Note that in the Gtk world it is considered safe to cast a function to a - * function with more arguments and call the resulting pointer, so functions - * like ganv_edge_select can safely be used where a GanvEdgeFunc is expected. - */ -typedef void (*GanvEdgeFunc)(GanvEdge* edge, void* data); - -/** - * GanvNodeFunc: - * @node: Canvas node. - * @data: User callback data. - * - * A node function that takes a user data argument (for callbacks). - * - * Note that in the Gtk world it is considered safe to cast a function to a - * function with more arguments and call the resulting pointer, so functions - * like ganv_node_select can safely be used where a GanvNodeFunc is expected. - */ -typedef void (*GanvNodeFunc)(GanvNode* node, void* data); - -typedef int (*GanvPortOrderFunc)(const GanvPort*, const GanvPort*, void* data); - -/** - * ganv_canvas_new: - * - * Return value: A newly-created canvas. - */ -GanvCanvas* -ganv_canvas_new(double width, double height); - -/** - * ganv_canvas_set_wrapper: - * - * Set the opaque wrapper object for the canvas. - */ -void -ganv_canvas_set_wrapper(GanvCanvas* canvas, void* wrapper); - -/** - * ganv_canvas_get_wrapper: - * - * Return an opaque pointer to the wrapper for the canvas. - */ -void* -ganv_canvas_get_wrapper(GanvCanvas* canvas); - -/** - * ganv_canvas_clear: - * - * Remove all items from the canvas. - */ -void -ganv_canvas_clear(GanvCanvas* canvas); - -/** - * ganv_canvas_empty: - * - * Return value: True if there are no items on the canvas. - */ -gboolean -ganv_canvas_empty(const GanvCanvas* canvas); - -/** - * ganv_canvas_resize: - * - * Resize the canvas to the given dimensions. - */ -void -ganv_canvas_resize(GanvCanvas* canvas, double width, double height); - -/** - * ganv_canvas_root: - * @canvas: A canvas. - * - * Return value: (transfer none): The root group of the canvas. - */ -GanvItem* -ganv_canvas_root(GanvCanvas* canvas); - -/** - * ganv_canvas_set_scroll_region: - * @canvas: A canvas. - * @x1: Leftmost limit of the scrolling region. - * @y1: Upper limit of the scrolling region. - * @x2: Rightmost limit of the scrolling region. - * @y2: Lower limit of the scrolling region. - * - * Sets the scrolling region of a canvas to the specified rectangle. The - * canvas will then be able to scroll only within this region. The view of the - * canvas is adjusted as appropriate to display as much of the new region as - * possible. - */ -void -ganv_canvas_set_scroll_region(GanvCanvas* canvas, - double x1, double y1, double x2, double y2); - -/** - * ganv_canvas_get_scroll_region: - * @canvas: A canvas. - * @x1: Leftmost limit of the scrolling region (return value). - * @y1: Upper limit of the scrolling region (return value). - * @x2: Rightmost limit of the scrolling region (return value). - * @y2: Lower limit of the scrolling region (return value). - * - * Queries the scrolling region of a canvas. - */ -void -ganv_canvas_get_scroll_region(GanvCanvas* canvas, - double* x1, double* y1, double* x2, double* y2); - -/** - * ganv_canvas_set_center_scroll_region: - * @canvas: A canvas. - * @center_scroll_region: Whether to center the scrolling region in the canvas - * window when it is smaller than the canvas' allocation. - * - * When the scrolling region of the canvas is smaller than the canvas window, - * e.g. the allocation of the canvas, it can be either centered on the window - * or simply made to be on the upper-left corner on the window. This function - * lets you configure this property. - */ -void -ganv_canvas_set_center_scroll_region(GanvCanvas* canvas, - gboolean center_scroll_region); - -/** - * ganv_canvas_get_center_scroll_region: - * @canvas: A canvas. - * - * Returns whether the canvas is set to center the scrolling region in the - * window if the former is smaller than the canvas' allocation. - * - * Returns: Whether the scroll region is being centered in the canvas window. - */ -gboolean -ganv_canvas_get_center_scroll_region(const GanvCanvas* canvas); - -/** - * ganv_canvas_scroll_to: - * @canvas: A canvas. - * @cx: Horizontal scrolling offset in canvas pixel units. - * @cy: Vertical scrolling offset in canvas pixel units. - * - * Makes a canvas scroll to the specified offsets, given in canvas pixel units. - * The canvas will adjust the view so that it is not outside the scrolling - * region. This function is typically not used, as it is better to hook - * scrollbars to the canvas layout's scrolling adjusments. - */ -void -ganv_canvas_scroll_to(GanvCanvas* canvas, int cx, int cy); - -/** - * ganv_canvas_get_scroll_offsets: - * @canvas: A canvas. - * @cx: Horizontal scrolling offset (return value). - * @cy: Vertical scrolling offset (return value). - * - * Queries the scrolling offsets of a canvas. The values are returned in canvas - * pixel units. - */ -void -ganv_canvas_get_scroll_offsets(const GanvCanvas* canvas, int* cx, int* cy); - -/** - * ganv_canvas_w2c_affine: - * @canvas: A canvas. - * @matrix: An affine transformation matrix (return value). - * - * Gets the affine transform that converts from world coordinates to canvas - * pixel coordinates. - */ -void -ganv_canvas_w2c_affine(GanvCanvas* canvas, cairo_matrix_t* matrix); - -/** - * ganv_canvas_w2c: - * @canvas: A canvas. - * @wx: World X coordinate. - * @wy: World Y coordinate. - * @cx: X pixel coordinate (return value). - * @cy: Y pixel coordinate (return value). - * - * Converts world coordinates into canvas pixel coordinates. - */ -void -ganv_canvas_w2c(GanvCanvas* canvas, double wx, double wy, int* cx, int* cy); - -/** - * ganv_canvas_w2c_d: - * @canvas: A canvas. - * @wx: World X coordinate. - * @wy: World Y coordinate. - * @cx: X pixel coordinate (return value). - * @cy: Y pixel coordinate (return value). - * - * Converts world coordinates into canvas pixel coordinates. This version - * uses floating point coordinates for greater precision. - */ -void -ganv_canvas_w2c_d(GanvCanvas* canvas, - double wx, - double wy, - double* cx, - double* cy); - -/** - * ganv_canvas_c2w: - * @canvas: A canvas. - * @cx: Canvas pixel X coordinate. - * @cy: Canvas pixel Y coordinate. - * @wx: X world coordinate (return value). - * @wy: Y world coordinate (return value). - * - * Converts canvas pixel coordinates to world coordinates. - */ -void -ganv_canvas_c2w(GanvCanvas* canvas, int cx, int cy, double* wx, double* wy); - -/** - * ganv_canvas_window_to_world: - * @canvas: A canvas. - * @winx: Window-relative X coordinate. - * @winy: Window-relative Y coordinate. - * @worldx: X world coordinate (return value). - * @worldy: Y world coordinate (return value). - * - * Converts window-relative coordinates into world coordinates. You can use - * this when you need to convert mouse coordinates into world coordinates, for - * example. - */ -void -ganv_canvas_window_to_world(GanvCanvas* canvas, - double winx, - double winy, - double* worldx, - double* worldy); - -/** - * ganv_canvas_world_to_window: - * @canvas: A canvas. - * @worldx: World X coordinate. - * @worldy: World Y coordinate. - * @winx: X window-relative coordinate. - * @winy: Y window-relative coordinate. - * - * Converts world coordinates into window-relative coordinates. - */ -void -ganv_canvas_world_to_window(GanvCanvas* canvas, - double worldx, - double worldy, - double* winx, - double* winy); - -/** - * ganv_canvas_get_item_at: - * @canvas: A canvas. - * @x: X position in world coordinates. - * @y: Y position in world coordinates. - * - * Looks for the item that is under the specified position, which must be - * specified in world coordinates. - * - * Returns: (transfer none): The sought item, or NULL if no item is at the - * specified coordinates. - */ -GanvItem* -ganv_canvas_get_item_at(GanvCanvas* canvas, double x, double y); - -/** - * ganv_canvas_get_edge: - * - * Get the edge between two nodes, or NULL if none exists. - * - * Return value: (transfer none): The root group of @canvas. - */ -GanvEdge* -ganv_canvas_get_edge(GanvCanvas* canvas, - GanvNode* tail, - GanvNode* head); - -/** - * ganv_canvas_remove_edge: - * - * Remove @edge from the canvas. - */ -void -ganv_canvas_remove_edge(GanvCanvas* canvas, - GanvEdge* edge); - -/** - * ganv_canvas_remove_edge_between: - * - * Remove the edge from @tail to @head if one exists. - */ -void -ganv_canvas_remove_edge_between(GanvCanvas* canvas, - GanvNode* tail, - GanvNode* head); - -/** - * ganv_canvas_get_direction: - * - * Return the direction of signal flow. - */ -GanvDirection -ganv_canvas_get_direction(GanvCanvas* canvas); - -/** - * ganv_canvas_set_direction: - * - * Set the direction of signal flow. - */ -void -ganv_canvas_set_direction(GanvCanvas* canvas, GanvDirection dir); - -/** - * ganv_canvas_arrange: - * - * Automatically arrange the canvas contents. - */ -void -ganv_canvas_arrange(GanvCanvas* canvas); - -/** - * ganv_canvas_export_image: - * - * Draw the canvas to an image file. The file type is determined by extension, - * currently supported: pdf, ps, svg, dot. - * - * Returns: 0 on success. - */ -int -ganv_canvas_export_image(GanvCanvas* canvas, - const char* filename, - gboolean draw_background); - -/** - * ganv_canvas_export_dot: - * - * Write a Graphviz DOT description of the canvas to a file. - */ -void -ganv_canvas_export_dot(GanvCanvas* canvas, const char* filename); - -/** - * ganv_canvas_supports_sprung_layout: - * - * Returns: true iff ganv is compiled with sprung layout support. - */ -gboolean -ganv_canvas_supports_sprung_layout(const GanvCanvas* canvas); - -/** - * ganv_canvas_set_sprung_layout: - * - * Enable or disable "live" force-directed canvas layout. - * - * Returns: true iff sprung layout was enabled. - */ -gboolean -ganv_canvas_set_sprung_layout(GanvCanvas* canvas, gboolean sprung_layout); - -/** - * ganv_canvas_get_locked: - * - * Return true iff the canvas is locked and nodes may not move. - */ -gboolean -ganv_canvas_get_locked(const GanvCanvas* canvas); - -/** - * ganv_canvas_for_each_node: - * @canvas: The canvas. - * @f: (scope call): A function to call on every node on @canvas. - * @data: Data to pass to @f. - */ -void -ganv_canvas_for_each_node(GanvCanvas* canvas, - GanvNodeFunc f, - void* data); - -/** - * ganv_canvas_for_each_selected_node: - * @canvas: The canvas. - * @f: (scope call): A function to call on every selected node on @canvas. - * @data: Data to pass to @f. - */ -void -ganv_canvas_for_each_selected_node(GanvCanvas* canvas, - GanvNodeFunc f, - void* data); - -/** - * ganv_canvas_for_each_edge: - * @canvas: The canvas. - * @f: (scope call): A function to call on every edge on @canvas. - * @data: Data to pass to @f. - */ -void -ganv_canvas_for_each_edge(GanvCanvas* canvas, - GanvEdgeFunc f, - void* data); - -/** - * ganv_canvas_for_each_edge_from: - * @canvas: The canvas. - * @tail: The tail to enumerate every edge for. - * @f: (scope call): A function to call on every edge leaving @tail. - */ -void -ganv_canvas_for_each_edge_from(GanvCanvas* canvas, - const GanvNode* tail, - GanvEdgeFunc f, - void* data); - -/** - * ganv_canvas_for_each_edge_to: - * @canvas: The canvas. - * @head: The head to enumerate every edge for. - * @f: (scope call): A function to call on every edge entering @head. - */ -void -ganv_canvas_for_each_edge_to(GanvCanvas* canvas, - const GanvNode* head, - GanvEdgeFunc f, - void* data); - -/** - * ganv_canvas_for_each_edge_on: - * @canvas: The canvas. - * @node: The node to enumerate every edge for. - * @f: (scope call): A function to call on every edge attached to @node. - */ -void -ganv_canvas_for_each_edge_on(GanvCanvas* canvas, - const GanvNode* node, - GanvEdgeFunc f, - void* data); - -/** - * ganv_canvas_for_each_selected_edge: - * @canvas: The canvas. - * @f: (scope call): A function to call on every edge attached to @node. - * @data: Data to pass to @f. - */ -void -ganv_canvas_for_each_selected_edge(GanvCanvas* canvas, - GanvEdgeFunc f, - void* data); - -/** - * ganv_canvas_select_all: - * - * Select all items on the canvas. - */ -void -ganv_canvas_select_all(GanvCanvas* canvas); - -/** - * ganv_canvas_clear_selection: - * - * Deselect any selected items on the canvas. - */ -void -ganv_canvas_clear_selection(GanvCanvas* canvas); - -/** - * ganv_canvas_get_zoom: - * - * Return the current zoom factor (pixels per unit). - */ -double -ganv_canvas_get_zoom(const GanvCanvas* canvas); - -/** - * ganv_canvas_set_zoom: - * @canvas: A canvas. - * @zoom: The number of pixels that correspond to one canvas unit. - * - * The anchor point for zooming, i.e. the point that stays fixed and all others - * zoom inwards or outwards from it, depends on whether the canvas is set to - * center the scrolling region or not. You can control this using the - * ganv_canvas_set_center_scroll_region() function. If the canvas is set to - * center the scroll region, then the center of the canvas window is used as - * the anchor point for zooming. Otherwise, the upper-left corner of the - * canvas window is used as the anchor point. - */ -void -ganv_canvas_set_zoom(GanvCanvas* canvas, double zoom); - -/** - * ganv_canvas_zoom_full: - * - * Zoom so all canvas contents are visible. - */ -void -ganv_canvas_zoom_full(GanvCanvas* canvas); - -/** - * ganv_canvas_get_default_font_size: - * - * Get the default font size in points. - */ -double -ganv_canvas_get_default_font_size(const GanvCanvas* canvas); - -/** - * ganv_canvas_get_font_size: - * - * Get the current font size in points. - */ -double -ganv_canvas_get_font_size(const GanvCanvas* canvas); - -/** - * ganv_canvas_set_font_size: - * - * Set the current font size in points. - */ -void -ganv_canvas_set_font_size(GanvCanvas* canvas, double points); - -/** - * ganv_canvas_get_move_cursor: - * - * Return the cursor to use while dragging canvas objects. - */ -GdkCursor* -ganv_canvas_get_move_cursor(const GanvCanvas* canvas); - -/** - * ganv_canvas_move_contents_to: - * - * Shift all canvas contents so the top-left object is at (x, y). - */ -void -ganv_canvas_move_contents_to(GanvCanvas* canvas, double x, double y); - -/** - * ganv_canvas_set_port_order: - * @canvas The canvas to set the default port order on. - * @port_cmp Port comparison function. - * @data Data to be passed to order. - * - * Set a comparator function to use as the default order for ports on modules. - * If left unset, ports are shown in the order they are added. - */ -void -ganv_canvas_set_port_order(GanvCanvas* canvas, - GanvPortOrderFunc port_cmp, - void* data); - - -G_END_DECLS - -#endif /* GANV_CANVAS_H */ diff --git a/ganv/circle.h b/ganv/circle.h deleted file mode 100644 index f181b54..0000000 --- a/ganv/circle.h +++ /dev/null @@ -1,78 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2014 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_CIRCLE_H -#define GANV_CIRCLE_H - -#include "ganv/node.h" - -G_BEGIN_DECLS - -#define GANV_TYPE_CIRCLE (ganv_circle_get_type()) -#define GANV_CIRCLE(obj) (GTK_CHECK_CAST((obj), GANV_TYPE_CIRCLE, GanvCircle)) -#define GANV_CIRCLE_CLASS(klass) (GTK_CHECK_CLASS_CAST((klass), GANV_TYPE_CIRCLE, GanvCircleClass)) -#define GANV_IS_CIRCLE(obj) (GTK_CHECK_TYPE((obj), GANV_TYPE_CIRCLE)) -#define GANV_IS_CIRCLE_CLASS(klass) (GTK_CHECK_CLASS_TYPE((klass), GANV_TYPE_CIRCLE)) -#define GANV_CIRCLE_GET_CLASS(obj) (GTK_CHECK_GET_CLASS((obj), GANV_TYPE_CIRCLE, GanvCircleClass)) - -typedef struct _GanvCircle GanvCircle; -typedef struct _GanvCircleClass GanvCircleClass; -typedef struct _GanvCirclePrivate GanvCirclePrivate; - -/** - * GanvCircle: - * - * A circular #GanvNode. A #GanvCircle is a leaf, that is, it does not contain - * any child nodes (though, like any #GanvNode, it may have a label). - */ -struct _GanvCircle { - GanvNode node; - GanvCirclePrivate* impl; -}; - -struct _GanvCircleClass { - GanvNodeClass parent_class; - - /* Reserved for future expansion */ - gpointer spare_vmethods[4]; -}; - -GType ganv_circle_get_type(void) G_GNUC_CONST; - -GanvCircle* -ganv_circle_new(GanvCanvas* canvas, - const char* first_prop_name, ...); - -double -ganv_circle_get_radius(const GanvCircle* circle); - -void -ganv_circle_set_radius(GanvCircle* circle, double radius); - -double -ganv_circle_get_radius_ems(const GanvCircle* circle); - -void -ganv_circle_set_radius_ems(GanvCircle* circle, double radius); - -gboolean -ganv_circle_get_fit_label(const GanvCircle* circle); - -void -ganv_circle_set_fit_label(GanvCircle* circle, gboolean fit_label); - -G_END_DECLS - -#endif /* GANV_CIRCLE_H */ diff --git a/ganv/edge.h b/ganv/edge.h deleted file mode 100644 index bf0fb14..0000000 --- a/ganv/edge.h +++ /dev/null @@ -1,129 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_EDGE_H -#define GANV_EDGE_H - -#include "ganv/item.h" -#include "ganv/node.h" -#include "ganv/types.h" - -G_BEGIN_DECLS - -#define GANV_TYPE_EDGE (ganv_edge_get_type()) -#define GANV_EDGE(obj) (GTK_CHECK_CAST((obj), GANV_TYPE_EDGE, GanvEdge)) -#define GANV_EDGE_CLASS(klass) (GTK_CHECK_CLASS_CAST((klass), GANV_TYPE_EDGE, GanvEdgeClass)) -#define GANV_IS_EDGE(obj) (GTK_CHECK_TYPE((obj), GANV_TYPE_EDGE)) -#define GANV_IS_EDGE_CLASS(klass) (GTK_CHECK_CLASS_TYPE((klass), GANV_TYPE_EDGE)) -#define GANV_EDGE_GET_CLASS(obj) (GTK_CHECK_GET_CLASS((obj), GANV_TYPE_EDGE, GanvEdgeClass)) - -typedef struct _GanvEdgeClass GanvEdgeClass; -typedef struct _GanvEdgePrivate GanvEdgePrivate; - -struct _GanvEdge { - GanvItem item; - GanvEdgePrivate* impl; -}; - -struct _GanvEdgeClass { - GanvItemClass parent_class; - - /* Reserved for future expansion */ - gpointer spare_vmethods[4]; -}; - -GType ganv_edge_get_type(void) G_GNUC_CONST; - -GanvEdge* -ganv_edge_new(GanvCanvas* canvas, - GanvNode* tail, - GanvNode* head, - const char* first_prop_name, ...); - -gboolean -ganv_edge_is_within(const GanvEdge* edge, - double x1, - double y1, - double x2, - double y2); - -gboolean -ganv_edge_get_curved(const GanvEdge* edge); - -void -ganv_edge_set_curved(GanvEdge* edge, gboolean curved); - -gboolean -ganv_edge_get_constraining(const GanvEdge* edge); - -void -ganv_edge_set_constraining(GanvEdge* edge, gboolean constraining); - -void -ganv_edge_set_selected(GanvEdge* edge, gboolean selected); - -void -ganv_edge_set_highlighted(GanvEdge* edge, gboolean highlighted); - -void -ganv_edge_select(GanvEdge* edge); - -void -ganv_edge_unselect(GanvEdge* edge); - -void -ganv_edge_highlight(GanvEdge* edge); - -void -ganv_edge_unhighlight(GanvEdge* edge); - -/** - * ganv_edge_disconnect: - * - * Disconnect the edge. This will disconnect the edge just as if it had been - * disconnected by the user via the canvas. The canvas disconnect signal will - * be emitted, allowing the application to control disconnect logic. - */ -void -ganv_edge_disconnect(GanvEdge* edge); - -/** - * ganv_edge_remove: - * - * Remove the edge from the canvas. This will only remove the edge visually, - * it will not emit the canvas disconnect signal to notify the application. - */ -void -ganv_edge_remove(GanvEdge* edge); - -/** - * ganv_edge_get_tail: - * - * Return value: (transfer none): The tail of `edge`. - */ -GanvNode* -ganv_edge_get_tail(const GanvEdge* edge); - -/** - * ganv_edge_get_head: - * - * Return value: (transfer none): The head of `edge`. - */ -GanvNode* -ganv_edge_get_head(const GanvEdge* edge); - -G_END_DECLS - -#endif /* GANV_EDGE_H */ diff --git a/ganv/ganv.h b/ganv/ganv.h deleted file mode 100644 index 9a00143..0000000 --- a/ganv/ganv.h +++ /dev/null @@ -1,31 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2016 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_GANV_H -#define GANV_GANV_H - -#include "ganv/box.h" -#include "ganv/canvas.h" -#include "ganv/circle.h" -#include "ganv/edge.h" -#include "ganv/ganv.h" -#include "ganv/group.h" -#include "ganv/module.h" -#include "ganv/node.h" -#include "ganv/port.h" -#include "ganv/text.h" -#include "ganv/types.h" - -#endif /* GANV_GANV_H */ diff --git a/ganv/ganv.hpp b/ganv/ganv.hpp deleted file mode 100644 index 9b0334d..0000000 --- a/ganv/ganv.hpp +++ /dev/null @@ -1,26 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_GANV_HPP -#define GANV_GANV_HPP - -#include "ganv/Canvas.hpp" -#include "ganv/Circle.hpp" -#include "ganv/Edge.hpp" -#include "ganv/Module.hpp" -#include "ganv/Node.hpp" -#include "ganv/Port.hpp" - -#endif // GANV_GANV_HPP diff --git a/ganv/group.h b/ganv/group.h deleted file mode 100644 index 0f835e4..0000000 --- a/ganv/group.h +++ /dev/null @@ -1,55 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2014 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_GROUP_H -#define GANV_GROUP_H - -#include "ganv/item.h" - -G_BEGIN_DECLS - -/* Based on GnomeCanvasGroup, by Federico Mena <federico@nuclecu.unam.mx> - * and Raph Levien <raph@gimp.org> - * Copyright 1997-2000 Free Software Foundation - */ - -#define GANV_TYPE_GROUP (ganv_group_get_type()) -#define GANV_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GANV_TYPE_GROUP, GanvGroup)) -#define GANV_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GANV_TYPE_GROUP, GanvGroupClass)) -#define GANV_IS_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GANV_TYPE_GROUP)) -#define GANV_IS_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GANV_TYPE_GROUP)) -#define GANV_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GANV_TYPE_GROUP, GanvGroupClass)) - -typedef struct _GanvGroup GanvGroup; -typedef struct _GanvGroupPrivate GanvGroupPrivate; -typedef struct _GanvGroupClass GanvGroupClass; - -struct _GanvGroup { - GanvItem item; - GanvGroupPrivate* impl; -}; - -struct _GanvGroupClass { - GanvItemClass parent_class; - - /* Reserved for future expansion */ - gpointer spare_vmethods[4]; -}; - -GType ganv_group_get_type(void) G_GNUC_CONST; - -G_END_DECLS - -#endif /* GANV_GROUP_H */ diff --git a/ganv/item.h b/ganv/item.h deleted file mode 100644 index 4605ffb..0000000 --- a/ganv/item.h +++ /dev/null @@ -1,184 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2016 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -/* Based on GnomeCanvas, by Federico Mena <federico@nuclecu.unam.mx> - * and Raph Levien <raph@gimp.org> - * Copyright 1997-2000 Free Software Foundation - */ - -#ifndef GANV_ITEM_H -#define GANV_ITEM_H - -#include <stdarg.h> - -#include <cairo.h> -#include <gtk/gtk.h> - -G_BEGIN_DECLS - -struct _GanvCanvas; - -typedef struct _GanvItem GanvItem; -typedef struct _GanvItemPrivate GanvItemPrivate; -typedef struct _GanvItemClass GanvItemClass; - -/* Object flags for items */ -enum { - GANV_ITEM_REALIZED = 1 << 1, - GANV_ITEM_MAPPED = 1 << 2, - GANV_ITEM_ALWAYS_REDRAW = 1 << 3, - GANV_ITEM_VISIBLE = 1 << 4, - GANV_ITEM_NEED_UPDATE = 1 << 5, - GANV_ITEM_NEED_VIS = 1 << 6 -}; - -#define GANV_TYPE_ITEM (ganv_item_get_type()) -#define GANV_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GANV_TYPE_ITEM, GanvItem)) -#define GANV_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GANV_TYPE_ITEM, GanvItemClass)) -#define GANV_IS_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GANV_TYPE_ITEM)) -#define GANV_IS_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GANV_TYPE_ITEM)) -#define GANV_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GANV_TYPE_ITEM, GanvItemClass)) - -struct _GanvItem { - GtkObject object; - GanvItemPrivate* impl; -}; - -struct _GanvItemClass { - GtkObjectClass parent_class; - - /* Add a child to this item (optional). */ - void (*add)(GanvItem* item, GanvItem* child); - - /* Remove a child from this item (optional). */ - void (*remove)(GanvItem* item, GanvItem* child); - - /* Tell the item to update itself. - * - * The flags are from the update flags defined above. The item should - * update its internal state from its queued state, and recompute and - * request its repaint area. The update method also recomputes the - * bounding box of the item. - */ - void (*update)(GanvItem* item, int flags); - - /* Realize an item (create GCs, etc.). */ - void (*realize)(GanvItem* item); - - /* Unrealize an item. */ - void (*unrealize)(GanvItem* item); - - /* Map an item - normally only need by items with their own GdkWindows. */ - void (*map)(GanvItem* item); - - /* Unmap an item */ - void (*unmap)(GanvItem* item); - - /* Draw an item of this type. - * - * (cx, cy) and (width, height) describe the rectangle being drawn in - * world-relative coordinates. - */ - void (*draw)(GanvItem* item, - cairo_t* cr, - double cx, - double cy, - double cw, - double ch); - - /* Calculate the distance from an item to the specified point. - * - * It also returns a canvas item which is actual item the point is within, - * which may not be equal to @item if @item has children. - * (x, y) are item-relative coordinates. - */ - double (*point)(GanvItem* item, - double x, - double y, - GanvItem** actual_item); - - /* Fetch the item's bounding box (need not be exactly tight). - * - * This should be in item-relative coordinates. - */ - void (*bounds)(GanvItem* item, double* x1, double* y1, double* x2, double* y2); - - /* Signal: an event occurred for an item of this type. - * - * The (x, y) coordinates are in the canvas world coordinate system. - */ - gboolean (*event)(GanvItem* item, GdkEvent* event); - - /* Reserved for future expansion */ - gpointer spare_vmethods[4]; -}; - -GType ganv_item_get_type(void) G_GNUC_CONST; - -GanvItem* ganv_item_new(GanvItem* parent, GType type, - const gchar* first_arg_name, ...); - -void ganv_item_construct(GanvItem* item, GanvItem* parent, - const gchar* first_arg_name, va_list args); - -void ganv_item_set(GanvItem* item, const gchar* first_arg_name, ...); - -void ganv_item_set_valist(GanvItem* item, - const gchar* first_arg_name, va_list args); - -/** - * ganv_item_get_canvas: - * @item: The item. - * - * Return value: (transfer none): The canvas @item is on. - */ -struct _GanvCanvas* ganv_item_get_canvas(GanvItem* item); - -/** - * ganv_item_get_parent: - * @item: The item. - * - * Return value: (transfer none): The parent of @item. - */ -GanvItem* ganv_item_get_parent(GanvItem* item); - -void ganv_item_raise(GanvItem* item); - -void ganv_item_lower(GanvItem* item); - -void ganv_item_move(GanvItem* item, double dx, double dy); - -void ganv_item_show(GanvItem* item); - -void ganv_item_hide(GanvItem* item); - -void ganv_item_i2w(GanvItem* item, double* x, double* y); - -void ganv_item_w2i(GanvItem* item, double* x, double* y); - -void ganv_item_grab_focus(GanvItem* item); - -void ganv_item_get_bounds(GanvItem* item, - double* x1, double* y1, double* x2, double* y2); - -void ganv_item_request_update(GanvItem* item); - -void ganv_item_set_wrapper(GanvItem* item, void* wrapper); - -void* ganv_item_get_wrapper(GanvItem* item); - -G_END_DECLS - -#endif /* GANV_ITEM_H */ diff --git a/ganv/module.h b/ganv/module.h deleted file mode 100644 index 37fcf96..0000000 --- a/ganv/module.h +++ /dev/null @@ -1,95 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2014 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_MODULE_H -#define GANV_MODULE_H - -#include <glib.h> -#include <gtk/gtk.h> - -#include "ganv/box.h" - -G_BEGIN_DECLS - -#define GANV_TYPE_MODULE (ganv_module_get_type()) -#define GANV_MODULE(obj) (GTK_CHECK_CAST((obj), GANV_TYPE_MODULE, GanvModule)) -#define GANV_MODULE_CLASS(klass) (GTK_CHECK_CLASS_CAST((klass), GANV_TYPE_MODULE, GanvModuleClass)) -#define GANV_IS_MODULE(obj) (GTK_CHECK_TYPE((obj), GANV_TYPE_MODULE)) -#define GANV_IS_MODULE_CLASS(klass) (GTK_CHECK_CLASS_TYPE((klass), GANV_TYPE_MODULE)) -#define GANV_MODULE_GET_CLASS(obj) (GTK_CHECK_GET_CLASS((obj), GANV_TYPE_MODULE, GanvModuleClass)) - -typedef struct _GanvModuleClass GanvModuleClass; -typedef struct _GanvModulePrivate GanvModulePrivate; - -typedef void (*GanvPortFunc)(GanvPort* port, void* data); - -struct _GanvModule { - GanvBox box; - GanvModulePrivate* impl; -}; - -struct _GanvModuleClass { - GanvBoxClass parent_class; - - /* Reserved for future expansion */ - gpointer spare_vmethods[4]; -}; - -GType ganv_module_get_type(void) G_GNUC_CONST; - -GanvModule* -ganv_module_new(GanvCanvas* canvas, - const char* first_prop_name, ...); - -guint -ganv_module_num_ports(const GanvModule* module); - -/** - * ganv_module_get_port: - * - * Get a port by index. - * - * Return value: (transfer none): The port on @module at @index. - */ -GanvPort* -ganv_module_get_port(GanvModule* module, - guint index); - -double -ganv_module_get_empty_port_breadth(const GanvModule* module); - -double -ganv_module_get_empty_port_depth(const GanvModule* module); - -void -ganv_module_embed(GanvModule* module, GtkWidget* widget); - -void -ganv_module_set_direction(GanvModule* module, GanvDirection direction); - -/** - * ganv_module_for_each_port: - * @module: The module. - * @f: (scope call): A function to call on every port on @module. - * @data: User data to pass to @f. - */ -void -ganv_module_for_each_port(GanvModule* module, - GanvPortFunc f, - void* data); - -G_END_DECLS - -#endif /* GANV_MODULE_H */ diff --git a/ganv/node.h b/ganv/node.h deleted file mode 100644 index b0dd82f..0000000 --- a/ganv/node.h +++ /dev/null @@ -1,179 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2014 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_NODE_H -#define GANV_NODE_H - -#include "ganv/item.h" -#include "ganv/types.h" -#include "ganv/text.h" - -G_BEGIN_DECLS - -#define GANV_TYPE_NODE (ganv_node_get_type()) -#define GANV_NODE(obj) (GTK_CHECK_CAST((obj), GANV_TYPE_NODE, GanvNode)) -#define GANV_NODE_CLASS(klass) (GTK_CHECK_CLASS_CAST((klass), GANV_TYPE_NODE, GanvNodeClass)) -#define GANV_IS_NODE(obj) (GTK_CHECK_TYPE((obj), GANV_TYPE_NODE)) -#define GANV_IS_NODE_CLASS(klass) (GTK_CHECK_CLASS_TYPE((klass), GANV_TYPE_NODE)) -#define GANV_NODE_GET_CLASS(obj) (GTK_CHECK_GET_CLASS((obj), GANV_TYPE_NODE, GanvNodeClass)) - -typedef struct _GanvNodeClass GanvNodeClass; -typedef struct _GanvNodePrivate GanvNodePrivate; - -struct _GanvNode { - GanvItem item; - GanvNodePrivate* impl; -}; - -struct _GanvNodeClass { - GanvItemClass parent_class; - - void (*tick)(GanvNode* self, - double seconds); - - void (*move)(GanvNode* node, - double dx, - double dy); - - void (*move_to)(GanvNode* node, - double x, - double y); - - void (*resize)(GanvNode* node); - - void (*redraw_text)(GanvNode* node); - - void (*disconnect)(GanvNode* node); - - gboolean (*is_within)(const GanvNode* self, - double x1, - double y1, - double x2, - double y2); - - void (*tail_vector)(const GanvNode* self, - const GanvNode* head, - double* x, - double* y, - double* dx, - double* dy); - - void (*head_vector)(const GanvNode* self, - const GanvNode* tail, - double* x, - double* y, - double* dx, - double* dy); - - /* Reserved for future expansion */ - gpointer spare_vmethods[4]; -}; - -GType ganv_node_get_type(void) G_GNUC_CONST; - -/** - * ganv_node_can_tail: - * - * Return value: True iff node can act as the tail of an edge. - */ -gboolean -ganv_node_can_tail(const GanvNode* node); - -/** - * ganv_node_can_head: - * - * Return value: True iff node can act as the head of an edge. - */ -gboolean -ganv_node_can_head(const GanvNode* node); - -/** - * ganv_node_set_is_source: - * - * Flag a node as a source. This information is used to influence layout. - */ -void -ganv_node_set_is_source(const GanvNode* node, gboolean is_source); - -/** - * ganv_node_is_within: - * - * Return value: True iff node is entirely within the given rectangle. - */ -gboolean -ganv_node_is_within(const GanvNode* node, - double x1, - double y1, - double x2, - double y2); - -const char* ganv_node_get_label(const GanvNode* node); - -double ganv_node_get_border_width(const GanvNode* node); - -void ganv_node_set_border_width(const GanvNode* node, double border_width); - -double ganv_node_get_dash_length(const GanvNode* node); - -void ganv_node_set_dash_length(const GanvNode* node, double dash_length); - -double ganv_node_get_dash_offset(const GanvNode* node); - -void ganv_node_set_dash_offset(const GanvNode* node, double dash_offset); - -guint ganv_node_get_fill_color(const GanvNode* node); - -void ganv_node_set_fill_color(const GanvNode* node, guint fill_color); - -guint ganv_node_get_border_color(const GanvNode* node); - -void ganv_node_set_border_color(const GanvNode* node, guint border_color); - -/** - * ganv_node_get_partner: - * - * Return value: (transfer none): The partner of @node. - */ -GanvNode* -ganv_node_get_partner(const GanvNode* node); - -void ganv_node_set_label(GanvNode* node, const char* str); -void ganv_node_set_show_label(GanvNode* node, gboolean show); - -void -ganv_node_move(GanvNode* node, - double dx, - double dy); - -void -ganv_node_move_to(GanvNode* node, - double x, - double y); - -void -ganv_node_resize(GanvNode* node); - -void -ganv_node_redraw_text(GanvNode* node); - -void -ganv_node_disconnect(GanvNode* node); - -gboolean -ganv_node_is_selected(GanvNode* node); - -G_END_DECLS - -#endif /* GANV_NODE_H */ diff --git a/ganv/port.h b/ganv/port.h deleted file mode 100644 index 03f4bb3..0000000 --- a/ganv/port.h +++ /dev/null @@ -1,103 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2014 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_PORT_H -#define GANV_PORT_H - -#include "ganv/box.h" - -struct _GanvModule; - -G_BEGIN_DECLS - -#define GANV_TYPE_PORT (ganv_port_get_type()) -#define GANV_PORT(obj) (GTK_CHECK_CAST((obj), GANV_TYPE_PORT, GanvPort)) -#define GANV_PORT_CLASS(klass) (GTK_CHECK_CLASS_CAST((klass), GANV_TYPE_PORT, GanvPortClass)) -#define GANV_IS_PORT(obj) (GTK_CHECK_TYPE((obj), GANV_TYPE_PORT)) -#define GANV_IS_PORT_CLASS(klass) (GTK_CHECK_CLASS_TYPE((klass), GANV_TYPE_PORT)) -#define GANV_PORT_GET_CLASS(obj) (GTK_CHECK_GET_CLASS((obj), GANV_TYPE_PORT, GanvPortClass)) - -typedef struct _GanvPortClass GanvPortClass; -typedef struct _GanvPortPrivate GanvPortPrivate; - -struct _GanvPort { - GanvBox box; - GanvPortPrivate* impl; -}; - -struct _GanvPortClass { - GanvBoxClass parent_class; - - /* Reserved for future expansion */ - gpointer spare_vmethods[4]; -}; - -GType ganv_port_get_type(void) G_GNUC_CONST; - -GanvPort* -ganv_port_new(GanvModule* module, - gboolean is_input, - const char* first_prop_name, ...); - -void -ganv_port_set_value_label(GanvPort* port, - const char* str); - -void -ganv_port_show_control(GanvPort* port); - -void -ganv_port_hide_control(GanvPort* port); - -void -ganv_port_set_control_is_toggle(GanvPort* port, - gboolean is_toggle); - -void -ganv_port_set_control_is_integer(GanvPort* port, - gboolean is_integer); - -void -ganv_port_set_control_value(GanvPort* port, - float value); - -void -ganv_port_set_control_min(GanvPort* port, - float min); - -void -ganv_port_set_control_max(GanvPort* port, - float max); - -double -ganv_port_get_natural_width(const GanvPort* port); - -/** - * ganv_port_get_module: - * @port: The port. - * - * Return value: (transfer none): The module @port is on. - */ -GanvModule* ganv_port_get_module(const GanvPort* port); - -float ganv_port_get_control_value(const GanvPort* port); -float ganv_port_get_control_min(const GanvPort* port); -float ganv_port_get_control_max(const GanvPort* port); -gboolean ganv_port_is_input(const GanvPort* port); -gboolean ganv_port_is_output(const GanvPort* port); - -G_END_DECLS - -#endif /* GANV_PORT_H */ diff --git a/ganv/text.h b/ganv/text.h deleted file mode 100644 index 6f03a1b..0000000 --- a/ganv/text.h +++ /dev/null @@ -1,52 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2014 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_TEXT_H -#define GANV_TEXT_H - -#include "ganv/item.h" - -G_BEGIN_DECLS - -#define GANV_TYPE_TEXT (ganv_text_get_type()) -#define GANV_TEXT(obj) (GTK_CHECK_CAST((obj), GANV_TYPE_TEXT, GanvText)) -#define GANV_TEXT_CLASS(klass) (GTK_CHECK_CLASS_CAST((klass), GANV_TYPE_TEXT, GanvTextClass)) -#define GANV_IS_TEXT(obj) (GTK_CHECK_TYPE((obj), GANV_TYPE_TEXT)) -#define GANV_IS_TEXT_CLASS(klass) (GTK_CHECK_CLASS_TYPE((klass), GANV_TYPE_TEXT)) -#define GANV_TEXT_GET_CLASS(obj) (GTK_CHECK_GET_CLASS((obj), GANV_TYPE_TEXT, GanvTextClass)) - -typedef struct _GanvText GanvText; -typedef struct _GanvTextClass GanvTextClass; -typedef struct _GanvTextPrivate GanvTextPrivate; - -struct _GanvText { - GanvItem item; - GanvTextPrivate* impl; -}; - -struct _GanvTextClass { - GanvItemClass parent_class; - - /* Reserved for future expansion */ - gpointer spare_vmethodsx[4]; -}; - -GType ganv_text_get_type(void) G_GNUC_CONST; - -void ganv_text_layout(GanvText* text); - -G_END_DECLS - -#endif /* GANV_TEXT_H */ diff --git a/ganv/types.h b/ganv/types.h deleted file mode 100644 index 70c21ec..0000000 --- a/ganv/types.h +++ /dev/null @@ -1,26 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2016 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_TYPES_H -#define GANV_TYPES_H - -typedef struct _GanvCanvas GanvCanvas; -typedef struct _GanvEdge GanvEdge; -typedef struct _GanvModule GanvModule; -typedef struct _GanvNode GanvNode; -typedef struct _GanvPort GanvPort; -typedef struct _GanvBox GanvBox; - -#endif /* GANV_TYPES_H */ diff --git a/ganv/types.hpp b/ganv/types.hpp deleted file mode 100644 index 280af16..0000000 --- a/ganv/types.hpp +++ /dev/null @@ -1,30 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_TYPES_HPP -#define GANV_TYPES_HPP - -namespace Ganv { - -class Canvas; -class Edge; -class Item; -class Module; -class Node; -class Port; - -}; // namespace Ganv - -#endif // GANV_TYPES_HPP diff --git a/ganv/widget.h b/ganv/widget.h deleted file mode 100644 index 5b54ba4..0000000 --- a/ganv/widget.h +++ /dev/null @@ -1,54 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2014 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -/* Based on GnomeCanvasWidget, by Federico Mena <federico@nuclecu.unam.mx> - * Copyright 1997-2000 Free Software Foundation - */ - -#ifndef GANV_WIDGET_H -#define GANV_WIDGET_H - -#include "ganv/item.h" - -G_BEGIN_DECLS - -#define GANV_TYPE_WIDGET (ganv_widget_get_type ()) -#define GANV_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GANV_TYPE_WIDGET, GanvWidget)) -#define GANV_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GANV_TYPE_WIDGET, GanvWidgetClass)) -#define GANV_IS_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GANV_TYPE_WIDGET)) -#define GANV_IS_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GANV_TYPE_WIDGET)) -#define GANV_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GANV_TYPE_WIDGET, GanvWidgetClass)) - -typedef struct _GanvWidget GanvWidget; -typedef struct _GanvWidgetPrivate GanvWidgetPrivate; -typedef struct _GanvWidgetClass GanvWidgetClass; - -struct _GanvWidget { - GanvItem item; - GanvWidgetPrivate* impl; -}; - -struct _GanvWidgetClass { - GanvItemClass parent_class; - - /* Reserved for future expansion */ - gpointer spare_vmethods [4]; -}; - -GType ganv_widget_get_type(void) G_GNUC_CONST; - -G_END_DECLS - -#endif /* GANV_WIDGET_H */ diff --git a/ganv/wrap.hpp b/ganv/wrap.hpp deleted file mode 100644 index 26e04d1..0000000 --- a/ganv/wrap.hpp +++ /dev/null @@ -1,131 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_WRAP_HPP -#define GANV_WRAP_HPP - -#include <glib.h> - -#define CONNECT_PROP_SIGNAL(gobj, name, notify, handler) \ - g_signal_connect(gobj, "notify::" #name, \ - G_CALLBACK(notify), &_signal_##name); \ - _signal_##name.connect(sigc::mem_fun(this, handler)); - -#define SIGNAL1(name, argtype) \ -public: \ - virtual bool on_##name(argtype arg) { return true; } \ - sigc::signal<bool, argtype>& signal_##name() { return _signal_##name; } \ -private: \ - sigc::signal<bool, argtype> _signal_##name; - -#define RW_PROPERTY(type, name) \ - virtual type get_##name() const { \ - type value; \ - g_object_get(G_OBJECT(_gobj), #name, &value, NULL); \ - return value; \ - } \ - virtual void set_##name(type value) { \ - g_object_set(G_OBJECT(_gobj), #name, value, NULL); \ - } \ - SIGNAL1(name, type) \ - public: - -#define RW_OBJECT_PROPERTY(type, name) \ - type get_##name() const { \ - if (!_gobj) return NULL; \ - Ganv##type ptr; \ - g_object_get(G_OBJECT(_gobj), #name, &ptr, NULL); \ - return Glib::wrap(ptr); \ - } \ - void set_##name(type value) { \ - if (!_gobj) return; \ - ganv_item_set(GANV_ITEM(_gobj), \ - #name, value->gobj(), \ - NULL); \ - } - -#define METHOD0(prefix, name) \ - virtual void name() { \ - prefix##_##name(gobj()); \ - } - -#define METHOD1(prefix, name, t1, a1) \ - virtual void name(t1 a1) { \ - prefix##_##name(gobj(), a1); \ - } - -#define METHODRET0(prefix, ret, name) \ - virtual ret name() const { \ - return prefix##_##name(gobj()); \ - } - -#define METHODRET1(prefix, ret, name, t1, a1) \ - virtual ret name(t1 a1) { \ - return prefix##_##name(gobj(), a1); \ - } - -#define METHODRET2(prefix, ret, name, t1, a1, t2, a2) \ - virtual ret name(t1 a1, t2 a2) { \ - return prefix##_##name(gobj(), a1, a2); \ - } - -#define METHODRETWRAP0(prefix, ret, name) \ - virtual ret name() const { \ - if (gobj()) { \ - return Glib::wrap(prefix##_##name(gobj())); \ - } else { \ - return NULL; \ - } \ - } - -#define METHOD2(prefix, name, t1, a1, t2, a2) \ - virtual void name(t1 a1, t2 a2) { \ - prefix##_##name(gobj(), a1, a2); \ - } - -#define METHOD3(prefix, name, t1, a1, t2, a2, t3, a3) \ - virtual void name(t1 a1, t2 a2, t3 a3) { \ - prefix##_##name(gobj(), a1, a2, a3); \ - } - -#define METHOD4(prefix, name, t1, a1, t2, a2, t3, a3, t4, a4) \ - virtual void name(t1 a1, t2 a2, t3 a3, t4 a4) { \ - prefix##_##name(gobj(), a1, a2, a3, a4); \ - } - -#define GANV_GLIB_WRAP(Name) \ - namespace Ganv { \ - class Name; \ - } \ - namespace Glib { \ - /** Return a Ganv::CPPType wrapper for a CType. */ \ - static inline Ganv::Name* \ - wrap(Ganv##Name* gobj) \ - { \ - if (gobj) { \ - return (Ganv::Name*)ganv_item_get_wrapper(GANV_ITEM(gobj)); \ - } else { \ - return NULL; \ - } \ - } \ - /** Return a Ganv::CPPType wrapper for a CType. */ \ - static inline const Ganv::Name* \ - wrap(const Ganv##Name* gobj) \ - { \ - return wrap((Ganv##Name*)gobj); \ - } \ - } - -#endif // GANV_WRAP_HPP diff --git a/gtkdoc.sh b/gtkdoc.sh deleted file mode 100755 index 42ff39d..0000000 --- a/gtkdoc.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -DOC_MODULE=ganv - -pwd=`pwd` -echo "gtkdoc.sh: Entering directory \`$pwd/docs'" - -mkdir -p docs -cd docs - -export CFLAGS="`pkg-config --cflags ganv-1`" -export LDFLAGS="`pkg-config --libs ganv-1`" - -# Sources have changed - -gtkdoc-scan --rebuild-sections --rebuild-types --ignore-headers=types.h --module=$DOC_MODULE --source-dir=../ganv -gtkdoc-scangobj --module=$DOC_MODULE -gtkdoc-mkdb --module=$DOC_MODULE --output-format=xml --source-dir=../ganv - -# XML files have changed -mkdir -p html -cd html && gtkdoc-mkhtml $DOC_MODULE ../ganv-docs.xml && cd - -gtkdoc-fixxref --module=$DOC_MODULE --module-dir=html - -echo "gtkdoc.sh: Leaving directory \`$pwd/docs'" -cd - diff --git a/waflib/processor.py b/processor.py index 2eecf3b..2eecf3b 100755 --- a/waflib/processor.py +++ b/processor.py diff --git a/src/Canvas.cpp b/src/Canvas.cpp deleted file mode 100644 index 6a18cdc..0000000 --- a/src/Canvas.cpp +++ /dev/null @@ -1,4184 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2016 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -/* Parts based on GnomeCanvas, by Federico Mena <federico@nuclecu.unam.mx> - * and Raph Levien <raph@gimp.org> - * Copyright 1997-2000 Free Software Foundation - */ - -#define _POSIX_C_SOURCE 200809L // strdup -#define _XOPEN_SOURCE 600 // isascii on BSD - -#include <math.h> -#include <stdio.h> -#include <string.h> - -#include <algorithm> -#include <cassert> -#include <cmath> -#include <iostream> -#include <map> -#include <set> -#include <sstream> -#include <string> -#include <vector> - -#include <cairo.h> -#include <gdk/gdkkeysyms.h> -#include <gtk/gtk.h> -#include <gtk/gtkstyle.h> -#include <gtkmm/widget.h> - -#include "ganv/Canvas.hpp" -#include "ganv/Circle.hpp" -#include "ganv/Edge.hpp" -#include "ganv/Module.hpp" -#include "ganv/Port.hpp" -#include "ganv/box.h" -#include "ganv/canvas.h" -#include "ganv/edge.h" -#include "ganv/group.h" -#include "ganv/node.h" -#include "ganv_config.h" - -#include "./color.h" -#include "./ganv-marshal.h" -#include "./ganv-private.h" -#include "./gettext.h" - -#ifdef HAVE_AGRAPH -// Deal with graphviz API amateur hour... -# define _DLL_BLD 0 -# define _dll_import 0 -# define _BLD_cdt 0 -# define _PACKAGE_ast 0 -# include <gvc.h> -#endif -#ifdef GANV_FDGL -# include "./fdgl.hpp" -#endif - -#define CANVAS_IDLE_PRIORITY (GDK_PRIORITY_REDRAW - 5) - -static const double GANV_CANVAS_PAD = 8.0; - -typedef struct { - int x; - int y; - int width; - int height; -} IRect; - -extern "C" { -static void add_idle(GanvCanvas* canvas); -static void ganv_canvas_destroy(GtkObject* object); -static void ganv_canvas_map(GtkWidget* widget); -static void ganv_canvas_unmap(GtkWidget* widget); -static void ganv_canvas_realize(GtkWidget* widget); -static void ganv_canvas_unrealize(GtkWidget* widget); -static void ganv_canvas_size_allocate(GtkWidget* widget, - GtkAllocation* allocation); -static gint ganv_canvas_button(GtkWidget* widget, - GdkEventButton* event); -static gint ganv_canvas_motion(GtkWidget* widget, - GdkEventMotion* event); -static gint ganv_canvas_expose(GtkWidget* widget, - GdkEventExpose* event); -static gboolean ganv_canvas_key(GtkWidget* widget, - GdkEventKey* event); -static gboolean ganv_canvas_scroll(GtkWidget* widget, - GdkEventScroll* event); -static gint ganv_canvas_crossing(GtkWidget* widget, - GdkEventCrossing* event); -static gint ganv_canvas_focus_in(GtkWidget* widget, - GdkEventFocus* event); -static gint ganv_canvas_focus_out(GtkWidget* widget, - GdkEventFocus* event); - -static GtkLayoutClass* canvas_parent_class; -} - -static guint signal_connect; -static guint signal_disconnect; - -static GEnumValue dir_values[3]; - -typedef std::set<GanvNode*> Items; - -#define FOREACH_ITEM(items, i) \ - for (Items::const_iterator i = items.begin(); i != items.end(); ++i) - -#define FOREACH_ITEM_MUT(items, i) \ - for (Items::iterator i = items.begin(); i != items.end(); ++i) - -#define FOREACH_EDGE(edges, i) \ - for (GanvCanvasImpl::Edges::const_iterator i = edges.begin(); \ - i != edges.end(); \ - ++i) - -#define FOREACH_EDGE_MUT(edges, i) \ - for (GanvCanvasImpl::Edges::iterator i = edges.begin(); \ - i != edges.end(); \ - ++i) - -#define FOREACH_SELECTED_EDGE(edges, i) \ - for (GanvCanvasImpl::SelectedEdges::const_iterator i = edges.begin(); \ - i != edges.end(); \ - ++i) - -#define FOREACH_SELECTED_PORT(p) \ - for (SelectedPorts::iterator p = _selected_ports.begin(); \ - p != _selected_ports.end(); ++p) - -#ifdef HAVE_AGRAPH -class GVNodes : public std::map<GanvNode*, Agnode_t*> { -public: - GVNodes() : gvc(0), G(0) {} - - void cleanup() { - gvFreeLayout(gvc, G); - agclose (G); - gvc = 0; - G = 0; - } - - GVC_t* gvc; - Agraph_t* G; -}; -#endif - -static const uint32_t SELECT_RECT_FILL_COLOUR = 0x2E444577; -static const uint32_t SELECT_RECT_BORDER_COLOUR = 0x2E4445FF; - -/* Order edges by (tail, head) */ -struct TailHeadOrder { - inline bool operator()(const GanvEdge* a, const GanvEdge* b) const { - return ((a->impl->tail < b->impl->tail) - || (a->impl->tail == b->impl->tail - && a->impl->head < b->impl->head)); - } -}; - -/* Order edges by (head, tail) */ -struct HeadTailOrder { - inline bool operator()(const GanvEdge* a, const GanvEdge* b) const { - return ((a->impl->head < b->impl->head) - || (a->impl->head == b->impl->head - && a->impl->tail < b->impl->tail)); - } -}; - -/* Callback used when the root item of a canvas is destroyed. The user should - * never ever do this, so we panic if this happens. - */ -static void -panic_root_destroyed(GtkObject* object, gpointer data) -{ - g_error("Eeeek, root item %p of canvas %p was destroyed!", (void*)object, data); -} - -struct GanvCanvasImpl { - GanvCanvasImpl(GanvCanvas* canvas) - : _gcanvas(canvas) - , _wrapper(NULL) - , _connect_port(NULL) - , _last_selected_port(NULL) - , _drag_edge(NULL) - , _drag_node(NULL) - , _select_rect(NULL) - , _select_start_x(0.0) - , _select_start_y(0.0) - , _drag_state(NOT_DRAGGING) - { - this->root = GANV_ITEM(g_object_new(ganv_group_get_type(), NULL)); - this->root->impl->canvas = canvas; - g_object_ref_sink(this->root); - - this->direction = GANV_DIRECTION_RIGHT; - this->width = 0; - this->height = 0; - - this->redraw_region = NULL; - this->current_item = NULL; - this->new_current_item = NULL; - this->grabbed_item = NULL; - this->focused_item = NULL; - this->pixmap_gc = NULL; - - this->pick_event.type = GDK_LEAVE_NOTIFY; - this->pick_event.crossing.x = 0; - this->pick_event.crossing.y = 0; - - this->scroll_x1 = 0.0; - this->scroll_y1 = 0.0; - this->scroll_x2 = canvas->layout.width; - this->scroll_y2 = canvas->layout.height; - - this->pixels_per_unit = 1.0; - this->font_size = ganv_canvas_get_default_font_size(canvas); - - this->idle_id = 0; - this->root_destroy_id = g_signal_connect( - this->root, "destroy", G_CALLBACK(panic_root_destroyed), canvas); - - this->redraw_x1 = 0; - this->redraw_y1 = 0; - this->redraw_x2 = 0; - this->redraw_y2 = 0; - - this->draw_xofs = 0; - this->draw_yofs = 0; - this->zoom_xofs = 0; - this->zoom_yofs = 0; - - this->state = 0; - this->grabbed_event_mask = 0; - - this->center_scroll_region = FALSE; - this->need_update = FALSE; - this->need_redraw = FALSE; - this->need_repick = TRUE; - this->left_grabbed_item = FALSE; - this->in_repick = FALSE; - this->locked = FALSE; - this->exporting = FALSE; - -#ifdef GANV_FDGL - this->layout_idle_id = 0; - this->layout_energy = 0.4; - this->sprung_layout = FALSE; -#endif - - _animate_idle_id = 0; - - _port_order.port_cmp = NULL; - _port_order.data = NULL; - - gtk_layout_set_hadjustment(GTK_LAYOUT(canvas), NULL); - gtk_layout_set_vadjustment(GTK_LAYOUT(canvas), NULL); - - _move_cursor = gdk_cursor_new(GDK_FLEUR); - } - - ~GanvCanvasImpl() - { - if (_animate_idle_id) { - g_source_remove(_animate_idle_id); - _animate_idle_id = 0; - } - - while (g_idle_remove_by_data(this)) {} - ganv_canvas_clear(_gcanvas); - gdk_cursor_unref(_move_cursor); - } - - static gboolean on_animate_timeout(gpointer impl); - -#ifdef GANV_FDGL - static gboolean on_layout_timeout(gpointer impl) { - return ((GanvCanvasImpl*)impl)->layout_iteration(); - } - - static void on_layout_done(gpointer impl) { - ((GanvCanvasImpl*)impl)->layout_idle_id = 0; - } - - gboolean layout_iteration(); - gboolean layout_calculate(double dur, bool update); -#endif - - void unselect_ports(); - -#ifdef HAVE_AGRAPH - GVNodes layout_dot(const std::string& filename); -#endif - - typedef std::set<GanvEdge*, TailHeadOrder> Edges; - typedef std::set<GanvEdge*, HeadTailOrder> DstEdges; - typedef std::set<GanvEdge*> SelectedEdges; - typedef std::set<GanvPort*> SelectedPorts; - - Edges::const_iterator first_edge_from(const GanvNode* src); - DstEdges::const_iterator first_edge_to(const GanvNode* dst); - - void select_port(GanvPort* p, bool unique=false); - void select_port_toggle(GanvPort* p, int mod_state); - void unselect_port(GanvPort* p); - void selection_joined_with(GanvPort* port); - void join_selection(); - - GanvNode* get_node_at(double x, double y); - - bool on_event(GdkEvent* event); - - bool scroll_drag_handler(GdkEvent* event); - bool select_drag_handler(GdkEvent* event); - bool connect_drag_handler(GdkEvent* event); - void end_connect_drag(); - - /* - Event handler for ports. - - This must be implemented as a Canvas method since port event handling - depends on shared data (for selection and connecting). This function - should only be used by Port implementations. - */ - bool port_event(GdkEvent* event, GanvPort* port); - - void ports_joined(GanvPort* port1, GanvPort* port2); - void port_clicked(GdkEvent* event, GanvPort* port); - void highlight_port(GanvPort* port, bool highlight); - - void move_contents_to_internal(double x, double y, double min_x, double min_y); - - GanvCanvas* _gcanvas; - Ganv::Canvas* _wrapper; - - Items _items; ///< Items on this canvas - Edges _edges; ///< Edges ordered (src, dst) - DstEdges _dst_edges; ///< Edges ordered (dst, src) - Items _selected_items; ///< Currently selected items - SelectedEdges _selected_edges; ///< Currently selected edges - - SelectedPorts _selected_ports; ///< Selected ports (hilited red) - GanvPort* _connect_port; ///< Port for which a edge is being made - GanvPort* _last_selected_port; - GanvEdge* _drag_edge; - GanvNode* _drag_node; - - GanvBox* _select_rect; ///< Rectangle for drag selection - double _select_start_x; ///< Selection drag start x coordinate - double _select_start_y; ///< Selection drag start y coordinate - - enum DragState { NOT_DRAGGING, EDGE, SCROLL, SELECT }; - DragState _drag_state; - - GdkCursor* _move_cursor; - guint _animate_idle_id; - - PortOrderCtx _port_order; - - /* Root canvas item */ - GanvItem* root; - - /* Flow direction */ - GanvDirection direction; - - /* Canvas width */ - double width; - - /* Canvas height */ - double height; - - /* Region that needs redrawing (list of rectangles) */ - GSList* redraw_region; - - /* The item containing the mouse pointer, or NULL if none */ - GanvItem* current_item; - - /* Item that is about to become current (used to track deletions and such) */ - GanvItem* new_current_item; - - /* Item that holds a pointer grab, or NULL if none */ - GanvItem* grabbed_item; - - /* If non-NULL, the currently focused item */ - GanvItem* focused_item; - - /* GC for temporary draw pixmap */ - GdkGC* pixmap_gc; - - /* Event on which selection of current item is based */ - GdkEvent pick_event; - - /* Scrolling region */ - double scroll_x1; - double scroll_y1; - double scroll_x2; - double scroll_y2; - - /* Scaling factor to be used for display */ - double pixels_per_unit; - - /* Font size in points */ - double font_size; - - /* Idle handler ID */ - guint idle_id; - - /* Signal handler ID for destruction of the root item */ - guint root_destroy_id; - - /* Area that is being redrawn. Contains (x1, y1) but not (x2, y2). - * Specified in canvas pixel coordinates. - */ - int redraw_x1; - int redraw_y1; - int redraw_x2; - int redraw_y2; - - /* Offsets of the temprary drawing pixmap */ - int draw_xofs; - int draw_yofs; - - /* Internal pixel offsets when zoomed out */ - int zoom_xofs; - int zoom_yofs; - - /* Last known modifier state, for deferred repick when a button is down */ - int state; - - /* Event mask specified when grabbing an item */ - guint grabbed_event_mask; - - /* Whether the canvas should center the scroll region in the middle of - * the window if the scroll region is smaller than the window. - */ - gboolean center_scroll_region; - - /* Whether items need update at next idle loop iteration */ - gboolean need_update; - - /* Whether the canvas needs redrawing at the next idle loop iteration */ - gboolean need_redraw; - - /* Whether current item will be repicked at next idle loop iteration */ - gboolean need_repick; - - /* For use by internal pick_current_item() function */ - gboolean left_grabbed_item; - - /* For use by internal pick_current_item() function */ - gboolean in_repick; - - /* Disable changes to canvas */ - gboolean locked; - - /* True if the current draw is an export */ - gboolean exporting; - -#ifdef GANV_FDGL - guint layout_idle_id; - gdouble layout_energy; - gboolean sprung_layout; -#endif -}; - -typedef struct { - GanvItem item; - GanvEdgePrivate* impl; - GanvEdgePrivate impl_data; -} GanvEdgeKey; - -static void -make_edge_search_key(GanvEdgeKey* key, - const GanvNode* tail, - const GanvNode* head) -{ - memset(key, '\0', sizeof(GanvEdgeKey)); - key->impl = &key->impl_data; - key->impl->tail = const_cast<GanvNode*>(tail); - key->impl->head = const_cast<GanvNode*>(head); -} - -GanvCanvasImpl::Edges::const_iterator -GanvCanvasImpl::first_edge_from(const GanvNode* tail) -{ - GanvEdgeKey key; - make_edge_search_key(&key, tail, NULL); - return _edges.lower_bound((GanvEdge*)&key); -} - -GanvCanvasImpl::DstEdges::const_iterator -GanvCanvasImpl::first_edge_to(const GanvNode* head) -{ - GanvEdgeKey key; - make_edge_search_key(&key, NULL, head); - return _dst_edges.lower_bound((GanvEdge*)&key); -} - -static void -select_if_tail_is_selected(GanvEdge* edge, void* data) -{ - GanvNode* tail = edge->impl->tail; - gboolean selected; - g_object_get(tail, "selected", &selected, NULL); - if (!selected && GANV_IS_PORT(tail)) { - g_object_get(ganv_port_get_module(GANV_PORT(tail)), - "selected", &selected, NULL); - } - - if (selected) { - ganv_edge_select(edge); - } -} - -static void -select_if_head_is_selected(GanvEdge* edge, void* data) -{ - GanvNode* head = edge->impl->head; - gboolean selected; - g_object_get(head, "selected", &selected, NULL); - if (!selected && GANV_IS_PORT(head)) { - g_object_get(ganv_port_get_module(GANV_PORT(head)), - "selected", &selected, NULL); - } - - if (selected) { - ganv_edge_set_selected(edge, TRUE); - } -} - -static void -select_edges(GanvPort* port, void* data) -{ - GanvCanvasImpl* impl = (GanvCanvasImpl*)data; - if (port->impl->is_input) { - ganv_canvas_for_each_edge_to(impl->_gcanvas, - GANV_NODE(port), - select_if_tail_is_selected, - NULL); - } else { - ganv_canvas_for_each_edge_from(impl->_gcanvas, - GANV_NODE(port), - select_if_head_is_selected, - NULL); - } -} - -#ifdef HAVE_AGRAPH -static void -gv_set(void* subject, const char* key, double value) -{ - std::ostringstream ss; - ss << value; - agsafeset(subject, (char*)key, (char*)ss.str().c_str(), (char*)""); -} - -GVNodes -GanvCanvasImpl::layout_dot(const std::string& filename) -{ - GVNodes nodes; - - const double dpi = gdk_screen_get_resolution(gdk_screen_get_default()); - - GVC_t* gvc = gvContext(); - - Agraph_t* G = agopen((char*)"g", Agdirected, NULL); - - agsafeset(G, (char*)"splines", (char*)"false", (char*)""); - agsafeset(G, (char*)"compound", (char*)"true", (char*)""); - agsafeset(G, (char*)"remincross", (char*)"true", (char*)""); - agsafeset(G, (char*)"overlap", (char*)"scale", (char*)""); - agsafeset(G, (char*)"nodesep", (char*)"0.05", (char*)""); - gv_set(G, "fontsize", ganv_canvas_get_font_size(_gcanvas)); - gv_set(G, "dpi", dpi); - - nodes.gvc = gvc; - nodes.G = G; - - const bool flow_right = _gcanvas->impl->direction; - if (flow_right) { - agattr(G, AGRAPH, (char*)"rankdir", (char*)"LR"); - } else { - agattr(G, AGRAPH, (char*)"rankdir", (char*)"TD"); - } - - unsigned id = 0; - std::ostringstream ss; - FOREACH_ITEM(_items, i) { - ss.str(""); - ss << "n" << id++; - const std::string node_id = ss.str(); - - Agnode_t* node = agnode(G, strdup(node_id.c_str()), true); - nodes.insert(std::make_pair(*i, node)); - - if (GANV_IS_MODULE(*i)) { - GanvModule* const m = GANV_MODULE(*i); - - agsafeset(node, (char*)"shape", (char*)"plaintext", (char*)""); - gv_set(node, "width", ganv_box_get_width(GANV_BOX(*i)) / dpi); - gv_set(node, "height", ganv_box_get_height(GANV_BOX(*i)) / dpi); - - std::string inputs; // Down flow - std::string outputs; // Down flow - std::string ports; // Right flow - unsigned n_inputs = 0; - unsigned n_outputs = 0; - for (size_t i = 0; i < ganv_module_num_ports(m); ++i) { - GanvPort* port = ganv_module_get_port(m, i); - ss.str(""); - ss << port; - - if (port->impl->is_input) { - ++n_inputs; - } else { - ++n_outputs; - } - - std::string cell = std::string("<TD PORT=\"") + ss.str() + "\""; - - cell += " FIXEDSIZE=\"TRUE\""; - ss.str(""); - ss << ganv_box_get_width(GANV_BOX(port));// / dpp * 1.3333333; - cell += " WIDTH=\"" + ss.str() + "\""; - - ss.str(""); - ss << ganv_box_get_height(GANV_BOX(port));// / dpp * 1.333333; - cell += " HEIGHT=\"" + ss.str() + "\""; - - cell += ">"; - const char* label = ganv_node_get_label(GANV_NODE(port)); - if (label && flow_right) { - cell += label; - } - cell += "</TD>"; - - if (flow_right) { - ports += "<TR>" + cell + "</TR>"; - } else if (port->impl->is_input) { - inputs += cell; - } else { - outputs += cell; - } - - nodes.insert(std::make_pair(GANV_NODE(port), node)); - } - - const unsigned n_cols = std::max(n_inputs, n_outputs); - - std::string html = "<TABLE CELLPADDING=\"0\" CELLSPACING=\"0\">"; - - // Input row (down flow only) - if (!inputs.empty()) { - for (unsigned i = n_inputs; i < n_cols + 1; ++i) { - inputs += "<TD BORDER=\"0\"></TD>"; - } - html += std::string("<TR>") + inputs + "</TR>"; - } - - // Label row - std::stringstream colspan; - colspan << (flow_right ? 1 : (n_cols + 1)); - html += std::string("<TR><TD BORDER=\"0\" CELLPADDING=\"2\" COLSPAN=\"") - + colspan.str() - + "\">"; - const char* label = ganv_node_get_label(GANV_NODE(m)); - if (label) { - html += label; - } - html += "</TD></TR>"; - - // Ports rows (right flow only) - if (!ports.empty()) { - html += ports; - } - - // Output row (down flow only) - if (!outputs.empty()) { - for (unsigned i = n_outputs; i < n_cols + 1; ++i) { - outputs += "<TD BORDER=\"0\"></TD>"; - } - html += std::string("<TR>") + outputs + "</TR>"; - } - html += "</TABLE>"; - - char* html_label_str = agstrdup_html(G, (char*)html.c_str()); - - agsafeset(node, (char*)"label", (char*)html_label_str, (char*)""); - } else if (GANV_IS_CIRCLE(*i)) { - agsafeset(node, (char*)"shape", (char*)"circle", (char*)""); - agsafeset(node, (char*)"fixedsize", (char*)"true", (char*)""); - agsafeset(node, (char*)"margin", (char*)"0.0,0.0", (char*)""); - - const double radius = ganv_circle_get_radius(GANV_CIRCLE(*i)); - const double penwidth = ganv_node_get_border_width(GANV_NODE(*i)); - const double span = (radius + penwidth) * 2.3 / dpi; - gv_set(node, (char*)"width", span); - gv_set(node, (char*)"height", span); - gv_set(node, (char*)"penwidth", penwidth); - - if (ganv_node_get_dash_length(GANV_NODE(*i)) > 0.0) { - agsafeset(node, (char*)"style", (char*)"dashed", (char*)""); - } - - const char* label = ganv_node_get_label(GANV_NODE(*i)); - if (label) { - agsafeset(node, (char*)"label", (char*)label, (char*)""); - } else { - agsafeset(node, (char*)"label", (char*)"", (char*)""); - } - } else { - std::cerr << "Unable to arrange item of unknown type" << std::endl; - } - } - - FOREACH_EDGE(_edges, i) { - const GanvEdge* const edge = *i; - GVNodes::iterator tail_i = nodes.find(edge->impl->tail); - GVNodes::iterator head_i = nodes.find(edge->impl->head); - - if (tail_i != nodes.end() && head_i != nodes.end()) { - Agedge_t* e = agedge(G, tail_i->second, head_i->second, NULL, true); - if (GANV_IS_PORT(edge->impl->tail)) { - ss.str((char*)""); - ss << edge->impl->tail << (flow_right ? ":e" : ":s"); - agsafeset(e, (char*)"tailport", (char*)ss.str().c_str(), (char*)""); - } - if (GANV_IS_PORT(edge->impl->head)) { - ss.str((char*)""); - ss << edge->impl->head << (flow_right ? ":w" : ":n"); - agsafeset(e, (char*)"headport", (char*)ss.str().c_str(), (char*)""); - } - if (!ganv_edge_get_constraining(edge)) { - agsafeset(e, (char*)"constraint", (char*)"false", (char*)""); - } - } else { - std::cerr << "Unable to find graphviz node" << std::endl; - } - } - - // Add edges between partners to have them lined up as if connected - for (GVNodes::iterator i = nodes.begin(); i != nodes.end(); ++i) { - GanvNode* partner = ganv_node_get_partner(i->first); - if (partner) { - GVNodes::iterator p = nodes.find(partner); - if (p != nodes.end()) { - Agedge_t* e = agedge(G, i->second, p->second, NULL, true); - agsafeset(e, (char*)"style", (char*)"invis", (char*)""); - } - } - } - - gvLayout(gvc, G, (char*)"dot"); - FILE* tmp = fopen("/dev/null", "w"); - gvRender(gvc, G, (char*)"dot", tmp); - fclose(tmp); - - if (filename != "") { - FILE* fd = fopen(filename.c_str(), "w"); - gvRender(gvc, G, (char*)"dot", fd); - fclose(fd); - } - - return nodes; -} -#endif - -inline uint64_t -get_monotonic_time() -{ -#if GLIB_CHECK_VERSION(2, 28, 0) - return g_get_monotonic_time(); -#else - GTimeVal time; - g_get_current_time(&time); - return time.tv_sec + time.tv_usec; -#endif -} - -#ifdef GANV_FDGL - -inline Region -get_region(GanvNode* node) -{ - GanvItem* item = &node->item; - - double x1, y1, x2, y2; - ganv_item_get_bounds(item, &x1, &y1, &x2, &y2); - - Region reg; - ganv_item_get_bounds(item, ®.pos.x, ®.pos.y, ®.area.x, ®.area.y); - reg.area.x = x2 - x1; - reg.area.y = y2 - y1; - reg.pos.x = item->impl->x + (reg.area.x / 2.0); - reg.pos.y = item->impl->y + (reg.area.y / 2.0); - - // No need for i2w here since we only care about top-level items - return reg; -} - -inline void -apply_force(GanvNode* a, GanvNode* b, const Vector& f) -{ - a->impl->force = vec_add(a->impl->force, f); - b->impl->force = vec_sub(b->impl->force, f); -} - -gboolean -GanvCanvasImpl::layout_iteration() -{ - if (_drag_state == EDGE) { - return FALSE; // Canvas is locked, halt layout process - } else if (!sprung_layout) { - return FALSE; // We shouldn't be running at all - } - - static const double T_PER_US = .0001; // Sym time per real microsecond - - static uint64_t prev = 0; // Previous iteration time - - const uint64_t now = get_monotonic_time(); - const double time_to_run = std::min((now - prev) * T_PER_US, 10.0); - - prev = now; - - const double QUANTUM = 0.05; - double sym_time = 0.0; - while (sym_time + QUANTUM < time_to_run) { - if (!layout_calculate(QUANTUM, FALSE)) { - break; - } - sym_time += QUANTUM; - } - - return layout_calculate(QUANTUM, TRUE); -} - -gboolean -GanvCanvasImpl::layout_calculate(double dur, bool update) -{ - // A light directional force to push sources to the top left - static const double DIR_MAGNITUDE = -1000.0; - Vector dir = { 0.0, 0.0 }; - switch (_gcanvas->impl->direction) { - case GANV_DIRECTION_RIGHT: dir.x = DIR_MAGNITUDE; break; - case GANV_DIRECTION_DOWN: dir.y = DIR_MAGNITUDE; break; - } - - // Calculate attractive spring forces for edges - FOREACH_EDGE(_edges, i) { - const GanvEdge* const edge = *i; - if (!ganv_edge_get_constraining(edge)) { - continue; - } - - GanvNode* tail = ganv_edge_get_tail(edge); - GanvNode* head = ganv_edge_get_head(edge); - if (GANV_IS_PORT(tail)) { - tail = GANV_NODE(ganv_port_get_module(GANV_PORT(tail))); - } - if (GANV_IS_PORT(head)) { - head = GANV_NODE(ganv_port_get_module(GANV_PORT(head))); - } - if (tail == head) { - continue; - } - - head->impl->connected = tail->impl->connected = TRUE; - - GanvEdgeCoords coords; - ganv_edge_get_coords(edge, &coords); - - const Vector tpos = { coords.x1, coords.y1 }; - const Vector hpos = { coords.x2, coords.y2 }; - apply_force(tail, head, edge_force(dir, hpos, tpos)); - } - - // Calculate repelling forces between nodes - FOREACH_ITEM(_items, i) { - if (!GANV_IS_MODULE(*i) && !GANV_IS_CIRCLE(*i)) { - continue; - } - - GanvNode* const node = *i; - GanvNode* partner = ganv_node_get_partner(node); - if (!partner && !node->impl->connected) { - continue; - } - - const Region reg = get_region(node); - if (partner) { - // Add fake long spring to partner to line up as if connected - const Region preg = get_region(partner); - apply_force(node, partner, edge_force(dir, preg.pos, reg.pos)); - } - - /* Add tide force which pulls all objects as if the layout is happening - on a flowing river surface. This prevents disconnected components - from being ejected, since at some point the tide force will be - greater than distant repelling charges. */ - const Vector mouth = { -100000.0, -100000.0 }; - node->impl->force = vec_add( - node->impl->force, - tide_force(mouth, reg.pos, 4000000000000.0)); - - // Add slight noise to force to limit oscillation - const Vector noise = { rand() / (float)RAND_MAX * 128.0, - rand() / (float)RAND_MAX * 128.0 }; - node->impl->force = vec_add(noise, node->impl->force); - - FOREACH_ITEM(_items, j) { - if (i == j || (!GANV_IS_MODULE(*i) && !GANV_IS_CIRCLE(*i))) { - continue; - } - apply_force(node, *j, repel_force(reg, get_region(*j))); - } - } - - // Update positions based on calculated forces - size_t n_moved = 0; - FOREACH_ITEM(_items, i) { - if (!GANV_IS_MODULE(*i) && !GANV_IS_CIRCLE(*i)) { - continue; - } - - GanvNode* const node = *i; - - if (node->impl->grabbed || - (!node->impl->connected && !ganv_node_get_partner(node))) { - node->impl->vel.x = 0.0; - node->impl->vel.y = 0.0; - } else { - node->impl->vel = vec_add(node->impl->vel, - vec_mult(node->impl->force, dur)); - node->impl->vel = vec_mult(node->impl->vel, layout_energy); - - static const double MAX_VEL = 1000.0; - static const double MIN_COORD = 4.0; - - // Clamp velocity - const double vel_mag = vec_mag(node->impl->vel); - if (vel_mag > MAX_VEL) { - node->impl->vel = vec_mult( - vec_mult(node->impl->vel, 1.0 / vel_mag), - MAX_VEL); - } - - // Update position - GanvItem* item = &node->item; - const double x0 = item->impl->x; - const double y0 = item->impl->y; - const Vector dpos = vec_mult(node->impl->vel, dur); - - item->impl->x = std::max(MIN_COORD, item->impl->x + dpos.x); - item->impl->y = std::max(MIN_COORD, item->impl->y + dpos.y); - - if (update) { - ganv_item_request_update(item); - item->impl->canvas->impl->need_repick = TRUE; - } - - if (lrint(x0) != lrint(item->impl->x) || lrint(y0) != lrint(item->impl->y)) { - ++n_moved; - } - } - - // Reset forces for next time - node->impl->force.x = 0.0; - node->impl->force.y = 0.0; - node->impl->connected = FALSE; - } - - if (update) { - // Now update edge positions to reflect new node positions - FOREACH_EDGE(_edges, i) { - GanvEdge* const edge = *i; - ganv_edge_update_location(edge); - } - } - - layout_energy *= 0.999; - return n_moved > 0; -} - -#endif // GANV_FDGL - -void -GanvCanvasImpl::select_port(GanvPort* p, bool unique) -{ - if (unique) { - unselect_ports(); - } - g_object_set(G_OBJECT(p), "selected", TRUE, NULL); - _selected_ports.insert(p); - _last_selected_port = p; -} - -void -GanvCanvasImpl::select_port_toggle(GanvPort* port, int mod_state) -{ - gboolean selected; - g_object_get(G_OBJECT(port), "selected", &selected, NULL); - if ((mod_state & GDK_CONTROL_MASK)) { - if (selected) - unselect_port(port); - else - select_port(port); - } else if ((mod_state & GDK_SHIFT_MASK)) { - GanvModule* const m = ganv_port_get_module(port); - if (_last_selected_port && m - && ganv_port_get_module(_last_selected_port) == m) { - // Pivot around _last_selected_port in a single pass over module ports each click - GanvPort* old_last_selected = _last_selected_port; - GanvPort* first = NULL; - bool done = false; - for (size_t i = 0; i < ganv_module_num_ports(m); ++i) { - GanvPort* const p = ganv_module_get_port(m, i); - if (!first && !done && (p == _last_selected_port || p == port)) { - first = p; - } - - if (first && !done && p->impl->is_input == first->impl->is_input) { - select_port(p, false); - } else { - unselect_port(p); - } - - if (p != first && (p == old_last_selected || p == port)) { - done = true; - } - } - _last_selected_port = old_last_selected; - } else { - if (selected) { - unselect_port(port); - } else { - select_port(port); - } - } - } else { - if (selected) { - unselect_ports(); - } else { - select_port(port, true); - } - } -} - -void -GanvCanvasImpl::unselect_port(GanvPort* p) -{ - _selected_ports.erase(p); - g_object_set(G_OBJECT(p), "selected", FALSE, NULL); - if (_last_selected_port == p) { - _last_selected_port = NULL; - } -} - -void -GanvCanvasImpl::selection_joined_with(GanvPort* port) -{ - FOREACH_SELECTED_PORT(i) - ports_joined(*i, port); -} - -void -GanvCanvasImpl::join_selection() -{ - std::vector<GanvPort*> inputs; - std::vector<GanvPort*> outputs; - FOREACH_SELECTED_PORT(i) { - if ((*i)->impl->is_input) { - inputs.push_back(*i); - } else { - outputs.push_back(*i); - } - } - - if (inputs.size() == 1) { // 1 -> n - for (size_t i = 0; i < outputs.size(); ++i) - ports_joined(inputs[0], outputs[i]); - } else if (outputs.size() == 1) { // n -> 1 - for (size_t i = 0; i < inputs.size(); ++i) - ports_joined(inputs[i], outputs[0]); - } else { // n -> m - size_t num_to_connect = std::min(inputs.size(), outputs.size()); - for (size_t i = 0; i < num_to_connect; ++i) { - ports_joined(inputs[i], outputs[i]); - } - } -} - -GanvNode* -GanvCanvasImpl::get_node_at(double x, double y) -{ - GanvItem* item = ganv_canvas_get_item_at(GANV_CANVAS(_gcanvas), x, y); - while (item) { - if (GANV_IS_NODE(item)) { - return GANV_NODE(item); - } else { - item = item->impl->parent; - } - } - - return NULL; -} - -bool -GanvCanvasImpl::on_event(GdkEvent* event) -{ - static const int scroll_increment = 10; - int scroll_x, scroll_y; - - bool handled = false; - switch (event->type) { - case GDK_KEY_PRESS: - handled = true; - ganv_canvas_get_scroll_offsets(GANV_CANVAS(_gcanvas), &scroll_x, &scroll_y); - switch (event->key.keyval) { - case GDK_Up: - scroll_y -= scroll_increment; - break; - case GDK_Down: - scroll_y += scroll_increment; - break; - case GDK_Left: - scroll_x -= scroll_increment; - break; - case GDK_Right: - scroll_x += scroll_increment; - break; - case GDK_Return: - if (_selected_ports.size() > 1) { - join_selection(); - ganv_canvas_clear_selection(_gcanvas); - } - break; - default: - handled = false; - } - if (handled) { - ganv_canvas_scroll_to(GANV_CANVAS(_gcanvas), scroll_x, scroll_y); - return true; - } - break; - - case GDK_SCROLL: - if ((event->scroll.state & GDK_CONTROL_MASK)) { - const double zoom = ganv_canvas_get_zoom(_gcanvas); - if (event->scroll.direction == GDK_SCROLL_UP) { - ganv_canvas_set_zoom(_gcanvas, zoom * 1.25); - return true; - } else if (event->scroll.direction == GDK_SCROLL_DOWN) { - ganv_canvas_set_zoom(_gcanvas, zoom * 0.75); - return true; - } - } - break; - - default: - break; - } - - return scroll_drag_handler(event) - || select_drag_handler(event) - || connect_drag_handler(event); -} - -bool -GanvCanvasImpl::scroll_drag_handler(GdkEvent* event) -{ - bool handled = true; - - static int original_scroll_x = 0; - static int original_scroll_y = 0; - static double origin_x = 0; - static double origin_y = 0; - static double scroll_offset_x = 0; - static double scroll_offset_y = 0; - static double last_x = 0; - static double last_y = 0; - - GanvItem* root = ganv_canvas_root(_gcanvas); - - if (event->type == GDK_BUTTON_PRESS && event->button.button == 2) { - ganv_canvas_grab_item( - root, - GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK, - NULL, event->button.time); - ganv_canvas_get_scroll_offsets(GANV_CANVAS(_gcanvas), &original_scroll_x, &original_scroll_y); - scroll_offset_x = 0; - scroll_offset_y = 0; - origin_x = event->button.x_root; - origin_y = event->button.y_root; - //cerr << "Origin: (" << origin_x << "," << origin_y << ")\n"; - last_x = origin_x; - last_y = origin_y; - _drag_state = SCROLL; - - } else if (event->type == GDK_MOTION_NOTIFY && _drag_state == SCROLL) { - const double x = event->motion.x_root; - const double y = event->motion.y_root; - const double x_offset = last_x - x; - const double y_offset = last_y - y; - - //cerr << "Coord: (" << x << "," << y << ")\n"; - //cerr << "Offset: (" << x_offset << "," << y_offset << ")\n"; - - scroll_offset_x += x_offset; - scroll_offset_y += y_offset; - ganv_canvas_scroll_to(GANV_CANVAS(_gcanvas), - lrint(original_scroll_x + scroll_offset_x), - lrint(original_scroll_y + scroll_offset_y)); - last_x = x; - last_y = y; - } else if (event->type == GDK_BUTTON_RELEASE && _drag_state == SCROLL) { - ganv_canvas_ungrab_item(root, event->button.time); - _drag_state = NOT_DRAGGING; - } else { - handled = false; - } - - return handled; -} - -static void -get_motion_coords(GdkEventMotion* motion, double* x, double* y) -{ - if (motion->is_hint) { - gint px; - gint py; - GdkModifierType state; - gdk_window_get_pointer(motion->window, &px, &py, &state); - *x = px; - *y = py; - } else { - *x = motion->x; - *y = motion->y; - } -} - -bool -GanvCanvasImpl::select_drag_handler(GdkEvent* event) -{ - GanvItem* root = ganv_canvas_root(_gcanvas); - if (event->type == GDK_BUTTON_PRESS && event->button.button == 1) { - assert(_select_rect == NULL); - _drag_state = SELECT; - if ( !(event->button.state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) ) - ganv_canvas_clear_selection(_gcanvas); - _select_rect = GANV_BOX( - ganv_item_new( - root, - ganv_box_get_type(), - "x1", event->button.x, - "y1", event->button.y, - "x2", event->button.x, - "y2", event->button.y, - "fill-color", SELECT_RECT_FILL_COLOUR, - "border-color", SELECT_RECT_BORDER_COLOUR, - NULL)); - _select_start_x = event->button.x; - _select_start_y = event->button.y; - ganv_canvas_grab_item( - root, GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK, - NULL, event->button.time); - return true; - } else if (event->type == GDK_MOTION_NOTIFY && _drag_state == SELECT) { - assert(_select_rect); - double x, y; - get_motion_coords(&event->motion, &x, &y); - _select_rect->impl->coords.x1 = MIN(_select_start_x, x); - _select_rect->impl->coords.y1 = MIN(_select_start_y, y); - _select_rect->impl->coords.x2 = MAX(_select_start_x, x); - _select_rect->impl->coords.y2 = MAX(_select_start_y, y); - ganv_item_request_update(&_select_rect->node.item); - return true; - } else if (event->type == GDK_BUTTON_RELEASE && _drag_state == SELECT) { - // Normalize select rect - ganv_box_normalize(_select_rect); - - // Select all modules within rect - FOREACH_ITEM(_items, i) { - GanvNode* node = *i; - if ((void*)node != (void*)_select_rect && - ganv_node_is_within( - node, - ganv_box_get_x1(_select_rect), - ganv_box_get_y1(_select_rect), - ganv_box_get_x2(_select_rect), - ganv_box_get_y2(_select_rect))) { - gboolean selected; - g_object_get(G_OBJECT(node), "selected", &selected, NULL); - if (selected) { - ganv_canvas_unselect_node(_gcanvas, node); - } else { - ganv_canvas_select_node(_gcanvas, node); - } - } - } - - // Select all edges with handles within rect - FOREACH_EDGE(_edges, i) { - if (ganv_edge_is_within( - (*i), - ganv_box_get_x1(_select_rect), - ganv_box_get_y1(_select_rect), - ganv_box_get_x2(_select_rect), - ganv_box_get_y2(_select_rect))) { - ganv_canvas_select_edge(_gcanvas, *i); - } - } - - ganv_canvas_ungrab_item(root, event->button.time); - - gtk_object_destroy(GTK_OBJECT(_select_rect)); - _select_rect = NULL; - _drag_state = NOT_DRAGGING; - return true; - } - return false; -} - -bool -GanvCanvasImpl::connect_drag_handler(GdkEvent* event) -{ - static bool snapped = false; - - if (_drag_state != EDGE) { - return false; - } - - if (event->type == GDK_MOTION_NOTIFY) { - double x, y; - get_motion_coords(&event->motion, &x, &y); - - if (!_drag_edge) { - // Create drag edge - assert(!_drag_node); - assert(_connect_port); - - _drag_node = GANV_NODE( - ganv_item_new( - GANV_ITEM(ganv_canvas_root(GANV_CANVAS(_gcanvas))), - ganv_node_get_type(), - "x", x, - "y", y, - NULL)); - - _drag_edge = ganv_edge_new( - _gcanvas, - GANV_NODE(_connect_port), - _drag_node, - "color", GANV_NODE(_connect_port)->impl->fill_color, - "curved", TRUE, - "ghost", TRUE, - NULL); - } - - GanvNode* joinee = get_node_at(x, y); - if (joinee && ganv_node_can_head(joinee) && joinee != _drag_node) { - // Snap to item - snapped = true; - ganv_item_set(&_drag_edge->item, "head", joinee, NULL); - } else if (snapped) { - // Unsnap from item - snapped = false; - ganv_item_set(&_drag_edge->item, "head", _drag_node, NULL); - } - - // Update drag edge for pointer position - ganv_node_move_to(_drag_node, x, y); - ganv_item_request_update(GANV_ITEM(_drag_node)); - ganv_item_request_update(GANV_ITEM(_drag_edge)); - - return true; - - } else if (event->type == GDK_BUTTON_RELEASE) { - ganv_canvas_ungrab_item(root, event->button.time); - - double x = event->button.x; - double y = event->button.y; - - GanvNode* joinee = get_node_at(x, y); - - if (GANV_IS_PORT(joinee)) { - if (joinee == GANV_NODE(_connect_port)) { - // Drag ended on the same port it started on, port clicked - if (_selected_ports.empty()) { - // No selected ports, port clicked - select_port(_connect_port); - } else { - // Connect to selected ports - selection_joined_with(_connect_port); - _connect_port = NULL; - } - } else { // drag ended on different port - ports_joined(_connect_port, GANV_PORT(joinee)); - _connect_port = NULL; - } - } - - end_connect_drag(); - return true; - } - - return false; -} - -void -GanvCanvasImpl::end_connect_drag() -{ - if (_connect_port) { - highlight_port(_connect_port, false); - } - gtk_object_destroy(GTK_OBJECT(_drag_edge)); - gtk_object_destroy(GTK_OBJECT(_drag_node)); - _drag_state = NOT_DRAGGING; - _connect_port = NULL; - _drag_edge = NULL; - _drag_node = NULL; -} - -bool -GanvCanvasImpl::port_event(GdkEvent* event, GanvPort* port) -{ - static bool port_pressed = true; - static bool port_dragging = false; - static bool control_dragging = false; - static double control_start_x = 0; - static double control_start_y = 0; - static float control_start_value = 0; - - switch (event->type) { - case GDK_BUTTON_PRESS: - if (event->button.button == 1) { - GanvModule* const module = ganv_port_get_module(port); - double port_x = event->button.x; - double port_y = event->button.y; - ganv_item_w2i(GANV_ITEM(port), &port_x, &port_y); - - if (_selected_ports.empty() && module && port->impl->control && - (port->impl->is_input || - (port->impl->is_controllable && - port_x < ganv_box_get_width(GANV_BOX(port)) / 2.0))) { - if (port->impl->control->is_toggle) { - if (port->impl->control->value >= 0.5) { - ganv_port_set_control_value_internal(port, 0.0); - } else { - ganv_port_set_control_value_internal(port, 1.0); - } - } else { - control_dragging = port_pressed = true; - control_start_x = event->button.x_root; - control_start_y = event->button.y_root; - control_start_value = ganv_port_get_control_value(port); - ganv_canvas_grab_item( - GANV_ITEM(port), - GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK, - NULL, event->button.time); - GANV_NODE(port)->impl->grabbed = TRUE; - - } - } else if (!port->impl->is_input) { - port_dragging = port_pressed = true; - ganv_canvas_grab_item( - GANV_ITEM(port), - GDK_BUTTON_RELEASE_MASK|GDK_POINTER_MOTION_MASK| - GDK_ENTER_NOTIFY_MASK|GDK_LEAVE_NOTIFY_MASK, - NULL, event->button.time); - } else { - port_pressed = true; - ganv_canvas_grab_item(GANV_ITEM(port), - GDK_BUTTON_RELEASE_MASK, - NULL, event->button.time); - } - return true; - } - break; - - case GDK_MOTION_NOTIFY: - if (control_dragging) { - const double mouse_x = event->button.x_root; - const double mouse_y = event->button.y_root; - GdkScreen* screen = gdk_screen_get_default(); - const int screen_width = gdk_screen_get_width(screen); - const int screen_height = gdk_screen_get_height(screen); - const double drag_dx = mouse_x - control_start_x; - const double drag_dy = mouse_y - control_start_y; - const double ythresh = 0.2; // Minimum y fraction for fine - - const double range_x = ((drag_dx > 0) - ? (screen_width - control_start_x) - : control_start_x) - GANV_CANVAS_PAD; - - const double range_y = ((drag_dy > 0) - ? (screen_height - control_start_y) - : control_start_y); - - const double dx = drag_dx / range_x; - const double dy = fabs(drag_dy / range_y); - - const double value_range = (drag_dx > 0) - ? port->impl->control->max - control_start_value - : control_start_value - port->impl->control->min; - - const double sens = (dy < ythresh) - ? 1.0 - : 1.0 - fabs(drag_dy / (range_y + ythresh)); - - const double dvalue = (dx * value_range) * sens; - double value = control_start_value + dvalue; - if (value < port->impl->control->min) { - value = port->impl->control->min; - } else if (value > port->impl->control->max) { - value = port->impl->control->max; - } - ganv_port_set_control_value_internal(port, value); - return true; - } else if (port_dragging) { - return true; - } - break; - - case GDK_BUTTON_RELEASE: - if (port_pressed) { - ganv_canvas_ungrab_item(GANV_ITEM(port), event->button.time); - } - - if (port_dragging) { - if (_connect_port) { // dragging - ports_joined(port, _connect_port); - } else { - port_clicked(event, port); - } - port_dragging = false; - } else if (control_dragging) { - control_dragging = false; - GANV_NODE(port)->impl->grabbed = FALSE; - if (event->button.x_root == control_start_x && - event->button.y_root == control_start_y) { - select_port_toggle(port, event->button.state); - } - } else { - port_clicked(event, port); - } - return true; - - case GDK_ENTER_NOTIFY: - gboolean selected; - g_object_get(G_OBJECT(port), "selected", &selected, NULL); - if (!control_dragging && !selected) { - highlight_port(port, true); - return true; - } - break; - - case GDK_LEAVE_NOTIFY: - if (port_dragging) { - _drag_state = GanvCanvasImpl::EDGE; - _connect_port = port; - port_dragging = false; - ganv_canvas_ungrab_item(GANV_ITEM(port), event->crossing.time); - ganv_canvas_grab_item( - root, - GDK_BUTTON_PRESS_MASK|GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK, - NULL, event->crossing.time); - return true; - } else if (!control_dragging) { - highlight_port(port, false); - return true; - } - break; - - default: - break; - } - - return false; -} - -/* Called when two ports are 'joined' (connected or disconnected) */ -void -GanvCanvasImpl::ports_joined(GanvPort* port1, GanvPort* port2) -{ - if (port1 == port2 || !port1 || !port2 || !port1->impl || !port2->impl) { - return; - } - - highlight_port(port1, false); - highlight_port(port2, false); - - GanvNode* src_node; - GanvNode* dst_node; - - if (port2->impl->is_input && !port1->impl->is_input) { - src_node = GANV_NODE(port1); - dst_node = GANV_NODE(port2); - } else if (!port2->impl->is_input && port1->impl->is_input) { - src_node = GANV_NODE(port2); - dst_node = GANV_NODE(port1); - } else { - return; - } - - if (!ganv_canvas_get_edge(_gcanvas, src_node, dst_node)) { - g_signal_emit(_gcanvas, signal_connect, 0, - src_node, dst_node, NULL); - } else { - g_signal_emit(_gcanvas, signal_disconnect, 0, - src_node, dst_node, NULL); - } -} - -void -GanvCanvasImpl::port_clicked(GdkEvent* event, GanvPort* port) -{ - const bool modded = event->button.state & (GDK_SHIFT_MASK|GDK_CONTROL_MASK); - if (!modded && _last_selected_port && - _last_selected_port->impl->is_input != port->impl->is_input) { - selection_joined_with(port); - } else { - select_port_toggle(port, event->button.state); - } -} - -void -GanvCanvasImpl::highlight_port(GanvPort* port, bool highlight) -{ - g_object_set(G_OBJECT(port), "highlighted", highlight, NULL); - ganv_canvas_for_each_edge_on(_gcanvas, - GANV_NODE(port), - (highlight - ? (GanvEdgeFunc)ganv_edge_highlight - : (GanvEdgeFunc)ganv_edge_unhighlight), - NULL); -} - -/* Update animated "rubber band" selection effect. */ -gboolean -GanvCanvasImpl::on_animate_timeout(gpointer data) -{ - GanvCanvasImpl* impl = (GanvCanvasImpl*)data; - if (!impl->pixmap_gc) { - return FALSE; // Unrealized - } - - const double seconds = get_monotonic_time() / 1000000.0; - - FOREACH_ITEM(impl->_selected_items, s) { - ganv_node_tick(*s, seconds); - } - - for (SelectedPorts::iterator p = impl->_selected_ports.begin(); - p != impl->_selected_ports.end(); - ++p) { - ganv_node_tick(GANV_NODE(*p), seconds); - } - - FOREACH_EDGE(impl->_selected_edges, c) { - ganv_edge_tick(*c, seconds); - } - - return TRUE; -} - -void -GanvCanvasImpl::move_contents_to_internal(double x, double y, double min_x, double min_y) -{ - FOREACH_ITEM(_items, i) { - ganv_node_move(*i, - x - min_x, - y - min_y); - } -} - -void -GanvCanvasImpl::unselect_ports() -{ - for (GanvCanvasImpl::SelectedPorts::iterator i = _selected_ports.begin(); - i != _selected_ports.end(); ++i) - g_object_set(G_OBJECT(*i), "selected", FALSE, NULL); - - _selected_ports.clear(); - _last_selected_port = NULL; -} - -namespace Ganv { - -static gboolean -on_event_after(GanvItem* canvasitem, - GdkEvent* ev, - void* canvas) -{ - return ((Canvas*)canvas)->signal_event.emit(ev); -} - -static void -on_connect(GanvCanvas* canvas, GanvNode* tail, GanvNode* head, void* data) -{ - Canvas* canvasmm = (Canvas*)data; - canvasmm->signal_connect.emit(Glib::wrap(tail), Glib::wrap(head)); -} - -static void -on_disconnect(GanvCanvas* canvas, GanvNode* tail, GanvNode* head, void* data) -{ - Canvas* canvasmm = (Canvas*)data; - canvasmm->signal_disconnect.emit(Glib::wrap(tail), Glib::wrap(head)); -} - -Canvas::Canvas(double width, double height) - : _gobj(GANV_CANVAS(ganv_canvas_new(width, height))) -{ - ganv_canvas_set_wrapper(_gobj, this); - - g_signal_connect_after(ganv_canvas_root(_gobj), "event", - G_CALLBACK(on_event_after), this); - g_signal_connect(gobj(), "connect", - G_CALLBACK(on_connect), this); - g_signal_connect(gobj(), "disconnect", - G_CALLBACK(on_disconnect), this); -} - -Canvas::~Canvas() -{ - delete _gobj->impl; -} - -void -Canvas::remove_edge_between(Node* item1, Node* item2) -{ - GanvEdge* edge = ganv_canvas_get_edge(_gobj, item1->gobj(), item2->gobj()); - if (edge) { - ganv_canvas_remove_edge(_gobj, edge); - } -} - -void -Canvas::remove_edge(Edge* edge) -{ - ganv_canvas_remove_edge(_gobj, edge->gobj()); -} - -Item* -Canvas::get_item_at(double x, double y) const -{ - GanvItem* item = ganv_canvas_get_item_at(_gobj, x, y); - if (item) { - return Glib::wrap(item); - } - return NULL; -} - -Edge* -Canvas::get_edge(Node* tail, Node* head) const -{ - GanvEdge* e = ganv_canvas_get_edge(_gobj, tail->gobj(), head->gobj()); - if (e) { - return Glib::wrap(e); - } - return NULL; -} - -} // namespace Ganv - -extern "C" { - -#include "ganv/canvas.h" - -#include "./boilerplate.h" -#include "./color.h" -#include "./gettext.h" - -G_DEFINE_TYPE_WITH_CODE(GanvCanvas, ganv_canvas, GTK_TYPE_LAYOUT, - G_ADD_PRIVATE(GanvCanvas)) - -enum { - PROP_0, - PROP_WIDTH, - PROP_HEIGHT, - PROP_DIRECTION, - PROP_FONT_SIZE, - PROP_LOCKED, - PROP_FOCUSED_ITEM -}; - -static gboolean -on_canvas_event(GanvItem* canvasitem, - GdkEvent* ev, - void* impl) -{ - return ((GanvCanvasImpl*)impl)->on_event(ev); -} - -static void -ganv_canvas_init(GanvCanvas* canvas) -{ - GTK_WIDGET_SET_FLAGS(canvas, GTK_CAN_FOCUS); - - canvas->impl = new GanvCanvasImpl(canvas); - - g_signal_connect(G_OBJECT(ganv_canvas_root(canvas)), - "event", G_CALLBACK(on_canvas_event), canvas->impl); -} - -static void -ganv_canvas_set_property(GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_CANVAS(object)); - - GanvCanvas* canvas = GANV_CANVAS(object); - - switch (prop_id) { - case PROP_WIDTH: - ganv_canvas_resize(canvas, g_value_get_double(value), canvas->impl->height); - break; - case PROP_HEIGHT: - ganv_canvas_resize(canvas, canvas->impl->width, g_value_get_double(value)); - break; - case PROP_DIRECTION: - ganv_canvas_set_direction(canvas, (GanvDirection)g_value_get_enum(value)); - break; - case PROP_FONT_SIZE: - ganv_canvas_set_font_size(canvas, g_value_get_double(value)); - break; - case PROP_LOCKED: - canvas->impl->locked = g_value_get_boolean(value); - break; - case PROP_FOCUSED_ITEM: - canvas->impl->focused_item = GANV_ITEM(g_value_get_object(value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_canvas_get_property(GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_CANVAS(object)); - - GanvCanvas* canvas = GANV_CANVAS(object); - - switch (prop_id) { - GET_CASE(WIDTH, double, canvas->impl->width) - GET_CASE(HEIGHT, double, canvas->impl->height) - GET_CASE(LOCKED, boolean, canvas->impl->locked); - case PROP_FOCUSED_ITEM: - g_value_set_object(value, GANV_CANVAS(object)->impl->focused_item); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_canvas_class_init(GanvCanvasClass* klass) -{ - GObjectClass* gobject_class = (GObjectClass*)klass; - GtkObjectClass* object_class = (GtkObjectClass*)klass; - GtkWidgetClass* widget_class = (GtkWidgetClass*)klass; - - canvas_parent_class = GTK_LAYOUT_CLASS(g_type_class_peek_parent(klass)); - - gobject_class->set_property = ganv_canvas_set_property; - gobject_class->get_property = ganv_canvas_get_property; - - object_class->destroy = ganv_canvas_destroy; - - widget_class->map = ganv_canvas_map; - widget_class->unmap = ganv_canvas_unmap; - widget_class->realize = ganv_canvas_realize; - widget_class->unrealize = ganv_canvas_unrealize; - widget_class->size_allocate = ganv_canvas_size_allocate; - widget_class->button_press_event = ganv_canvas_button; - widget_class->button_release_event = ganv_canvas_button; - widget_class->motion_notify_event = ganv_canvas_motion; - widget_class->expose_event = ganv_canvas_expose; - widget_class->key_press_event = ganv_canvas_key; - widget_class->key_release_event = ganv_canvas_key; - widget_class->enter_notify_event = ganv_canvas_crossing; - widget_class->leave_notify_event = ganv_canvas_crossing; - widget_class->focus_in_event = ganv_canvas_focus_in; - widget_class->focus_out_event = ganv_canvas_focus_out; - widget_class->scroll_event = ganv_canvas_scroll; - - g_object_class_install_property( - gobject_class, PROP_FOCUSED_ITEM, g_param_spec_object( - "focused-item", - _("Focused item"), - _("The item that currently has keyboard focus."), - GANV_TYPE_ITEM, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE))); - - g_object_class_install_property( - gobject_class, PROP_WIDTH, g_param_spec_double( - "width", - _("Width"), - _("The width of the canvas."), - 0.0, G_MAXDOUBLE, - 800.0, - (GParamFlags)G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_HEIGHT, g_param_spec_double( - "height", - _("Height"), - _("The height of the canvas"), - 0.0, G_MAXDOUBLE, - 600.0, - (GParamFlags)G_PARAM_READWRITE)); - - GEnumValue down_dir = { GANV_DIRECTION_DOWN, "down", "down" }; - GEnumValue right_dir = { GANV_DIRECTION_RIGHT, "right", "right" }; - GEnumValue null_dir = { 0, 0, 0 }; - dir_values[0] = down_dir; - dir_values[1] = right_dir; - dir_values[2] = null_dir; - GType dir_type = g_enum_register_static("GanvDirection", - dir_values); - - g_object_class_install_property( - gobject_class, PROP_DIRECTION, g_param_spec_enum( - "direction", - _("Direction"), - _("The direction of the signal flow on the canvas."), - dir_type, - GANV_DIRECTION_RIGHT, - (GParamFlags)G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_FONT_SIZE, g_param_spec_double( - "font-size", - _("Font size"), - _("The default font size for the canvas"), - 0.0, G_MAXDOUBLE, - 12.0, - (GParamFlags)G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_LOCKED, g_param_spec_boolean( - "locked", - _("Locked"), - _("If true, nodes on the canvas can not be moved by the user."), - FALSE, - (GParamFlags)G_PARAM_READWRITE)); - - signal_connect = g_signal_new("connect", - ganv_canvas_get_type(), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - ganv_marshal_VOID__OBJECT_OBJECT, - G_TYPE_NONE, - 2, - ganv_node_get_type(), - ganv_node_get_type(), - 0); - - signal_disconnect = g_signal_new("disconnect", - ganv_canvas_get_type(), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - ganv_marshal_VOID__OBJECT_OBJECT, - G_TYPE_NONE, - 2, - ganv_node_get_type(), - ganv_node_get_type(), - 0); -} - -void -ganv_canvas_resize(GanvCanvas* canvas, double width, double height) -{ - if (width != canvas->impl->width || height != canvas->impl->height) { - canvas->impl->width = width; - canvas->impl->height = height; - ganv_canvas_set_scroll_region(canvas, 0.0, 0.0, width, height); - } -} - -void -ganv_canvas_contents_changed(GanvCanvas* canvas) -{ -#ifdef GANV_FDGL - if (!canvas->impl->layout_idle_id && canvas->impl->sprung_layout) { - canvas->impl->layout_energy = 0.4; - canvas->impl->layout_idle_id = g_timeout_add_full( - G_PRIORITY_DEFAULT_IDLE, - 33, - GanvCanvasImpl::on_layout_timeout, - canvas->impl, - GanvCanvasImpl::on_layout_done); - } -#endif -} - -double -ganv_canvas_get_default_font_size(const GanvCanvas* canvas) -{ - GtkStyle* style = gtk_rc_get_style(GTK_WIDGET(canvas)); - const PangoFontDescription* font = style->font_desc; - return pango_font_description_get_size(font) / (double)PANGO_SCALE; -} - -double -ganv_canvas_get_font_size(const GanvCanvas* canvas) -{ - return canvas->impl->font_size; -} - -void -ganv_canvas_set_zoom(GanvCanvas* canvas, double zoom) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - zoom = std::max(zoom, 0.01); - if (zoom == canvas->impl->pixels_per_unit) { - return; - } - - const int anchor_x = (canvas->impl->center_scroll_region) - ? GTK_WIDGET(canvas)->allocation.width / 2 - : 0; - const int anchor_y = (canvas->impl->center_scroll_region) - ? GTK_WIDGET(canvas)->allocation.height / 2 - : 0; - - /* Find the coordinates of the anchor point in units. */ - const double ax = (canvas->layout.hadjustment) - ? ((canvas->layout.hadjustment->value + anchor_x) - / canvas->impl->pixels_per_unit - + canvas->impl->scroll_x1 + canvas->impl->zoom_xofs) - : ((0.0 + anchor_x) / canvas->impl->pixels_per_unit - + canvas->impl->scroll_x1 + canvas->impl->zoom_xofs); - const double ay = (canvas->layout.hadjustment) - ? ((canvas->layout.vadjustment->value + anchor_y) - / canvas->impl->pixels_per_unit - + canvas->impl->scroll_y1 + canvas->impl->zoom_yofs) - : ((0.0 + anchor_y) / canvas->impl->pixels_per_unit - + canvas->impl->scroll_y1 + canvas->impl->zoom_yofs); - - /* Now calculate the new offset of the upper left corner. */ - const int x1 = ((ax - canvas->impl->scroll_x1) * zoom) - anchor_x; - const int y1 = ((ay - canvas->impl->scroll_y1) * zoom) - anchor_y; - - canvas->impl->pixels_per_unit = zoom; - ganv_canvas_scroll_to(canvas, x1, y1); - - ganv_canvas_request_update(canvas); - gtk_widget_queue_draw(GTK_WIDGET(canvas)); - - canvas->impl->need_repick = TRUE; -} - -void -ganv_canvas_set_font_size(GanvCanvas* canvas, double points) -{ - points = std::max(points, 1.0); - if (points != canvas->impl->font_size) { - canvas->impl->font_size = points; - FOREACH_ITEM(canvas->impl->_items, i) { - ganv_node_redraw_text(*i); - } - } -} - -void -ganv_canvas_zoom_full(GanvCanvas* canvas) -{ - if (canvas->impl->_items.empty()) - return; - - int win_width, win_height; - GdkWindow* win = gtk_widget_get_window( - GTK_WIDGET(canvas->impl->_gcanvas)); - gdk_window_get_size(win, &win_width, &win_height); - - // Box containing all canvas items - double left = DBL_MAX; - double right = DBL_MIN; - double top = DBL_MIN; - double bottom = DBL_MAX; - - FOREACH_ITEM(canvas->impl->_items, i) { - GanvItem* const item = GANV_ITEM(*i); - const double x = item->impl->x; - const double y = item->impl->y; - if (GANV_IS_CIRCLE(*i)) { - const double r = GANV_CIRCLE(*i)->impl->coords.radius; - left = MIN(left, x - r); - right = MAX(right, x + r); - bottom = MIN(bottom, y - r); - top = MAX(top, y + r); - } else { - left = MIN(left, x); - right = MAX(right, x + ganv_box_get_width(GANV_BOX(*i))); - bottom = MIN(bottom, y); - top = MAX(top, y + ganv_box_get_height(GANV_BOX(*i))); - } - } - - static const double pad = GANV_CANVAS_PAD; - - const double new_zoom = std::min( - ((double)win_width / (double)(right - left + pad*2.0)), - ((double)win_height / (double)(top - bottom + pad*2.0))); - - ganv_canvas_set_zoom(canvas, new_zoom); - - int scroll_x, scroll_y; - ganv_canvas_w2c(canvas->impl->_gcanvas, - lrintf(left - pad), lrintf(bottom - pad), - &scroll_x, &scroll_y); - - ganv_canvas_scroll_to(canvas->impl->_gcanvas, - scroll_x, scroll_y); -} - -static void -set_node_direction(GanvNode* node, void* data) -{ - if (GANV_IS_MODULE(node)) { - ganv_module_set_direction(GANV_MODULE(node), *(GanvDirection*)data); - } -} - -GanvDirection -ganv_canvas_get_direction(GanvCanvas* canvas) -{ - return canvas->impl->direction; -} - -void -ganv_canvas_set_direction(GanvCanvas* canvas, GanvDirection dir) -{ - if (canvas->impl->direction != dir) { - canvas->impl->direction = dir; - ganv_canvas_for_each_node(canvas, set_node_direction, &dir); - ganv_canvas_contents_changed(canvas); - } -} - -void -ganv_canvas_clear_selection(GanvCanvas* canvas) -{ - canvas->impl->unselect_ports(); - - Items items(canvas->impl->_selected_items); - canvas->impl->_selected_items.clear(); - FOREACH_ITEM(items, i) { - ganv_item_set(GANV_ITEM(*i), "selected", FALSE, NULL); - } - - GanvCanvasImpl::SelectedEdges edges(canvas->impl->_selected_edges); - canvas->impl->_selected_edges.clear(); - FOREACH_SELECTED_EDGE(edges, c) { - ganv_item_set(GANV_ITEM(*c), "selected", FALSE, NULL); - } -} - -void -ganv_canvas_move_selected_items(GanvCanvas* canvas, - double dx, - double dy) -{ - FOREACH_ITEM(canvas->impl->_selected_items, i) { - if ((*i)->item.impl->parent == canvas->impl->root) { - ganv_node_move(*i, dx, dy); - } - } -} - -void -ganv_canvas_selection_move_finished(GanvCanvas* canvas) -{ - FOREACH_ITEM(canvas->impl->_selected_items, i) { - const double x = GANV_ITEM(*i)->impl->x; - const double y = GANV_ITEM(*i)->impl->y; - g_signal_emit(*i, signal_moved, 0, x, y, NULL); - } -} - -static void -select_if_ends_are_selected(GanvEdge* edge, void* data) -{ - if (ganv_node_is_selected(ganv_edge_get_tail(edge)) && - ganv_node_is_selected(ganv_edge_get_head(edge))) { - ganv_edge_set_selected(edge, TRUE); - } -} - -static void -unselect_edges(GanvPort* port, void* data) -{ - GanvCanvasImpl* impl = (GanvCanvasImpl*)data; - if (port->impl->is_input) { - ganv_canvas_for_each_edge_to(impl->_gcanvas, - GANV_NODE(port), - (GanvEdgeFunc)ganv_edge_unselect, - NULL); - } else { - ganv_canvas_for_each_edge_from(impl->_gcanvas, - GANV_NODE(port), - (GanvEdgeFunc)ganv_edge_unselect, - NULL); - } -} - -void -ganv_canvas_select_node(GanvCanvas* canvas, - GanvNode* node) -{ - canvas->impl->_selected_items.insert(node); - - // Select any connections to or from this node - if (GANV_IS_MODULE(node)) { - ganv_module_for_each_port(GANV_MODULE(node), select_edges, canvas->impl); - } else { - ganv_canvas_for_each_edge_on( - canvas, node, select_if_ends_are_selected, canvas->impl); - } - - g_object_set(node, "selected", TRUE, NULL); -} - -void -ganv_canvas_unselect_node(GanvCanvas* canvas, - GanvNode* node) -{ - // Unselect any connections to or from canvas->impl node - if (GANV_IS_MODULE(node)) { - ganv_module_for_each_port(GANV_MODULE(node), unselect_edges, canvas->impl); - } else { - ganv_canvas_for_each_edge_on( - canvas, node, (GanvEdgeFunc)ganv_edge_unselect, NULL); - } - - // Unselect item - canvas->impl->_selected_items.erase(node); - g_object_set(node, "selected", FALSE, NULL); -} - -void -ganv_canvas_add_node(GanvCanvas* canvas, - GanvNode* node) -{ - GanvItem* item = GANV_ITEM(node); - if (item->impl->parent == ganv_canvas_root(canvas)) { - canvas->impl->_items.insert(node); - } -} - -void -ganv_canvas_remove_node(GanvCanvas* canvas, - GanvNode* node) -{ - if (node == (GanvNode*)canvas->impl->_connect_port) { - if (canvas->impl->_drag_state == GanvCanvasImpl::EDGE) { - ganv_canvas_ungrab_item(ganv_canvas_root(canvas), 0); - canvas->impl->end_connect_drag(); - } - canvas->impl->_connect_port = NULL; - } - - // Remove from selection - canvas->impl->_selected_items.erase(node); - - // Remove children ports from selection if item is a module - if (GANV_IS_MODULE(node)) { - GanvModule* const module = GANV_MODULE(node); - for (unsigned i = 0; i < ganv_module_num_ports(module); ++i) { - canvas->impl->unselect_port(ganv_module_get_port(module, i)); - } - } - - // Remove from items - canvas->impl->_items.erase(node); -} - -GanvEdge* -ganv_canvas_get_edge(GanvCanvas* canvas, - GanvNode* tail, - GanvNode* head) -{ - GanvEdgeKey key; - make_edge_search_key(&key, tail, head); - GanvCanvasImpl::Edges::const_iterator i = canvas->impl->_edges.find((GanvEdge*)&key); - return (i != canvas->impl->_edges.end()) ? *i : NULL; -} - -void -ganv_canvas_remove_edge_between(GanvCanvas* canvas, - GanvNode* tail, - GanvNode* head) -{ - ganv_canvas_remove_edge(canvas, ganv_canvas_get_edge(canvas, tail, head)); -} - -void -ganv_canvas_disconnect_edge(GanvCanvas* canvas, - GanvEdge* edge) -{ - g_signal_emit(canvas, signal_disconnect, 0, - edge->impl->tail, edge->impl->head, NULL); -} - -void -ganv_canvas_add_edge(GanvCanvas* canvas, - GanvEdge* edge) -{ - canvas->impl->_edges.insert(edge); - canvas->impl->_dst_edges.insert(edge); - ganv_canvas_contents_changed(canvas); -} - -void -ganv_canvas_remove_edge(GanvCanvas* canvas, - GanvEdge* edge) -{ - if (edge) { - canvas->impl->_selected_edges.erase(edge); - canvas->impl->_edges.erase(edge); - canvas->impl->_dst_edges.erase(edge); - ganv_edge_request_redraw(GANV_ITEM(edge), &edge->impl->coords); - gtk_object_destroy(GTK_OBJECT(edge)); - ganv_canvas_contents_changed(canvas); - } -} - -void -ganv_canvas_select_edge(GanvCanvas* canvas, - GanvEdge* edge) -{ - ganv_item_set(GANV_ITEM(edge), "selected", TRUE, NULL); - canvas->impl->_selected_edges.insert(edge); -} - -void -ganv_canvas_unselect_edge(GanvCanvas* canvas, - GanvEdge* edge) -{ - ganv_item_set(GANV_ITEM(edge), "selected", FALSE, NULL); - canvas->impl->_selected_edges.erase(edge); -} - -void -ganv_canvas_for_each_node(GanvCanvas* canvas, - GanvNodeFunc f, - void* data) -{ - FOREACH_ITEM(canvas->impl->_items, i) { - f(*i, data); - } -} - -void -ganv_canvas_for_each_selected_node(GanvCanvas* canvas, - GanvNodeFunc f, - void* data) -{ - FOREACH_ITEM(canvas->impl->_selected_items, i) { - f(*i, data); - } -} - -gboolean -ganv_canvas_empty(const GanvCanvas* canvas) -{ - return canvas->impl->_items.empty(); -} - -void -ganv_canvas_for_each_edge(GanvCanvas* canvas, - GanvEdgeFunc f, - void* data) -{ - GanvCanvasImpl* impl = canvas->impl; - for (GanvCanvasImpl::Edges::const_iterator i = impl->_edges.begin(); - i != impl->_edges.end();) { - GanvCanvasImpl::Edges::const_iterator next = i; - ++next; - f((*i), data); - i = next; - } -} - -void -ganv_canvas_for_each_edge_from(GanvCanvas* canvas, - const GanvNode* tail, - GanvEdgeFunc f, - void* data) -{ - GanvCanvasImpl* impl = canvas->impl; - for (GanvCanvasImpl::Edges::const_iterator i = impl->first_edge_from(tail); - i != impl->_edges.end() && (*i)->impl->tail == tail;) { - GanvCanvasImpl::Edges::const_iterator next = i; - ++next; - f((*i), data); - i = next; - } -} - -void -ganv_canvas_for_each_edge_to(GanvCanvas* canvas, - const GanvNode* head, - GanvEdgeFunc f, - void* data) -{ - GanvCanvasImpl* impl = canvas->impl; - for (GanvCanvasImpl::Edges::const_iterator i = impl->first_edge_to(head); - i != impl->_dst_edges.end() && (*i)->impl->head == head;) { - GanvCanvasImpl::Edges::const_iterator next = i; - ++next; - f((*i), data); - i = next; - } -} - -void -ganv_canvas_for_each_edge_on(GanvCanvas* canvas, - const GanvNode* node, - GanvEdgeFunc f, - void* data) -{ - ganv_canvas_for_each_edge_from(canvas, node, f, data); - ganv_canvas_for_each_edge_to(canvas, node, f, data); -} - -void -ganv_canvas_for_each_selected_edge(GanvCanvas* canvas, - GanvEdgeFunc f, - void* data) -{ - FOREACH_EDGE(canvas->impl->_selected_edges, i) { - f((*i), data); - } -} - -GdkCursor* -ganv_canvas_get_move_cursor(const GanvCanvas* canvas) -{ - return canvas->impl->_move_cursor; -} - -gboolean -ganv_canvas_port_event(GanvCanvas* canvas, - GanvPort* port, - GdkEvent* event) -{ - return canvas->impl->port_event(event, port); -} - -void -ganv_canvas_clear(GanvCanvas* canvas) -{ - canvas->impl->_selected_items.clear(); - canvas->impl->_selected_edges.clear(); - - Items items = canvas->impl->_items; // copy - FOREACH_ITEM(items, i) { - gtk_object_destroy(GTK_OBJECT(*i)); - } - canvas->impl->_items.clear(); - - GanvCanvasImpl::Edges edges = canvas->impl->_edges; // copy - FOREACH_EDGE(edges, i) { - gtk_object_destroy(GTK_OBJECT(*i)); - } - canvas->impl->_edges.clear(); - canvas->impl->_dst_edges.clear(); - - canvas->impl->_selected_ports.clear(); - canvas->impl->_connect_port = NULL; -} - -void -ganv_canvas_select_all(GanvCanvas* canvas) -{ - ganv_canvas_clear_selection(canvas); - FOREACH_ITEM(canvas->impl->_items, i) { - ganv_canvas_select_node(canvas, *i); - } -} - -double -ganv_canvas_get_zoom(const GanvCanvas* canvas) -{ - return canvas->impl->pixels_per_unit; -} - -void -ganv_canvas_move_contents_to(GanvCanvas* canvas, double x, double y) -{ - double min_x=HUGE_VAL, min_y=HUGE_VAL; - FOREACH_ITEM(canvas->impl->_items, i) { - const double x = GANV_ITEM(*i)->impl->x; - const double y = GANV_ITEM(*i)->impl->y; - min_x = std::min(min_x, x); - min_y = std::min(min_y, y); - } - canvas->impl->move_contents_to_internal(x, y, min_x, min_y); -} - -void -ganv_canvas_arrange(GanvCanvas* canvas) -{ -#ifdef HAVE_AGRAPH - GVNodes nodes = canvas->impl->layout_dot((char*)""); - - double least_x=HUGE_VAL, least_y=HUGE_VAL, most_x=0, most_y=0; - - // Set numeric locale to POSIX for reading graphviz output with strtod - char* locale = strdup(setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "POSIX"); - - const double dpi = gdk_screen_get_resolution(gdk_screen_get_default()); - const double dpp = dpi / 72.0; - - // Arrange to graphviz coordinates - for (GVNodes::iterator i = nodes.begin(); i != nodes.end(); ++i) { - if (GANV_ITEM(i->first)->impl->parent != GANV_ITEM(ganv_canvas_root(canvas))) { - continue; - } - const std::string pos = agget(i->second, (char*)"pos"); - const std::string x_str = pos.substr(0, pos.find(",")); - const std::string y_str = pos.substr(pos.find(",") + 1); - const double cx = lrint(strtod(x_str.c_str(), NULL) * dpp); - const double cy = lrint(strtod(y_str.c_str(), NULL) * dpp); - - double w, h; - if (GANV_IS_BOX(i->first)) { - w = ganv_box_get_width(GANV_BOX(i->first)); - h = ganv_box_get_height(GANV_BOX(i->first)); - } else { - w = h = ganv_circle_get_radius(GANV_CIRCLE(i->first)) * 2.3; - } - - /* Dot node positions are supposedly node centers, but things only - match up if x is interpreted as center and y as top... - */ - double x = cx - (w / 2.0); - double y = -cy - (h / 2.0); - - ganv_node_move_to(i->first, x, y); - - if (GANV_IS_CIRCLE(i->first)) { - // Offset least x and y to avoid cutting off circles at origin - const double r = ganv_circle_get_radius(GANV_CIRCLE(i->first)); - x -= r; - y -= r; - } - - least_x = std::min(least_x, x); - least_y = std::min(least_y, y); - most_x = std::max(most_x, x + w); - most_y = std::max(most_y, y + h); - } - - // Reset numeric locale to original value - setlocale(LC_NUMERIC, locale); - free(locale); - - const double graph_width = most_x - least_x; - const double graph_height = most_y - least_y; - - //cerr << "CWH: " << _width << ", " << _height << endl; - //cerr << "GWH: " << graph_width << ", " << graph_height << endl; - - double old_width, old_height; - g_object_get(G_OBJECT(canvas), - "width", &old_width, - "height", &old_height, - NULL); - - const double new_width = std::max(graph_width + 10.0, old_width); - const double new_height = std::max(graph_height + 10.0, old_height); - if (new_width != old_width || new_height != old_height) { - ganv_canvas_resize(canvas, new_width, new_height); - } - nodes.cleanup(); - - static const double border_width = GANV_CANVAS_PAD; - canvas->impl->move_contents_to_internal(border_width, border_width, least_x, least_y); - ganv_canvas_scroll_to(canvas->impl->_gcanvas, 0, 0); - - FOREACH_ITEM(canvas->impl->_items, i) { - const double x = GANV_ITEM(*i)->impl->x; - const double y = GANV_ITEM(*i)->impl->y; - g_signal_emit(*i, signal_moved, 0, x, y, NULL); - } -#endif -} - -int -ganv_canvas_export_image(GanvCanvas* canvas, - const char* filename, - gboolean draw_background) -{ - const char* ext = strrchr(filename, '.'); - if (!ext) { - return 1; - } else if (!strcmp(ext, ".dot")) { - ganv_canvas_export_dot(canvas, filename); - return 0; - } - - cairo_surface_t* rec_surface = cairo_recording_surface_create( - CAIRO_CONTENT_COLOR_ALPHA, NULL); - - // Draw to recording surface - cairo_t* cr = cairo_create(rec_surface); - canvas->impl->exporting = TRUE; - (*GANV_ITEM_GET_CLASS(canvas->impl->root)->draw)( - canvas->impl->root, cr, - 0, 0, canvas->impl->width, canvas->impl->height); - canvas->impl->exporting = FALSE; - cairo_destroy(cr); - - // Get draw extent - double x, y, w, h; - cairo_recording_surface_ink_extents(rec_surface, &x, &y, &w, &h); - - // Create image surface with the appropriate size - const double pad = GANV_CANVAS_PAD; - const double img_w = w + pad * 2; - const double img_h = h + pad * 2; - cairo_surface_t* img = NULL; - if (!strcmp(ext, ".svg")) { - img = cairo_svg_surface_create(filename, img_w, img_h); - } else if (!strcmp(ext, ".pdf")) { - img = cairo_pdf_surface_create(filename, img_w, img_h); - } else if (!strcmp(ext, ".ps")) { - img = cairo_ps_surface_create(filename, img_w, img_h); - } else { - cairo_surface_destroy(rec_surface); - return 1; - } - - // Draw recording to image surface - cr = cairo_create(img); - if (draw_background) { - double r, g, b, a; - color_to_rgba(DEFAULT_BACKGROUND_COLOR, &r, &g, &b, &a); - cairo_set_source_rgba(cr, r, g, b, a); - cairo_rectangle(cr, 0, 0, w + 2 * pad, h + 2 * pad); - cairo_fill(cr); - } - cairo_set_source_surface(cr, rec_surface, -x + pad, -y + pad); - cairo_paint(cr); - cairo_destroy(cr); - cairo_surface_destroy(rec_surface); - cairo_surface_destroy(img); - return 0; -} - -void -ganv_canvas_export_dot(GanvCanvas* canvas, const char* filename) -{ -#ifdef HAVE_AGRAPH - GVNodes nodes = canvas->impl->layout_dot(filename); - nodes.cleanup(); -#endif -} - -gboolean -ganv_canvas_supports_sprung_layout(const GanvCanvas* canvas) -{ -#ifdef GANV_FDGL - return TRUE; -#else - return FALSE; -#endif -} - -gboolean -ganv_canvas_set_sprung_layout(GanvCanvas* canvas, gboolean sprung_layout) -{ -#ifndef GANV_FDGL - return FALSE; -#else - canvas->impl->sprung_layout = sprung_layout; - ganv_canvas_contents_changed(canvas); - return TRUE; -#endif -} - -gboolean -ganv_canvas_get_locked(const GanvCanvas* canvas) -{ - return canvas->impl->locked; -} - -/* Convenience function to remove the idle handler of a canvas */ -static void -remove_idle(GanvCanvas* canvas) -{ - if (canvas->impl->idle_id == 0) { - return; - } - - g_source_remove(canvas->impl->idle_id); - canvas->impl->idle_id = 0; -} - -/* Removes the transient state of the canvas (idle handler, grabs). */ -static void -shutdown_transients(GanvCanvas* canvas) -{ - /* We turn off the need_redraw flag, since if the canvas is mapped again - * it will request a redraw anyways. We do not turn off the need_update - * flag, though, because updates are not queued when the canvas remaps - * itself. - */ - if (canvas->impl->need_redraw) { - canvas->impl->need_redraw = FALSE; - g_slist_foreach(canvas->impl->redraw_region, (GFunc)g_free, NULL); - g_slist_free(canvas->impl->redraw_region); - canvas->impl->redraw_region = NULL; - canvas->impl->redraw_x1 = 0; - canvas->impl->redraw_y1 = 0; - canvas->impl->redraw_x2 = 0; - canvas->impl->redraw_y2 = 0; - } - - if (canvas->impl->grabbed_item) { - canvas->impl->grabbed_item = NULL; - gdk_pointer_ungrab(GDK_CURRENT_TIME); - } - - remove_idle(canvas); -} - -/* Destroy handler for GanvCanvas */ -static void -ganv_canvas_destroy(GtkObject* object) -{ - g_return_if_fail(GANV_IS_CANVAS(object)); - - /* remember, destroy can be run multiple times! */ - - GanvCanvas* canvas = GANV_CANVAS(object); - - if (canvas->impl->root_destroy_id) { - g_signal_handler_disconnect(canvas->impl->root, canvas->impl->root_destroy_id); - canvas->impl->root_destroy_id = 0; - } - if (canvas->impl->root) { - gtk_object_destroy(GTK_OBJECT(canvas->impl->root)); - g_object_unref(G_OBJECT(canvas->impl->root)); - canvas->impl->root = NULL; - } - - shutdown_transients(canvas); - - if (GTK_OBJECT_CLASS(canvas_parent_class)->destroy) { - (*GTK_OBJECT_CLASS(canvas_parent_class)->destroy)(object); - } -} - -GanvCanvas* -ganv_canvas_new(double width, double height) -{ - GanvCanvas* canvas = GANV_CANVAS( - g_object_new(ganv_canvas_get_type(), - "width", width, - "height", height, - NULL)); - - ganv_canvas_set_scroll_region(canvas, 0.0, 0.0, width, height); - - return canvas; -} - -void -ganv_canvas_set_wrapper(GanvCanvas* canvas, void* wrapper) -{ - canvas->impl->_wrapper = (Ganv::Canvas*)wrapper; -} - -void* -ganv_canvas_get_wrapper(GanvCanvas* canvas) -{ - return canvas->impl->_wrapper; -} - -/* Map handler for the canvas */ -static void -ganv_canvas_map(GtkWidget* widget) -{ - g_return_if_fail(GANV_IS_CANVAS(widget)); - - /* Normal widget mapping stuff */ - - if (GTK_WIDGET_CLASS(canvas_parent_class)->map) { - (*GTK_WIDGET_CLASS(canvas_parent_class)->map)(widget); - } - - GanvCanvas* canvas = GANV_CANVAS(widget); - - if (canvas->impl->need_update) { - add_idle(canvas); - } - - /* Map items */ - - if (GANV_ITEM_GET_CLASS(canvas->impl->root)->map) { - (*GANV_ITEM_GET_CLASS(canvas->impl->root)->map)(canvas->impl->root); - } -} - -/* Unmap handler for the canvas */ -static void -ganv_canvas_unmap(GtkWidget* widget) -{ - g_return_if_fail(GANV_IS_CANVAS(widget)); - - GanvCanvas* canvas = GANV_CANVAS(widget); - - shutdown_transients(canvas); - - /* Unmap items */ - - if (GANV_ITEM_GET_CLASS(canvas->impl->root)->unmap) { - (*GANV_ITEM_GET_CLASS(canvas->impl->root)->unmap)(canvas->impl->root); - } - - /* Normal widget unmapping stuff */ - - if (GTK_WIDGET_CLASS(canvas_parent_class)->unmap) { - (*GTK_WIDGET_CLASS(canvas_parent_class)->unmap)(widget); - } -} - -/* Realize handler for the canvas */ -static void -ganv_canvas_realize(GtkWidget* widget) -{ - g_return_if_fail(GANV_IS_CANVAS(widget)); - - /* Normal widget realization stuff */ - - if (GTK_WIDGET_CLASS(canvas_parent_class)->realize) { - (*GTK_WIDGET_CLASS(canvas_parent_class)->realize)(widget); - } - - GanvCanvas* canvas = GANV_CANVAS(widget); - - gdk_window_set_events( - canvas->layout.bin_window, - (GdkEventMask)(gdk_window_get_events(canvas->layout.bin_window) - | GDK_EXPOSURE_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_BUTTON_RELEASE_MASK - | GDK_POINTER_MOTION_MASK - | GDK_KEY_PRESS_MASK - | GDK_KEY_RELEASE_MASK - | GDK_ENTER_NOTIFY_MASK - | GDK_LEAVE_NOTIFY_MASK - | GDK_FOCUS_CHANGE_MASK)); - - /* Create our own temporary pixmap gc and realize all the items */ - - canvas->impl->pixmap_gc = gdk_gc_new(canvas->layout.bin_window); - - (*GANV_ITEM_GET_CLASS(canvas->impl->root)->realize)(canvas->impl->root); - - canvas->impl->_animate_idle_id = g_timeout_add( - 120, GanvCanvasImpl::on_animate_timeout, canvas->impl); -} - -/* Unrealize handler for the canvas */ -static void -ganv_canvas_unrealize(GtkWidget* widget) -{ - g_return_if_fail(GANV_IS_CANVAS(widget)); - - GanvCanvas* canvas = GANV_CANVAS(widget); - - if (canvas->impl->_animate_idle_id) { - g_source_remove(canvas->impl->_animate_idle_id); - canvas->impl->_animate_idle_id = 0; - } - while (g_idle_remove_by_data(canvas->impl)) {} - - shutdown_transients(canvas); - - /* Unrealize items and parent widget */ - - (*GANV_ITEM_GET_CLASS(canvas->impl->root)->unrealize)(canvas->impl->root); - - g_object_unref(canvas->impl->pixmap_gc); - canvas->impl->pixmap_gc = NULL; - - if (GTK_WIDGET_CLASS(canvas_parent_class)->unrealize) { - (*GTK_WIDGET_CLASS(canvas_parent_class)->unrealize)(widget); - } -} - -/* Handles scrolling of the canvas. Adjusts the scrolling and zooming offset to - * keep as much as possible of the canvas scrolling region in view. - */ -static void -scroll_to(GanvCanvas* canvas, int cx, int cy) -{ - int scroll_width, scroll_height; - int right_limit, bottom_limit; - int old_zoom_xofs, old_zoom_yofs; - int changed_x = FALSE, changed_y = FALSE; - int canvas_width, canvas_height; - - canvas_width = GTK_WIDGET(canvas)->allocation.width; - canvas_height = GTK_WIDGET(canvas)->allocation.height; - - scroll_width = floor((canvas->impl->scroll_x2 - canvas->impl->scroll_x1) * canvas->impl->pixels_per_unit - + 0.5); - scroll_height = floor((canvas->impl->scroll_y2 - canvas->impl->scroll_y1) * canvas->impl->pixels_per_unit - + 0.5); - - right_limit = scroll_width - canvas_width; - bottom_limit = scroll_height - canvas_height; - - old_zoom_xofs = canvas->impl->zoom_xofs; - old_zoom_yofs = canvas->impl->zoom_yofs; - - if (right_limit < 0) { - cx = 0; - - if (canvas->impl->center_scroll_region) { - canvas->impl->zoom_xofs = (canvas_width - scroll_width) / 2; - scroll_width = canvas_width; - } else { - canvas->impl->zoom_xofs = 0; - } - } else if (cx < 0) { - cx = 0; - canvas->impl->zoom_xofs = 0; - } else if (cx > right_limit) { - cx = right_limit; - canvas->impl->zoom_xofs = 0; - } else { - canvas->impl->zoom_xofs = 0; - } - - if (bottom_limit < 0) { - cy = 0; - - if (canvas->impl->center_scroll_region) { - canvas->impl->zoom_yofs = (canvas_height - scroll_height) / 2; - scroll_height = canvas_height; - } else { - canvas->impl->zoom_yofs = 0; - } - } else if (cy < 0) { - cy = 0; - canvas->impl->zoom_yofs = 0; - } else if (cy > bottom_limit) { - cy = bottom_limit; - canvas->impl->zoom_yofs = 0; - } else { - canvas->impl->zoom_yofs = 0; - } - - if ((canvas->impl->zoom_xofs != old_zoom_xofs) || (canvas->impl->zoom_yofs != old_zoom_yofs)) { - ganv_canvas_request_update(canvas); - gtk_widget_queue_draw(GTK_WIDGET(canvas)); - } - - if (canvas->layout.hadjustment && ( ((int)canvas->layout.hadjustment->value) != cx) ) { - canvas->layout.hadjustment->value = cx; - changed_x = TRUE; - } - - if (canvas->layout.vadjustment && ( ((int)canvas->layout.vadjustment->value) != cy) ) { - canvas->layout.vadjustment->value = cy; - changed_y = TRUE; - } - - if ((scroll_width != (int)canvas->layout.width) - || (scroll_height != (int)canvas->layout.height)) { - gtk_layout_set_size(GTK_LAYOUT(canvas), scroll_width, scroll_height); - } - - /* Signal GtkLayout that it should do a redraw. */ - - if (changed_x) { - g_signal_emit_by_name(canvas->layout.hadjustment, "value_changed"); - } - - if (changed_y) { - g_signal_emit_by_name(canvas->layout.vadjustment, "value_changed"); - } -} - -/* Size allocation handler for the canvas */ -static void -ganv_canvas_size_allocate(GtkWidget* widget, GtkAllocation* allocation) -{ - g_return_if_fail(GANV_IS_CANVAS(widget)); - g_return_if_fail(allocation != NULL); - - if (GTK_WIDGET_CLASS(canvas_parent_class)->size_allocate) { - (*GTK_WIDGET_CLASS(canvas_parent_class)->size_allocate)(widget, allocation); - } - - GanvCanvas* canvas = GANV_CANVAS(widget); - - /* Recenter the view, if appropriate */ - - canvas->layout.hadjustment->page_size = allocation->width; - canvas->layout.hadjustment->page_increment = allocation->width / 2; - - canvas->layout.vadjustment->page_size = allocation->height; - canvas->layout.vadjustment->page_increment = allocation->height / 2; - - scroll_to(canvas, - canvas->layout.hadjustment->value, - canvas->layout.vadjustment->value); - - g_signal_emit_by_name(canvas->layout.hadjustment, "changed"); - g_signal_emit_by_name(canvas->layout.vadjustment, "changed"); -} - -/* Returns whether the item is an inferior of or is equal to the parent. */ -static gboolean -is_descendant(GanvItem* item, GanvItem* parent) -{ - for (; item; item = item->impl->parent) { - if (item == parent) { - return TRUE; - } - } - - return FALSE; -} - - -/* Emits an event for an item in the canvas, be it the current item, grabbed - * item, or focused item, as appropriate. - */ -int -ganv_canvas_emit_event(GanvCanvas* canvas, GdkEvent* event) -{ - GdkEvent* ev; - gint finished; - GanvItem* item; - GanvItem* parent; - guint mask; - - /* Perform checks for grabbed items */ - - if (canvas->impl->grabbed_item - && !is_descendant(canvas->impl->current_item, canvas->impl->grabbed_item)) { - /* I think this warning is annoying and I don't know what it's for - * so I'll disable it for now. - */ - /* g_warning ("emit_event() returning FALSE!\n");*/ - return FALSE; - } - - if (canvas->impl->grabbed_item) { - switch (event->type) { - case GDK_ENTER_NOTIFY: - mask = GDK_ENTER_NOTIFY_MASK; - break; - - case GDK_LEAVE_NOTIFY: - mask = GDK_LEAVE_NOTIFY_MASK; - break; - - case GDK_MOTION_NOTIFY: - mask = GDK_POINTER_MOTION_MASK; - break; - - case GDK_BUTTON_PRESS: - case GDK_2BUTTON_PRESS: - case GDK_3BUTTON_PRESS: - mask = GDK_BUTTON_PRESS_MASK; - break; - - case GDK_BUTTON_RELEASE: - mask = GDK_BUTTON_RELEASE_MASK; - break; - - case GDK_KEY_PRESS: - mask = GDK_KEY_PRESS_MASK; - break; - - case GDK_KEY_RELEASE: - mask = GDK_KEY_RELEASE_MASK; - break; - - case GDK_SCROLL: - mask = GDK_SCROLL_MASK; - break; - - default: - mask = 0; - break; - } - - if (!(mask & canvas->impl->grabbed_event_mask)) { - return FALSE; - } - } - - /* Convert to world coordinates -- we have two cases because of diferent - * offsets of the fields in the event structures. - */ - - ev = gdk_event_copy(event); - - switch (ev->type) { - case GDK_ENTER_NOTIFY: - case GDK_LEAVE_NOTIFY: - ganv_canvas_window_to_world(canvas, - ev->crossing.x, ev->crossing.y, - &ev->crossing.x, &ev->crossing.y); - break; - - case GDK_MOTION_NOTIFY: - case GDK_BUTTON_PRESS: - case GDK_2BUTTON_PRESS: - case GDK_3BUTTON_PRESS: - case GDK_BUTTON_RELEASE: - ganv_canvas_window_to_world(canvas, - ev->motion.x, ev->motion.y, - &ev->motion.x, &ev->motion.y); - break; - - default: - break; - } - - /* Choose where we send the event */ - - item = canvas->impl->current_item; - - if (canvas->impl->focused_item - && ((event->type == GDK_KEY_PRESS) - || (event->type == GDK_KEY_RELEASE) - || (event->type == GDK_FOCUS_CHANGE))) { - item = canvas->impl->focused_item; - } - - /* The event is propagated up the hierarchy (for if someone connected to - * a group instead of a leaf event), and emission is stopped if a - * handler returns TRUE, just like for GtkWidget events. - */ - - finished = FALSE; - - while (item && !finished) { - g_object_ref(G_OBJECT(item)); - - ganv_item_emit_event(item, ev, &finished); - - parent = item->impl->parent; - g_object_unref(G_OBJECT(item)); - - item = parent; - } - - gdk_event_free(ev); - - return finished; -} - -void -ganv_canvas_set_need_repick(GanvCanvas* canvas) -{ - canvas->impl->need_repick = TRUE; -} - -void -ganv_canvas_forget_item(GanvCanvas* canvas, GanvItem* item) -{ - if (canvas->impl && item == canvas->impl->current_item) { - canvas->impl->current_item = NULL; - canvas->impl->need_repick = TRUE; - } - - if (canvas->impl && item == canvas->impl->new_current_item) { - canvas->impl->new_current_item = NULL; - canvas->impl->need_repick = TRUE; - } - - if (canvas->impl && item == canvas->impl->grabbed_item) { - canvas->impl->grabbed_item = NULL; - gdk_pointer_ungrab(GDK_CURRENT_TIME); - } - - if (canvas->impl && item == canvas->impl->focused_item) { - canvas->impl->focused_item = NULL; - } -} - -void -ganv_canvas_grab_focus(GanvCanvas* canvas, GanvItem* item) -{ - g_return_if_fail(GANV_IS_ITEM(item)); - g_return_if_fail(GTK_WIDGET_CAN_FOCUS(GTK_WIDGET(canvas))); - - GanvItem* focused_item = canvas->impl->focused_item; - GdkEvent ev; - - if (focused_item) { - ev.focus_change.type = GDK_FOCUS_CHANGE; - ev.focus_change.window = canvas->layout.bin_window; - ev.focus_change.send_event = FALSE; - ev.focus_change.in = FALSE; - - ganv_canvas_emit_event(canvas, &ev); - } - - canvas->impl->focused_item = item; - gtk_widget_grab_focus(GTK_WIDGET(canvas)); - - if (focused_item) { - ev.focus_change.type = GDK_FOCUS_CHANGE; - ev.focus_change.window = canvas->layout.bin_window; - ev.focus_change.send_event = FALSE; - ev.focus_change.in = TRUE; - - ganv_canvas_emit_event(canvas, &ev); - } -} - -/** - * ganv_canvas_grab_item: - * @item: A canvas item. - * @event_mask: Mask of events that will be sent to this item. - * @cursor: If non-NULL, the cursor that will be used while the grab is active. - * @etime: The timestamp required for grabbing the mouse, or GDK_CURRENT_TIME. - * - * Specifies that all events that match the specified event mask should be sent - * to the specified item, and also grabs the mouse by calling - * gdk_pointer_grab(). The event mask is also used when grabbing the pointer. - * If @cursor is not NULL, then that cursor is used while the grab is active. - * The @etime parameter is the timestamp required for grabbing the mouse. - * - * Return value: If an item was already grabbed, it returns %GDK_GRAB_ALREADY_GRABBED. If - * the specified item was hidden by calling ganv_item_hide(), then it - * returns %GDK_GRAB_NOT_VIEWABLE. Else, it returns the result of calling - * gdk_pointer_grab(). - **/ -int -ganv_canvas_grab_item(GanvItem* item, guint event_mask, GdkCursor* cursor, guint32 etime) -{ - g_return_val_if_fail(GANV_IS_ITEM(item), GDK_GRAB_NOT_VIEWABLE); - g_return_val_if_fail(GTK_WIDGET_MAPPED(item->impl->canvas), GDK_GRAB_NOT_VIEWABLE); - - if (item->impl->canvas->impl->grabbed_item) { - return GDK_GRAB_ALREADY_GRABBED; - } - - if (!(item->object.flags & GANV_ITEM_VISIBLE)) { - return GDK_GRAB_NOT_VIEWABLE; - } - - int retval = gdk_pointer_grab(item->impl->canvas->layout.bin_window, - FALSE, - (GdkEventMask)event_mask, - NULL, - cursor, - etime); - - if (retval != GDK_GRAB_SUCCESS) { - return retval; - } - - item->impl->canvas->impl->grabbed_item = item; - item->impl->canvas->impl->grabbed_event_mask = event_mask; - item->impl->canvas->impl->current_item = item; /* So that events go to the grabbed item */ - - return retval; -} - -/** - * ganv_canvas_ungrab_item: - * @item: A canvas item that holds a grab. - * @etime: The timestamp for ungrabbing the mouse. - * - * Ungrabs the item, which must have been grabbed in the canvas, and ungrabs the - * mouse. - **/ -void -ganv_canvas_ungrab_item(GanvItem* item, guint32 etime) -{ - g_return_if_fail(GANV_IS_ITEM(item)); - - if (item->impl->canvas->impl->grabbed_item != item) { - return; - } - - item->impl->canvas->impl->grabbed_item = NULL; - - gdk_pointer_ungrab(etime); -} - -void -ganv_canvas_get_zoom_offsets(GanvCanvas* canvas, int* x, int* y) -{ - *x = canvas->impl->zoom_xofs; - *y = canvas->impl->zoom_yofs; -} - -/* Re-picks the current item in the canvas, based on the event's coordinates. - * Also emits enter/leave events for items as appropriate. - */ -static int -pick_current_item(GanvCanvas* canvas, GdkEvent* event) -{ - int retval = FALSE; - - /* If a button is down, we'll perform enter and leave events on the - * current item, but not enter on any other item. This is more or less - * like X pointer grabbing for canvas items. - */ - int button_down = canvas->impl->state & (GDK_BUTTON1_MASK - | GDK_BUTTON2_MASK - | GDK_BUTTON3_MASK - | GDK_BUTTON4_MASK - | GDK_BUTTON5_MASK); - if (!button_down) { - canvas->impl->left_grabbed_item = FALSE; - } - - /* Save the event in the canvas. This is used to synthesize enter and - * leave events in case the current item changes. It is also used to - * re-pick the current item if the current one gets deleted. Also, - * synthesize an enter event. - */ - if (event != &canvas->impl->pick_event) { - if ((event->type == GDK_MOTION_NOTIFY) || (event->type == GDK_BUTTON_RELEASE)) { - /* these fields have the same offsets in both types of events */ - - canvas->impl->pick_event.crossing.type = GDK_ENTER_NOTIFY; - canvas->impl->pick_event.crossing.window = event->motion.window; - canvas->impl->pick_event.crossing.send_event = event->motion.send_event; - canvas->impl->pick_event.crossing.subwindow = NULL; - canvas->impl->pick_event.crossing.x = event->motion.x; - canvas->impl->pick_event.crossing.y = event->motion.y; - canvas->impl->pick_event.crossing.mode = GDK_CROSSING_NORMAL; - canvas->impl->pick_event.crossing.detail = GDK_NOTIFY_NONLINEAR; - canvas->impl->pick_event.crossing.focus = FALSE; - canvas->impl->pick_event.crossing.state = event->motion.state; - - /* these fields don't have the same offsets in both types of events */ - - if (event->type == GDK_MOTION_NOTIFY) { - canvas->impl->pick_event.crossing.x_root = event->motion.x_root; - canvas->impl->pick_event.crossing.y_root = event->motion.y_root; - } else { - canvas->impl->pick_event.crossing.x_root = event->button.x_root; - canvas->impl->pick_event.crossing.y_root = event->button.y_root; - } - } else { - canvas->impl->pick_event = *event; - } - } - - /* Don't do anything else if this is a recursive call */ - - if (canvas->impl->in_repick) { - return retval; - } - - /* LeaveNotify means that there is no current item, so we don't look for one */ - - if (canvas->impl->pick_event.type != GDK_LEAVE_NOTIFY) { - /* these fields don't have the same offsets in both types of events */ - - double x, y; - if (canvas->impl->pick_event.type == GDK_ENTER_NOTIFY) { - x = canvas->impl->pick_event.crossing.x - canvas->impl->zoom_xofs; - y = canvas->impl->pick_event.crossing.y - canvas->impl->zoom_yofs; - } else { - x = canvas->impl->pick_event.motion.x - canvas->impl->zoom_xofs; - y = canvas->impl->pick_event.motion.y - canvas->impl->zoom_yofs; - } - - /* world coords */ - - x = canvas->impl->scroll_x1 + x / canvas->impl->pixels_per_unit; - y = canvas->impl->scroll_y1 + y / canvas->impl->pixels_per_unit; - - /* find the closest item */ - - if (canvas->impl->root->object.flags & GANV_ITEM_VISIBLE) { - GANV_ITEM_GET_CLASS(canvas->impl->root)->point( - canvas->impl->root, - x - canvas->impl->root->impl->x, y - canvas->impl->root->impl->y, - &canvas->impl->new_current_item); - } else { - canvas->impl->new_current_item = NULL; - } - } else { - canvas->impl->new_current_item = NULL; - } - - if ((canvas->impl->new_current_item == canvas->impl->current_item) && !canvas->impl->left_grabbed_item) { - return retval; /* current item did not change */ - - } - /* Synthesize events for old and new current items */ - - if ((canvas->impl->new_current_item != canvas->impl->current_item) - && (canvas->impl->current_item != NULL) - && !canvas->impl->left_grabbed_item) { - GdkEvent new_event; - - new_event = canvas->impl->pick_event; - new_event.type = GDK_LEAVE_NOTIFY; - - new_event.crossing.detail = GDK_NOTIFY_ANCESTOR; - new_event.crossing.subwindow = NULL; - canvas->impl->in_repick = TRUE; - retval = ganv_canvas_emit_event(canvas, &new_event); - canvas->impl->in_repick = FALSE; - } - - /* new_current_item may have been set to NULL during the call to ganv_canvas_emit_event() above */ - - if ((canvas->impl->new_current_item != canvas->impl->current_item) && button_down) { - canvas->impl->left_grabbed_item = TRUE; - return retval; - } - - /* Handle the rest of cases */ - - canvas->impl->left_grabbed_item = FALSE; - canvas->impl->current_item = canvas->impl->new_current_item; - - if (canvas->impl->current_item != NULL) { - GdkEvent new_event; - - new_event = canvas->impl->pick_event; - new_event.type = GDK_ENTER_NOTIFY; - new_event.crossing.detail = GDK_NOTIFY_ANCESTOR; - new_event.crossing.subwindow = NULL; - retval = ganv_canvas_emit_event(canvas, &new_event); - } - - return retval; -} - -/* Button event handler for the canvas */ -static gint -ganv_canvas_button(GtkWidget* widget, GdkEventButton* event) -{ - int mask; - int retval; - - g_return_val_if_fail(GANV_IS_CANVAS(widget), FALSE); - g_return_val_if_fail(event != NULL, FALSE); - - retval = FALSE; - - GanvCanvas* canvas = GANV_CANVAS(widget); - - /* - * dispatch normally regardless of the event's window if an item has - * has a pointer grab in effect - */ - if (!canvas->impl->grabbed_item && ( event->window != canvas->layout.bin_window) ) { - return retval; - } - - switch (event->button) { - case 1: - mask = GDK_BUTTON1_MASK; - break; - case 2: - mask = GDK_BUTTON2_MASK; - break; - case 3: - mask = GDK_BUTTON3_MASK; - break; - case 4: - mask = GDK_BUTTON4_MASK; - break; - case 5: - mask = GDK_BUTTON5_MASK; - break; - default: - mask = 0; - } - - switch (event->type) { - case GDK_BUTTON_PRESS: - case GDK_2BUTTON_PRESS: - case GDK_3BUTTON_PRESS: - /* Pick the current item as if the button were not pressed, and - * then process the event. - */ - canvas->impl->state = event->state; - pick_current_item(canvas, (GdkEvent*)event); - canvas->impl->state ^= mask; - retval = ganv_canvas_emit_event(canvas, (GdkEvent*)event); - break; - - case GDK_BUTTON_RELEASE: - /* Process the event as if the button were pressed, then repick - * after the button has been released - */ - canvas->impl->state = event->state; - retval = ganv_canvas_emit_event(canvas, (GdkEvent*)event); - event->state ^= mask; - canvas->impl->state = event->state; - pick_current_item(canvas, (GdkEvent*)event); - event->state ^= mask; - break; - - default: - g_assert_not_reached(); - } - - return retval; -} - -/* Motion event handler for the canvas */ -static gint -ganv_canvas_motion(GtkWidget* widget, GdkEventMotion* event) -{ - g_return_val_if_fail(GANV_IS_CANVAS(widget), FALSE); - g_return_val_if_fail(event != NULL, FALSE); - - GanvCanvas* canvas = GANV_CANVAS(widget); - - if (event->window != canvas->layout.bin_window) { - return FALSE; - } - - canvas->impl->state = event->state; - pick_current_item(canvas, (GdkEvent*)event); - return ganv_canvas_emit_event(canvas, (GdkEvent*)event); -} - -static gboolean -ganv_canvas_scroll(GtkWidget* widget, GdkEventScroll* event) -{ - g_return_val_if_fail(GANV_IS_CANVAS(widget), FALSE); - g_return_val_if_fail(event != NULL, FALSE); - - GanvCanvas* canvas = GANV_CANVAS(widget); - - if (event->window != canvas->layout.bin_window) { - return FALSE; - } - - canvas->impl->state = event->state; - pick_current_item(canvas, (GdkEvent*)event); - return ganv_canvas_emit_event(canvas, (GdkEvent*)event); -} - -/* Key event handler for the canvas */ -static gboolean -ganv_canvas_key(GtkWidget* widget, GdkEventKey* event) -{ - g_return_val_if_fail(GANV_IS_CANVAS(widget), FALSE); - g_return_val_if_fail(event != NULL, FALSE); - - GanvCanvas* canvas = GANV_CANVAS(widget); - - if (!ganv_canvas_emit_event(canvas, (GdkEvent*)event)) { - GtkWidgetClass* widget_class; - - widget_class = GTK_WIDGET_CLASS(canvas_parent_class); - - if (event->type == GDK_KEY_PRESS) { - if (widget_class->key_press_event) { - return (*widget_class->key_press_event)(widget, event); - } - } else if (event->type == GDK_KEY_RELEASE) { - if (widget_class->key_release_event) { - return (*widget_class->key_release_event)(widget, event); - } - } else { - g_assert_not_reached(); - } - - return FALSE; - } else { - return TRUE; - } -} - -/* Crossing event handler for the canvas */ -static gint -ganv_canvas_crossing(GtkWidget* widget, GdkEventCrossing* event) -{ - g_return_val_if_fail(GANV_IS_CANVAS(widget), FALSE); - g_return_val_if_fail(event != NULL, FALSE); - - GanvCanvas* canvas = GANV_CANVAS(widget); - - if (event->window != canvas->layout.bin_window) { - return FALSE; - } - - canvas->impl->state = event->state; - return pick_current_item(canvas, (GdkEvent*)event); -} - -/* Focus in handler for the canvas */ -static gint -ganv_canvas_focus_in(GtkWidget* widget, GdkEventFocus* event) -{ - GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); - - GanvCanvas* canvas = GANV_CANVAS(widget); - - if (canvas->impl->focused_item) { - return ganv_canvas_emit_event(canvas, (GdkEvent*)event); - } else { - return FALSE; - } -} - -/* Focus out handler for the canvas */ -static gint -ganv_canvas_focus_out(GtkWidget* widget, GdkEventFocus* event) -{ - GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); - - GanvCanvas* canvas = GANV_CANVAS(widget); - - if (canvas->impl->focused_item) { - return ganv_canvas_emit_event(canvas, (GdkEvent*)event); - } else { - return FALSE; - } -} - -#define REDRAW_QUANTUM_SIZE 512 - -static void -ganv_canvas_paint_rect(GanvCanvas* canvas, gint x0, gint y0, gint x1, gint y1) -{ - gint draw_x1, draw_y1; - gint draw_x2, draw_y2; - gint draw_width, draw_height; - - g_return_if_fail(!canvas->impl->need_update); - - draw_x1 = MAX(x0, canvas->layout.hadjustment->value - canvas->impl->zoom_xofs); - draw_y1 = MAX(y0, canvas->layout.vadjustment->value - canvas->impl->zoom_yofs); - draw_x2 = MIN(draw_x1 + GTK_WIDGET(canvas)->allocation.width, x1); - draw_y2 = MIN(draw_y1 + GTK_WIDGET(canvas)->allocation.height, y1); - - draw_width = draw_x2 - draw_x1; - draw_height = draw_y2 - draw_y1; - - if ((draw_width < 1) || (draw_height < 1)) { - return; - } - - canvas->impl->redraw_x1 = draw_x1; - canvas->impl->redraw_y1 = draw_y1; - canvas->impl->redraw_x2 = draw_x2; - canvas->impl->redraw_y2 = draw_y2; - canvas->impl->draw_xofs = draw_x1; - canvas->impl->draw_yofs = draw_y1; - - cairo_t* cr = gdk_cairo_create(canvas->layout.bin_window); - - double win_x, win_y; - ganv_canvas_window_to_world(canvas, 0, 0, &win_x, &win_y); - cairo_translate(cr, -win_x, -win_y); - cairo_scale(cr, canvas->impl->pixels_per_unit, canvas->impl->pixels_per_unit); - - if (canvas->impl->root->object.flags & GANV_ITEM_VISIBLE) { - double wx1, wy1, ww, wh; - ganv_canvas_c2w(canvas, draw_x1, draw_y1, &wx1, &wy1); - ganv_canvas_c2w(canvas, draw_width, draw_height, &ww, &wh); - - // Draw background - double r, g, b, a; - color_to_rgba(DEFAULT_BACKGROUND_COLOR, &r, &g, &b, &a); - cairo_set_source_rgba(cr, r, g, b, a); - cairo_rectangle(cr, wx1, wy1, ww, wh); - cairo_fill(cr); - - // Draw root group - (*GANV_ITEM_GET_CLASS(canvas->impl->root)->draw)( - canvas->impl->root, cr, - wx1, wy1, ww, wh); - } - - cairo_destroy(cr); -} - -/* Expose handler for the canvas */ -static gint -ganv_canvas_expose(GtkWidget* widget, GdkEventExpose* event) -{ - GanvCanvas* canvas = GANV_CANVAS(widget); - if (!GTK_WIDGET_DRAWABLE(widget) || - (event->window != canvas->layout.bin_window)) { - return FALSE; - } - - /* Find a single bounding rectangle for all rectangles in the region. - Since drawing the root group is O(n) and thus very expensive for large - canvases, it's much faster to do a single paint than many, even though - more area may be painted that way. With a better group implementation, - it would likely be better to paint each changed rectangle separately. */ - GdkRectangle clip; - gdk_region_get_clipbox(event->region, &clip); - - const int x2 = clip.x + clip.width; - const int y2 = clip.y + clip.height; - - if (canvas->impl->need_update || canvas->impl->need_redraw) { - /* Update or drawing is scheduled, so just mark exposed area as dirty */ - ganv_canvas_request_redraw_c(canvas, clip.x, clip.y, x2, y2); - } else { - /* No pending updates, draw exposed area immediately */ - ganv_canvas_paint_rect(canvas, clip.x, clip.y, x2, y2); - - /* And call expose on parent container class */ - if (GTK_WIDGET_CLASS(canvas_parent_class)->expose_event) { - (*GTK_WIDGET_CLASS(canvas_parent_class)->expose_event)( - widget, event); - } - } - - return FALSE; -} - -/* Repaints the areas in the canvas that need it */ -static void -paint(GanvCanvas* canvas) -{ - for (GSList* l = canvas->impl->redraw_region; l; l = l->next) { - IRect* rect = (IRect*)l->data; - - const GdkRectangle gdkrect = { - rect->x + canvas->impl->zoom_xofs, - rect->y + canvas->impl->zoom_yofs, - rect->width, - rect->height - }; - - gdk_window_invalidate_rect(canvas->layout.bin_window, &gdkrect, FALSE); - g_free(rect); - } - - g_slist_free(canvas->impl->redraw_region); - canvas->impl->redraw_region = NULL; - canvas->impl->need_redraw = FALSE; - - canvas->impl->redraw_x1 = 0; - canvas->impl->redraw_y1 = 0; - canvas->impl->redraw_x2 = 0; - canvas->impl->redraw_y2 = 0; -} - -static void -do_update(GanvCanvas* canvas) -{ - /* Cause the update if necessary */ - -update_again: - if (canvas->impl->need_update) { - ganv_item_invoke_update(canvas->impl->root, 0); - - canvas->impl->need_update = FALSE; - } - - /* Pick new current item */ - - while (canvas->impl->need_repick) { - canvas->impl->need_repick = FALSE; - pick_current_item(canvas, &canvas->impl->pick_event); - } - - /* it is possible that during picking we emitted an event in which - the user then called some function which then requested update - of something. Without this we'd be left in a state where - need_update would have been left TRUE and the canvas would have - been left unpainted. */ - if (canvas->impl->need_update) { - goto update_again; - } - - /* Paint if able to */ - - if (GTK_WIDGET_DRAWABLE(canvas) && canvas->impl->need_redraw) { - paint(canvas); - } -} - -/* Idle handler for the canvas. It deals with pending updates and redraws. */ -static gboolean -idle_handler(gpointer data) -{ - GDK_THREADS_ENTER(); - - GanvCanvas* canvas = GANV_CANVAS(data); - - do_update(canvas); - - /* Reset idle id */ - canvas->impl->idle_id = 0; - - GDK_THREADS_LEAVE(); - - return FALSE; -} - -/* Convenience function to add an idle handler to a canvas */ -static void -add_idle(GanvCanvas* canvas) -{ - g_assert(canvas->impl->need_update || canvas->impl->need_redraw); - - if (!canvas->impl->idle_id) { - canvas->impl->idle_id = g_idle_add_full(CANVAS_IDLE_PRIORITY, - idle_handler, - canvas, - NULL); - } - - /* canvas->idle_id = gtk_idle_add (idle_handler, canvas); */ -} - -GanvItem* -ganv_canvas_root(GanvCanvas* canvas) -{ - g_return_val_if_fail(GANV_IS_CANVAS(canvas), NULL); - - return canvas->impl->root; -} - -void -ganv_canvas_set_scroll_region(GanvCanvas* canvas, - double x1, double y1, double x2, double y2) -{ - double wxofs, wyofs; - int xofs, yofs; - - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - /* - * Set the new scrolling region. If possible, do not move the visible contents of the - * canvas. - */ - - ganv_canvas_c2w(canvas, - GTK_LAYOUT(canvas)->hadjustment->value + canvas->impl->zoom_xofs, - GTK_LAYOUT(canvas)->vadjustment->value + canvas->impl->zoom_yofs, - /*canvas->impl->zoom_xofs, - canvas->impl->zoom_yofs,*/ - &wxofs, &wyofs); - - canvas->impl->scroll_x1 = x1; - canvas->impl->scroll_y1 = y1; - canvas->impl->scroll_x2 = x2; - canvas->impl->scroll_y2 = y2; - - ganv_canvas_w2c(canvas, wxofs, wyofs, &xofs, &yofs); - - scroll_to(canvas, xofs, yofs); - - canvas->impl->need_repick = TRUE; -#if 0 - /* todo: should be requesting update */ - (*GANV_ITEM_CLASS(canvas->impl->root->object.klass)->update)( - canvas->impl->root, NULL, NULL, 0); -#endif -} - -void -ganv_canvas_get_scroll_region(GanvCanvas* canvas, - double* x1, double* y1, double* x2, double* y2) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - if (x1) { - *x1 = canvas->impl->scroll_x1; - } - - if (y1) { - *y1 = canvas->impl->scroll_y1; - } - - if (x2) { - *x2 = canvas->impl->scroll_x2; - } - - if (y2) { - *y2 = canvas->impl->scroll_y2; - } -} - -void -ganv_canvas_set_center_scroll_region(GanvCanvas* canvas, gboolean center_scroll_region) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - canvas->impl->center_scroll_region = center_scroll_region != 0; - - scroll_to(canvas, - canvas->layout.hadjustment->value, - canvas->layout.vadjustment->value); -} - -gboolean -ganv_canvas_get_center_scroll_region(const GanvCanvas* canvas) -{ - g_return_val_if_fail(GANV_IS_CANVAS(canvas), FALSE); - - return canvas->impl->center_scroll_region ? TRUE : FALSE; -} - -void -ganv_canvas_scroll_to(GanvCanvas* canvas, int cx, int cy) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - scroll_to(canvas, cx, cy); -} - -void -ganv_canvas_get_scroll_offsets(const GanvCanvas* canvas, int* cx, int* cy) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - if (cx) { - *cx = canvas->layout.hadjustment->value; - } - - if (cy) { - *cy = canvas->layout.vadjustment->value; - } -} - -GanvItem* -ganv_canvas_get_item_at(GanvCanvas* canvas, double x, double y) -{ - g_return_val_if_fail(GANV_IS_CANVAS(canvas), NULL); - - GanvItem* item = NULL; - double dist = GANV_ITEM_GET_CLASS(canvas->impl->root)->point( - canvas->impl->root, - x - canvas->impl->root->impl->x, - y - canvas->impl->root->impl->y, - &item); - if ((int)(dist * canvas->impl->pixels_per_unit + 0.5) <= GANV_CLOSE_ENOUGH) { - return item; - } else { - return NULL; - } -} - -void -ganv_canvas_request_update(GanvCanvas* canvas) -{ - if (canvas->impl->need_update) { - return; - } - - canvas->impl->need_update = TRUE; - if (GTK_WIDGET_MAPPED((GtkWidget*)canvas)) { - add_idle(canvas); - } -} - -static inline gboolean -rect_overlaps(const IRect* a, const IRect* b) -{ - if ((a->x > b->x + b->width) || - (a->y > b->y + b->height) || - (a->x + a->width < b->x) || - (a->y + a->height < b->y)) { - return FALSE; - } - return TRUE; -} - -static inline gboolean -rect_is_visible(GanvCanvas* canvas, const IRect* r) -{ - const IRect rect = { - (int)(canvas->layout.hadjustment->value - canvas->impl->zoom_xofs), - (int)(canvas->layout.vadjustment->value - canvas->impl->zoom_yofs), - GTK_WIDGET(canvas)->allocation.width, - GTK_WIDGET(canvas)->allocation.height - }; - - return rect_overlaps(&rect, r); -} - -void -ganv_canvas_request_redraw_c(GanvCanvas* canvas, - int x1, int y1, int x2, int y2) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - if (!GTK_WIDGET_DRAWABLE(canvas) || (x1 >= x2) || (y1 >= y2)) { - return; - } - - const IRect rect = { x1, y1, x2 - x1, y2 - y1 }; - - if (!rect_is_visible(canvas, &rect)) { - return; - } - - IRect* r = (IRect*)g_malloc(sizeof(IRect)); - *r = rect; - - canvas->impl->redraw_region = g_slist_prepend(canvas->impl->redraw_region, r); - canvas->impl->need_redraw = TRUE; - - if (canvas->impl->idle_id == 0) { - add_idle(canvas); - } -} - -/* Request a redraw of the specified rectangle in world coordinates */ -void -ganv_canvas_request_redraw_w(GanvCanvas* canvas, - double x1, double y1, double x2, double y2) -{ - int cx1, cx2, cy1, cy2; - ganv_canvas_w2c(canvas, x1, y1, &cx1, &cy1); - ganv_canvas_w2c(canvas, x2, y2, &cx2, &cy2); - ganv_canvas_request_redraw_c(canvas, cx1, cy1, cx2, cy2); -} - -void -ganv_canvas_w2c_affine(GanvCanvas* canvas, cairo_matrix_t* matrix) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - g_return_if_fail(matrix != NULL); - - cairo_matrix_init_translate(matrix, - -canvas->impl->scroll_x1, - -canvas->impl->scroll_y1); - - cairo_matrix_scale(matrix, - canvas->impl->pixels_per_unit, - canvas->impl->pixels_per_unit); -} - -void -ganv_canvas_w2c(GanvCanvas* canvas, double wx, double wy, int* cx, int* cy) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - cairo_matrix_t matrix; - ganv_canvas_w2c_affine(canvas, &matrix); - - cairo_matrix_transform_point(&matrix, &wx, &wy); - - if (cx) { - *cx = floor(wx + 0.5); - } - if (cy) { - *cy = floor(wy + 0.5); - } -} - -void -ganv_canvas_w2c_d(GanvCanvas* canvas, double wx, double wy, double* cx, double* cy) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - cairo_matrix_t matrix; - ganv_canvas_w2c_affine(canvas, &matrix); - - cairo_matrix_transform_point(&matrix, &wx, &wy); - - if (cx) { - *cx = wx; - } - if (cy) { - *cy = wy; - } -} - -void -ganv_canvas_c2w(GanvCanvas* canvas, int cx, int cy, double* wx, double* wy) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - cairo_matrix_t matrix; - ganv_canvas_w2c_affine(canvas, &matrix); - cairo_matrix_invert(&matrix); - - double x = cx; - double y = cy; - cairo_matrix_transform_point(&matrix, &x, &y); - - if (wx) { - *wx = x; - } - if (wy) { - *wy = y; - } -} - -void -ganv_canvas_window_to_world(GanvCanvas* canvas, double winx, double winy, - double* worldx, double* worldy) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - if (worldx) { - *worldx = canvas->impl->scroll_x1 + ((winx - canvas->impl->zoom_xofs) - / canvas->impl->pixels_per_unit); - } - - if (worldy) { - *worldy = canvas->impl->scroll_y1 + ((winy - canvas->impl->zoom_yofs) - / canvas->impl->pixels_per_unit); - } -} - -void -ganv_canvas_world_to_window(GanvCanvas* canvas, double worldx, double worldy, - double* winx, double* winy) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - if (winx) { - *winx = (canvas->impl->pixels_per_unit) * (worldx - canvas->impl->scroll_x1) + canvas->impl->zoom_xofs; - } - - if (winy) { - *winy = (canvas->impl->pixels_per_unit) * (worldy - canvas->impl->scroll_y1) + canvas->impl->zoom_yofs; - } -} - -void -ganv_canvas_set_port_order(GanvCanvas* canvas, - GanvPortOrderFunc port_cmp, - void* data) -{ - g_return_if_fail(GANV_IS_CANVAS(canvas)); - - canvas->impl->_port_order.port_cmp = port_cmp; - canvas->impl->_port_order.data = data; -} - -PortOrderCtx -ganv_canvas_get_port_order(GanvCanvas* canvas) -{ - return canvas->impl->_port_order; -} - -gboolean -ganv_canvas_exporting(GanvCanvas* canvas) -{ - return canvas->impl->exporting; -} - -} // extern "C" diff --git a/src/Port.cpp b/src/Port.cpp deleted file mode 100644 index 3f0d02b..0000000 --- a/src/Port.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <string> - -#include <glib.h> - -#include "ganv/Canvas.hpp" -#include "ganv/Module.hpp" -#include "ganv/Port.hpp" - -#include "./color.h" - -namespace Ganv { - -static void -on_value_changed(GanvPort* port, double value, void* portmm) -{ - ((Port*)portmm)->signal_value_changed.emit(value); -} - -/* Construct a Port on an existing module. */ -Port::Port(Module& module, - const std::string& name, - bool is_input, - uint32_t color) - : Box(module.canvas(), - GANV_BOX(ganv_port_new(module.gobj(), is_input, - "fill-color", color, - "border-color", PORT_BORDER_COLOR(color), - "border-width", 2.0, - "label", name.c_str(), - NULL))) -{ - g_signal_connect(gobj(), "value-changed", - G_CALLBACK(on_value_changed), this); -} - -Module* -Port::get_module() const -{ - return Glib::wrap(ganv_port_get_module(gobj())); -} - -} // namespace Ganv diff --git a/src/boilerplate.h b/src/boilerplate.h deleted file mode 100644 index a419711..0000000 --- a/src/boilerplate.h +++ /dev/null @@ -1,43 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2016 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -typedef gpointer gobject; - -/** - A case in a switch statement in a set_properties implementation. - @prop: Property enumeration ID. - @type: Name of the value type, e.g. uint for guint. - @field: Field to set to the new value. -*/ -#define SET_CASE(prop, type, field) \ - case PROP_##prop: { \ - const g##type tmp = g_value_get_##type(value); \ - if ((field) != tmp) { \ - (field) = tmp; \ - ganv_item_request_update(GANV_ITEM(object)); \ - } \ - break; \ - } - -/** - A case in a switch statement in a get_properties implementation. - @prop: Property enumeration ID. - @type: Name of the value type, e.g. uint for guint. - @field: Field to set to the new value. -*/ -#define GET_CASE(prop, type, field) \ - case PROP_##prop: \ - g_value_set_##type(value, field); \ - break; diff --git a/src/box.c b/src/box.c deleted file mode 100644 index e7ecac8..0000000 --- a/src/box.c +++ /dev/null @@ -1,561 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <math.h> -#include <string.h> - -#include <cairo.h> - -#include "ganv/box.h" - -#include "./boilerplate.h" -#include "./color.h" -#include "./gettext.h" -#include "./ganv-private.h" - -static const double STACKED_OFFSET = 4.0; - -G_DEFINE_TYPE_WITH_CODE(GanvBox, ganv_box, GANV_TYPE_NODE, - G_ADD_PRIVATE(GanvBox)) - -static GanvNodeClass* parent_class; - -enum { - PROP_0, - PROP_X1, - PROP_Y1, - PROP_X2, - PROP_Y2, - PROP_RADIUS_TL, - PROP_RADIUS_TR, - PROP_RADIUS_BR, - PROP_RADIUS_BL, - PROP_STACKED, - PROP_BEVELED -}; - -static void -ganv_box_init(GanvBox* box) -{ - box->impl = ganv_box_get_instance_private(box); - - memset(&box->impl->coords, '\0', sizeof(GanvBoxCoords)); - - box->impl->coords.border_width = GANV_NODE(box)->impl->border_width; - box->impl->old_coords = box->impl->coords; - box->impl->radius_tl = 0.0; - box->impl->radius_tr = 0.0; - box->impl->radius_br = 0.0; - box->impl->radius_bl = 0.0; - box->impl->beveled = FALSE; -} - -static void -ganv_box_destroy(GtkObject* object) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_BOX(object)); - - if (GTK_OBJECT_CLASS(parent_class)->destroy) { - (*GTK_OBJECT_CLASS(parent_class)->destroy)(object); - } -} - -static void -ganv_box_set_property(GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_BOX(object)); - - GanvBox* box = GANV_BOX(object); - GanvBoxPrivate* impl = box->impl; - GanvBoxCoords* coords = &impl->coords; - - switch (prop_id) { - SET_CASE(X1, double, coords->x1); - SET_CASE(Y1, double, coords->y1); - SET_CASE(X2, double, coords->x2); - SET_CASE(Y2, double, coords->y2); - SET_CASE(RADIUS_TL, double, impl->radius_tl); - SET_CASE(RADIUS_TR, double, impl->radius_tr); - SET_CASE(RADIUS_BR, double, impl->radius_br); - SET_CASE(RADIUS_BL, double, impl->radius_bl); - SET_CASE(STACKED, boolean, coords->stacked); - SET_CASE(BEVELED, boolean, impl->beveled); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_box_get_property(GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_BOX(object)); - - GanvBox* box = GANV_BOX(object); - GanvBoxPrivate* impl = box->impl; - GanvBoxCoords* coords = &impl->coords; - - switch (prop_id) { - GET_CASE(X1, double, coords->x1); - GET_CASE(X2, double, coords->x2); - GET_CASE(Y1, double, coords->y1); - GET_CASE(Y2, double, coords->y2); - GET_CASE(RADIUS_TL, double, impl->radius_tl); - GET_CASE(RADIUS_TR, double, impl->radius_tr); - GET_CASE(RADIUS_BR, double, impl->radius_br); - GET_CASE(RADIUS_BL, double, impl->radius_bl); - GET_CASE(STACKED, boolean, impl->coords.stacked); - GET_CASE(BEVELED, boolean, impl->beveled); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_box_bounds_item(const GanvBoxCoords* coords, - double* x1, double* y1, - double* x2, double* y2) -{ - *x1 = coords->x1 - coords->border_width; - *y1 = coords->y1 - coords->border_width; - *x2 = coords->x2 + coords->border_width + (coords->stacked * STACKED_OFFSET); - *y2 = coords->y2 + coords->border_width + (coords->stacked * STACKED_OFFSET); -} - -void -ganv_box_request_redraw(GanvItem* item, - const GanvBoxCoords* coords, - gboolean world) -{ - double x1, y1, x2, y2; - ganv_box_bounds_item(coords, &x1, &y1, &x2, &y2); - - if (!world) { - // Convert from item-relative coordinates to world coordinates - ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2); - } - - ganv_canvas_request_redraw_w(item->impl->canvas, x1, y1, x2, y2); -} - -static void -coords_i2w(GanvItem* item, GanvBoxCoords* coords) -{ - ganv_item_i2w_pair(item, &coords->x1, &coords->y1, &coords->x2, &coords->y2); -} - -static void -ganv_box_bounds(GanvItem* item, - double* x1, double* y1, - double* x2, double* y2) -{ - // Note this will not be correct if children are outside the box bounds - GanvBox* box = (GanvBox*)item; - ganv_box_bounds_item(&box->impl->coords, x1, y1, x2, y2); -} - -static void -ganv_box_update(GanvItem* item, int flags) -{ - GanvBox* box = GANV_BOX(item); - GanvBoxPrivate* impl = box->impl; - impl->coords.border_width = box->node.impl->border_width; - - // Request redraw of old location - ganv_box_request_redraw(item, &impl->old_coords, TRUE); - - // Store old coordinates in world relative coordinates in case the - // group we are in moves between now and the next update - impl->old_coords = impl->coords; - coords_i2w(item, &impl->old_coords); - - // Call parent class update method, resizing if necessary - GANV_ITEM_CLASS(parent_class)->update(item, flags); - ganv_box_normalize(box); - - // Update world-relative bounding box - ganv_box_bounds(item, &item->impl->x1, &item->impl->y1, &item->impl->x2, &item->impl->y2); - ganv_item_i2w_pair(item, &item->impl->x1, &item->impl->y1, &item->impl->x2, &item->impl->y2); - - // Request redraw of new location - ganv_box_request_redraw(item, &impl->coords, FALSE); -} - -void -ganv_box_path(GanvBox* box, - cairo_t* cr, double x1, double y1, double x2, double y2, - double dr) -{ - static const double degrees = G_PI / 180.0; - - GanvBoxPrivate* impl = box->impl; - - if (impl->radius_tl == 0.0 && impl->radius_tr == 0.0 - && impl->radius_br == 0.0 && impl->radius_bl == 0.0) { - // Simple rectangle - cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1); - } else if (impl->beveled) { - // Beveled rectangle - cairo_new_sub_path(cr); - cairo_move_to(cr, x1 + impl->radius_tl, y1); - cairo_line_to(cr, x2 - impl->radius_tr, y1); - cairo_line_to(cr, x2, y1 + impl->radius_tr); - cairo_line_to(cr, x2, y2 - impl->radius_br); - cairo_line_to(cr, x2 - impl->radius_br, y2); - cairo_line_to(cr, x1 + impl->radius_bl, y2); - cairo_line_to(cr, x1, y2 - impl->radius_bl); - cairo_line_to(cr, x1, y2 - impl->radius_bl); - cairo_line_to(cr, x1, y1 + impl->radius_tl); - cairo_close_path(cr); - } else { - // Rounded rectangle - cairo_new_sub_path(cr); - cairo_arc(cr, - x2 - impl->radius_tr - dr, - y1 + impl->radius_tr + dr, - impl->radius_tr + dr, -90 * degrees, 0 * degrees); - cairo_arc(cr, - x2 - impl->radius_br - dr, y2 - impl->radius_br - dr, - impl->radius_br + dr, 0 * degrees, 90 * degrees); - cairo_arc(cr, - x1 + impl->radius_bl + dr, y2 - impl->radius_bl - dr, - impl->radius_bl + dr, 90 * degrees, 180 * degrees); - cairo_arc(cr, - x1 + impl->radius_tl + dr, y1 + impl->radius_tl + dr, - impl->radius_tl + dr, 180 * degrees, 270 * degrees); - cairo_close_path(cr); - } -} - -static void -ganv_box_draw(GanvItem* item, - cairo_t* cr, double cx, double cy, double cw, double ch) -{ - GanvBox* box = GANV_BOX(item); - GanvBoxPrivate* impl = box->impl; - - double x1 = impl->coords.x1; - double y1 = impl->coords.y1; - double x2 = impl->coords.x2; - double y2 = impl->coords.y2; - ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2); - - double dash_length, border_color, fill_color; - ganv_node_get_draw_properties( - &box->node, &dash_length, &border_color, &fill_color); - - double r, g, b, a; - - for (int i = (impl->coords.stacked ? 1 : 0); i >= 0; --i) { - const double x = 0.0 - (STACKED_OFFSET * i); - const double y = 0.0 - (STACKED_OFFSET * i); - - // Trace basic box path - ganv_box_path(box, cr, x1 - x, y1 - y, x2 - x, y2 - y, 0.0); - - // Fill - color_to_rgba(fill_color, &r, &g, &b, &a); - cairo_set_source_rgba(cr, r, g, b, a); - - // Border - if (impl->coords.border_width > 0.0) { - cairo_fill_preserve(cr); - color_to_rgba(border_color, &r, &g, &b, &a); - cairo_set_source_rgba(cr, r, g, b, a); - cairo_set_line_width(cr, impl->coords.border_width); - if (dash_length > 0) { - cairo_set_dash(cr, &dash_length, 1, box->node.impl->dash_offset); - } else { - cairo_set_dash(cr, &dash_length, 0, 0); - } - cairo_stroke(cr); - } else { - cairo_fill(cr); - } - } - - GanvItemClass* item_class = GANV_ITEM_CLASS(parent_class); - item_class->draw(item, cr, cx, cy, cw, ch); -} - -static double -ganv_box_point(GanvItem* item, double x, double y, GanvItem** actual_item) -{ - GanvBox* box = GANV_BOX(item); - GanvBoxPrivate* impl = box->impl; - - *actual_item = NULL; - - double x1, y1, x2, y2; - ganv_box_bounds_item(&impl->coords, &x1, &y1, &x2, &y2); - - // Point is inside the box (distance 0) - if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) { - *actual_item = item; - return 0.0; - } - - // Point is outside the box - double dx = 0.0; - double dy = 0.0; - - // Find horizontal distance to nearest edge - if (x < x1) { - dx = x1 - x; - } else if (x > x2) { - dx = x - x2; - } - - // Find vertical distance to nearest edge - if (y < y1) { - dy = y1 - y; - } else if (y > y2) { - dy = y - y2; - } - - return sqrt((dx * dx) + (dy * dy)); -} - -static gboolean -ganv_box_is_within(const GanvNode* self, - double x1, - double y1, - double x2, - double y2) -{ - double bx1, by1, bx2, by2; - g_object_get(G_OBJECT(self), - "x1", &bx1, - "y1", &by1, - "x2", &bx2, - "y2", &by2, - NULL); - - ganv_item_i2w_pair(GANV_ITEM(self), &bx1, &by1, &bx2, &by2); - - return ( bx1 >= x1 - && by2 >= y1 - && bx2 <= x2 - && by2 <= y2); -} - -static void -ganv_box_default_set_width(GanvBox* box, double width) -{ - box->impl->coords.x2 = ganv_box_get_x1(box) + width; - ganv_item_request_update(GANV_ITEM(box)); -} - -static void -ganv_box_default_set_height(GanvBox* box, double height) -{ - box->impl->coords.y2 = ganv_box_get_y1(box) + height; - ganv_item_request_update(GANV_ITEM(box)); -} - -static void -ganv_box_class_init(GanvBoxClass* klass) -{ - GObjectClass* gobject_class = (GObjectClass*)klass; - GtkObjectClass* object_class = (GtkObjectClass*)klass; - GanvItemClass* item_class = (GanvItemClass*)klass; - GanvNodeClass* node_class = (GanvNodeClass*)klass; - - parent_class = GANV_NODE_CLASS(g_type_class_peek_parent(klass)); - - gobject_class->set_property = ganv_box_set_property; - gobject_class->get_property = ganv_box_get_property; - - g_object_class_install_property( - gobject_class, PROP_X1, g_param_spec_double( - "x1", - _("x1"), - _("Top left x coordinate."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_Y1, g_param_spec_double( - "y1", - _("y1"), - _("Top left y coordinate."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_X2, g_param_spec_double( - "x2", - _("x2"), - _("Bottom right x coordinate."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_Y2, g_param_spec_double( - "y2", - _("y2"), - _("Bottom right y coordinate."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_RADIUS_TL, g_param_spec_double( - "radius-tl", - _("Top left radius"), - _("The radius of the top left corner."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_RADIUS_TR, g_param_spec_double( - "radius-tr", - _("Top right radius"), - _("The radius of the top right corner."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_RADIUS_BR, g_param_spec_double( - "radius-br", - _("Bottom right radius"), - _("The radius of the bottom right corner."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_RADIUS_BL, g_param_spec_double( - "radius-bl", - _("Bottom left radius"), - _("The radius of the bottom left corner."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_STACKED, g_param_spec_boolean( - "stacked", - _("Stacked"), - _("Show box with a stacked appearance."), - FALSE, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_BEVELED, g_param_spec_boolean( - "beveled", - _("Beveled"), - _("Show radiused corners with a sharp bevel."), - FALSE, - G_PARAM_READWRITE)); - - object_class->destroy = ganv_box_destroy; - - item_class->update = ganv_box_update; - item_class->bounds = ganv_box_bounds; - item_class->point = ganv_box_point; - item_class->draw = ganv_box_draw; - - node_class->is_within = ganv_box_is_within; - - klass->set_width = ganv_box_default_set_width; - klass->set_height = ganv_box_default_set_height; -} - -void -ganv_box_normalize(GanvBox* box) -{ - if (box->impl->coords.x2 < box->impl->coords.x1) { - const double tmp = box->impl->coords.x1; - box->impl->coords.x1 = box->impl->coords.x2; - box->impl->coords.x2 = tmp; - } - if (box->impl->coords.y2 < box->impl->coords.y1) { - const double tmp = box->impl->coords.y1; - box->impl->coords.y1 = box->impl->coords.y2; - box->impl->coords.y2 = tmp; - } -} - -double -ganv_box_get_x1(const GanvBox* box) -{ - return box->impl->coords.x1; -} - -double -ganv_box_get_y1(const GanvBox* box) -{ - return box->impl->coords.y1; -} - -double -ganv_box_get_x2(const GanvBox* box) -{ - return box->impl->coords.x2; -} - -double -ganv_box_get_y2(const GanvBox* box) -{ - return box->impl->coords.y2; -} - -double -ganv_box_get_width(const GanvBox* box) -{ - return box->impl->coords.x2 - box->impl->coords.x1; -} - -void -ganv_box_set_width(GanvBox* box, - double width) -{ - GANV_BOX_GET_CLASS(box)->set_width(box, width); -} - -double -ganv_box_get_height(const GanvBox* box) -{ - return box->impl->coords.y2 - box->impl->coords.y1; -} - -void -ganv_box_set_height(GanvBox* box, - double height) -{ - GANV_BOX_GET_CLASS(box)->set_height(box, height); -} - -double -ganv_box_get_border_width(const GanvBox* box) -{ - return box->impl->coords.border_width; -} diff --git a/src/circle.c b/src/circle.c deleted file mode 100644 index a69c207..0000000 --- a/src/circle.c +++ /dev/null @@ -1,467 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <math.h> -#include <string.h> - -#include "ganv/canvas.h" -#include "ganv/circle.h" - -#include "./color.h" -#include "./boilerplate.h" -#include "./gettext.h" -#include "./ganv-private.h" - -G_DEFINE_TYPE_WITH_CODE(GanvCircle, ganv_circle, GANV_TYPE_NODE, - G_ADD_PRIVATE(GanvCircle)) - -static GanvNodeClass* parent_class; - -enum { - PROP_0, - PROP_RADIUS, - PROP_RADIUS_EMS, - PROP_FIT_LABEL -}; - -static void -ganv_circle_init(GanvCircle* circle) -{ - circle->impl = ganv_circle_get_instance_private(circle); - - memset(&circle->impl->coords, '\0', sizeof(GanvCircleCoords)); - circle->impl->coords.radius = 0.0; - circle->impl->coords.radius_ems = 1.0; - circle->impl->coords.width = 2.0; - circle->impl->old_coords = circle->impl->coords; - circle->impl->fit_label = TRUE; -} - -static void -ganv_circle_destroy(GtkObject* object) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_CIRCLE(object)); - - if (GTK_OBJECT_CLASS(parent_class)->destroy) { - (*GTK_OBJECT_CLASS(parent_class)->destroy)(object); - } -} - -static void -ganv_circle_set_property(GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_CIRCLE(object)); - - GanvCircle* circle = GANV_CIRCLE(object); - - switch (prop_id) { - SET_CASE(RADIUS, double, circle->impl->coords.radius); - SET_CASE(RADIUS_EMS, double, circle->impl->coords.radius_ems); - SET_CASE(FIT_LABEL, boolean, circle->impl->fit_label); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } - - if (prop_id == PROP_RADIUS_EMS) { - ganv_circle_set_radius_ems(circle, circle->impl->coords.radius_ems); - } -} - -static void -ganv_circle_get_property(GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_CIRCLE(object)); - - GanvCircle* circle = GANV_CIRCLE(object); - - switch (prop_id) { - GET_CASE(RADIUS, double, circle->impl->coords.radius); - GET_CASE(RADIUS_EMS, double, circle->impl->coords.radius_ems); - GET_CASE(FIT_LABEL, boolean, circle->impl->fit_label); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_circle_resize(GanvNode* self) -{ - GanvNode* node = GANV_NODE(self); - GanvCircle* circle = GANV_CIRCLE(self); - GanvCanvas* canvas = GANV_CANVAS(GANV_ITEM(node)->impl->canvas); - - if (node->impl->label) { - if (node->impl->label->impl->needs_layout) { - ganv_text_layout(node->impl->label); - } - - const double label_w = node->impl->label->impl->coords.width; - const double label_h = node->impl->label->impl->coords.height; - if (circle->impl->fit_label) { - // Resize to fit text - const double radius = MAX(label_w, label_h) / 2.0 + 3.0; - if (radius != circle->impl->coords.radius) { - ganv_item_set(GANV_ITEM(self), - "radius", radius, - NULL); - } - } - - // Center label - ganv_item_set(GANV_ITEM(node->impl->label), - "x", label_w / -2.0, - "y", label_h / -2.0, - NULL); - } - - if (parent_class->resize) { - parent_class->resize(self); - } - - ganv_canvas_for_each_edge_on( - canvas, node, (GanvEdgeFunc)ganv_edge_update_location, NULL); -} - -static void -ganv_circle_redraw_text(GanvNode* self) -{ - GanvCircle* circle = GANV_CIRCLE(self); - if (circle->impl->coords.radius_ems) { - ganv_circle_set_radius_ems(circle, circle->impl->coords.radius_ems); - } - - if (parent_class->redraw_text) { - parent_class->redraw_text(self); - } -} - -static gboolean -ganv_circle_is_within(const GanvNode* self, - double x1, - double y1, - double x2, - double y2) -{ - const double x = GANV_ITEM(self)->impl->x; - const double y = GANV_ITEM(self)->impl->y; - - return x >= x1 - && x <= x2 - && y >= y1 - && y <= y2; -} - -static void -ganv_circle_vector(const GanvNode* self, - const GanvNode* other, - double* x, - double* y, - double* dx, - double* dy) -{ - GanvCircle* circle = GANV_CIRCLE(self); - - const double cx = GANV_ITEM(self)->impl->x; - const double cy = GANV_ITEM(self)->impl->y; - const double other_x = GANV_ITEM(other)->impl->x; - const double other_y = GANV_ITEM(other)->impl->y; - - const double border = circle->node.impl->border_width; - const double xdist = other_x - cx; - const double ydist = other_y - cy; - const double h = sqrt((xdist * xdist) + (ydist * ydist)); - const double theta = asin(xdist / (h + DBL_EPSILON)); - const double y_mod = (cy < other_y) ? 1 : -1; - const double ret_h = h - circle->impl->coords.radius - border / 2.0; - const double ret_x = other_x - sin(theta) * ret_h; - const double ret_y = other_y - cos(theta) * ret_h * y_mod; - - *x = ret_x; - *y = ret_y; - *dx = 0.0; - *dy = 0.0; - - ganv_item_i2w(GANV_ITEM(circle)->impl->parent, x, y); -} - -static void -request_redraw(GanvItem* item, - const GanvCircleCoords* coords, - gboolean world) -{ - const double w = coords->width; - - double x1 = coords->x - coords->radius - w; - double y1 = coords->y - coords->radius - w; - double x2 = coords->x + coords->radius + w; - double y2 = coords->y + coords->radius + w; - - if (!world) { - // Convert from parent-relative coordinates to world coordinates - ganv_item_i2w_pair(item, &x1, &y1, &x2, &y2); - } - - ganv_canvas_request_redraw_w(item->impl->canvas, x1, y1, x2, y2); -} - -static void -coords_i2w(GanvItem* item, GanvCircleCoords* coords) -{ - ganv_item_i2w(item, &coords->x, &coords->y); -} - -static void -ganv_circle_bounds_item(GanvItem* item, - double* x1, double* y1, - double* x2, double* y2) -{ - const GanvCircle* circle = GANV_CIRCLE(item); - const GanvCircleCoords* coords = &circle->impl->coords; - *x1 = coords->x - coords->radius - coords->width; - *y1 = coords->y - coords->radius - coords->width; - *x2 = coords->x + coords->radius + coords->width; - *y2 = coords->y + coords->radius + coords->width; -} - -static void -ganv_circle_bounds(GanvItem* item, - double* x1, double* y1, - double* x2, double* y2) -{ - ganv_circle_bounds_item(item, x1, y1, x2, y2); -} - -static void -ganv_circle_update(GanvItem* item, int flags) -{ - GanvCircle* circle = GANV_CIRCLE(item); - GanvCirclePrivate* impl = circle->impl; - impl->coords.width = circle->node.impl->border_width; - - // Request redraw of old location - request_redraw(item, &impl->old_coords, TRUE); - - // Store old coordinates in world relative coordinates in case the - // group we are in moves between now and the next update - impl->old_coords = impl->coords; - coords_i2w(item, &impl->old_coords); - - // Update world-relative bounding box - ganv_circle_bounds(item, &item->impl->x1, &item->impl->y1, &item->impl->x2, &item->impl->y2); - ganv_item_i2w_pair(item, &item->impl->x1, &item->impl->y1, &item->impl->x2, &item->impl->y2); - - // Request redraw of new location - request_redraw(item, &impl->coords, FALSE); - - GANV_ITEM_CLASS(parent_class)->update(item, flags); -} - -static void -ganv_circle_draw(GanvItem* item, - cairo_t* cr, double cx, double cy, double cw, double ch) -{ - GanvNode* node = GANV_NODE(item); - GanvCircle* circle = GANV_CIRCLE(item); - GanvCirclePrivate* impl = circle->impl; - - double r, g, b, a; - - double x = impl->coords.x; - double y = impl->coords.y; - ganv_item_i2w(item, &x, &y); - - double dash_length, border_color, fill_color; - ganv_node_get_draw_properties( - &circle->node, &dash_length, &border_color, &fill_color); - - // Fill - cairo_new_path(cr); - cairo_arc(cr, - x, - y, - impl->coords.radius + (impl->coords.width / 2.0), - 0, 2 * G_PI); - color_to_rgba(fill_color, &r, &g, &b, &a); - cairo_set_source_rgba(cr, r, g, b, a); - cairo_fill(cr); - - // Border - cairo_arc(cr, - x, - y, - impl->coords.radius, - 0, 2 * G_PI); - color_to_rgba(border_color, &r, &g, &b, &a); - cairo_set_source_rgba(cr, r, g, b, a); - cairo_set_line_width(cr, impl->coords.width); - if (dash_length > 0) { - cairo_set_dash(cr, &dash_length, 1, circle->node.impl->dash_offset); - } else { - cairo_set_dash(cr, &dash_length, 0, 0); - } - cairo_stroke(cr); - - // Draw label - if (node->impl->label) { - GanvItem* label_item = GANV_ITEM(node->impl->label); - - if (label_item->object.flags & GANV_ITEM_VISIBLE) { - GANV_ITEM_GET_CLASS(label_item)->draw( - label_item, cr, cx, cy, cw, ch); - } - } -} - -static double -ganv_circle_point(GanvItem* item, double x, double y, GanvItem** actual_item) -{ - const GanvCircle* circle = GANV_CIRCLE(item); - const GanvCircleCoords* coords = &circle->impl->coords; - - *actual_item = item; - - const double dx = fabs(x - coords->x); - const double dy = fabs(y - coords->y); - const double d = sqrt((dx * dx) + (dy * dy)); - - if (d <= coords->radius + coords->width) { - // Point is inside the circle - return 0.0; - } else { - // Distance from the edge of the circle - return d - (coords->radius + coords->width); - } -} - -static void -ganv_circle_class_init(GanvCircleClass* klass) -{ - GObjectClass* gobject_class = (GObjectClass*)klass; - GtkObjectClass* object_class = (GtkObjectClass*)klass; - GanvItemClass* item_class = (GanvItemClass*)klass; - GanvNodeClass* node_class = (GanvNodeClass*)klass; - - parent_class = GANV_NODE_CLASS(g_type_class_peek_parent(klass)); - - gobject_class->set_property = ganv_circle_set_property; - gobject_class->get_property = ganv_circle_get_property; - - g_object_class_install_property( - gobject_class, PROP_RADIUS, g_param_spec_double( - "radius", - _("Radius"), - _("The radius of the circle."), - 0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_RADIUS_EMS, g_param_spec_double( - "radius-ems", - _("Radius in ems"), - _("The radius of the circle in ems."), - 0, G_MAXDOUBLE, - 1.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_FIT_LABEL, g_param_spec_boolean( - "fit-label", - _("Fit label"), - _("If true, expand circle to fit its label"), - TRUE, - (GParamFlags)G_PARAM_READWRITE)); - - object_class->destroy = ganv_circle_destroy; - - node_class->resize = ganv_circle_resize; - node_class->is_within = ganv_circle_is_within; - node_class->tail_vector = ganv_circle_vector; - node_class->head_vector = ganv_circle_vector; - node_class->redraw_text = ganv_circle_redraw_text; - - item_class->update = ganv_circle_update; - item_class->bounds = ganv_circle_bounds; - item_class->point = ganv_circle_point; - item_class->draw = ganv_circle_draw; -} - -GanvCircle* -ganv_circle_new(GanvCanvas* canvas, - const char* first_property_name, ...) -{ - GanvCircle* circle = GANV_CIRCLE( - g_object_new(ganv_circle_get_type(), "canvas", canvas, NULL)); - - va_list args; - va_start(args, first_property_name); - g_object_set_valist(G_OBJECT(circle), first_property_name, args); - va_end(args); - - return circle; -} - -double -ganv_circle_get_radius(const GanvCircle* circle) -{ - return circle->impl->coords.radius; -} - -void -ganv_circle_set_radius(GanvCircle* circle, double radius) -{ - circle->impl->coords.radius = radius; - ganv_item_request_update(GANV_ITEM(circle)); -} - -double -ganv_circle_get_radius_ems(const GanvCircle* circle) -{ - return circle->impl->coords.radius_ems; -} - -void -ganv_circle_set_radius_ems(GanvCircle* circle, double ems) -{ - GanvCanvas* canvas = GANV_CANVAS(GANV_ITEM(circle)->impl->canvas); - const double points = ganv_canvas_get_font_size(canvas); - circle->impl->coords.radius_ems = ems; - circle->impl->coords.radius = points * ems; - ganv_item_request_update(GANV_ITEM(circle)); -} - -gboolean -ganv_circle_get_fit_label(const GanvCircle* circle) -{ - return circle->impl->fit_label; -} - -void -ganv_circle_set_fit_label(GanvCircle* circle, gboolean fit_label) -{ - circle->impl->fit_label = fit_label; - ganv_item_request_update(GANV_ITEM(circle)); -} diff --git a/src/color.h b/src/color.h deleted file mode 100644 index ca52d98..0000000 --- a/src/color.h +++ /dev/null @@ -1,63 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_UTIL_H -#define GANV_UTIL_H - -#include <glib.h> - -#ifdef GANV_USE_LIGHT_THEME -# define DEFAULT_BACKGROUND_COLOR 0xFFFFFFFF -# define DEFAULT_TEXT_COLOR 0x000000FF -# define DIM_TEXT_COLOR 0x333333BB -# define DEFAULT_FILL_COLOR 0xEEEEEEFF -# define DEFAULT_BORDER_COLOR 0x000000FF -# define PORT_BORDER_COLOR(fill) 0x000000FF -# define EDGE_COLOR(base) highlight_color(tail_color, -48) -#else -# define DEFAULT_BACKGROUND_COLOR 0x000000FF -# define DEFAULT_TEXT_COLOR 0xFFFFFFFF -# define DIM_TEXT_COLOR 0xCCCCCCBB -# define DEFAULT_FILL_COLOR 0x1E2224FF -# define DEFAULT_BORDER_COLOR 0x3E4244FF -# define PORT_BORDER_COLOR(fill) highlight_color(fill, 0x20) -# define EDGE_COLOR(base) highlight_color(tail_color, 48) -#endif - -static inline void -color_to_rgba(guint color, double* r, double* g, double* b, double* a) -{ - *r = ((color >> 24) & 0xFF) / 255.0; - *g = ((color >> 16) & 0xFF) / 255.0; - *b = ((color >> 8) & 0xFF) / 255.0; - *a = ((color) & 0xFF) / 255.0; -} - -static inline guint -highlight_color(guint c, guint delta) -{ - const guint max_char = 255; - const guint r = MIN((c >> 24) + delta, max_char); - const guint g = MIN(((c >> 16) & 0xFF) + delta, max_char); - const guint b = MIN(((c >> 8) & 0xFF) + delta, max_char); - const guint a = c & 0xFF; - - return ((((guint)(r)) << 24) | - (((guint)(g)) << 16) | - (((guint)(b)) << 8) | - (((guint)(a)))); -} - -#endif // GANV_UTIL_H diff --git a/src/edge.c b/src/edge.c deleted file mode 100644 index a22bc73..0000000 --- a/src/edge.c +++ /dev/null @@ -1,786 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2016 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <math.h> -#include <string.h> - -#include <cairo.h> - -#include "ganv/canvas.h" -#include "ganv/edge.h" -#include "ganv/node.h" - -#include "./boilerplate.h" -#include "./color.h" -#include "./gettext.h" - -#include "color.h" -#include "ganv-private.h" - -#define ARROW_DEPTH 32 -#define ARROW_BREADTH 32 - -// Uncomment to see control point path as straight lines -//#define GANV_DEBUG_CURVES 1 - -// Uncomment along with GANV_DEBUG_CURVES to see bounding box (buggy) -//#define GANV_DEBUG_BOUNDS 1 - -enum { - PROP_0, - PROP_TAIL, - PROP_HEAD, - PROP_WIDTH, - PROP_HANDLE_RADIUS, - PROP_DASH_LENGTH, - PROP_DASH_OFFSET, - PROP_COLOR, - PROP_CONSTRAINING, - PROP_CURVED, - PROP_ARROWHEAD, - PROP_SELECTED, - PROP_HIGHLIGHTED, - PROP_GHOST -}; - -G_DEFINE_TYPE_WITH_CODE(GanvEdge, ganv_edge, GANV_TYPE_ITEM, - G_ADD_PRIVATE(GanvEdge)) - -static GanvItemClass* parent_class; - -static void -ganv_edge_init(GanvEdge* edge) -{ - GanvEdgePrivate* impl = ganv_edge_get_instance_private(edge); - - edge->impl = impl; - - impl->tail = NULL; - impl->head = NULL; - - memset(&impl->coords, '\0', sizeof(GanvEdgeCoords)); - impl->coords.width = 2.0; - impl->coords.handle_radius = 4.0; - impl->coords.constraining = TRUE; - impl->coords.curved = FALSE; - impl->coords.arrowhead = FALSE; - - impl->old_coords = impl->coords; - impl->dash_length = 0.0; - impl->dash_offset = 0.0; - impl->color = 0; -} - -static void -ganv_edge_destroy(GtkObject* object) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_EDGE(object)); - - GanvEdge* edge = GANV_EDGE(object); - GanvCanvas* canvas = GANV_CANVAS(edge->item.impl->canvas); - if (canvas && !edge->impl->ghost) { - edge->item.impl->canvas = NULL; - } - edge->item.impl->parent = NULL; - - if (GTK_OBJECT_CLASS(parent_class)->destroy) { - (*GTK_OBJECT_CLASS(parent_class)->destroy)(object); - } -} - -static void -ganv_edge_set_property(GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_EDGE(object)); - - GanvItem* item = GANV_ITEM(object); - GanvEdge* edge = GANV_EDGE(object); - GanvEdgePrivate* impl = edge->impl; - GanvEdgeCoords* coords = &impl->coords; - - switch (prop_id) { - SET_CASE(WIDTH, double, coords->width); - SET_CASE(HANDLE_RADIUS, double, coords->handle_radius); - SET_CASE(DASH_LENGTH, double, impl->dash_length); - SET_CASE(DASH_OFFSET, double, impl->dash_offset); - SET_CASE(COLOR, uint, impl->color); - SET_CASE(CONSTRAINING, boolean, impl->coords.constraining); - SET_CASE(CURVED, boolean, impl->coords.curved); - SET_CASE(ARROWHEAD, boolean, impl->coords.arrowhead); - SET_CASE(SELECTED, boolean, impl->selected); - SET_CASE(HIGHLIGHTED, boolean, impl->highlighted); - SET_CASE(GHOST, boolean, impl->ghost); - case PROP_TAIL: { - const gobject tmp = g_value_get_object(value); - if (impl->tail != tmp) { - impl->tail = GANV_NODE(tmp); - ganv_item_request_update(item); - } - break; - } - case PROP_HEAD: { - const gobject tmp = g_value_get_object(value); - if (impl->head != tmp) { - impl->head = GANV_NODE(tmp); - ganv_item_request_update(item); - } - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_edge_get_property(GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_EDGE(object)); - - GanvEdge* edge = GANV_EDGE(object); - GanvEdgePrivate* impl = edge->impl; - - switch (prop_id) { - GET_CASE(TAIL, object, impl->tail); - GET_CASE(HEAD, object, impl->head); - GET_CASE(WIDTH, double, impl->coords.width); - SET_CASE(HANDLE_RADIUS, double, impl->coords.handle_radius); - GET_CASE(DASH_LENGTH, double, impl->dash_length); - GET_CASE(DASH_OFFSET, double, impl->dash_offset); - GET_CASE(COLOR, uint, impl->color); - GET_CASE(CONSTRAINING, boolean, impl->coords.constraining); - GET_CASE(CURVED, boolean, impl->coords.curved); - GET_CASE(ARROWHEAD, boolean, impl->coords.arrowhead); - GET_CASE(SELECTED, boolean, impl->selected); - GET_CASE(HIGHLIGHTED, boolean, impl->highlighted); - SET_CASE(GHOST, boolean, impl->ghost); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -void -ganv_edge_request_redraw(GanvItem* item, - const GanvEdgeCoords* coords) -{ - GanvCanvas* canvas = item->impl->canvas; - const double w = coords->width; - if (coords->curved) { - const double src_x = coords->x1; - const double src_y = coords->y1; - const double dst_x = coords->x2; - const double dst_y = coords->y2; - const double join_x = (src_x + dst_x) / 2.0; - const double join_y = (src_y + dst_y) / 2.0; - const double src_x1 = coords->cx1; - const double src_y1 = coords->cy1; - const double dst_x1 = coords->cx2; - const double dst_y1 = coords->cy2; - - const double r1x1 = MIN(MIN(src_x, join_x), src_x1); - const double r1y1 = MIN(MIN(src_y, join_y), src_y1); - const double r1x2 = MAX(MAX(src_x, join_x), src_x1); - const double r1y2 = MAX(MAX(src_y, join_y), src_y1); - ganv_canvas_request_redraw_w(canvas, - r1x1 - w, r1y1 - w, - r1x2 + w, r1y2 + w); - - const double r2x1 = MIN(MIN(dst_x, join_x), dst_x1); - const double r2y1 = MIN(MIN(dst_y, join_y), dst_y1); - const double r2x2 = MAX(MAX(dst_x, join_x), dst_x1); - const double r2y2 = MAX(MAX(dst_y, join_y), dst_y1); - ganv_canvas_request_redraw_w(canvas, - r2x1 - w, r2y1 - w, - r2x2 + w, r2y2 + w); - - } else { - const double x1 = MIN(coords->x1, coords->x2); - const double y1 = MIN(coords->y1, coords->y2); - const double x2 = MAX(coords->x1, coords->x2); - const double y2 = MAX(coords->y1, coords->y2); - - ganv_canvas_request_redraw_w(canvas, - x1 - w, y1 - w, - x2 + w, y2 + w); - } - - if (coords->handle_radius > 0.0) { - ganv_canvas_request_redraw_w( - canvas, - coords->handle_x - coords->handle_radius - w, - coords->handle_y - coords->handle_radius - w, - coords->handle_x + coords->handle_radius + w, - coords->handle_y + coords->handle_radius + w); - } - - if (coords->arrowhead) { - ganv_canvas_request_redraw_w( - canvas, - coords->x2 - ARROW_DEPTH, - coords->y2 - ARROW_BREADTH, - coords->x2 + ARROW_DEPTH, - coords->y2 + ARROW_BREADTH); - } -} - -static void -ganv_edge_bounds(GanvItem* item, - double* x1, double* y1, - double* x2, double* y2) -{ - GanvEdge* edge = GANV_EDGE(item); - GanvEdgePrivate* impl = edge->impl; - GanvEdgeCoords* coords = &impl->coords; - const double w = coords->width; - - if (coords->curved) { - *x1 = MIN(coords->x1, MIN(coords->cx1, MIN(coords->x2, coords->cx2))) - w; - *y1 = MIN(coords->y1, MIN(coords->cy1, MIN(coords->y2, coords->cy2))) - w; - *x2 = MAX(coords->x1, MAX(coords->cx1, MAX(coords->x2, coords->cx2))) + w; - *y2 = MAX(coords->y1, MAX(coords->cy1, MAX(coords->y2, coords->cy2))) + w; - } else { - *x1 = MIN(impl->coords.x1, impl->coords.x2) - w; - *y1 = MIN(impl->coords.y1, impl->coords.y2) - w; - *x2 = MAX(impl->coords.x1, impl->coords.x2) + w; - *y2 = MAX(impl->coords.y1, impl->coords.y2) + w; - } -} - -void -ganv_edge_get_coords(const GanvEdge* edge, GanvEdgeCoords* coords) -{ - GanvEdgePrivate* impl = edge->impl; - - GANV_NODE_GET_CLASS(impl->tail)->tail_vector( - impl->tail, impl->head, - &coords->x1, &coords->y1, &coords->cx1, &coords->cy1); - GANV_NODE_GET_CLASS(impl->head)->head_vector( - impl->head, impl->tail, - &coords->x2, &coords->y2, &coords->cx2, &coords->cy2); - - const double dx = coords->x2 - coords->x1; - const double dy = coords->y2 - coords->y1; - - coords->handle_x = coords->x1 + (dx / 2.0); - coords->handle_y = coords->y1 + (dy / 2.0); - - const double abs_dx = fabs(dx); - const double abs_dy = fabs(dy); - - coords->cx1 = coords->x1 + (coords->cx1 * (abs_dx / 4.0)); - coords->cy1 = coords->y1 + (coords->cy1 * (abs_dy / 4.0)); - coords->cx2 = coords->x2 + (coords->cx2 * (abs_dx / 4.0)); - coords->cy2 = coords->y2 + (coords->cy2 * (abs_dy / 4.0)); -} - -static void -ganv_edge_update(GanvItem* item, int flags) -{ - GanvEdge* edge = GANV_EDGE(item); - GanvEdgePrivate* impl = edge->impl; - - // Request redraw of old location - ganv_edge_request_redraw(item, &impl->old_coords); - - // Calculate new coordinates from tail and head - ganv_edge_get_coords(edge, &impl->coords); - - // Update old coordinates - impl->old_coords = impl->coords; - - // Get bounding box - double x1, x2, y1, y2; - ganv_edge_bounds(item, &x1, &y1, &x2, &y2); - - // Ensure bounding box has non-zero area - if (x1 == x2) { - x2 += 1.0; - } - if (y1 == y2) { - y2 += 1.0; - } - - // Update world-relative bounding box - item->impl->x1 = x1; - item->impl->y1 = y1; - item->impl->x2 = x2; - item->impl->y2 = y2; - ganv_item_i2w_pair(item, &item->impl->x1, &item->impl->y1, &item->impl->x2, &item->impl->y2); - - // Request redraw of new location - ganv_edge_request_redraw(item, &impl->coords); - - parent_class->update(item, flags); -} - -static void -ganv_edge_draw(GanvItem* item, - cairo_t* cr, double cx, double cy, double cw, double ch) -{ - GanvEdge* edge = GANV_EDGE(item); - GanvEdgePrivate* impl = edge->impl; - - double src_x = impl->coords.x1; - double src_y = impl->coords.y1; - double dst_x = impl->coords.x2; - double dst_y = impl->coords.y2; - double dx = src_x - dst_x; - double dy = src_y - dst_y; - - double r, g, b, a; - if (impl->highlighted) { - color_to_rgba(highlight_color(impl->color, 0x40), &r, &g, &b, &a); - } else { - color_to_rgba(impl->color, &r, &g, &b, &a); - } - cairo_set_source_rgba(cr, r, g, b, a); - - cairo_set_line_width(cr, impl->coords.width); - cairo_move_to(cr, src_x, src_y); - - const double dash_length = (impl->selected ? 4.0 : impl->dash_length); - if (dash_length > 0.0) { - double dashed[2] = { dash_length, dash_length }; - cairo_set_dash(cr, dashed, 2, impl->dash_offset); - } else { - cairo_set_dash(cr, &dash_length, 0, 0); - } - - const double join_x = (src_x + dst_x) / 2.0; - const double join_y = (src_y + dst_y) / 2.0; - - if (impl->coords.curved) { - // Curved line as 2 paths which join at the middle point - - // Path 1 (src_x, src_y) -> (join_x, join_y) - // Control point 1 - const double src_x1 = impl->coords.cx1; - const double src_y1 = impl->coords.cy1; - // Control point 2 - const double src_x2 = (join_x + src_x1) / 2.0; - const double src_y2 = (join_y + src_y1) / 2.0; - - // Path 2, (join_x, join_y) -> (dst_x, dst_y) - // Control point 1 - const double dst_x1 = impl->coords.cx2; - const double dst_y1 = impl->coords.cy2; - // Control point 2 - const double dst_x2 = (join_x + dst_x1) / 2.0; - const double dst_y2 = (join_y + dst_y1) / 2.0; - - cairo_move_to(cr, src_x, src_y); - cairo_curve_to(cr, src_x1, src_y1, src_x2, src_y2, join_x, join_y); - cairo_curve_to(cr, dst_x2, dst_y2, dst_x1, dst_y1, dst_x, dst_y); - -#ifdef GANV_DEBUG_CURVES - cairo_stroke(cr); - cairo_save(cr); - cairo_set_source_rgba(cr, 1.0, 0, 0, 0.5); - - cairo_move_to(cr, src_x, src_y); - cairo_line_to(cr, src_x1, src_y1); - cairo_stroke(cr); - - cairo_move_to(cr, join_x, join_y); - cairo_line_to(cr, src_x2, src_y2); - cairo_stroke(cr); - - cairo_move_to(cr, join_x, join_y); - cairo_line_to(cr, dst_x2, dst_y2); - cairo_stroke(cr); - - cairo_move_to(cr, dst_x, dst_y); - cairo_line_to(cr, dst_x1, dst_y1); - cairo_stroke(cr); - -#ifdef GANV_DEBUG_BOUNDS - double bounds_x1, bounds_y1, bounds_x2, bounds_y2; - ganv_edge_bounds(item, &bounds_x1, &bounds_y1, &bounds_x2, &bounds_y2); - cairo_rectangle(cr, - bounds_x1, bounds_y1, - bounds_x2 - bounds_x1, bounds_y2 - bounds_y1); -#endif - - cairo_restore(cr); -#endif - - cairo_stroke(cr); - if (impl->coords.arrowhead) { - cairo_move_to(cr, dst_x - 12, dst_y - 4); - cairo_line_to(cr, dst_x, dst_y); - cairo_line_to(cr, dst_x - 12, dst_y + 4); - cairo_close_path(cr); - cairo_stroke_preserve(cr); - cairo_fill(cr); - } - - } else { - // Straight line from (x1, y1) to (x2, y2) - cairo_move_to(cr, src_x, src_y); - cairo_line_to(cr, dst_x, dst_y); - cairo_stroke(cr); - - if (impl->coords.arrowhead) { - const double ah = sqrt(dx * dx + dy * dy); - const double adx = dx / ah * 8.0; - const double ady = dy / ah * 8.0; - - cairo_move_to(cr, - dst_x + adx - ady/1.5, - dst_y + ady + adx/1.5); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL); - cairo_line_to(cr, dst_x, dst_y); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_MITER); - cairo_line_to(cr, - dst_x + adx + ady/1.5, - dst_y + ady - adx/1.5); - cairo_close_path(cr); - cairo_stroke_preserve(cr); - cairo_fill(cr); - } - } - - if (!ganv_canvas_exporting(item->impl->canvas) && - impl->coords.handle_radius > 0.0) { - cairo_move_to(cr, join_x, join_y); - cairo_arc(cr, join_x, join_y, impl->coords.handle_radius, 0, 2 * G_PI); - cairo_fill(cr); - } -} - -static double -ganv_edge_point(GanvItem* item, double x, double y, GanvItem** actual_item) -{ - const GanvEdge* edge = GANV_EDGE(item); - const GanvEdgeCoords* coords = &edge->impl->coords; - - const double dx = fabs(x - coords->handle_x); - const double dy = fabs(y - coords->handle_y); - const double d = sqrt((dx * dx) + (dy * dy)); - - *actual_item = item; - - if (d <= coords->handle_radius) { - // Point is inside the handle - return 0.0; - } else { - // Distance from the edge of the handle - return d - (coords->handle_radius + coords->width); - } -} - -gboolean -ganv_edge_is_within(const GanvEdge* edge, - double x1, - double y1, - double x2, - double y2) -{ - const double handle_x = edge->impl->coords.handle_x; - const double handle_y = edge->impl->coords.handle_y; - - return handle_x >= x1 - && handle_x <= x2 - && handle_y >= y1 - && handle_y <= y2; -} - -static void -ganv_edge_class_init(GanvEdgeClass* klass) -{ - GObjectClass* gobject_class = (GObjectClass*)klass; - GtkObjectClass* object_class = (GtkObjectClass*)klass; - GanvItemClass* item_class = (GanvItemClass*)klass; - - parent_class = GANV_ITEM_CLASS(g_type_class_peek_parent(klass)); - - gobject_class->set_property = ganv_edge_set_property; - gobject_class->get_property = ganv_edge_get_property; - - g_object_class_install_property( - gobject_class, PROP_TAIL, g_param_spec_object( - "tail", - _("Tail"), - _("Node this edge starts from."), - GANV_TYPE_NODE, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_HEAD, g_param_spec_object( - "head", - _("Head"), - _("Node this edge ends at."), - GANV_TYPE_NODE, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_WIDTH, g_param_spec_double( - "width", - _("Line width"), - _("Width of edge line."), - 0.0, G_MAXDOUBLE, - 2.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_HANDLE_RADIUS, g_param_spec_double( - "handle-radius", - _("Gandle radius"), - _("Radius of handle in canvas units."), - 0.0, G_MAXDOUBLE, - 4.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_DASH_LENGTH, g_param_spec_double( - "dash-length", - _("Line dash length"), - _("Length of line dashes, or zero for no dashing."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_DASH_OFFSET, g_param_spec_double( - "dash-offset", - _("Line dash offset"), - _("Start offset for line dashes, used for selected animation."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_COLOR, g_param_spec_uint( - "color", - _("Color"), - _("Line color as an RGBA integer."), - 0, G_MAXUINT, - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_CONSTRAINING, g_param_spec_boolean( - "constraining", - _("Constraining"), - _("Whether edge should constrain the layout."), - 1, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_CURVED, g_param_spec_boolean( - "curved", - _("Curved"), - _("Whether line should be curved rather than straight."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_ARROWHEAD, g_param_spec_boolean( - "arrowhead", - _("Arrowhead"), - _("Whether to show an arrowhead at the head of this edge."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_SELECTED, g_param_spec_boolean( - "selected", - _("Selected"), - _("Whether this edge is selected."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_HIGHLIGHTED, g_param_spec_boolean( - "highlighted", - _("Highlighted"), - _("Whether to highlight the edge."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_GHOST, g_param_spec_boolean( - "ghost", - _("Ghost"), - _("Whether this edge is a `ghost', which is an edge that is not " - "added to the canvas data structures. Ghost edges are used for " - "temporary edges that are not considered `real', e.g. the edge " - "made while dragging to make a connection."), - 0, - G_PARAM_READWRITE)); - - object_class->destroy = ganv_edge_destroy; - - item_class->update = ganv_edge_update; - item_class->bounds = ganv_edge_bounds; - item_class->point = ganv_edge_point; - item_class->draw = ganv_edge_draw; -} - -GanvEdge* -ganv_edge_new(GanvCanvas* canvas, - GanvNode* tail, - GanvNode* head, - const char* first_prop_name, ...) -{ - GanvEdge* edge = GANV_EDGE( - g_object_new(ganv_edge_get_type(), NULL)); - - va_list args; - va_start(args, first_prop_name); - ganv_item_construct(&edge->item, - GANV_ITEM(ganv_canvas_root(canvas)), - first_prop_name, args); - va_end(args); - - edge->impl->tail = tail; - edge->impl->head = head; - - if (!edge->impl->color) { - const guint tail_color = GANV_NODE(tail)->impl->fill_color; - g_object_set(G_OBJECT(edge), - "color", EDGE_COLOR(tail_color), - NULL); - } - - if (!edge->impl->ghost) { - ganv_canvas_add_edge(canvas, edge); - } - return edge; -} - -void -ganv_edge_update_location(GanvEdge* edge) -{ - ganv_item_request_update(GANV_ITEM(edge)); -} - -gboolean -ganv_edge_get_constraining(const GanvEdge* edge) -{ - return edge->impl->coords.constraining; -} - -void -ganv_edge_set_constraining(GanvEdge* edge, gboolean constraining) -{ - edge->impl->coords.constraining = constraining; - ganv_edge_request_redraw(GANV_ITEM(edge), &edge->impl->coords); -} - -gboolean -ganv_edge_get_curved(const GanvEdge* edge) -{ - return edge->impl->coords.curved; -} - -void -ganv_edge_set_curved(GanvEdge* edge, gboolean curved) -{ - edge->impl->coords.curved = curved; - ganv_edge_request_redraw(GANV_ITEM(edge), &edge->impl->coords); -} - -void -ganv_edge_set_selected(GanvEdge* edge, gboolean selected) -{ - GanvCanvas* canvas = GANV_CANVAS(edge->item.impl->canvas); - if (selected) { - ganv_canvas_select_edge(canvas, edge); - } else { - ganv_canvas_unselect_edge(canvas, edge); - } -} - -void -ganv_edge_select(GanvEdge* edge) -{ - ganv_edge_set_selected(edge, TRUE); -} - -void -ganv_edge_unselect(GanvEdge* edge) -{ - ganv_edge_set_selected(edge, FALSE); -} - -void -ganv_edge_highlight(GanvEdge* edge) -{ - ganv_edge_set_highlighted(edge, TRUE); -} - -void -ganv_edge_unhighlight(GanvEdge* edge) -{ - ganv_edge_set_highlighted(edge, FALSE); -} - -void -ganv_edge_set_highlighted(GanvEdge* edge, gboolean highlighted) -{ - edge->impl->highlighted = highlighted; - ganv_edge_request_redraw(GANV_ITEM(edge), &edge->impl->coords); -} - -void -ganv_edge_tick(GanvEdge* edge, double seconds) -{ - ganv_item_set(GANV_ITEM(edge), - "dash-offset", seconds * 8.0, - NULL); -} - -void -ganv_edge_disconnect(GanvEdge* edge) -{ - if (!edge->impl->ghost) { - ganv_canvas_disconnect_edge( - GANV_CANVAS(edge->item.impl->canvas), - edge); - } -} - -void -ganv_edge_remove(GanvEdge* edge) -{ - if (!edge->impl->ghost) { - ganv_canvas_remove_edge( - GANV_CANVAS(edge->item.impl->canvas), - edge); - } -} - -GanvNode* -ganv_edge_get_tail(const GanvEdge* edge) -{ - return edge->impl->tail; -} - -GanvNode* -ganv_edge_get_head(const GanvEdge* edge) -{ - return edge->impl->head; -} diff --git a/src/fdgl.hpp b/src/fdgl.hpp deleted file mode 100644 index 38fded1..0000000 --- a/src/fdgl.hpp +++ /dev/null @@ -1,166 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <float.h> -#include <math.h> - -static const double CHARGE_KE = 4000000.0; -static const double EDGE_K = 16.0; -static const double EDGE_LEN = 0.1; - -struct Region { - Vector pos; - Vector area; -}; - -inline Vector -vec_add(const Vector& a, const Vector& b) -{ - const Vector result = { a.x + b.x, a.y + b.y }; - return result; -} - -inline Vector -vec_sub(const Vector& a, const Vector& b) -{ - const Vector result = { a.x - b.x, a.y - b.y }; - return result; -} - -inline Vector -vec_mult(const Vector& a, double m) -{ - const Vector result = { a.x * m, a.y * m }; - return result; -} - -inline double -vec_mult(const Vector& a, const Vector& b) -{ - return a.x * b.x + a.y * b.y; -} - -/** Magnitude. */ -inline double -vec_mag(const Vector& vec) -{ - return sqrt(vec.x * vec.x + vec.y * vec.y); -} - -/** Reciprocal of magnitude. */ -inline double -vec_rmag(const Vector& vec) -{ - return 1.0 / sqrt(vec.x * vec.x + vec.y * vec.y); -} - -/** Hooke's law */ -inline Vector -spring_force(const Vector& a, const Vector& b, double length, double k) -{ - const Vector vec = vec_sub(b, a); - const double mag = vec_mag(vec); - const double displacement = length - mag; - return vec_mult(vec, k * displacement * 0.5 / mag); -} - -/** Spring force with a directional force to align with flow direction. */ -static const Vector -edge_force(const Vector& dir, const Vector& hpos, const Vector& tpos) -{ - return vec_add(dir, spring_force(hpos, tpos, EDGE_LEN, EDGE_K)); -} - -/** Constant tide force, does not vary with distance. */ -inline Vector -tide_force(const Vector& a, const Vector& b, double power) -{ - static const double G = 0.0000000000667; - const Vector vec = vec_sub(a, b); - const double mag = vec_mag(vec); - return vec_mult(vec, G * power / mag); -} - -inline double -rect_distance(Vector* vec, - const double ax1, const double ay1, - const double ax2, const double ay2, - const double bx1, const double by1, - const double bx2, const double by2) -{ - vec->x = 0.0; - vec->y = 0.0; - - if (ax2 <= bx1) { // A is completely to the left of B - vec->x = ax2 - bx1; - if (ay2 <= by1) { // Top Left - const double dx = bx1 - ax2; - const double dy = by1 - ay2; - vec->y = ay2 - by1; - return sqrt(dx * dx + dy * dy); - } else if (ay1 >= by2) { // Bottom left - const double dx = bx1 - ax2; - const double dy = ay1 - by2; - vec->y = ay1 - by2; - return sqrt(dx * dx + dy * dy); - } else { // Left - return bx1 - ax2; - } - } else if (ax1 >= bx2) { // A is completely to the right of B - vec->x = ax1 - bx2; - if (ay2 <= by1) { // Top right - const double dx = ax1 - bx2; - const double dy = by1 - ay2; - vec->y = ay2 - by1; - return sqrt(dx * dx + dy * dy); - } else if (ay1 >= by2) { // Bottom right - const double dx = ax1 - bx2; - const double dy = ay1 - by2; - vec->y = ay1 - by2; - return sqrt(dx * dx + dy * dy); - } else { // Right - return ax1 - bx2; - } - } else if (ay2 <= by1) { // Top - vec->y = ay2 - by1; - return by1 - ay2; - } else if (ay1 >= by2) { // Bottom - vec->y = ay1 - by2; - return ay1 - by2; - } else { // Overlap - return 0.0; - } -} - -/** Repelling charge force, ala Coulomb's law. */ -inline Vector -repel_force(const Region& a, const Region& b) -{ - static const double MIN_DIST = 1.0; - - Vector vec; - double dist = rect_distance( - &vec, - a.pos.x - (a.area.x / 2.0), a.pos.y - (a.area.y / 2.0), - a.pos.x + (a.area.x / 2.0), a.pos.y + (a.area.y / 2.0), - b.pos.x - (b.area.x / 2.0), b.pos.y - (b.area.y / 2.0), - b.pos.x + (b.area.x / 2.0), b.pos.y + (b.area.y / 2.0)); - - if (dist <= MIN_DIST) { - dist = MIN_DIST; - vec = vec_sub(a.pos, b.pos); - } - return vec_mult(vec, (CHARGE_KE * 0.5 / (vec_mag(vec) * dist * dist))); -} diff --git a/src/ganv-marshal.list b/src/ganv-marshal.list deleted file mode 100644 index 64e6c6b..0000000 --- a/src/ganv-marshal.list +++ /dev/null @@ -1,4 +0,0 @@ -BOOLEAN:BOXED -VOID:DOUBLE,DOUBLE -VOID:OBJECT,INT,INT,INT,INT -VOID:OBJECT,OBJECT diff --git a/src/ganv-private.h b/src/ganv-private.h deleted file mode 100644 index df611a9..0000000 --- a/src/ganv-private.h +++ /dev/null @@ -1,403 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_PRIVATE_H -#define GANV_PRIVATE_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include <cairo.h> - -#include "ganv/canvas.h" -#include "ganv/text.h" -#include "ganv/types.h" - -#define GANV_CLOSE_ENOUGH 1 - -extern guint signal_moved; - -/* Box */ - -typedef struct { - double x1, y1, x2, y2; - double border_width; - gboolean stacked; -} GanvBoxCoords; - -struct _GanvBoxPrivate { - GanvBoxCoords coords; - GanvBoxCoords old_coords; - double radius_tl; - double radius_tr; - double radius_br; - double radius_bl; - gboolean beveled; -}; - -/* Circle */ - -typedef struct { - double x, y, radius, radius_ems; - double width; -} GanvCircleCoords; - -struct _GanvCirclePrivate { - GanvCircleCoords coords; - GanvCircleCoords old_coords; - gboolean fit_label; -}; - -/* Edge */ - -typedef struct { - double x1, y1, x2, y2; - double cx1, cy1, cx2, cy2; - double handle_x, handle_y, handle_radius; - double width; - gboolean constraining; - gboolean curved; - gboolean arrowhead; -} GanvEdgeCoords; - -struct _GanvEdgePrivate -{ - GanvNode* tail; - GanvNode* head; - GanvEdgeCoords coords; - GanvEdgeCoords old_coords; - double dash_length; - double dash_offset; - guint color; - gboolean selected; - gboolean highlighted; - gboolean ghost; -}; - -/* Module */ - -struct _GanvModulePrivate -{ - GPtrArray* ports; - GanvItem* embed_item; - int embed_width; - int embed_height; - double widest_input; - double widest_output; - gboolean must_reorder; -}; - -/* Node */ - -#ifdef GANV_FDGL -typedef struct { - double x; - double y; -} Vector; -#endif - -struct _GanvNodePrivate { - struct _GanvNode* partner; - GanvText* label; - double dash_length; - double dash_offset; - double border_width; - guint fill_color; - guint border_color; - gboolean can_tail; - gboolean can_head; - gboolean is_source; - gboolean selected; - gboolean highlighted; - gboolean draggable; - gboolean show_label; - gboolean grabbed; - gboolean must_resize; -#ifdef GANV_FDGL - Vector force; - Vector vel; - gboolean connected; -#endif -}; - -/* Widget */ - -struct _GanvWidgetPrivate { - GtkWidget* widget; /* The child widget */ - - double x, y; /* Position at anchor */ - double width, height; /* Dimensions of widget */ - GtkAnchorType anchor; /* Anchor side for widget */ - - int cx, cy; /* Top-left canvas coordinates for widget */ - int cwidth, cheight; /* Size of widget in pixels */ - - guint destroy_id; /* Signal connection id for destruction of child widget */ - - guint size_pixels : 1; /* Is size specified in (unchanging) pixels or units (get scaled)? */ - guint in_destroy : 1; /* Is child widget being destroyed? */ -}; - -/* Group */ -struct _GanvGroupPrivate { - GList* item_list; - GList* item_list_end; -}; - -/* Item */ -struct _GanvItemPrivate { - /* Parent canvas for this item */ - struct _GanvCanvas* canvas; - - /* Parent for this item */ - GanvItem* parent; - - /* Wrapper object for this item, if any */ - void* wrapper; - - /* Layer (z order), higher values are on top */ - guint layer; - - /* Position in parent-relative coordinates. */ - double x, y; - - /* Bounding box for this item (in world coordinates) */ - double x1, y1, x2, y2; - - /* True if parent manages this item (don't call add/remove) */ - gboolean managed; -}; - -void -ganv_node_tick(GanvNode* self, double seconds); - -void -ganv_node_tail_vector(const GanvNode* self, - const GanvNode* head, - double* x1, - double* y1, - double* x2, - double* y2); - -void -ganv_node_head_vector(const GanvNode* self, - const GanvNode* tail, - double* x1, - double* y1, - double* x2, - double* y2); - -/** - * ganv_node_get_draw_properties: - * - * Get the colours that should currently be used for drawing this node. Note - * these may not be identical to the property values because of highlighting - * and selection. - */ -void -ganv_node_get_draw_properties(const GanvNode* node, - double* dash_length, - double* border_color, - double* fill_color); - -/* Port */ - -typedef struct { - GanvBox* rect; - float value; - float min; - float max; - gboolean is_toggle; - gboolean is_integer; -} GanvPortControl; - -struct _GanvPortPrivate { - GanvPortControl* control; - GanvText* value_label; - gboolean is_input; - gboolean is_controllable; -}; - -/* Text */ - -typedef struct -{ - double x; - double y; - double width; - double height; -} GanvTextCoords; - -struct _GanvTextPrivate -{ - PangoLayout* layout; - char* text; - GanvTextCoords coords; - GanvTextCoords old_coords; - double font_size; - guint color; - gboolean needs_layout; -}; - -/* Canvas */ - -typedef struct { - GanvPortOrderFunc port_cmp; - void* data; -} PortOrderCtx; - -void -ganv_canvas_move_selected_items(GanvCanvas* canvas, - double dx, - double dy); - -void -ganv_canvas_selection_move_finished(GanvCanvas* canvas); - -void -ganv_canvas_add_node(GanvCanvas* canvas, - GanvNode* node); - -void -ganv_canvas_remove_node(GanvCanvas* canvas, - GanvNode* node); - -void -ganv_canvas_select_node(GanvCanvas* canvas, - GanvNode* node); - -void -ganv_canvas_unselect_node(GanvCanvas* canvas, - GanvNode* node); - -void -ganv_canvas_add_edge(GanvCanvas* canvas, - GanvEdge* edge); - -void -ganv_canvas_select_edge(GanvCanvas* canvas, - GanvEdge* edge); - -void -ganv_canvas_unselect_edge(GanvCanvas* canvas, - GanvEdge* edge); - -void -ganv_canvas_disconnect_edge(GanvCanvas* canvas, - GanvEdge* edge); - -gboolean -ganv_canvas_port_event(GanvCanvas* canvas, - GanvPort* port, - GdkEvent* event); - -void -ganv_canvas_contents_changed(GanvCanvas* canvas); - -void -ganv_item_i2w_offset(GanvItem* item, double* px, double* py); - -void -ganv_item_i2w_pair(GanvItem* item, double* x1, double* y1, double* x2, double* y2); - -void -ganv_item_invoke_update(GanvItem* item, int flags); - -void -ganv_item_emit_event(GanvItem* item, GdkEvent* event, gint* finished); - -void -ganv_canvas_request_update(GanvCanvas* canvas); - -int -ganv_canvas_emit_event(GanvCanvas* canvas, GdkEvent* event); - -void -ganv_canvas_set_need_repick(GanvCanvas* canvas); - -void -ganv_canvas_forget_item(GanvCanvas* canvas, GanvItem* item); - -void -ganv_canvas_grab_focus(GanvCanvas* canvas, GanvItem* item); - -void -ganv_canvas_get_zoom_offsets(GanvCanvas* canvas, int* x, int* y); - -int -ganv_canvas_grab_item(GanvItem* item, guint event_mask, GdkCursor* cursor, guint32 etime); - -void -ganv_canvas_ungrab_item(GanvItem* item, guint32 etime); - -/* Request a redraw of the specified rectangle in canvas coordinates */ -void -ganv_canvas_request_redraw_c(GanvCanvas* canvas, - int x1, int y1, int x2, int y2); - -/* Request a redraw of the specified rectangle in world coordinates */ -void -ganv_canvas_request_redraw_w(GanvCanvas* canvas, - double x1, double y1, double x2, double y2); - -PortOrderCtx -ganv_canvas_get_port_order(GanvCanvas* canvas); - -gboolean -ganv_canvas_exporting(GanvCanvas* canvas); - -/* Edge */ - -void -ganv_edge_update_location(GanvEdge* edge); - -void -ganv_edge_get_coords(const GanvEdge* edge, GanvEdgeCoords* coords); - -void -ganv_edge_request_redraw(GanvItem* item, - const GanvEdgeCoords* coords); - -void -ganv_edge_tick(GanvEdge* edge, double seconds); - -/* Box */ - -void -ganv_box_path(GanvBox* box, - cairo_t* cr, double x1, double y1, double x2, double y2, - double dr); - -void -ganv_box_request_redraw(GanvItem* item, - const GanvBoxCoords* coords, - gboolean world); - -/* Port */ - -void -ganv_port_set_control_value_internal(GanvPort* port, - float value); - -void -ganv_port_set_direction(GanvPort* port, - GanvDirection direction); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* GANV_PRIVATE_H */ diff --git a/src/ganv_bench.cpp b/src/ganv_bench.cpp deleted file mode 100644 index b1bdefb..0000000 --- a/src/ganv_bench.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2013 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <glibmm.h> -#include <gtkmm/main.h> -#include <gtkmm/scrolledwindow.h> -#include <gtkmm/window.h> - -#include "ganv/ganv.hpp" - -using namespace std; -using namespace Ganv; - -static const int MAX_NUM_PORTS = 16; - -vector<Node*> ins; -vector<Node*> outs; - -static Module* -make_module(Canvas* canvas) -{ - char name[8]; - - snprintf(name, 8, "mod%d", rand() % 10000); - Module* m(new Module(*canvas, name, - rand() % (int)canvas->get_width(), - rand() % (int)canvas->get_height(), - true)); - - int n_ins = rand() % MAX_NUM_PORTS; - for (int i = 0; i < n_ins; ++i) { - snprintf(name, 8, "in%d", rand() % 10000); - Port* p(new Port(*m, name, true, - ((rand() % 0xFFFFFF) << 8) | 0xFF)); - ins.push_back(p); - } - - int n_outs = rand() % MAX_NUM_PORTS; - for (int i = 0; i < n_outs; ++i) { - snprintf(name, 8, "out%d", rand() % 10000); - Port* p(new Port(*m, name, false, - ((rand() % 0xFFFFFF) << 8) | 0xFF)); - outs.push_back(p); - } - - m->show(); - return m; -} - -static Circle* -make_circle(Canvas* canvas) -{ - char name[8]; - - snprintf(name, 8, "%d", rand() % 10000); - Circle* e(new Circle(*canvas, name, - rand() % (int)canvas->get_width(), - rand() % (int)canvas->get_height())); - - ins.push_back(e); - outs.push_back(e); - - return e; -} - -static bool -quit() -{ - Gtk::Main::quit(); - return true; -} - -static int -print_usage(const char* name) -{ - fprintf(stderr, - "USAGE: %s [OPTION]... CANVAS_W CANVAS_H N_MODULES N_CIRCLES N_EDGES\n\n" - "Options:\n" - " -o Remain open (do not close immediately)\n" - " -a Arrange canvas\n" - " -s Straight edges\n", - name); - return 1; -} - -int -main(int argc, char** argv) -{ - if (argc < 5) { - return print_usage(argv[0]); - } - - int arg = 1; - - bool remain_open = false; - bool arrange = false; - bool straight = false; - for (; arg < argc && argv[arg][0] == '-'; ++arg) { - if (argv[arg][1] == 'o') { - remain_open = true; - } else if (argv[arg][1] == 'a') { - arrange = true; - } else if (argv[arg][1] == 's') { - straight = true; - } else { - return print_usage(argv[0]); - } - } - - const int canvas_w = atoi(argv[arg++]); - const int canvas_h = atoi(argv[arg++]); - - if (argc - arg < 3) { - return print_usage(argv[0]); - } - - const int n_modules = atoi(argv[arg++]); - const int n_circles = atoi(argv[arg++]); - const int n_edges = atoi(argv[arg++]); - - srand(time(NULL)); - - Gtk::Main kit(argc, argv); - - Gtk::Window window; - Gtk::ScrolledWindow* scroller = Gtk::manage(new Gtk::ScrolledWindow()); - - Canvas* canvas = new Canvas(canvas_w, canvas_h); - scroller->add(canvas->widget()); - window.add(*scroller); - - window.show_all(); - - for (int i = 0; i < n_modules; ++i) { - make_module(canvas); - } - - for (int i = 0; i < n_circles; ++i) { - make_circle(canvas); - } - - for (int i = 0; i < n_edges; ++i) { - Node* src = outs[rand() % outs.size()]; - Node* dst = ins[rand() % ins.size()]; - Edge* c = new Edge(*canvas, src, dst, 0x808080FF); - if (straight) { - c->set_curved(false); - } - } - - if (arrange) { - canvas->arrange(); - } - - if (!remain_open) { - Glib::signal_idle().connect(sigc::ptr_fun(quit)); - } - - Gtk::Main::run(window); - - return 0; -} diff --git a/src/ganv_test.c b/src/ganv_test.c deleted file mode 100644 index ec1b0a8..0000000 --- a/src/ganv_test.c +++ /dev/null @@ -1,119 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2013 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <gtk/gtk.h> - -#include "ganv/ganv.h" - -static void -on_window_destroy(GtkWidget* widget, void* data) -{ - gtk_main_quit(); -} - -static void -on_connect(GanvCanvas* canvas, GanvNode* tail, GanvNode* head, void* data) -{ - ganv_edge_new(canvas, tail, head, "color", 0xFFFFFFFF, NULL); -} - -static void -on_disconnect(GanvCanvas* canvas, GanvNode* tail, GanvNode* head, void* data) -{ - ganv_canvas_remove_edge_between(canvas, tail, head); -} - -static void -on_value_changed(GanvPort* port, double value, void* data) -{ - fprintf(stderr, "Value changed: port %p = %lf\n", (void*)port, value); -} - -int -main(int argc, char** argv) -{ - gtk_init(&argc, &argv); - - GtkWindow* win = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); - gtk_window_set_title(win, "Ganv Test"); - g_signal_connect(win, "destroy", - G_CALLBACK(on_window_destroy), NULL); - - GanvCanvas* canvas = ganv_canvas_new(1024, 768); - gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(canvas)); - - GanvCircle* circle = ganv_circle_new(canvas, - "x", 400.0, - "y", 400.0, - "draggable", TRUE, - "label", "state", - "radius", 32.0, - NULL); - ganv_item_show(GANV_ITEM(circle)); - - GanvModule* module = ganv_module_new(canvas, - "x", 10.0, - "y", 10.0, - "draggable", TRUE, - "label", "test", - NULL); - - ganv_port_new(module, FALSE, - "label", "Signal", - NULL); - - GanvPort* cport = ganv_port_new(module, TRUE, - "label", "Control", - NULL); - ganv_port_show_control(cport); - g_signal_connect(cport, "value-changed", - G_CALLBACK(on_value_changed), NULL); - - //GtkWidget* entry = gtk_entry_new(); - //ganv_module_embed(module, entry); - - GanvPort* tport = ganv_port_new(module, TRUE, - "label", "Toggle", - NULL); - ganv_port_show_control(tport); - ganv_port_set_control_is_toggle(tport, TRUE); - - ganv_item_show(GANV_ITEM(module)); - - GanvModule* module2 = ganv_module_new(canvas, - "x", 200.0, - "y", 10.0, - "draggable", TRUE, - "label", "test2", - NULL); - - ganv_port_new(module2, TRUE, - "label", "Signal", - NULL); - - g_signal_connect(canvas, "connect", - G_CALLBACK(on_connect), canvas); - - g_signal_connect(canvas, "disconnect", - G_CALLBACK(on_disconnect), canvas); - - ganv_item_show(GANV_ITEM(module2)); - - gtk_widget_show_all(GTK_WIDGET(win)); - gtk_window_present(win); - gtk_main(); - - return 0; -} diff --git a/src/ganv_test.py b/src/ganv_test.py deleted file mode 100755 index 1ea53c2..0000000 --- a/src/ganv_test.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python - -from gi.repository import Ganv, Gtk - -win = Gtk.Window() -win.set_title("Ganv Python Test") -win.connect("destroy", lambda obj: Gtk.main_quit()) - -canvas = Ganv.Canvas.new(1024, 768) -module = Ganv.Module(canvas=canvas, - label="Test") -# iport = Ganv.Port(module=module, -# is_input=True, -# label="In") -# oport = Ganv.Port(module=module, -# is_input=False, -# label="In") - -win.add(canvas) -win.show_all() -win.present() -Gtk.main() diff --git a/src/gettext.h b/src/gettext.h deleted file mode 100644 index d32bb70..0000000 --- a/src/gettext.h +++ /dev/null @@ -1,26 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2013 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef GANV_GETTEXT_H -#define GANV_GETTEXT_H - -#ifdef ENABLE_NLS -# include <libintl.h> -# define _(str) dgettext("ganv", str) -#else -# define _(str) str -#endif - -#endif /* GANV_GETTEXT_H */ diff --git a/src/group.c b/src/group.c deleted file mode 100644 index 503e57b..0000000 --- a/src/group.c +++ /dev/null @@ -1,446 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -/* Based on GnomeCanvasGroup, by Federico Mena <federico@nuclecu.unam.mx> - * and Raph Levien <raph@gimp.org> - * Copyright 1997-2000 Free Software Foundation - */ - -#include <math.h> - -#include "ganv/canvas.h" -#include "ganv/group.h" - -#include "./gettext.h" -#include "./ganv-private.h" - -enum { - GROUP_PROP_0 -}; - -G_DEFINE_TYPE_WITH_CODE(GanvGroup, ganv_group, GANV_TYPE_ITEM, - G_ADD_PRIVATE(GanvGroup)) - -static GanvItemClass* group_parent_class; - -static void -ganv_group_init(GanvGroup* group) -{ - GanvGroupPrivate* impl = ganv_group_get_instance_private(group); - - group->impl = impl; - group->impl->item_list = NULL; - group->impl->item_list_end = NULL; -} - -static void -ganv_group_set_property(GObject* gobject, guint param_id, - const GValue* value, GParamSpec* pspec) -{ - g_return_if_fail(GANV_IS_GROUP(gobject)); - - switch (param_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, param_id, pspec); - break; - } -} - -static void -ganv_group_get_property(GObject* gobject, guint param_id, - GValue* value, GParamSpec* pspec) -{ - g_return_if_fail(GANV_IS_GROUP(gobject)); - - switch (param_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, param_id, pspec); - break; - } -} - -static void -ganv_group_destroy(GtkObject* object) -{ - GanvGroup* group; - - g_return_if_fail(GANV_IS_GROUP(object)); - - group = GANV_GROUP(object); - - while (group->impl->item_list) { - // child is unref'ed by the child's group_remove(). - gtk_object_destroy(GTK_OBJECT(group->impl->item_list->data)); - } - if (GTK_OBJECT_CLASS(group_parent_class)->destroy) { - (*GTK_OBJECT_CLASS(group_parent_class)->destroy)(object); - } -} - -static void -ganv_group_update(GanvItem* item, int flags) -{ - GanvGroup* group = GANV_GROUP(item); - - double min_x = 0.0; - double min_y = 0.0; - double max_x = 0.0; - double max_y = 0.0; - - for (GList* list = group->impl->item_list; list; list = list->next) { - GanvItem* i = (GanvItem*)list->data; - - ganv_item_invoke_update(i, flags); - - min_x = fmin(min_x, fmin(i->impl->x1, i->impl->x2)); - min_y = fmin(min_y, fmin(i->impl->y1, i->impl->y2)); - max_x = fmax(max_x, fmax(i->impl->x1, i->impl->x2)); - max_y = fmax(max_y, fmax(i->impl->y2, i->impl->y2)); - } - item->impl->x1 = min_x; - item->impl->y1 = min_y; - item->impl->x2 = max_x; - item->impl->y2 = max_y; - - (*group_parent_class->update)(item, flags); -} - -static void -ganv_group_realize(GanvItem* item) -{ - GanvGroup* group; - GList* list; - GanvItem* i; - - group = GANV_GROUP(item); - - for (list = group->impl->item_list; list; list = list->next) { - i = (GanvItem*)list->data; - - if (!(i->object.flags & GANV_ITEM_REALIZED)) { - (*GANV_ITEM_GET_CLASS(i)->realize)(i); - } - } - - (*group_parent_class->realize)(item); -} - -static void -ganv_group_unrealize(GanvItem* item) -{ - GanvGroup* group; - GList* list; - GanvItem* i; - - group = GANV_GROUP(item); - - for (list = group->impl->item_list; list; list = list->next) { - i = (GanvItem*)list->data; - - if (i->object.flags & GANV_ITEM_REALIZED) { - (*GANV_ITEM_GET_CLASS(i)->unrealize)(i); - } - } - - (*group_parent_class->unrealize)(item); -} - -static void -ganv_group_map(GanvItem* item) -{ - GanvGroup* group; - GList* list; - GanvItem* i; - - group = GANV_GROUP(item); - - for (list = group->impl->item_list; list; list = list->next) { - i = (GanvItem*)list->data; - - if (!(i->object.flags & GANV_ITEM_MAPPED)) { - (*GANV_ITEM_GET_CLASS(i)->map)(i); - } - } - - (*group_parent_class->map)(item); -} - -static void -ganv_group_unmap(GanvItem* item) -{ - GanvGroup* group; - GList* list; - GanvItem* i; - - group = GANV_GROUP(item); - - for (list = group->impl->item_list; list; list = list->next) { - i = (GanvItem*)list->data; - - if (i->object.flags & GANV_ITEM_MAPPED) { - (*GANV_ITEM_GET_CLASS(i)->unmap)(i); - } - } - - (*group_parent_class->unmap)(item); -} - -static void -ganv_group_draw(GanvItem* item, - cairo_t* cr, double cx, double cy, double cw, double ch) -{ - GanvGroup* group = GANV_GROUP(item); - - // TODO: Layered drawing - - for (GList* list = group->impl->item_list; list; list = list->next) { - GanvItem* child = (GanvItem*)list->data; - - if (((child->object.flags & GANV_ITEM_VISIBLE) - && ((child->impl->x1 < (cx + cw)) - && (child->impl->y1 < (cy + ch)) - && (child->impl->x2 > cx) - && (child->impl->y2 > cy)))) { - if (GANV_ITEM_GET_CLASS(child)->draw) { - (*GANV_ITEM_GET_CLASS(child)->draw)( - child, cr, cx, cy, cw, ch); - } - } - } -} - -static double -ganv_group_point(GanvItem* item, double x, double y, GanvItem** actual_item) -{ - GanvGroup* group = GANV_GROUP(item); - - const double x1 = x - GANV_CLOSE_ENOUGH; - const double y1 = y - GANV_CLOSE_ENOUGH; - const double x2 = x + GANV_CLOSE_ENOUGH; - const double y2 = y + GANV_CLOSE_ENOUGH; - - double dist = 0.0; - double best = 0.0; - - *actual_item = NULL; - - for (GList* list = group->impl->item_list; list; list = list->next) { - GanvItem* child = (GanvItem*)list->data; - if ((child->impl->x1 > x2) || (child->impl->y1 > y2) || (child->impl->x2 < x1) || (child->impl->y2 < y1)) { - continue; - } - - GanvItem* point_item = NULL; - - int has_point = FALSE; - if ((child->object.flags & GANV_ITEM_VISIBLE) - && GANV_ITEM_GET_CLASS(child)->point) { - dist = GANV_ITEM_GET_CLASS(child)->point( - child, - x - child->impl->x, y - child->impl->y, - &point_item); - has_point = TRUE; - } - - if (has_point - && point_item - && ((int)(dist + 0.5) <= GANV_CLOSE_ENOUGH)) { - best = dist; - *actual_item = point_item; - } - } - - if (*actual_item) { - return best; - } else { - *actual_item = item; - return 0.0; - } -} - -/* Get bounds of child item in group-relative coordinates. */ -static void -get_child_bounds(GanvItem* child, double* x1, double* y1, double* x2, double* y2) -{ - ganv_item_get_bounds(child, x1, y1, x2, y2); - - // Make bounds relative to the item's parent coordinate system - *x1 -= child->impl->x; - *y1 -= child->impl->y; - *x2 -= child->impl->x; - *y2 -= child->impl->y; -} - -static void -ganv_group_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2) -{ - GanvGroup* group; - GanvItem* child; - GList* list; - double tx1, ty1, tx2, ty2; - double minx, miny, maxx, maxy; - int set; - - group = GANV_GROUP(item); - - /* Get the bounds of the first visible item */ - - child = NULL; /* Unnecessary but eliminates a warning. */ - - set = FALSE; - - for (list = group->impl->item_list; list; list = list->next) { - child = (GanvItem*)list->data; - - if (child->object.flags & GANV_ITEM_VISIBLE) { - set = TRUE; - get_child_bounds(child, &minx, &miny, &maxx, &maxy); - break; - } - } - - /* If there were no visible items, return an empty bounding box */ - - if (!set) { - *x1 = *y1 = *x2 = *y2 = 0.0; - return; - } - - /* Now we can grow the bounds using the rest of the items */ - - list = list->next; - - for (; list; list = list->next) { - child = (GanvItem*)list->data; - - if (!(child->object.flags & GANV_ITEM_VISIBLE)) { - continue; - } - - get_child_bounds(child, &tx1, &ty1, &tx2, &ty2); - - if (tx1 < minx) { - minx = tx1; - } - - if (ty1 < miny) { - miny = ty1; - } - - if (tx2 > maxx) { - maxx = tx2; - } - - if (ty2 > maxy) { - maxy = ty2; - } - } - - *x1 = minx; - *y1 = miny; - *x2 = maxx; - *y2 = maxy; -} - -static void -ganv_group_add(GanvItem* parent, GanvItem* item) -{ - GanvGroup* group = GANV_GROUP(parent); - g_object_ref_sink(G_OBJECT(item)); - - if (!group->impl->item_list) { - group->impl->item_list = g_list_append(group->impl->item_list, item); - group->impl->item_list_end = group->impl->item_list; - } else { - group->impl->item_list_end = g_list_append(group->impl->item_list_end, item)->next; - } - - if (group->item.object.flags & GANV_ITEM_REALIZED) { - (*GANV_ITEM_GET_CLASS(item)->realize)(item); - } - - if (group->item.object.flags & GANV_ITEM_MAPPED) { - (*GANV_ITEM_GET_CLASS(item)->map)(item); - } - - g_object_notify(G_OBJECT(item), "parent"); -} - -static void -ganv_group_remove(GanvItem* parent, GanvItem* item) -{ - GanvGroup* group = GANV_GROUP(parent); - GList* children; - - g_return_if_fail(GANV_IS_GROUP(group)); - g_return_if_fail(GANV_IS_ITEM(item)); - - for (children = group->impl->item_list; children; children = children->next) { - if (children->data == item) { - if (item->object.flags & GANV_ITEM_MAPPED) { - (*GANV_ITEM_GET_CLASS(item)->unmap)(item); - } - - if (item->object.flags & GANV_ITEM_REALIZED) { - (*GANV_ITEM_GET_CLASS(item)->unrealize)(item); - } - - /* Unparent the child */ - - item->impl->parent = NULL; - g_object_unref(G_OBJECT(item)); - - /* Remove it from the list */ - - if (children == group->impl->item_list_end) { - group->impl->item_list_end = children->prev; - } - - group->impl->item_list = g_list_remove_link(group->impl->item_list, children); - g_list_free(children); - break; - } - } -} - -static void -ganv_group_class_init(GanvGroupClass* klass) -{ - GObjectClass* gobject_class; - GtkObjectClass* object_class; - GanvItemClass* item_class; - - gobject_class = (GObjectClass*)klass; - object_class = (GtkObjectClass*)klass; - item_class = (GanvItemClass*)klass; - - group_parent_class = (GanvItemClass*)g_type_class_peek_parent(klass); - - gobject_class->set_property = ganv_group_set_property; - gobject_class->get_property = ganv_group_get_property; - - object_class->destroy = ganv_group_destroy; - - item_class->add = ganv_group_add; - item_class->remove = ganv_group_remove; - item_class->update = ganv_group_update; - item_class->realize = ganv_group_realize; - item_class->unrealize = ganv_group_unrealize; - item_class->map = ganv_group_map; - item_class->unmap = ganv_group_unmap; - item_class->draw = ganv_group_draw; - item_class->point = ganv_group_point; - item_class->bounds = ganv_group_bounds; -} diff --git a/src/item.c b/src/item.c deleted file mode 100644 index a458acd..0000000 --- a/src/item.c +++ /dev/null @@ -1,707 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2016 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -/* Based on GnomeCanvas, by Federico Mena <federico@nuclecu.unam.mx> - * and Raph Levien <raph@gimp.org> - * Copyright 1997-2000 Free Software Foundation - */ - -#include "ganv/canvas.h" -#include "ganv/node.h" - -#include "./boilerplate.h" -#include "./ganv-marshal.h" -#include "./ganv-private.h" -#include "./gettext.h" - -/* All canvas items are derived from GanvItem. The only information a GanvItem - * contains is its parent canvas, its parent canvas item, its bounding box in - * world coordinates, and its current affine transformation. - * - * Items inside a canvas are organized in a tree, where leaves are items - * without any children. Each canvas has a single root item, which can be - * obtained with the ganv_canvas_base_get_root() function. - * - * The abstract GanvItem class does not have any configurable or queryable - * attributes. - */ - -/* Update flags for items */ -enum { - GANV_CANVAS_UPDATE_REQUESTED = 1 << 0, - GANV_CANVAS_UPDATE_AFFINE = 1 << 1, - GANV_CANVAS_UPDATE_VISIBILITY = 1 << 2 -}; - -#define GCI_UPDATE_MASK (GANV_CANVAS_UPDATE_REQUESTED \ - | GANV_CANVAS_UPDATE_AFFINE \ - | GANV_CANVAS_UPDATE_VISIBILITY) - -enum { - ITEM_PROP_0, - ITEM_PROP_PARENT, - ITEM_PROP_X, - ITEM_PROP_Y, - ITEM_PROP_MANAGED -}; - -enum { - ITEM_EVENT, - ITEM_LAST_SIGNAL -}; - -static guint item_signals[ITEM_LAST_SIGNAL]; - -G_DEFINE_TYPE_WITH_CODE(GanvItem, ganv_item, GTK_TYPE_OBJECT, - G_ADD_PRIVATE(GanvItem)) - -static GtkObjectClass* item_parent_class; - -/* Object initialization function for GanvItem */ -static void -ganv_item_init(GanvItem* item) -{ - GanvItemPrivate* impl = ganv_item_get_instance_private(item); - - item->object.flags |= GANV_ITEM_VISIBLE; - item->impl = impl; - item->impl->managed = FALSE; - item->impl->wrapper = NULL; -} - -/** - * ganv_item_new: - * @parent: The parent group for the new item. - * @type: The object type of the item. - * @first_arg_name: A list of object argument name/value pairs, NULL-terminated, - * used to configure the item. For example, "fill_color", "black", - * "width_units", 5.0, NULL. - * @...: first argument value, second argument name, second argument value, ... - * - * Creates a new canvas item with @parent as its parent group. The item is - * created at the top of its parent's stack, and starts up as visible. The item - * is of the specified @type, for example, it can be - * ganv_canvas_rect_get_type(). The list of object arguments/value pairs is - * used to configure the item. If you need to pass construct time parameters, you - * should use g_object_new() to pass the parameters and - * ganv_item_construct() to set up the canvas item. - * - * Return value: (transfer full): The newly-created item. - **/ -GanvItem* -ganv_item_new(GanvItem* parent, GType type, const gchar* first_arg_name, ...) -{ - g_return_val_if_fail(g_type_is_a(type, ganv_item_get_type()), NULL); - - GanvItem* item = GANV_ITEM(g_object_new(type, NULL)); - - va_list args; - va_start(args, first_arg_name); - ganv_item_construct(item, parent, first_arg_name, args); - va_end(args); - - return item; -} - -/* Performs post-creation operations on a canvas item (adding it to its parent - * group, etc.) - */ -static void -item_post_create_setup(GanvItem* item) -{ - GanvItemClass* parent_class = GANV_ITEM_GET_CLASS(item->impl->parent); - if (!item->impl->managed) { - if (parent_class->add) { - parent_class->add(item->impl->parent, item); - } else { - g_warning("item added to non-parent item\n"); - } - } - ganv_canvas_request_redraw_w(item->impl->canvas, - item->impl->x1, item->impl->y1, - item->impl->x2 + 1, item->impl->y2 + 1); - ganv_canvas_set_need_repick(item->impl->canvas); -} - -static void -ganv_item_set_property(GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_ITEM(object)); - - GanvItem* item = GANV_ITEM(object); - - switch (prop_id) { - case ITEM_PROP_PARENT: - if (item->impl->parent != NULL) { - g_warning("Cannot set `parent' argument after item has " - "already been constructed."); - } else if (g_value_get_object(value)) { - item->impl->parent = GANV_ITEM(g_value_get_object(value)); - item->impl->canvas = item->impl->parent->impl->canvas; - item_post_create_setup(item); - } - break; - case ITEM_PROP_X: - item->impl->x = g_value_get_double(value); - ganv_item_request_update(item); - break; - case ITEM_PROP_Y: - item->impl->y = g_value_get_double(value); - ganv_item_request_update(item); - break; - case ITEM_PROP_MANAGED: - item->impl->managed = g_value_get_boolean(value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_item_get_property(GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_ITEM(object)); - - GanvItem* item = GANV_ITEM(object); - - switch (prop_id) { - case ITEM_PROP_PARENT: - g_value_set_object(value, item->impl->parent); - break; - case ITEM_PROP_X: - g_value_set_double(value, item->impl->x); - break; - case ITEM_PROP_Y: - g_value_set_double(value, item->impl->y); - break; - case ITEM_PROP_MANAGED: - g_value_set_boolean(value, item->impl->managed); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/** - * ganv_item_construct: - * @item: An unconstructed canvas item. - * @parent: The parent group for the item. - * @first_arg_name: The name of the first argument for configuring the item. - * @args: The list of arguments used to configure the item. - * - * Constructs a canvas item; meant for use only by item implementations. - **/ -void -ganv_item_construct(GanvItem* item, GanvItem* parent, - const gchar* first_arg_name, va_list args) -{ - g_return_if_fail(GANV_IS_ITEM(item)); - - item->impl->parent = parent; - item->impl->wrapper = NULL; - item->impl->canvas = item->impl->parent->impl->canvas; - item->impl->layer = 0; - - g_object_set_valist(G_OBJECT(item), first_arg_name, args); - - item_post_create_setup(item); -} - -/* If the item is visible, requests a redraw of it. */ -static void -redraw_if_visible(GanvItem* item) -{ - if (item->object.flags & GANV_ITEM_VISIBLE) { - ganv_canvas_request_redraw_w(item->impl->canvas, - item->impl->x1, item->impl->y1, - item->impl->x2 + 1, item->impl->y2 + 1); - } -} - -/* Standard object dispose function for canvas items */ -static void -ganv_item_dispose(GObject* object) -{ - GanvItem* item; - - g_return_if_fail(GANV_IS_ITEM(object)); - - item = GANV_ITEM(object); - - if (item->impl->canvas) { - redraw_if_visible(item); - ganv_canvas_forget_item(item->impl->canvas, item); - } - - /* Normal destroy stuff */ - - if (item->object.flags & GANV_ITEM_MAPPED) { - (*GANV_ITEM_GET_CLASS(item)->unmap)(item); - } - - if (item->object.flags & GANV_ITEM_REALIZED) { - (*GANV_ITEM_GET_CLASS(item)->unrealize)(item); - } - - if (!item->impl->managed && item->impl->parent) { - if (GANV_ITEM_GET_CLASS(item->impl->parent)->remove) { - GANV_ITEM_GET_CLASS(item->impl->parent)->remove(item->impl->parent, item); - } else { - fprintf(stderr, "warning: Item parent has no remove method\n"); - } - } - - G_OBJECT_CLASS(item_parent_class)->dispose(object); - /* items should remove any reference to item->impl->canvas after the - first ::destroy */ - item->impl->canvas = NULL; -} - -/* Realize handler for canvas items */ -static void -ganv_item_realize(GanvItem* item) -{ - GTK_OBJECT_SET_FLAGS(item, GANV_ITEM_REALIZED); - - ganv_item_request_update(item); -} - -/* Unrealize handler for canvas items */ -static void -ganv_item_unrealize(GanvItem* item) -{ - GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_REALIZED); -} - -/* Map handler for canvas items */ -static void -ganv_item_map(GanvItem* item) -{ - GTK_OBJECT_SET_FLAGS(item, GANV_ITEM_MAPPED); -} - -/* Unmap handler for canvas items */ -static void -ganv_item_unmap(GanvItem* item) -{ - GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_MAPPED); -} - -/* Update handler for canvas items */ -static void -ganv_item_update(GanvItem* item, int flags) -{ - GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_NEED_UPDATE); - GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_NEED_VIS); -} - -/* Point handler for canvas items */ -static double -ganv_item_point(GanvItem* item, double x, double y, GanvItem** actual_item) -{ - *actual_item = NULL; - return G_MAXDOUBLE; -} - -void -ganv_item_invoke_update(GanvItem* item, int flags) -{ - int child_flags = flags; - - /* apply object flags to child flags */ - - child_flags &= ~GANV_CANVAS_UPDATE_REQUESTED; - - if (item->object.flags & GANV_ITEM_NEED_UPDATE) { - child_flags |= GANV_CANVAS_UPDATE_REQUESTED; - } - - if (item->object.flags & GANV_ITEM_NEED_VIS) { - child_flags |= GANV_CANVAS_UPDATE_VISIBILITY; - } - - if (child_flags & GCI_UPDATE_MASK) { - if (GANV_ITEM_GET_CLASS(item)->update) { - GANV_ITEM_GET_CLASS(item)->update(item, child_flags); - g_assert(!(GTK_OBJECT_FLAGS(item) & GANV_ITEM_NEED_UPDATE)); - } - } -} - -/** - * ganv_item_set: - * @item: A canvas item. - * @first_arg_name: The list of object argument name/value pairs used to configure the item. - * @...: first argument value, second argument name, second argument value, ... - * - * Configures a canvas item. The arguments in the item are set to the specified - * values, and the item is repainted as appropriate. - **/ -void -ganv_item_set(GanvItem* item, const gchar* first_arg_name, ...) -{ - va_list args; - - va_start(args, first_arg_name); - ganv_item_set_valist(item, first_arg_name, args); - va_end(args); -} - -/** - * ganv_item_set_valist: - * @item: A canvas item. - * @first_arg_name: The name of the first argument used to configure the item. - * @args: The list of object argument name/value pairs used to configure the item. - * - * Configures a canvas item. The arguments in the item are set to the specified - * values, and the item is repainted as appropriate. - **/ -void -ganv_item_set_valist(GanvItem* item, const gchar* first_arg_name, va_list args) -{ - g_return_if_fail(GANV_IS_ITEM(item)); - - g_object_set_valist(G_OBJECT(item), first_arg_name, args); - - ganv_canvas_set_need_repick(item->impl->canvas); -} - -GanvCanvas* -ganv_item_get_canvas(GanvItem* item) -{ - return item->impl->canvas; -} - -GanvItem* -ganv_item_get_parent(GanvItem* item) -{ - return item->impl->parent; -} - -void -ganv_item_raise(GanvItem* item) -{ - ++item->impl->layer; -} - -void -ganv_item_lower(GanvItem* item) -{ - --item->impl->layer; -} - -/** - * ganv_item_move: - * @item: A canvas item. - * @dx: Horizontal offset. - * @dy: Vertical offset. - **/ -void -ganv_item_move(GanvItem* item, double dx, double dy) -{ - if (!item || !GANV_IS_ITEM(item)) { - return; - } - - item->impl->x += dx; - item->impl->y += dy; - - ganv_item_request_update(item); - ganv_canvas_set_need_repick(item->impl->canvas); -} - -/** - * ganv_item_show: - * @item: A canvas item. - * - * Shows a canvas item. If the item was already shown, then no action is taken. - **/ -void -ganv_item_show(GanvItem* item) -{ - g_return_if_fail(GANV_IS_ITEM(item)); - - if (!(item->object.flags & GANV_ITEM_VISIBLE)) { - item->object.flags |= GANV_ITEM_VISIBLE; - ganv_canvas_request_redraw_w(item->impl->canvas, - item->impl->x1, item->impl->y1, - item->impl->x2 + 1, item->impl->y2 + 1); - ganv_canvas_set_need_repick(item->impl->canvas); - } -} - -/** - * ganv_item_hide: - * @item: A canvas item. - * - * Hides a canvas item. If the item was already hidden, then no action is - * taken. - **/ -void -ganv_item_hide(GanvItem* item) -{ - g_return_if_fail(GANV_IS_ITEM(item)); - - if (item->object.flags & GANV_ITEM_VISIBLE) { - item->object.flags &= ~GANV_ITEM_VISIBLE; - ganv_canvas_request_redraw_w(item->impl->canvas, - item->impl->x1, item->impl->y1, - item->impl->x2 + 1, item->impl->y2 + 1); - ganv_canvas_set_need_repick(item->impl->canvas); - } -} - -void -ganv_item_i2w_offset(GanvItem* item, double* px, double* py) -{ - double x = 0.0; - double y = 0.0; - while (item) { - x += item->impl->x; - y += item->impl->y; - item = item->impl->parent; - } - *px = x; - *py = y; -} - -/** - * ganv_item_i2w: - * @item: A canvas item. - * @x: X coordinate to convert (input/output value). - * @y: Y coordinate to convert (input/output value). - * - * Converts a coordinate pair from item-relative coordinates to world - * coordinates. - **/ -void -ganv_item_i2w(GanvItem* item, double* x, double* y) -{ - /*g_return_if_fail(GANV_IS_ITEM(item)); - g_return_if_fail(x != NULL); - g_return_if_fail(y != NULL);*/ - - double off_x; - double off_y; - ganv_item_i2w_offset(item, &off_x, &off_y); - - *x += off_x; - *y += off_y; -} - -void -ganv_item_i2w_pair(GanvItem* item, double* x1, double* y1, double* x2, double* y2) -{ - double off_x; - double off_y; - ganv_item_i2w_offset(item, &off_x, &off_y); - - *x1 += off_x; - *y1 += off_y; - *x2 += off_x; - *y2 += off_y; -} - -/** - * ganv_item_w2i: - * @item: A canvas item. - * @x: X coordinate to convert (input/output value). - * @y: Y coordinate to convert (input/output value). - * - * Converts a coordinate pair from world coordinates to item-relative - * coordinates. - **/ -void -ganv_item_w2i(GanvItem* item, double* x, double* y) -{ - double off_x; - double off_y; - ganv_item_i2w_offset(item, &off_x, &off_y); - - *x -= off_x; - *y -= off_y; -} - -/** - * ganv_item_grab_focus: - * @item: A canvas item. - * - * Makes the specified item take the keyboard focus, so all keyboard events will - * be sent to it. If the canvas widget itself did not have the focus, it grabs - * it as well. - **/ -void -ganv_item_grab_focus(GanvItem* item) -{ - ganv_canvas_grab_focus(item->impl->canvas, item); -} - -void -ganv_item_emit_event(GanvItem* item, GdkEvent* event, gint* finished) -{ - g_signal_emit(item, item_signals[ITEM_EVENT], 0, event, finished); -} - -static void -ganv_item_default_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2) -{ - *x1 = *y1 = *x2 = *y2 = 0.0; -} - -/** - * ganv_item_get_bounds: - * @item: A canvas item. - * @x1: Leftmost edge of the bounding box (return value). - * @y1: Upper edge of the bounding box (return value). - * @x2: Rightmost edge of the bounding box (return value). - * @y2: Lower edge of the bounding box (return value). - * - * Queries the bounding box of a canvas item. The bounding box may not be - * exactly tight, but the canvas items will do the best they can. The bounds - * are returned in the coordinate system of the item's parent. - **/ -void -ganv_item_get_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2) -{ - GANV_ITEM_GET_CLASS(item)->bounds(item, x1, y1, x2, y2); -} - -/** - * ganv_item_request_update: - * @item: A canvas item. - * - * To be used only by item implementations. Requests that the canvas queue an - * update for the specified item. - **/ -void -ganv_item_request_update(GanvItem* item) -{ - if (!item->impl->canvas) { - /* Item is being / has been destroyed, ignore */ - return; - } - - item->object.flags |= GANV_ITEM_NEED_UPDATE; - - if (item->impl->parent != NULL && - !(item->impl->parent->object.flags & GANV_ITEM_NEED_UPDATE)) { - /* Recurse up the tree */ - ganv_item_request_update(item->impl->parent); - } else { - /* Have reached the top of the tree, make sure the update call gets scheduled. */ - ganv_canvas_request_update(item->impl->canvas); - } -} - -void -ganv_item_set_wrapper(GanvItem* item, void* wrapper) -{ - item->impl->wrapper = wrapper; -} - -void* -ganv_item_get_wrapper(GanvItem* item) -{ - return item->impl->wrapper; -} - -static gboolean -boolean_handled_accumulator(GSignalInvocationHint* ihint, - GValue* return_accu, - const GValue* handler_return, - gpointer dummy) -{ - gboolean continue_emission; - gboolean signal_handled; - - signal_handled = g_value_get_boolean(handler_return); - g_value_set_boolean(return_accu, signal_handled); - continue_emission = !signal_handled; - - return continue_emission; -} - -/* Class initialization function for GanvItemClass */ -static void -ganv_item_class_init(GanvItemClass* klass) -{ - GObjectClass* gobject_class; - - gobject_class = (GObjectClass*)klass; - - item_parent_class = (GtkObjectClass*)g_type_class_peek_parent(klass); - - gobject_class->set_property = ganv_item_set_property; - gobject_class->get_property = ganv_item_get_property; - - g_object_class_install_property - (gobject_class, ITEM_PROP_PARENT, - g_param_spec_object("parent", NULL, NULL, - GANV_TYPE_ITEM, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE))); - - g_object_class_install_property - (gobject_class, ITEM_PROP_X, - g_param_spec_double("x", - _("X"), - _("X"), - -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE))); - g_object_class_install_property - (gobject_class, ITEM_PROP_Y, - g_param_spec_double("y", - _("Y"), - _("Y"), - -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE))); - - g_object_class_install_property - (gobject_class, ITEM_PROP_MANAGED, - g_param_spec_boolean("managed", - _("Managed"), - _("Whether the item is managed by its parent"), - 0, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE))); - - item_signals[ITEM_EVENT] - = g_signal_new("event", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET(GanvItemClass, event), - boolean_handled_accumulator, NULL, - ganv_marshal_BOOLEAN__BOXED, - G_TYPE_BOOLEAN, 1, - GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); - - gobject_class->dispose = ganv_item_dispose; - - klass->realize = ganv_item_realize; - klass->unrealize = ganv_item_unrealize; - klass->map = ganv_item_map; - klass->unmap = ganv_item_unmap; - klass->update = ganv_item_update; - klass->point = ganv_item_point; - klass->bounds = ganv_item_default_bounds; -} diff --git a/src/module.c b/src/module.c deleted file mode 100644 index bad930b..0000000 --- a/src/module.c +++ /dev/null @@ -1,859 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2016 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <stdlib.h> -#include <string.h> - -#include "ganv/canvas.h" -#include "ganv/module.h" -#include "ganv/port.h" -#include "ganv/widget.h" - -#include "./color.h" -#include "./boilerplate.h" -#include "./gettext.h" -#include "./ganv-private.h" - -#define FOREACH_PORT(ports, i) \ - for (GanvPort** i = (GanvPort**)ports->pdata; \ - i != (GanvPort**)ports->pdata + ports->len; ++i) - -#define FOREACH_PORT_CONST(ports, i) \ - for (const GanvPort** i = (const GanvPort**)ports->pdata; \ - i != (const GanvPort**)ports->pdata + ports->len; ++i) - -static const double PAD = 2.0; -static const double EDGE_PAD = 5.0; -static const double MODULE_LABEL_PAD = 2.0; - -G_DEFINE_TYPE_WITH_CODE(GanvModule, ganv_module, GANV_TYPE_BOX, - G_ADD_PRIVATE(GanvModule)) - -static GanvBoxClass* parent_class; - -enum { - PROP_0 -}; - -static void -ganv_module_init(GanvModule* module) -{ - GanvModulePrivate* impl = ganv_module_get_instance_private(module); - - module->impl = impl; - - GANV_NODE(module)->impl->can_head = FALSE; - GANV_NODE(module)->impl->can_tail = FALSE; - - impl->ports = g_ptr_array_new(); - impl->embed_item = NULL; - impl->embed_width = 0; - impl->embed_height = 0; - impl->widest_input = 0.0; - impl->widest_output = 0.0; - impl->must_reorder = FALSE; -} - -static void -ganv_module_destroy(GtkObject* object) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_MODULE(object)); - - GanvModule* module = GANV_MODULE(object); - GanvModulePrivate* impl = module->impl; - - if (impl->ports) { - FOREACH_PORT(impl->ports, p) { - g_object_unref(GTK_OBJECT(*p)); - } - g_ptr_array_free(impl->ports, TRUE); - impl->ports = NULL; - } - - if (impl->embed_item) { - g_object_unref(GTK_OBJECT(impl->embed_item)); - impl->embed_item = NULL; - } - - if (GTK_OBJECT_CLASS(parent_class)->destroy) { - (*GTK_OBJECT_CLASS(parent_class)->destroy)(object); - } -} - -static void -ganv_module_set_property(GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_MODULE(object)); - - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_module_get_property(GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_MODULE(object)); - - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -typedef struct { - double embed_x; - double width; - double input_width; - double output_width; - gboolean horiz; - gboolean embed_between; -} Metrics; - -static void -title_size(GanvModule* module, double* w, double* h) -{ - if (module->box.node.impl->label) { - g_object_get(G_OBJECT(module->box.node.impl->label), - "width", w, - "height", h, - NULL); - } else { - *w = *h = 0.0; - } -} - -static void -measure(GanvModule* module, Metrics* m) -{ - memset(m, '\0', sizeof(Metrics)); - - double title_w, title_h; - title_size(module, &title_w, &title_h); - - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module)); - GanvText* canvas_title = GANV_NODE(module)->impl->label; - GanvModulePrivate* impl = module->impl; - - if (ganv_canvas_get_direction(canvas) == GANV_DIRECTION_DOWN) { - double contents_width = 0.0; - if (canvas_title) { - contents_width += title_w + (2.0 * PAD); - } - - m->embed_x = 0; - m->input_width = ganv_module_get_empty_port_breadth(module); - m->output_width = ganv_module_get_empty_port_breadth(module); - - // TODO: cache this or merge with resize_right - unsigned n_inputs = 0; - unsigned n_outputs = 0; - FOREACH_PORT(impl->ports, pi) { - if ((*pi)->impl->is_input) { - ++n_inputs; - } else { - ++n_outputs; - } - } - - const unsigned hor_ports = MAX(1, MAX(n_inputs, n_outputs)); - const double ports_width = (2 * EDGE_PAD) + - ((m->input_width) * hor_ports) + - ((PAD + 1.0) * (hor_ports - 1)); - - m->width = MAX(contents_width, ports_width); - m->width = MAX(m->width, impl->embed_width); - - if (impl->embed_item) { - m->width = MAX(impl->embed_width + 2.0 * PAD, m->width); - m->embed_x = PAD; - } - return; - } - - // The amount of space between a port edge and the module edge (on the - // side that the port isn't right on the edge). - const double hor_pad = (canvas_title ? 10.0 : 20.0); - - m->width = (canvas_title) ? title_w + 10.0 : 1.0; - - // Title is wide or there is an embedded widget, - // put inputs and outputs beside each other - m->horiz = (impl->embed_item || - (impl->widest_input + impl->widest_output + 10.0 - < MAX(m->width, impl->embed_width))); - - // Fit ports to module (or vice-versa) - m->input_width = impl->widest_input; - m->output_width = impl->widest_output; - double expand_w = (m->horiz ? (m->width / 2.0) : m->width) - hor_pad; - if (!impl->embed_item) { - m->input_width = MAX(impl->widest_input, expand_w); - m->output_width = MAX(impl->widest_output, expand_w); - } - - const double widest = MAX(m->input_width, m->output_width); - - if (impl->embed_item) { - double above_w = MAX(m->width, widest + hor_pad); - double between_w = MAX(m->width, - (m->input_width - + m->output_width - + impl->embed_width)); - - above_w = MAX(above_w, impl->embed_width); - - // Decide where to place embedded widget if necessary) - if (impl->embed_width < impl->embed_height * 2.0) { - m->embed_between = TRUE; - m->width = between_w; - m->embed_x = m->input_width; - } else { - m->width = above_w; - m->embed_x = 2.0; - } - } - - if (!canvas_title && (impl->widest_input == 0.0 - || impl->widest_output == 0.0)) { - m->width += 10.0; - } - - m->width += 4.0; - m->width = MAX(m->width, widest + hor_pad); -} - -static void -place_title(GanvModule* module, GanvDirection dir) -{ - GanvBox* box = GANV_BOX(module); - GanvText* canvas_title = GANV_NODE(module)->impl->label; - - double title_w, title_h; - title_size(module, &title_w, &title_h); - - if (!canvas_title) { - return; - } - - GanvItem* t = GANV_ITEM(canvas_title); - if (dir == GANV_DIRECTION_RIGHT) { - t->impl->x = (ganv_box_get_width(box) - title_w) / 2.0; - t->impl->y = 1.0; - } else { - t->impl->x = (ganv_box_get_width(box) - title_w) / 2.0; - t->impl->y = ganv_module_get_empty_port_depth(module) + 1.0; - } -} - -static void -resize_right(GanvModule* module) -{ - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module)); - GanvModulePrivate* impl = module->impl; - - Metrics m; - measure(module, &m); - - double title_w, title_h; - title_size(module, &title_w, &title_h); - - // Basic height contains title - double header_height = title_h ? (3.0 + title_h) : EDGE_PAD; - - if (impl->embed_item) { - ganv_item_set(impl->embed_item, - "x", (double)m.embed_x, - "y", header_height, - NULL); - } - - // Actually set width and height - ganv_box_set_width(GANV_BOX(module), m.width); - - // Offset ports below embedded widget - if (!m.embed_between) { - header_height += impl->embed_height; - } - - // Move ports to appropriate locations - double in_y = header_height; - double out_y = header_height; - FOREACH_PORT(impl->ports, pi) { - GanvPort* const p = (*pi); - GanvBox* const pbox = GANV_BOX(p); - GanvNode* const pnode = GANV_NODE(p); - const double h = ganv_box_get_height(pbox); - - // Offset to shift ports to make borders line up - const double border_off = (GANV_NODE(module)->impl->border_width - - pnode->impl->border_width) / 2.0; - - if (p->impl->is_input) { - ganv_node_move_to(pnode, -border_off, in_y + 1.0); - ganv_box_set_width(pbox, m.input_width); - in_y += h + pnode->impl->border_width + 1.0; - - ganv_canvas_for_each_edge_to( - canvas, pnode, - (GanvEdgeFunc)ganv_edge_update_location, NULL); - } else { - ganv_node_move_to(pnode, m.width - m.output_width + border_off, out_y + 1.0); - ganv_box_set_width(pbox, m.output_width); - out_y += h + pnode->impl->border_width + 1.0; - - ganv_canvas_for_each_edge_from( - canvas, pnode, - (GanvEdgeFunc)ganv_edge_update_location, NULL); - } - - if (!m.horiz) { - in_y = MAX(in_y, out_y); - out_y = MAX(in_y, out_y); - } - } - - double height = MAX(in_y, out_y) + EDGE_PAD; - if (impl->embed_item && m.embed_between) - height = MAX(height, impl->embed_height + header_height + 2.0); - - ganv_box_set_height(GANV_BOX(module), height); - - place_title(module, GANV_DIRECTION_RIGHT); -} - -static void -resize_down(GanvModule* module) -{ - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module)); - GanvModulePrivate* impl = module->impl; - - Metrics m; - measure(module, &m); - - double title_w, title_h; - title_size(module, &title_w, &title_h); - - const double port_depth = ganv_module_get_empty_port_depth(module); - const double port_breadth = ganv_module_get_empty_port_breadth(module); - - if (impl->embed_item) { - ganv_item_set(impl->embed_item, - "x", (double)m.embed_x, - "y", port_depth + title_h, - NULL); - } - - const double height = PAD + title_h - + impl->embed_height + (port_depth * 2.0); - - // Move ports to appropriate locations - guint in_count = 0; - guint out_count = 0; - double in_x = 0.0; - double out_x = 0.0; - FOREACH_PORT(impl->ports, pi) { - GanvPort* const p = (*pi); - GanvBox* const pbox = GANV_BOX(p); - GanvNode* const pnode = GANV_NODE(p); - ganv_box_set_width(pbox, port_breadth); - ganv_box_set_height(pbox, port_depth); - - // Offset to shift ports to make borders line up - const double border_off = (GANV_NODE(module)->impl->border_width - - pnode->impl->border_width) / 2.0; - - if (p->impl->is_input) { - in_x = EDGE_PAD + (in_count++ * (port_breadth + PAD + 1.0)); - ganv_node_move_to(pnode, in_x, -border_off); - ganv_canvas_for_each_edge_to( - canvas, pnode, - (GanvEdgeFunc)ganv_edge_update_location, NULL); - } else { - out_x = EDGE_PAD + (out_count++ * (port_breadth + PAD + 1.0)); - ganv_node_move_to(pnode, out_x, height - port_depth + border_off); - ganv_canvas_for_each_edge_from( - canvas, pnode, - (GanvEdgeFunc)ganv_edge_update_location, NULL); - } - } - - ganv_box_set_height(GANV_BOX(module), height); - ganv_box_set_width(GANV_BOX(module), m.width); - place_title(module, GANV_DIRECTION_DOWN); -} - -static void -measure_ports(GanvModule* module) -{ - GanvModulePrivate* impl = module->impl; - - impl->widest_input = 0.0; - impl->widest_output = 0.0; - FOREACH_PORT_CONST(impl->ports, pi) { - const GanvPort* const p = (*pi); - const double w = ganv_port_get_natural_width(p); - if (p->impl->is_input) { - if (w > impl->widest_input) { - impl->widest_input = w; - } - } else { - if (w > impl->widest_output) { - impl->widest_output = w; - } - } - } -} - -static void -ganv_module_resize(GanvNode* self) -{ - GanvModule* module = GANV_MODULE(self); - GanvNode* node = GANV_NODE(self); - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module)); - - double label_w = 0.0; - double label_h = 0.0; - if (node->impl->label) { - g_object_get(node->impl->label, - "width", &label_w, - "height", &label_h, - NULL); - } - - measure_ports(module); - - ganv_box_set_width(GANV_BOX(module), label_w + (MODULE_LABEL_PAD * 2.0)); - ganv_box_set_height(GANV_BOX(module), label_h); - - switch (ganv_canvas_get_direction(canvas)) { - case GANV_DIRECTION_RIGHT: - resize_right(module); - break; - case GANV_DIRECTION_DOWN: - resize_down(module); - break; - } - - if (GANV_NODE_CLASS(parent_class)->resize) { - GANV_NODE_CLASS(parent_class)->resize(self); - } -} - -static void -ganv_module_redraw_text(GanvNode* self) -{ - FOREACH_PORT(GANV_MODULE(self)->impl->ports, p) { - ganv_node_redraw_text(GANV_NODE(*p)); - } - - if (parent_class->parent_class.redraw_text) { - parent_class->parent_class.redraw_text(self); - } -} - -static void -ganv_module_add_port(GanvModule* module, - GanvPort* port) -{ - GanvModulePrivate* impl = module->impl; - - // Update widest input/output measurements if necessary - const double width = ganv_port_get_natural_width(port); - if (port->impl->is_input && width > impl->widest_input) { - impl->widest_input = width; - } else if (!port->impl->is_input && width > impl->widest_output) { - impl->widest_output = width; - } - - // Add to port array - g_ptr_array_add(impl->ports, port); - - // Request update with resize and reorder - GANV_NODE(module)->impl->must_resize = TRUE; - impl->must_reorder = TRUE; -} - -static void -ganv_module_remove_port(GanvModule* module, - GanvPort* port) -{ - gboolean removed = g_ptr_array_remove(module->impl->ports, port); - if (removed) { - const double width = ganv_box_get_width(GANV_BOX(port)); - // Find new widest input or output, if necessary - if (port->impl->is_input && width >= module->impl->widest_input) { - module->impl->widest_input = 0; - FOREACH_PORT_CONST(module->impl->ports, i) { - const GanvPort* const p = (*i); - const double w = ganv_box_get_width(GANV_BOX(p)); - if (p->impl->is_input && w >= module->impl->widest_input) { - module->impl->widest_input = w; - } - } - } else if (!port->impl->is_input && width >= module->impl->widest_output) { - module->impl->widest_output = 0; - FOREACH_PORT_CONST(module->impl->ports, i) { - const GanvPort* const p = (*i); - const double w = ganv_box_get_width(GANV_BOX(p)); - if (!p->impl->is_input && w >= module->impl->widest_output) { - module->impl->widest_output = w; - } - } - } - - GANV_NODE(module)->impl->must_resize = TRUE; - } else { - fprintf(stderr, "Failed to find port to remove\n"); - } -} - -static void -ganv_module_add(GanvItem* item, GanvItem* child) -{ - if (GANV_IS_PORT(child)) { - ganv_module_add_port(GANV_MODULE(item), GANV_PORT(child)); - } - ganv_item_request_update(item); - if (GANV_ITEM_CLASS(parent_class)->add) { - GANV_ITEM_CLASS(parent_class)->add(item, child); - } -} - -static void -ganv_module_remove(GanvItem* item, GanvItem* child) -{ - if (GANV_IS_PORT(child)) { - ganv_module_remove_port(GANV_MODULE(item), GANV_PORT(child)); - } - ganv_item_request_update(item); - if (GANV_ITEM_CLASS(parent_class)->remove) { - GANV_ITEM_CLASS(parent_class)->remove(item, child); - } -} - -static int -ptr_sort(const GanvPort** a, const GanvPort** b, const PortOrderCtx* ctx) -{ - return ctx->port_cmp(*a, *b, ctx->data); -} - -static void -ganv_module_update(GanvItem* item, int flags) -{ - GanvModule* module = GANV_MODULE(item); - GanvCanvas* canvas = ganv_item_get_canvas(item); - - if (module->impl->must_reorder) { - // Sort ports array - PortOrderCtx ctx = ganv_canvas_get_port_order(canvas); - if (ctx.port_cmp) { - g_ptr_array_sort_with_data(module->impl->ports, - (GCompareDataFunc)ptr_sort, - - &ctx); - } - module->impl->must_reorder = FALSE; - } - - if (module->impl->embed_item) { - // Kick the embedded item to update position if we have moved - ganv_item_move(GANV_ITEM(module->impl->embed_item), 0.0, 0.0); - } - - FOREACH_PORT(module->impl->ports, p) { - ganv_item_invoke_update(GANV_ITEM(*p), flags); - } - - if (module->impl->embed_item) { - ganv_item_invoke_update(GANV_ITEM(module->impl->embed_item), flags); - } - - GANV_ITEM_CLASS(parent_class)->update(item, flags); -} - -static void -ganv_module_draw(GanvItem* item, - cairo_t* cr, double cx, double cy, double cw, double ch) -{ - GanvNode* node = GANV_NODE(item); - GanvModule* module = GANV_MODULE(item); - - // Draw box - if (GANV_ITEM_CLASS(parent_class)->draw) { - (*GANV_ITEM_CLASS(parent_class)->draw)(item, cr, cx, cy, cw, ch); - } - - // Draw label - if (node->impl->label) { - GanvItem* label_item = GANV_ITEM(node->impl->label); - GANV_ITEM_GET_CLASS(label_item)->draw(label_item, cr, cx, cy, cw, ch); - } - - // Draw ports - FOREACH_PORT(module->impl->ports, p) { - GANV_ITEM_GET_CLASS(GANV_ITEM(*p))->draw( - GANV_ITEM(*p), cr, cx, cy, cw, ch); - } - - // Draw embed item - if (module->impl->embed_item) { - GANV_ITEM_GET_CLASS(module->impl->embed_item)->draw( - module->impl->embed_item, cr, cx, cy, cw, ch); - } -} - -static void -ganv_module_move_to(GanvNode* node, - double x, - double y) -{ - GanvModule* module = GANV_MODULE(node); - GANV_NODE_CLASS(parent_class)->move_to(node, x, y); - FOREACH_PORT(module->impl->ports, p) { - ganv_node_move(GANV_NODE(*p), 0.0, 0.0); - } - if (module->impl->embed_item) { - ganv_item_move(GANV_ITEM(module->impl->embed_item), 0.0, 0.0); - } -} - -static void -ganv_module_move(GanvNode* node, - double dx, - double dy) -{ - GanvModule* module = GANV_MODULE(node); - GANV_NODE_CLASS(parent_class)->move(node, dx, dy); - FOREACH_PORT(module->impl->ports, p) { - ganv_node_move(GANV_NODE(*p), 0.0, 0.0); - } - if (module->impl->embed_item) { - ganv_item_move(GANV_ITEM(module->impl->embed_item), 0.0, 0.0); - } -} - -static double -ganv_module_point(GanvItem* item, double x, double y, GanvItem** actual_item) -{ - GanvModule* module = GANV_MODULE(item); - - double d = GANV_ITEM_CLASS(parent_class)->point(item, x, y, actual_item); - - if (!*actual_item) { - // Point is not inside module at all, no point in checking children - return d; - } - - FOREACH_PORT(module->impl->ports, p) { - GanvItem* const port = GANV_ITEM(*p); - - *actual_item = NULL; - d = GANV_ITEM_GET_CLASS(port)->point( - port, x - port->impl->x, y - port->impl->y, actual_item); - - if (*actual_item) { - // Point is inside a port - return d; - } - } - - // Point is inside module, but not a child port - *actual_item = item; - return 0.0; -} - -static void -ganv_module_class_init(GanvModuleClass* klass) -{ - GObjectClass* gobject_class = (GObjectClass*)klass; - GtkObjectClass* object_class = (GtkObjectClass*)klass; - GanvItemClass* item_class = (GanvItemClass*)klass; - GanvNodeClass* node_class = (GanvNodeClass*)klass; - - parent_class = GANV_BOX_CLASS(g_type_class_peek_parent(klass)); - - gobject_class->set_property = ganv_module_set_property; - gobject_class->get_property = ganv_module_get_property; - - object_class->destroy = ganv_module_destroy; - - item_class->add = ganv_module_add; - item_class->remove = ganv_module_remove; - item_class->update = ganv_module_update; - item_class->draw = ganv_module_draw; - item_class->point = ganv_module_point; - - node_class->move = ganv_module_move; - node_class->move_to = ganv_module_move_to; - node_class->resize = ganv_module_resize; - node_class->redraw_text = ganv_module_redraw_text; -} - -GanvModule* -ganv_module_new(GanvCanvas* canvas, - const char* first_property_name, ...) -{ - GanvModule* module = GANV_MODULE( - g_object_new(ganv_module_get_type(), "canvas", canvas, NULL)); - - va_list args; - va_start(args, first_property_name); - g_object_set_valist(G_OBJECT(module), first_property_name, args); - va_end(args); - - return module; -} - -guint -ganv_module_num_ports(const GanvModule* module) -{ - return module->impl->ports ? module->impl->ports->len : 0; -} - -GanvPort* -ganv_module_get_port(GanvModule* module, - guint index) -{ - return (GanvPort*)g_ptr_array_index(module->impl->ports, index); -} - -double -ganv_module_get_empty_port_breadth(const GanvModule* module) -{ - return ganv_module_get_empty_port_depth(module) * 2.0; -} - -double -ganv_module_get_empty_port_depth(const GanvModule* module) -{ - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(module)); - - return ganv_canvas_get_font_size(canvas) * 1.1; -} - -static void -on_embed_size_request(GtkWidget* widget, - GtkRequisition* r, - void* user_data) -{ - GanvModule* module = GANV_MODULE(user_data); - GanvModulePrivate* impl = module->impl; - if (impl->embed_width == r->width && impl->embed_height == r->height) { - return; - } - - impl->embed_width = r->width; - impl->embed_height = r->height; - GANV_NODE(module)->impl->must_resize = TRUE; - - GtkAllocation allocation; - allocation.width = r->width; - allocation.height = r->width; - - gtk_widget_size_allocate(widget, &allocation); - ganv_item_set(impl->embed_item, - "width", (double)r->width, - "height", (double)r->height, - NULL); -} - -void -ganv_module_embed(GanvModule* module, - GtkWidget* widget) -{ - GanvModulePrivate* impl = module->impl; - if (!widget && !impl->embed_item) { - return; - } - - if (impl->embed_item) { - // Free existing embedded widget - gtk_object_destroy(GTK_OBJECT(impl->embed_item)); - impl->embed_item = NULL; - } - - if (!widget) { - // Removing an existing embedded widget - impl->embed_width = 0; - impl->embed_height = 0; - GANV_NODE(module)->impl->must_resize = TRUE; - ganv_item_request_update(GANV_ITEM(module)); - return; - } - - double title_w, title_h; - title_size(module, &title_w, &title_h); - - impl->embed_item = ganv_item_new( - GANV_ITEM(module), - ganv_widget_get_type(), - "x", 2.0, - "y", 4.0 + title_h, - "widget", widget, - NULL); - - GtkRequisition r; - gtk_widget_show_all(widget); - gtk_widget_size_request(widget, &r); - on_embed_size_request(widget, &r, module); - ganv_item_show(impl->embed_item); - - g_signal_connect(widget, "size-request", - G_CALLBACK(on_embed_size_request), module); - - GANV_NODE(module)->impl->must_resize = TRUE; - ganv_item_request_update(GANV_ITEM(module)); -} - -void -ganv_module_set_direction(GanvModule* module, - GanvDirection direction) -{ - FOREACH_PORT(module->impl->ports, p) { - ganv_port_set_direction(*p, direction); - } - GANV_NODE(module)->impl->must_resize = TRUE; - ganv_item_request_update(GANV_ITEM(module)); -} - -void -ganv_module_for_each_port(GanvModule* module, - GanvPortFunc f, - void* data) -{ - GanvModulePrivate* impl = module->impl; - const int len = impl->ports->len; - GanvPort** copy = (GanvPort**)malloc(sizeof(GanvPort*) * len); - memcpy(copy, impl->ports->pdata, sizeof(GanvPort*) * len); - - for (int i = 0; i < len; ++i) { - f(copy[i], data); - } - - free(copy); -} diff --git a/src/node.c b/src/node.c deleted file mode 100644 index 4955f36..0000000 --- a/src/node.c +++ /dev/null @@ -1,897 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2016 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "ganv/canvas.h" -#include "ganv/node.h" - -#include "./boilerplate.h" -#include "./color.h" -#include "./ganv-marshal.h" -#include "./ganv-private.h" -#include "./gettext.h" - -guint signal_moved; - -G_DEFINE_TYPE_WITH_CODE(GanvNode, ganv_node, GANV_TYPE_ITEM, - G_ADD_PRIVATE(GanvNode)) - -static GanvItemClass* parent_class; - -enum { - PROP_0, - PROP_CANVAS, - PROP_PARTNER, - PROP_LABEL, - PROP_SHOW_LABEL, - PROP_DASH_LENGTH, - PROP_DASH_OFFSET, - PROP_BORDER_WIDTH, - PROP_FILL_COLOR, - PROP_BORDER_COLOR, - PROP_CAN_TAIL, - PROP_CAN_HEAD, - PROP_IS_SOURCE, - PROP_SELECTED, - PROP_HIGHLIGHTED, - PROP_DRAGGABLE, - PROP_GRABBED -}; - -static void -ganv_node_init(GanvNode* node) -{ - GanvNodePrivate* impl = ganv_node_get_instance_private(node); - - node->impl = impl; - - impl->partner = NULL; - impl->label = NULL; - impl->dash_length = 0.0; - impl->dash_offset = 0.0; - impl->border_width = 2.0; - impl->fill_color = DEFAULT_FILL_COLOR; - impl->border_color = DEFAULT_BORDER_COLOR; - impl->can_tail = FALSE; - impl->can_head = FALSE; - impl->is_source = FALSE; - impl->selected = FALSE; - impl->highlighted = FALSE; - impl->draggable = FALSE; - impl->show_label = TRUE; - impl->grabbed = FALSE; - impl->must_resize = FALSE; -#ifdef GANV_FDGL - impl->force.x = 0.0; - impl->force.y = 0.0; - impl->vel.x = 0.0; - impl->vel.y = 0.0; - impl->connected = FALSE; -#endif -} - -static void -ganv_node_realize(GanvItem* item) -{ - GANV_ITEM_CLASS(parent_class)->realize(item); - ganv_canvas_add_node(ganv_item_get_canvas(item), GANV_NODE(item)); -} - -static void -ganv_node_destroy(GtkObject* object) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_NODE(object)); - - GanvNode* node = GANV_NODE(object); - GanvNodePrivate* impl = node->impl; - if (impl->label) { - g_object_unref(impl->label); - impl->label = NULL; - } - - GanvItem* item = GANV_ITEM(object); - ganv_node_disconnect(node); - if (item->impl->canvas) { - ganv_canvas_remove_node(item->impl->canvas, node); - } - - if (GTK_OBJECT_CLASS(parent_class)->destroy) { - (*GTK_OBJECT_CLASS(parent_class)->destroy)(object); - } - - impl->partner = NULL; - item->impl->canvas = NULL; -} - -static void -ganv_node_update(GanvItem* item, int flags) -{ - GanvNode* node = GANV_NODE(item); - if (node->impl->must_resize) { - ganv_node_resize(node); - node->impl->must_resize = FALSE; - } - - if (node->impl->label) { - ganv_item_invoke_update(GANV_ITEM(node->impl->label), flags); - } - - GANV_ITEM_CLASS(parent_class)->update(item, flags); -} - -static void -ganv_node_draw(GanvItem* item, - cairo_t* cr, double cx, double cy, double cw, double ch) -{ - /* TODO: Label is not drawn here because ports need to draw control - rects then the label on top. I can't see a way of solving this since - there's no single time parent class draw needs to be called, so perhaps - label shouldn't be part of this class... */ -} - -static void -ganv_node_set_property(GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_NODE(object)); - - GanvNode* node = GANV_NODE(object); - GanvNodePrivate* impl = node->impl; - - switch (prop_id) { - SET_CASE(DASH_LENGTH, double, impl->dash_length); - SET_CASE(DASH_OFFSET, double, impl->dash_offset); - SET_CASE(BORDER_WIDTH, double, impl->border_width); - SET_CASE(FILL_COLOR, uint, impl->fill_color); - SET_CASE(BORDER_COLOR, uint, impl->border_color); - SET_CASE(CAN_TAIL, boolean, impl->can_tail); - SET_CASE(CAN_HEAD, boolean, impl->can_head); - SET_CASE(IS_SOURCE, boolean, impl->is_source); - SET_CASE(HIGHLIGHTED, boolean, impl->highlighted); - SET_CASE(DRAGGABLE, boolean, impl->draggable); - SET_CASE(GRABBED, boolean, impl->grabbed); - case PROP_PARTNER: - impl->partner = (GanvNode*)g_value_get_object(value); - break; - case PROP_SELECTED: - if (impl->selected != g_value_get_boolean(value)) { - GanvItem* item = GANV_ITEM(object); - impl->selected = g_value_get_boolean(value); - if (item->impl->canvas) { - if (impl->selected) { - ganv_canvas_select_node(ganv_item_get_canvas(item), node); - } else { - ganv_canvas_unselect_node(ganv_item_get_canvas(item), node); - } - ganv_item_request_update(item); - } - } - break; - case PROP_CANVAS: - if (!GANV_ITEM(object)->impl->parent) { - GanvCanvas* canvas = GANV_CANVAS(g_value_get_object(value)); - g_object_set(object, "parent", ganv_canvas_root(canvas), NULL); - ganv_canvas_add_node(canvas, node); - } else { - g_warning("Cannot change `canvas' property after construction"); - } - break; - case PROP_LABEL: - ganv_node_set_label(node, g_value_get_string(value)); - break; - case PROP_SHOW_LABEL: - ganv_node_set_show_label(node, g_value_get_boolean(value)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_node_get_property(GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_NODE(object)); - - GanvNode* node = GANV_NODE(object); - GanvNodePrivate* impl = node->impl; - - switch (prop_id) { - GET_CASE(PARTNER, object, impl->partner); - GET_CASE(LABEL, string, impl->label ? impl->label->impl->text : NULL); - GET_CASE(DASH_LENGTH, double, impl->dash_length); - GET_CASE(DASH_OFFSET, double, impl->dash_offset); - GET_CASE(BORDER_WIDTH, double, impl->border_width); - GET_CASE(FILL_COLOR, uint, impl->fill_color); - GET_CASE(BORDER_COLOR, uint, impl->border_color); - GET_CASE(CAN_TAIL, boolean, impl->can_tail); - GET_CASE(CAN_HEAD, boolean, impl->can_head); - GET_CASE(IS_SOURCE, boolean, impl->is_source); - GET_CASE(SELECTED, boolean, impl->selected); - GET_CASE(HIGHLIGHTED, boolean, impl->highlighted); - GET_CASE(DRAGGABLE, boolean, impl->draggable); - GET_CASE(GRABBED, boolean, impl->grabbed); - case PROP_CANVAS: - g_value_set_object(value, ganv_item_get_canvas(GANV_ITEM(object))); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_node_default_tail_vector(const GanvNode* self, - const GanvNode* head, - double* x, - double* y, - double* dx, - double* dy) -{ - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(self)); - - *x = GANV_ITEM(self)->impl->x; - *y = GANV_ITEM(self)->impl->y; - - switch (ganv_canvas_get_direction(canvas)) { - case GANV_DIRECTION_RIGHT: - *dx = 1.0; - *dy = 0.0; - break; - case GANV_DIRECTION_DOWN: - *dx = 0.0; - *dy = 1.0; - break; - } - - ganv_item_i2w(GANV_ITEM(self)->impl->parent, x, y); -} - -static void -ganv_node_default_head_vector(const GanvNode* self, - const GanvNode* tail, - double* x, - double* y, - double* dx, - double* dy) -{ - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(self)); - - *x = GANV_ITEM(self)->impl->x; - *y = GANV_ITEM(self)->impl->y; - - switch (ganv_canvas_get_direction(canvas)) { - case GANV_DIRECTION_RIGHT: - *dx = -1.0; - *dy = 0.0; - break; - case GANV_DIRECTION_DOWN: - *dx = 0.0; - *dy = -1.0; - break; - } - - ganv_item_i2w(GANV_ITEM(self)->impl->parent, x, y); -} - -void -ganv_node_get_draw_properties(const GanvNode* node, - double* dash_length, - double* border_color, - double* fill_color) -{ - GanvNodePrivate* impl = node->impl; - - *dash_length = impl->dash_length; - *border_color = impl->border_color; - *fill_color = impl->fill_color; - - if (impl->selected) { - *dash_length = 4.0; - *border_color = highlight_color(impl->border_color, 0x40); - } - - if (impl->highlighted) { - *border_color = highlight_color(impl->border_color, 0x40); - *fill_color = impl->fill_color; - } -} - -void -ganv_node_set_label(GanvNode* node, const char* str) -{ - GanvNodePrivate* impl = node->impl; - if (!str || str[0] == '\0') { - if (impl->label) { - gtk_object_destroy(GTK_OBJECT(impl->label)); - impl->label = NULL; - } - } else if (impl->label) { - ganv_item_set(GANV_ITEM(impl->label), - "text", str, - NULL); - } else { - impl->label = GANV_TEXT(ganv_item_new(GANV_ITEM(node), - ganv_text_get_type(), - "text", str, - "color", DEFAULT_TEXT_COLOR, - "managed", TRUE, - NULL)); - } - - impl->must_resize = TRUE; - ganv_item_request_update(GANV_ITEM(node)); -} - -void -ganv_node_set_show_label(GanvNode* node, gboolean show) -{ - if (node->impl->label) { - if (show) { - ganv_item_show(GANV_ITEM(node->impl->label)); - } else { - ganv_item_hide(GANV_ITEM(node->impl->label)); - } - } - node->impl->show_label = show; - ganv_item_request_update(GANV_ITEM(node)); -} - -static void -ganv_node_default_tick(GanvNode* self, - double seconds) -{ - GanvNode* node = GANV_NODE(self); - node->impl->dash_offset = seconds * 8.0; - ganv_item_request_update(GANV_ITEM(self)); -} - -static void -ganv_node_default_disconnect(GanvNode* node) -{ - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(node)); - if (canvas) { - ganv_canvas_for_each_edge_on( - canvas, node, (GanvEdgeFunc)ganv_edge_disconnect, NULL); - } -} - -static void -ganv_node_default_move(GanvNode* node, - double dx, - double dy) -{ - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(node)); - ganv_item_move(GANV_ITEM(node), dx, dy); - ganv_canvas_for_each_edge_on( - canvas, node, (GanvEdgeFunc)ganv_edge_update_location, NULL); - ganv_item_request_update(GANV_ITEM(node)); -} - -static void -ganv_node_default_move_to(GanvNode* node, - double x, - double y) -{ - GanvItem* item = GANV_ITEM(node); - GanvCanvas* canvas = ganv_item_get_canvas(item); - item->impl->x = x; - item->impl->y = y; - if (node->impl->can_tail) { - ganv_canvas_for_each_edge_from( - canvas, node, (GanvEdgeFunc)ganv_edge_update_location, NULL); - } else if (node->impl->can_head) { - ganv_canvas_for_each_edge_to( - canvas, node, (GanvEdgeFunc)ganv_edge_update_location, NULL); - } - ganv_item_request_update(GANV_ITEM(node)); -} - -static void -ganv_node_default_resize(GanvNode* node) -{ - GanvItem* item = GANV_ITEM(node); - if (GANV_IS_NODE(item->impl->parent)) { - ganv_node_resize(GANV_NODE(item->impl->parent)); - } - node->impl->must_resize = FALSE; -} - -static void -ganv_node_default_redraw_text(GanvNode* node) -{ - if (node->impl->label) { - ganv_text_layout(node->impl->label); - node->impl->must_resize = TRUE; - ganv_item_request_update(GANV_ITEM(node)); - } -} - -static gboolean -ganv_node_default_event(GanvItem* item, - GdkEvent* event) -{ - GanvNode* node = GANV_NODE(item); - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(node)); - - // FIXME: put these somewhere better - static double last_x, last_y; - static double drag_start_x, drag_start_y; - static gboolean dragging = FALSE; - - switch (event->type) { - case GDK_ENTER_NOTIFY: - ganv_item_raise(GANV_ITEM(node)); - node->impl->highlighted = TRUE; - ganv_item_request_update(item); - return TRUE; - - case GDK_LEAVE_NOTIFY: - ganv_item_lower(GANV_ITEM(node)); - node->impl->highlighted = FALSE; - ganv_item_request_update(item); - return TRUE; - - case GDK_BUTTON_PRESS: - drag_start_x = event->button.x; - drag_start_y = event->button.y; - last_x = event->button.x; - last_y = event->button.y; - if (!ganv_canvas_get_locked(canvas) && node->impl->draggable && event->button.button == 1) { - ganv_canvas_grab_item( - GANV_ITEM(node), - GDK_POINTER_MOTION_MASK|GDK_BUTTON_RELEASE_MASK|GDK_BUTTON_PRESS_MASK, - ganv_canvas_get_move_cursor(canvas), - event->button.time); - node->impl->grabbed = TRUE; - dragging = TRUE; - return TRUE; - } - break; - - case GDK_BUTTON_RELEASE: - if (dragging) { - gboolean selected; - g_object_get(G_OBJECT(node), "selected", &selected, NULL); - ganv_canvas_ungrab_item(GANV_ITEM(node), event->button.time); - node->impl->grabbed = FALSE; - dragging = FALSE; - if (event->button.x != drag_start_x || event->button.y != drag_start_y) { - ganv_canvas_contents_changed(canvas); - if (selected) { - ganv_canvas_selection_move_finished(canvas); - } else { - const double x = GANV_ITEM(node)->impl->x; - const double y = GANV_ITEM(node)->impl->y; - g_signal_emit(node, signal_moved, 0, x, y, NULL); - } - } else { - // Clicked - if (selected) { - ganv_canvas_unselect_node(canvas, node); - } else { - if (!(event->button.state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK))) { - ganv_canvas_clear_selection(canvas); - } - ganv_canvas_select_node(canvas, node); - } - } - return TRUE; - } - break; - - case GDK_MOTION_NOTIFY: - if ((dragging && (event->motion.state & GDK_BUTTON1_MASK))) { - gboolean selected; - g_object_get(G_OBJECT(node), "selected", &selected, NULL); - - double new_x = event->motion.x; - double new_y = event->motion.y; - - if (event->motion.is_hint) { - int t_x; - int t_y; - GdkModifierType state; - gdk_window_get_pointer(event->motion.window, &t_x, &t_y, &state); - new_x = t_x; - new_y = t_y; - } - - const double dx = new_x - last_x; - const double dy = new_y - last_y; - if (selected) { - ganv_canvas_move_selected_items(canvas, dx, dy); - } else { - ganv_node_move(node, dx, dy); - } - - last_x = new_x; - last_y = new_y; - return TRUE; - } - - default: - break; - } - - return FALSE; -} - -static void -ganv_node_class_init(GanvNodeClass* klass) -{ - GObjectClass* gobject_class = (GObjectClass*)klass; - GtkObjectClass* object_class = (GtkObjectClass*)klass; - GanvItemClass* item_class = (GanvItemClass*)klass; - - parent_class = GANV_ITEM_CLASS(g_type_class_peek_parent(klass)); - - gobject_class->set_property = ganv_node_set_property; - gobject_class->get_property = ganv_node_get_property; - - g_object_class_install_property( - gobject_class, PROP_CANVAS, g_param_spec_object( - "canvas", - _("Canvas"), - _("The canvas this node is on."), - GANV_TYPE_CANVAS, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_PARTNER, g_param_spec_object( - "partner", - _("Partner"), - _("Partners are nodes that should be visually aligned to correspond" - " to each other, even if they are not necessarily connected (e.g." - " for separate modules representing the inputs and outputs of a" - " single thing). When the canvas is arranged, the partner will" - " be aligned as if there was an edge from this node to its" - " partner."), - GANV_TYPE_NODE, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_LABEL, g_param_spec_string( - "label", - _("Label"), - _("The text to display as a label on this node."), - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_SHOW_LABEL, g_param_spec_boolean( - "show-label", - _("Show label"), - _("Whether or not to show the label."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_DASH_LENGTH, g_param_spec_double( - "dash-length", - _("Border dash length"), - _("Length of border dashes, or zero for no dashing."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_DASH_OFFSET, g_param_spec_double( - "dash-offset", - _("Border dash offset"), - _("Start offset for border dashes, used for selected animation."), - 0.0, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_BORDER_WIDTH, g_param_spec_double( - "border-width", - _("Border width"), - _("Width of the border line."), - 0.0, G_MAXDOUBLE, - 2.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_FILL_COLOR, g_param_spec_uint( - "fill-color", - _("Fill color"), - _("Color of internal area."), - 0, G_MAXUINT, - DEFAULT_FILL_COLOR, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_BORDER_COLOR, g_param_spec_uint( - "border-color", - _("Border color"), - _("Color of border line."), - 0, G_MAXUINT, - DEFAULT_BORDER_COLOR, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_CAN_TAIL, g_param_spec_boolean( - "can-tail", - _("Can tail"), - _("Whether this node can be the tail of an edge."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_CAN_HEAD, g_param_spec_boolean( - "can-head", - _("Can head"), - _("Whether this object can be the head of an edge."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_IS_SOURCE, g_param_spec_boolean( - "is-source", - _("Is source"), - _("Whether this object should be positioned at the start of signal flow."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_SELECTED, g_param_spec_boolean( - "selected", - _("Selected"), - _("Whether this object is selected."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_HIGHLIGHTED, g_param_spec_boolean( - "highlighted", - _("Highlighted"), - _("Whether this object is highlighted."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_DRAGGABLE, g_param_spec_boolean( - "draggable", - _("Draggable"), - _("Whether this object is draggable."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_GRABBED, g_param_spec_boolean( - "grabbed", - _("Grabbed"), - _("Whether this object is grabbed by the user."), - 0, - G_PARAM_READWRITE)); - - signal_moved = g_signal_new("moved", - ganv_node_get_type(), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, - ganv_marshal_VOID__DOUBLE_DOUBLE, - G_TYPE_NONE, - 2, - G_TYPE_DOUBLE, - G_TYPE_DOUBLE, - 0); - - object_class->destroy = ganv_node_destroy; - - item_class->realize = ganv_node_realize; - item_class->event = ganv_node_default_event; - item_class->update = ganv_node_update; - item_class->draw = ganv_node_draw; - - klass->disconnect = ganv_node_default_disconnect; - klass->move = ganv_node_default_move; - klass->move_to = ganv_node_default_move_to; - klass->resize = ganv_node_default_resize; - klass->redraw_text = ganv_node_default_redraw_text; - klass->tick = ganv_node_default_tick; - klass->tail_vector = ganv_node_default_tail_vector; - klass->head_vector = ganv_node_default_head_vector; -} - -gboolean -ganv_node_can_tail(const GanvNode* self) -{ - return self->impl->can_tail; -} - -gboolean -ganv_node_can_head(const GanvNode* self) -{ - return self->impl->can_head; -} - -void -ganv_node_set_is_source(const GanvNode* node, gboolean is_source) -{ - node->impl->is_source = is_source; -} - -gboolean -ganv_node_is_within(const GanvNode* node, - double x1, - double y1, - double x2, - double y2) -{ - return GANV_NODE_GET_CLASS(node)->is_within(node, x1, y1, x2, y2); -} - -void -ganv_node_tick(GanvNode* node, - double seconds) -{ - GanvNodeClass* klass = GANV_NODE_GET_CLASS(node); - if (klass->tick) { - klass->tick(node, seconds); - } -} - -void -ganv_node_tail_vector(const GanvNode* self, - const GanvNode* head, - double* x1, - double* y1, - double* x2, - double* y2) -{ - GANV_NODE_GET_CLASS(self)->tail_vector( - self, head, x1, y1, x2, y2); -} - -void -ganv_node_head_vector(const GanvNode* self, - const GanvNode* tail, - double* x1, - double* y1, - double* x2, - double* y2) -{ - GANV_NODE_GET_CLASS(self)->head_vector( - self, tail, x1, y1, x2, y2); -} - -const char* -ganv_node_get_label(const GanvNode* node) -{ - return node->impl->label ? node->impl->label->impl->text : NULL; -} - -double -ganv_node_get_border_width(const GanvNode* node) -{ - return node->impl->border_width; -} - -void -ganv_node_set_border_width(const GanvNode* node, double border_width) -{ - node->impl->border_width = border_width; - ganv_item_request_update(GANV_ITEM(node)); -} - -double -ganv_node_get_dash_length(const GanvNode* node) -{ - return node->impl->dash_length; -} - -void -ganv_node_set_dash_length(const GanvNode* node, double dash_length) -{ - node->impl->dash_length = dash_length; - ganv_item_request_update(GANV_ITEM(node)); -} - -double -ganv_node_get_dash_offset(const GanvNode* node) -{ - return node->impl->dash_offset; -} - -void -ganv_node_set_dash_offset(const GanvNode* node, double dash_offset) -{ - node->impl->dash_offset = dash_offset; - ganv_item_request_update(GANV_ITEM(node)); -} - -guint -ganv_node_get_fill_color(const GanvNode* node) -{ - return node->impl->fill_color; -} - -void -ganv_node_set_fill_color(const GanvNode* node, guint fill_color) -{ - node->impl->fill_color = fill_color; - ganv_item_request_update(GANV_ITEM(node)); -} - -guint -ganv_node_get_border_color(const GanvNode* node) -{ - return node->impl->border_color; -} - -void -ganv_node_set_border_color(const GanvNode* node, guint border_color) -{ - node->impl->border_color = border_color; - ganv_item_request_update(GANV_ITEM(node)); -} - -GanvNode* -ganv_node_get_partner(const GanvNode* node) -{ - return node->impl->partner; -} - -void -ganv_node_move(GanvNode* node, - double dx, - double dy) -{ - GANV_NODE_GET_CLASS(node)->move(node, dx, dy); -} - -void -ganv_node_move_to(GanvNode* node, - double x, - double y) -{ - GANV_NODE_GET_CLASS(node)->move_to(node, x, y); -} - -void -ganv_node_resize(GanvNode* node) -{ - GANV_NODE_GET_CLASS(node)->resize(node); - node->impl->must_resize = FALSE; -} - -void -ganv_node_redraw_text(GanvNode* node) -{ - GANV_NODE_GET_CLASS(node)->redraw_text(node); -} - -void -ganv_node_disconnect(GanvNode* node) -{ - GANV_NODE_GET_CLASS(node)->disconnect(node); -} - -gboolean -ganv_node_is_selected(GanvNode* node) -{ - gboolean selected = FALSE; - g_object_get(node, "selected", &selected, NULL); - return selected; -} diff --git a/src/port.c b/src/port.c deleted file mode 100644 index fa76f22..0000000 --- a/src/port.c +++ /dev/null @@ -1,735 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <math.h> -#include <stdlib.h> - -#include "ganv/canvas.h" -#include "ganv/port.h" -#include "ganv/module.h" - -#include "./boilerplate.h" -#include "./color.h" -#include "./ganv-private.h" -#include "./gettext.h" - -static const double PORT_LABEL_HPAD = 4.0; -static const double PORT_LABEL_VPAD = 1.0; - -static void -ganv_port_update_control_slider(GanvPort* port, float value, gboolean force); - -G_DEFINE_TYPE_WITH_CODE(GanvPort, ganv_port, GANV_TYPE_BOX, - G_ADD_PRIVATE(GanvPort)) - -static GanvBoxClass* parent_class; - -enum { - PROP_0, - PROP_IS_INPUT, - PROP_IS_CONTROLLABLE -}; - -enum { - PORT_VALUE_CHANGED, - PORT_LAST_SIGNAL -}; - -static guint port_signals[PORT_LAST_SIGNAL]; - -static void -ganv_port_init(GanvPort* port) -{ - port->impl = ganv_port_get_instance_private(port); - - port->impl->control = NULL; - port->impl->value_label = NULL; - port->impl->is_input = TRUE; - port->impl->is_controllable = FALSE; -} - -static void -ganv_port_destroy(GtkObject* object) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_PORT(object)); - - GanvItem* item = GANV_ITEM(object); - GanvPort* port = GANV_PORT(object); - GanvCanvas* canvas = ganv_item_get_canvas(item); - if (canvas) { - if (port->impl->is_input) { - ganv_canvas_for_each_edge_to( - canvas, &port->box.node, (GanvEdgeFunc)ganv_edge_remove, NULL); - } else { - ganv_canvas_for_each_edge_from( - canvas, &port->box.node, (GanvEdgeFunc)ganv_edge_remove, NULL); - } - } - - if (GTK_OBJECT_CLASS(parent_class)->destroy) { - (*GTK_OBJECT_CLASS(parent_class)->destroy)(object); - } -} - -static void -ganv_port_set_property(GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_PORT(object)); - - GanvPort* port = GANV_PORT(object); - - switch (prop_id) { - SET_CASE(IS_INPUT, boolean, port->impl->is_input); - SET_CASE(IS_CONTROLLABLE, boolean, port->impl->is_controllable); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_port_get_property(GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_PORT(object)); - - GanvPort* port = GANV_PORT(object); - - switch (prop_id) { - GET_CASE(IS_INPUT, boolean, port->impl->is_input); - GET_CASE(IS_CONTROLLABLE, boolean, port->impl->is_controllable); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_port_update(GanvItem* item, int flags) -{ - GanvPort* port = GANV_PORT(item); - GanvPortPrivate* impl = port->impl; - - if (impl->control) { - ganv_item_invoke_update(GANV_ITEM(impl->control->rect), flags); - } - - if (impl->value_label) { - ganv_item_invoke_update(GANV_ITEM(port->impl->value_label), flags); - } - - GanvItemClass* item_class = GANV_ITEM_CLASS(parent_class); - item_class->update(item, flags); -} - -static void -ganv_port_draw(GanvItem* item, - cairo_t* cr, double cx, double cy, double cw, double ch) -{ - GanvPort* port = GANV_PORT(item); - GanvCanvas* canvas = ganv_item_get_canvas(item); - - // Draw Box - GanvItemClass* item_class = GANV_ITEM_CLASS(parent_class); - item_class->draw(item, cr, cx, cy, cw, ch); - - if (port->impl->control) { - // Clip to port boundaries (to stay within radiused borders) - cairo_save(cr); - const double pad = GANV_NODE(port)->impl->border_width / 2.0; - GanvBoxCoords coords = GANV_BOX(port)->impl->coords; - ganv_item_i2w_pair(GANV_ITEM(port), - &coords.x1, &coords.y1, &coords.x2, &coords.y2); - ganv_box_path(GANV_BOX(port), cr, - coords.x1 + pad, coords.y1 + pad, - coords.x2 - pad, coords.y2 - pad, - -pad); - cairo_clip(cr); - - GanvItem* const rect = GANV_ITEM(port->impl->control->rect); - GANV_ITEM_GET_CLASS(rect)->draw(rect, cr, cx, cy, cw, ch); - - cairo_restore(cr); - } - - if (ganv_canvas_get_direction(canvas) == GANV_DIRECTION_DOWN || - !GANV_NODE(port)->impl->show_label) { - return; - } - - GanvItem* labels[2] = { - GANV_ITEM(GANV_NODE(item)->impl->label), - port->impl->value_label ? GANV_ITEM(port->impl->value_label) : NULL - }; - for (int i = 0; i < 2; ++i) { - if (labels[i] && (labels[i]->object.flags & GANV_ITEM_VISIBLE)) { - GANV_ITEM_GET_CLASS(labels[i])->draw( - labels[i], cr, cx, cy, cw, ch); - } - } -} - -static void -ganv_port_tail_vector(const GanvNode* self, - const GanvNode* head, - double* x, - double* y, - double* dx, - double* dy) -{ - GanvPort* port = GANV_PORT(self); - GanvItem* item = &port->box.node.item; - GanvCanvas* canvas = ganv_item_get_canvas(item); - - const double px = item->impl->x; - const double py = item->impl->y; - const double border_width = GANV_NODE(port)->impl->border_width; - - switch (ganv_canvas_get_direction(canvas)) { - case GANV_DIRECTION_RIGHT: - *x = px + ganv_box_get_width(&port->box) + (border_width / 2.0); - *y = py + ganv_box_get_height(&port->box) / 2.0; - *dx = 1.0; - *dy = 0.0; - break; - case GANV_DIRECTION_DOWN: - *x = px + ganv_box_get_width(&port->box) / 2.0; - *y = py + ganv_box_get_height(&port->box) + (border_width / 2.0); - *dx = 0.0; - *dy = 1.0; - break; - } - - ganv_item_i2w(item->impl->parent, x, y); -} - -static void -ganv_port_head_vector(const GanvNode* self, - const GanvNode* tail, - double* x, - double* y, - double* dx, - double* dy) -{ - GanvPort* port = GANV_PORT(self); - GanvItem* item = &port->box.node.item; - GanvCanvas* canvas = ganv_item_get_canvas(item); - - const double px = item->impl->x; - const double py = item->impl->y; - const double border_width = GANV_NODE(port)->impl->border_width; - - switch (ganv_canvas_get_direction(canvas)) { - case GANV_DIRECTION_RIGHT: - *x = px - (border_width / 2.0); - *y = py + ganv_box_get_height(&port->box) / 2.0; - *dx = -1.0; - *dy = 0.0; - break; - case GANV_DIRECTION_DOWN: - *x = px + ganv_box_get_width(&port->box) / 2.0; - *y = py - (border_width / 2.0); - *dx = 0.0; - *dy = -1.0; - break; - } - - ganv_item_i2w(item->impl->parent, x, y); -} - -static void -ganv_port_place_labels(GanvPort* port) -{ - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(port)); - GanvPortPrivate* impl = port->impl; - GanvText* label = GANV_NODE(port)->impl->label; - const double port_w = ganv_box_get_width(&port->box); - const double port_h = ganv_box_get_height(&port->box); - double vlabel_w = 0.0; - if (impl->value_label) { - const double vlabel_h = impl->value_label->impl->coords.height; - vlabel_w = impl->value_label->impl->coords.width; - if (ganv_canvas_get_direction(canvas) == GANV_DIRECTION_RIGHT) { - ganv_item_set(GANV_ITEM(impl->value_label), - "x", PORT_LABEL_HPAD, - "y", (port_h - vlabel_h) / 2.0 - PORT_LABEL_VPAD, - NULL); - } else { - ganv_item_set(GANV_ITEM(impl->value_label), - "x", (port_w - vlabel_w) / 2.0, - "y", (port_h - vlabel_h) / 2.0 - PORT_LABEL_VPAD, - NULL); - } - vlabel_w += PORT_LABEL_HPAD; - } - if (label) { - const double label_h = label->impl->coords.height; - if (ganv_canvas_get_direction(canvas) == GANV_DIRECTION_RIGHT) { - ganv_item_set(GANV_ITEM(label), - "x", vlabel_w + PORT_LABEL_HPAD, - "y", (port_h - label_h) / 2.0 - PORT_LABEL_VPAD, - NULL); - } - } -} - -static void -ganv_port_resize(GanvNode* self) -{ - GanvPort* port = GANV_PORT(self); - GanvNode* node = GANV_NODE(self); - GanvText* label = node->impl->label; - GanvText* vlabel = port->impl->value_label; - - double label_w = 0.0; - double label_h = 0.0; - double vlabel_w = 0.0; - double vlabel_h = 0.0; - if (label && (GANV_ITEM(label)->object.flags & GANV_ITEM_VISIBLE)) { - g_object_get(label, "width", &label_w, "height", &label_h, NULL); - } - if (vlabel && (GANV_ITEM(vlabel)->object.flags & GANV_ITEM_VISIBLE)) { - g_object_get(vlabel, "width", &vlabel_w, "height", &vlabel_h, NULL); - } - - if (label || vlabel) { - double labels_w = label_w + PORT_LABEL_HPAD * 2.0; - if (vlabel_w != 0.0) { - labels_w += vlabel_w + PORT_LABEL_HPAD; - } - ganv_box_set_width(&port->box, labels_w); - ganv_box_set_height(&port->box, - MAX(label_h, vlabel_h) + (PORT_LABEL_VPAD * 2.0)); - - ganv_port_place_labels(port); - } - - if (GANV_NODE_CLASS(parent_class)->resize) { - GANV_NODE_CLASS(parent_class)->resize(self); - } -} - -static void -ganv_port_redraw_text(GanvNode* node) -{ - GanvPort* port = GANV_PORT(node); - if (port->impl->value_label) { - ganv_text_layout(port->impl->value_label); - } - if (GANV_NODE_CLASS(parent_class)->redraw_text) { - (*GANV_NODE_CLASS(parent_class)->redraw_text)(node); - } - ganv_port_place_labels(port); -} - -static void -ganv_port_set_width(GanvBox* box, - double width) -{ - GanvPort* port = GANV_PORT(box); - parent_class->set_width(box, width); - if (port->impl->control) { - ganv_port_update_control_slider(port, port->impl->control->value, TRUE); - } - ganv_port_place_labels(port); -} - -static void -ganv_port_set_height(GanvBox* box, - double height) -{ - GanvPort* port = GANV_PORT(box); - parent_class->set_height(box, height); - if (port->impl->control) { - ganv_item_set(GANV_ITEM(port->impl->control->rect), - "y1", box->impl->coords.border_width / 2.0, - "y2", height - box->impl->coords.border_width / 2.0, - NULL); - } - ganv_port_place_labels(port); -} - -static gboolean -ganv_port_event(GanvItem* item, GdkEvent* event) -{ - GanvCanvas* canvas = ganv_item_get_canvas(item); - - return ganv_canvas_port_event(canvas, GANV_PORT(item), event); -} - -static void -ganv_port_class_init(GanvPortClass* klass) -{ - GObjectClass* gobject_class = (GObjectClass*)klass; - GtkObjectClass* object_class = (GtkObjectClass*)klass; - GanvItemClass* item_class = (GanvItemClass*)klass; - GanvNodeClass* node_class = (GanvNodeClass*)klass; - GanvBoxClass* box_class = (GanvBoxClass*)klass; - - parent_class = GANV_BOX_CLASS(g_type_class_peek_parent(klass)); - - gobject_class->set_property = ganv_port_set_property; - gobject_class->get_property = ganv_port_get_property; - - g_object_class_install_property( - gobject_class, PROP_IS_INPUT, g_param_spec_boolean( - "is-input", - _("Is input"), - _("Whether this port is an input, rather than an output."), - 0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_IS_CONTROLLABLE, g_param_spec_boolean( - "is-controllable", - _("Is controllable"), - _("Whether this port can be controlled by the user."), - 0, - G_PARAM_READWRITE)); - - port_signals[PORT_VALUE_CHANGED] - = g_signal_new("value-changed", - G_TYPE_FROM_CLASS(klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - NULL, - G_TYPE_NONE, 1, - G_TYPE_DOUBLE); - - object_class->destroy = ganv_port_destroy; - - item_class->update = ganv_port_update; - item_class->event = ganv_port_event; - item_class->draw = ganv_port_draw; - - node_class->tail_vector = ganv_port_tail_vector; - node_class->head_vector = ganv_port_head_vector; - node_class->resize = ganv_port_resize; - node_class->redraw_text = ganv_port_redraw_text; - - box_class->set_width = ganv_port_set_width; - box_class->set_height = ganv_port_set_height; -} - -GanvPort* -ganv_port_new(GanvModule* module, - gboolean is_input, - const char* first_prop_name, ...) -{ - GanvPort* port = GANV_PORT(g_object_new(ganv_port_get_type(), NULL)); - - port->impl->is_input = is_input; - - GanvItem* item = GANV_ITEM(port); - va_list args; - va_start(args, first_prop_name); - ganv_item_construct(item, - GANV_ITEM(module), - first_prop_name, args); - va_end(args); - - GanvBox* box = GANV_BOX(port); - box->impl->coords.border_width = 1.0; - - GanvNode* node = GANV_NODE(port); - node->impl->can_tail = !is_input; - node->impl->can_head = is_input; - node->impl->draggable = FALSE; - node->impl->border_width = 2.0; - - GanvCanvas* canvas = ganv_item_get_canvas(GANV_ITEM(port)); - ganv_port_set_direction(port, ganv_canvas_get_direction(canvas)); - - return port; -} - -void -ganv_port_set_direction(GanvPort* port, - GanvDirection direction) -{ - GanvNode* node = GANV_NODE(port); - GanvBox* box = GANV_BOX(port); - gboolean is_input = port->impl->is_input; - switch (direction) { - case GANV_DIRECTION_RIGHT: - box->impl->radius_tl = (is_input ? 0.0 : 5.0); - box->impl->radius_tr = (is_input ? 5.0 : 0.0); - box->impl->radius_br = (is_input ? 5.0 : 0.0); - box->impl->radius_bl = (is_input ? 0.0 : 5.0); - break; - case GANV_DIRECTION_DOWN: - box->impl->radius_tl = (is_input ? 0.0 : 5.0); - box->impl->radius_tr = (is_input ? 0.0 : 5.0); - box->impl->radius_br = (is_input ? 5.0 : 0.0); - box->impl->radius_bl = (is_input ? 5.0 : 0.0); - break; - } - - node->impl->must_resize = TRUE; - ganv_item_request_update(GANV_ITEM(node)); -} - -void -ganv_port_show_control(GanvPort* port) -{ - if (port->impl->control) { - return; - } - - const guint color = 0xFFFFFF66; - const double border_width = GANV_NODE(port)->impl->border_width; - - GanvPortControl* control = (GanvPortControl*)malloc(sizeof(GanvPortControl)); - port->impl->control = control; - - control->value = 0.0f; - control->min = 0.0f; - control->max = 1.0f; - control->is_toggle = FALSE; - control->is_integer = FALSE; - control->rect = GANV_BOX( - ganv_item_new(GANV_ITEM(port), - ganv_box_get_type(), - "x1", border_width / 2.0, - "y1", border_width / 2.0, - "x2", 0.0, - "y2", ganv_box_get_height(&port->box) - border_width / 2.0, - "fill-color", color, - "border-color", color, - "border-width", 0.0, - "managed", TRUE, - NULL)); - ganv_item_show(GANV_ITEM(control->rect)); -} - -void -ganv_port_hide_control(GanvPort* port) -{ - gtk_object_destroy(GTK_OBJECT(port->impl->control->rect)); - free(port->impl->control); - port->impl->control = NULL; -} - -void -ganv_port_set_value_label(GanvPort* port, - const char* str) -{ - GanvPortPrivate* impl = port->impl; - - if (!str || str[0] == '\0') { - if (impl->value_label) { - gtk_object_destroy(GTK_OBJECT(impl->value_label)); - impl->value_label = NULL; - } - } else if (impl->value_label) { - ganv_item_set(GANV_ITEM(impl->value_label), - "text", str, - NULL); - } else { - impl->value_label = GANV_TEXT(ganv_item_new(GANV_ITEM(port), - ganv_text_get_type(), - "text", str, - "color", DIM_TEXT_COLOR, - "managed", TRUE, - NULL)); - } -} - -static void -ganv_port_update_control_slider(GanvPort* port, float value, gboolean force) -{ - GanvPortPrivate* impl = port->impl; - if (!impl->control) { - return; - } - - // Clamp to toggle or integer value if applicable - if (impl->control->is_toggle) { - if (value != 0.0f) { - value = impl->control->max; - } else { - value = impl->control->min; - } - } else if (impl->control->is_integer) { - value = lrintf(value); - } - - // Clamp to range - if (value < impl->control->min) { - value = impl->control->min; - } - if (value > impl->control->max) { - value = impl->control->max; - } - - if (!force && value == impl->control->value) { - return; // No change, do nothing - } - - const double span = (ganv_box_get_width(&port->box) - - GANV_NODE(port)->impl->border_width); - - const double w = (value - impl->control->min) - / (impl->control->max - impl->control->min) - * span; - - if (isnan(w)) { - return; // Shouldn't happen, but ignore crazy values - } - - // Redraw port - impl->control->value = value; - ganv_box_set_width(impl->control->rect, MAX(0.0, w)); - ganv_box_request_redraw( - GANV_ITEM(port), &GANV_BOX(port)->impl->coords, FALSE); -} - -void -ganv_port_set_control_is_toggle(GanvPort* port, - gboolean is_toggle) -{ - if (port->impl->control) { - port->impl->control->is_toggle = is_toggle; - ganv_port_update_control_slider(port, port->impl->control->value, TRUE); - } -} - -void -ganv_port_set_control_is_integer(GanvPort* port, - gboolean is_integer) -{ - if (port->impl->control) { - port->impl->control->is_integer = is_integer; - const float rounded = rintf(port->impl->control->value); - ganv_port_update_control_slider(port, rounded, TRUE); - } -} - -void -ganv_port_set_control_value(GanvPort* port, - float value) -{ - ganv_port_update_control_slider(port, value, FALSE); -} - -void -ganv_port_set_control_value_internal(GanvPort* port, - float value) -{ - // Update slider - ganv_port_set_control_value(port, value); - - // Fire signal to notify user value has changed - const double dvalue = port->impl->control->value; - g_signal_emit(port, port_signals[PORT_VALUE_CHANGED], 0, dvalue, NULL); -} - -void -ganv_port_set_control_min(GanvPort* port, - float min) -{ - if (port->impl->control) { - const gboolean force = port->impl->control->min != min; - port->impl->control->min = min; - if (port->impl->control->max < min) { - port->impl->control->max = min; - } - ganv_port_update_control_slider(port, port->impl->control->value, force); - } -} - -void -ganv_port_set_control_max(GanvPort* port, - float max) -{ - if (port->impl->control) { - const gboolean force = port->impl->control->max != max; - port->impl->control->max = max; - if (port->impl->control->min > max) { - port->impl->control->min = max; - } - ganv_port_update_control_slider(port, port->impl->control->value, force); - } -} - -double -ganv_port_get_natural_width(const GanvPort* port) -{ - GanvCanvas* const canvas = ganv_item_get_canvas(GANV_ITEM(port)); - GanvText* const label = port->box.node.impl->label; - double w = 0.0; - if (ganv_canvas_get_direction(canvas) == GANV_DIRECTION_DOWN) { - w = ganv_module_get_empty_port_breadth(ganv_port_get_module(port)); - } else if (label && (GANV_ITEM(label)->object.flags & GANV_ITEM_VISIBLE)) { - double label_w; - g_object_get(port->box.node.impl->label, "width", &label_w, NULL); - w = label_w + (PORT_LABEL_HPAD * 2.0); - } else { - w = ganv_module_get_empty_port_depth(ganv_port_get_module(port)); - } - if (port->impl->value_label && - (GANV_ITEM(port->impl->value_label)->object.flags - & GANV_ITEM_VISIBLE)) { - double label_w; - g_object_get(port->impl->value_label, "width", &label_w, NULL); - w += label_w + PORT_LABEL_HPAD; - } - return w; -} - -GanvModule* -ganv_port_get_module(const GanvPort* port) -{ - return GANV_MODULE(GANV_ITEM(port)->impl->parent); -} - -float -ganv_port_get_control_value(const GanvPort* port) -{ - return port->impl->control ? port->impl->control->value : 0.0f; -} - -float -ganv_port_get_control_min(const GanvPort* port) -{ - return port->impl->control ? port->impl->control->min : 0.0f; -} - -float -ganv_port_get_control_max(const GanvPort* port) -{ - return port->impl->control ? port->impl->control->max : 0.0f; -} - -gboolean -ganv_port_is_input(const GanvPort* port) -{ - return port->impl->is_input; -} - -gboolean -ganv_port_is_output(const GanvPort* port) -{ - return !port->impl->is_input; -} diff --git a/src/text.c b/src/text.c deleted file mode 100644 index bbac187..0000000 --- a/src/text.c +++ /dev/null @@ -1,381 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2015 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <math.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include <gtk/gtkstyle.h> - -#include "ganv/canvas.h" -#include "ganv/text.h" - -#include "./color.h" -#include "./boilerplate.h" -#include "./gettext.h" -#include "./ganv-private.h" - -G_DEFINE_TYPE_WITH_CODE(GanvText, ganv_text, GANV_TYPE_ITEM, - G_ADD_PRIVATE(GanvText)) - -static GanvItemClass* parent_class; - -enum { - PROP_0, - PROP_TEXT, - PROP_X, - PROP_Y, - PROP_WIDTH, - PROP_HEIGHT, - PROP_COLOR, - PROP_FONT_SIZE -}; - -static void -ganv_text_init(GanvText* text) -{ - GanvTextPrivate* impl = ganv_text_get_instance_private(text); - - text->impl = impl; - - memset(&impl->coords, '\0', sizeof(GanvTextCoords)); - impl->coords.width = 1.0; - impl->coords.height = 1.0; - impl->old_coords = impl->coords; - - impl->layout = NULL; - impl->text = NULL; - impl->font_size = 0.0; - impl->color = DEFAULT_TEXT_COLOR; - impl->needs_layout = FALSE; -} - -static void -ganv_text_destroy(GtkObject* object) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_TEXT(object)); - - GanvText* text = GANV_TEXT(object); - GanvTextPrivate* impl = text->impl; - - if (impl->text) { - g_free(impl->text); - impl->text = NULL; - } - - if (impl->layout) { - g_object_unref(impl->layout); - impl->layout = NULL; - } - - if (GTK_OBJECT_CLASS(parent_class)->destroy) { - (*GTK_OBJECT_CLASS(parent_class)->destroy)(object); - } -} - -void -ganv_text_layout(GanvText* text) -{ - GanvTextPrivate* impl = text->impl; - GanvItem* item = GANV_ITEM(text); - GanvCanvas* canvas = ganv_item_get_canvas(item); - GtkWidget* widget = GTK_WIDGET(canvas); - double points = impl->font_size; - GtkStyle* style = gtk_rc_get_style(widget); - - if (impl->font_size == 0.0) { - points = ganv_canvas_get_font_size(canvas); - } - - if (impl->layout) { - g_object_unref(impl->layout); - } - impl->layout = gtk_widget_create_pango_layout(widget, impl->text); - - PangoFontDescription* font = pango_font_description_copy(style->font_desc); - PangoContext* ctx = pango_layout_get_context(impl->layout); - cairo_font_options_t* opt = cairo_font_options_copy( - pango_cairo_context_get_font_options(ctx)); - - pango_font_description_set_size(font, points * (double)PANGO_SCALE); - pango_layout_set_font_description(impl->layout, font); - pango_cairo_context_set_font_options(ctx, opt); - cairo_font_options_destroy(opt); - pango_font_description_free(font); - - int width, height; - pango_layout_get_pixel_size(impl->layout, &width, &height); - - impl->coords.width = width; - impl->coords.height = height; - impl->needs_layout = FALSE; - - ganv_item_request_update(GANV_ITEM(text)); -} - -static void -ganv_text_set_property(GObject* object, - guint prop_id, - const GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_TEXT(object)); - - GanvText* text = GANV_TEXT(object); - GanvTextPrivate* impl = text->impl; - - switch (prop_id) { - case PROP_X: - impl->coords.x = g_value_get_double(value); - break; - case PROP_Y: - impl->coords.y = g_value_get_double(value); - break; - case PROP_COLOR: - impl->color = g_value_get_uint(value); - break; - case PROP_FONT_SIZE: - impl->font_size = g_value_get_double(value); - impl->needs_layout = TRUE; - break; - case PROP_TEXT: - free(impl->text); - impl->text = g_value_dup_string(value); - impl->needs_layout = TRUE; - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - return; - } - if (impl->needs_layout) { - if (GANV_IS_NODE(GANV_ITEM(text)->impl->parent)) { - GANV_NODE(GANV_ITEM(text)->impl->parent)->impl->must_resize = TRUE; - } - } - ganv_item_request_update(GANV_ITEM(text)); -} - -static void -ganv_text_get_property(GObject* object, - guint prop_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_TEXT(object)); - - GanvText* text = GANV_TEXT(object); - GanvTextPrivate* impl = text->impl; - - if (impl->needs_layout && (prop_id == PROP_WIDTH - || prop_id == PROP_HEIGHT)) { - ganv_text_layout(text); - } - - switch (prop_id) { - GET_CASE(TEXT, string, impl->text); - GET_CASE(X, double, impl->coords.x); - GET_CASE(Y, double, impl->coords.y); - GET_CASE(WIDTH, double, impl->coords.width); - GET_CASE(HEIGHT, double, impl->coords.height); - GET_CASE(COLOR, uint, impl->color); - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -static void -ganv_text_bounds_item(GanvItem* item, - double* x1, double* y1, - double* x2, double* y2) -{ - GanvText* text = GANV_TEXT(item); - GanvTextPrivate* impl = text->impl; - - if (impl->needs_layout) { - ganv_text_layout(text); - } - - *x1 = impl->coords.x; - *y1 = impl->coords.y; - *x2 = impl->coords.x + impl->coords.width; - *y2 = impl->coords.y + impl->coords.height; -} - -static void -ganv_text_bounds(GanvItem* item, - double* x1, double* y1, - double* x2, double* y2) -{ - ganv_text_bounds_item(item, x1, y1, x2, y2); -} - -static void -ganv_text_update(GanvItem* item, int flags) -{ - // Update world-relative bounding box - ganv_text_bounds(item, &item->impl->x1, &item->impl->y1, &item->impl->x2, &item->impl->y2); - ganv_item_i2w_pair(item, &item->impl->x1, &item->impl->y1, &item->impl->x2, &item->impl->y2); - - ganv_canvas_request_redraw_w( - item->impl->canvas, item->impl->x1, item->impl->y1, item->impl->x2, item->impl->y2); - - parent_class->update(item, flags); -} - -static double -ganv_text_point(GanvItem* item, double x, double y, GanvItem** actual_item) -{ - *actual_item = NULL; - - double x1, y1, x2, y2; - ganv_text_bounds_item(item, &x1, &y1, &x2, &y2); - if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) { - return 0.0; - } - - // Point is outside the box - double dx, dy; - - // Find horizontal distance to nearest edge - if (x < x1) { - dx = x1 - x; - } else if (x > x2) { - dx = x - x2; - } else { - dx = 0.0; - } - - // Find vertical distance to nearest edge - if (y < y1) { - dy = y1 - y; - } else if (y > y2) { - dy = y - y2; - } else { - dy = 0.0; - } - - return sqrt((dx * dx) + (dy * dy)); -} - -static void -ganv_text_draw(GanvItem* item, - cairo_t* cr, double cx, double cy, double cw, double ch) -{ - GanvText* text = GANV_TEXT(item); - GanvTextPrivate* impl = text->impl; - - double wx = impl->coords.x; - double wy = impl->coords.y; - ganv_item_i2w(item, &wx, &wy); - - if (impl->needs_layout) { - ganv_text_layout(text); - } - - double r, g, b, a; - color_to_rgba(impl->color, &r, &g, &b, &a); - - cairo_set_source_rgba(cr, r, g, b, a); - cairo_move_to(cr, wx, wy); - pango_cairo_show_layout(cr, impl->layout); -} - -static void -ganv_text_class_init(GanvTextClass* klass) -{ - GObjectClass* gobject_class = (GObjectClass*)klass; - GtkObjectClass* object_class = (GtkObjectClass*)klass; - GanvItemClass* item_class = (GanvItemClass*)klass; - - parent_class = GANV_ITEM_CLASS(g_type_class_peek_parent(klass)); - - gobject_class->set_property = ganv_text_set_property; - gobject_class->get_property = ganv_text_get_property; - - g_object_class_install_property( - gobject_class, PROP_TEXT, g_param_spec_string( - "text", - _("Text"), - _("The string to display."), - NULL, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_X, g_param_spec_double( - "x", - _("x"), - _("Top left x coordinate."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_Y, g_param_spec_double( - "y", - _("y"), - _("Top left y coordinate."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_WIDTH, g_param_spec_double( - "width", - _("Width"), - _("The current width of the text."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 1.0, - G_PARAM_READABLE)); - - g_object_class_install_property( - gobject_class, PROP_HEIGHT, g_param_spec_double( - "height", - _("Height"), - _("The current height of the text."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 1.0, - G_PARAM_READABLE)); - - g_object_class_install_property( - gobject_class, PROP_COLOR, g_param_spec_uint( - "color", - _("Color"), - _("The color of the text."), - 0, G_MAXUINT, - DEFAULT_TEXT_COLOR, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_FONT_SIZE, g_param_spec_double( - "font-size", - _("Font size"), - _("The font size in points."), - -G_MAXDOUBLE, G_MAXDOUBLE, - 0.0, - G_PARAM_READWRITE)); - - - object_class->destroy = ganv_text_destroy; - - item_class->update = ganv_text_update; - item_class->bounds = ganv_text_bounds; - item_class->point = ganv_text_point; - item_class->draw = ganv_text_draw; -} diff --git a/src/widget.c b/src/widget.c deleted file mode 100644 index b08715b..0000000 --- a/src/widget.c +++ /dev/null @@ -1,503 +0,0 @@ -/* This file is part of Ganv. - * Copyright 2007-2016 David Robillard <http://drobilla.net> - * - * Ganv is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or any later version. - * - * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. - * - * You should have received a copy of the GNU General Public License along - * with Ganv. If not, see <http://www.gnu.org/licenses/>. - */ - -/* Based on GnomeCanvasWidget, by Federico Mena <federico@nuclecu.unam.mx> - * Copyright 1997-2000 Free Software Foundation - */ - -#include <math.h> - -#include <gtk/gtksignal.h> - -#include "ganv/canvas.h" -#include "ganv/widget.h" - -#include "./gettext.h" -#include "./ganv-private.h" - -G_DEFINE_TYPE_WITH_CODE(GanvWidget, ganv_widget, GANV_TYPE_ITEM, - G_ADD_PRIVATE(GanvWidget)) - -static GanvItemClass* parent_class; - -enum { - PROP_0, - PROP_WIDGET, - PROP_X, - PROP_Y, - PROP_WIDTH, - PROP_HEIGHT, - PROP_ANCHOR, - PROP_SIZE_PIXELS -}; - -static void -ganv_widget_init(GanvWidget* witem) -{ - GanvWidgetPrivate* impl = ganv_widget_get_instance_private(witem); - - witem->impl = impl; - witem->impl->x = 0.0; - witem->impl->y = 0.0; - witem->impl->width = 0.0; - witem->impl->height = 0.0; - witem->impl->anchor = GTK_ANCHOR_NW; - witem->impl->size_pixels = FALSE; -} - -static void -ganv_widget_destroy(GtkObject* object) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_WIDGET(object)); - - GanvWidget* witem = GANV_WIDGET(object); - - if (witem->impl->widget && !witem->impl->in_destroy) { - g_signal_handler_disconnect(witem->impl->widget, witem->impl->destroy_id); - gtk_widget_destroy(witem->impl->widget); - witem->impl->widget = NULL; - } - - if (GTK_OBJECT_CLASS(parent_class)->destroy) { - (*GTK_OBJECT_CLASS(parent_class)->destroy)(object); - } -} - -static void -recalc_bounds(GanvWidget* witem) -{ - GanvItem* item = GANV_ITEM(witem); - - /* Get world coordinates */ - - double wx = witem->impl->x; - double wy = witem->impl->y; - ganv_item_i2w(item, &wx, &wy); - - /* Get canvas pixel coordinates */ - - ganv_canvas_w2c(item->impl->canvas, wx, wy, &witem->impl->cx, &witem->impl->cy); - - /* Anchor widget item */ - - switch (witem->impl->anchor) { - case GTK_ANCHOR_N: - case GTK_ANCHOR_CENTER: - case GTK_ANCHOR_S: - witem->impl->cx -= witem->impl->cwidth / 2; - break; - - case GTK_ANCHOR_NE: - case GTK_ANCHOR_E: - case GTK_ANCHOR_SE: - witem->impl->cx -= witem->impl->cwidth; - break; - - default: - break; - } - - switch (witem->impl->anchor) { - case GTK_ANCHOR_W: - case GTK_ANCHOR_CENTER: - case GTK_ANCHOR_E: - witem->impl->cy -= witem->impl->cheight / 2; - break; - - case GTK_ANCHOR_SW: - case GTK_ANCHOR_S: - case GTK_ANCHOR_SE: - witem->impl->cy -= witem->impl->cheight; - break; - - default: - break; - } - - /* Bounds */ - - item->impl->x1 = witem->impl->cx; - item->impl->y1 = witem->impl->cy; - item->impl->x2 = witem->impl->cx + witem->impl->cwidth; - item->impl->y2 = witem->impl->cy + witem->impl->cheight; - - int zoom_xofs, zoom_yofs; - ganv_canvas_get_zoom_offsets(item->impl->canvas, &zoom_xofs, &zoom_yofs); - if (witem->impl->widget) { - gtk_layout_move(GTK_LAYOUT(item->impl->canvas), witem->impl->widget, - witem->impl->cx + zoom_xofs, - witem->impl->cy + zoom_yofs); - } -} - -static void -do_destroy(GtkObject* object, gpointer data) -{ - GanvWidget* witem = GANV_WIDGET(data); - - witem->impl->in_destroy = TRUE; - gtk_object_destroy(GTK_OBJECT(data)); -} - -static void -ganv_widget_set_property(GObject* object, - guint param_id, - const GValue* value, - GParamSpec* pspec) -{ - GanvItem* item = GANV_ITEM(object); - GanvWidget* witem = GANV_WIDGET(object); - int update = FALSE; - int calc_bounds = FALSE; - GObject* obj; - - switch (param_id) { - case PROP_WIDGET: - if (witem->impl->widget) { - g_signal_handler_disconnect(witem->impl->widget, witem->impl->destroy_id); - gtk_container_remove(GTK_CONTAINER(item->impl->canvas), witem->impl->widget); - } - - obj = (GObject*)g_value_get_object(value); - if (obj) { - witem->impl->widget = GTK_WIDGET(obj); - witem->impl->destroy_id = g_signal_connect(obj, "destroy", - G_CALLBACK(do_destroy), - witem); - int zoom_xofs, zoom_yofs; - ganv_canvas_get_zoom_offsets(item->impl->canvas, &zoom_xofs, &zoom_yofs); - - gtk_layout_put(GTK_LAYOUT(item->impl->canvas), witem->impl->widget, - witem->impl->cx + zoom_xofs, - witem->impl->cy + zoom_yofs); - } - - update = TRUE; - break; - - case PROP_X: - if (witem->impl->x != g_value_get_double(value)) { - witem->impl->x = g_value_get_double(value); - calc_bounds = TRUE; - } - break; - - case PROP_Y: - if (witem->impl->y != g_value_get_double(value)) { - witem->impl->y = g_value_get_double(value); - calc_bounds = TRUE; - } - break; - - case PROP_WIDTH: - if (witem->impl->width != fabs(g_value_get_double(value))) { - witem->impl->width = fabs(g_value_get_double(value)); - update = TRUE; - } - break; - - case PROP_HEIGHT: - if (witem->impl->height != fabs(g_value_get_double(value))) { - witem->impl->height = fabs(g_value_get_double(value)); - update = TRUE; - } - break; - - case PROP_ANCHOR: - if (witem->impl->anchor != (GtkAnchorType)g_value_get_enum(value)) { - witem->impl->anchor = (GtkAnchorType)g_value_get_enum(value); - update = TRUE; - } - break; - - case PROP_SIZE_PIXELS: - if (witem->impl->size_pixels != g_value_get_boolean(value)) { - witem->impl->size_pixels = g_value_get_boolean(value); - update = TRUE; - } - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); - break; - } - - if (update) { - (*GANV_ITEM_GET_CLASS(item)->update)(item, 0); - } - - if (calc_bounds) { - recalc_bounds(witem); - } -} - -static void -ganv_widget_get_property(GObject* object, - guint param_id, - GValue* value, - GParamSpec* pspec) -{ - g_return_if_fail(object != NULL); - g_return_if_fail(GANV_IS_WIDGET(object)); - - GanvWidget* witem = GANV_WIDGET(object); - - switch (param_id) { - case PROP_WIDGET: - g_value_set_object(value, (GObject*)witem->impl->widget); - break; - - case PROP_X: - g_value_set_double(value, witem->impl->x); - break; - - case PROP_Y: - g_value_set_double(value, witem->impl->y); - break; - - case PROP_WIDTH: - g_value_set_double(value, witem->impl->width); - break; - - case PROP_HEIGHT: - g_value_set_double(value, witem->impl->height); - break; - - case PROP_ANCHOR: - g_value_set_enum(value, witem->impl->anchor); - break; - - case PROP_SIZE_PIXELS: - g_value_set_boolean(value, witem->impl->size_pixels); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); - break; - } -} - -static void -ganv_widget_update(GanvItem* item, int flags) -{ - GanvWidget* witem = GANV_WIDGET(item); - - if (parent_class->update) { - (*parent_class->update)(item, flags); - } - - if (witem->impl->widget) { - const double pixels_per_unit = ganv_canvas_get_zoom(item->impl->canvas); - if (witem->impl->size_pixels) { - witem->impl->cwidth = (int)(witem->impl->width + 0.5); - witem->impl->cheight = (int)(witem->impl->height + 0.5); - } else { - witem->impl->cwidth = (int)(witem->impl->width * pixels_per_unit + 0.5); - witem->impl->cheight = (int)(witem->impl->height * pixels_per_unit + 0.5); - } - - gtk_widget_set_size_request(witem->impl->widget, witem->impl->cwidth, witem->impl->cheight); - } else { - witem->impl->cwidth = 0.0; - witem->impl->cheight = 0.0; - } - - recalc_bounds(witem); -} - -static void -ganv_widget_draw(GanvItem* item, - cairo_t* cr, double cx, double cy, double cw, double ch) -{ - GanvWidget* witem = GANV_WIDGET(item); - - if (witem->impl->widget) { - gtk_widget_queue_draw(witem->impl->widget); - } -} - -static double -ganv_widget_point(GanvItem* item, double x, double y, GanvItem** actual_item) -{ - GanvWidget* witem = GANV_WIDGET(item); - - *actual_item = item; - - double x1, y1; - ganv_canvas_c2w(item->impl->canvas, witem->impl->cx, witem->impl->cy, &x1, &y1); - - const double pixels_per_unit = ganv_canvas_get_zoom(item->impl->canvas); - - double x2 = x1 + (witem->impl->cwidth - 1) / pixels_per_unit; - double y2 = y1 + (witem->impl->cheight - 1) / pixels_per_unit; - - /* Is point inside widget bounds? */ - - if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) { - return 0.0; - } - - /* Point is outside widget bounds */ - - double dx; - if (x < x1) { - dx = x1 - x; - } else if (x > x2) { - dx = x - x2; - } else { - dx = 0.0; - } - - double dy; - if (y < y1) { - dy = y1 - y; - } else if (y > y2) { - dy = y - y2; - } else { - dy = 0.0; - } - - return sqrt(dx * dx + dy * dy); -} - -static void -ganv_widget_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2) -{ - GanvWidget* witem = GANV_WIDGET(item); - - *x1 = witem->impl->x; - *y1 = witem->impl->y; - - switch (witem->impl->anchor) { - case GTK_ANCHOR_NW: - case GTK_ANCHOR_W: - case GTK_ANCHOR_SW: - break; - - case GTK_ANCHOR_N: - case GTK_ANCHOR_CENTER: - case GTK_ANCHOR_S: - *x1 -= witem->impl->width / 2.0; - break; - - case GTK_ANCHOR_NE: - case GTK_ANCHOR_E: - case GTK_ANCHOR_SE: - *x1 -= witem->impl->width; - break; - - default: - break; - } - - switch (witem->impl->anchor) { - case GTK_ANCHOR_NW: - case GTK_ANCHOR_N: - case GTK_ANCHOR_NE: - break; - - case GTK_ANCHOR_W: - case GTK_ANCHOR_CENTER: - case GTK_ANCHOR_E: - *y1 -= witem->impl->height / 2.0; - break; - - case GTK_ANCHOR_SW: - case GTK_ANCHOR_S: - case GTK_ANCHOR_SE: - *y1 -= witem->impl->height; - break; - - default: - break; - } - - *x2 = *x1 + witem->impl->width; - *y2 = *y1 + witem->impl->height; -} - -static void -ganv_widget_class_init(GanvWidgetClass* klass) -{ - GObjectClass* gobject_class = (GObjectClass*)klass; - GtkObjectClass* object_class = (GtkObjectClass*)klass; - GanvItemClass* item_class = (GanvItemClass*)klass; - - parent_class = (GanvItemClass*)g_type_class_peek_parent(klass); - - gobject_class->set_property = ganv_widget_set_property; - gobject_class->get_property = ganv_widget_get_property; - - g_object_class_install_property( - gobject_class, PROP_WIDGET, g_param_spec_object( - "widget", _("Widget"), - _("The widget to embed in this item."), - GTK_TYPE_WIDGET, - (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE))); - - g_object_class_install_property( - gobject_class, PROP_X, g_param_spec_double( - "x", _("x"), - _("The x coordinate of the anchor"), - -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_Y, g_param_spec_double( - "y", _("y"), - _("The x coordinate of the anchor"), - -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_WIDTH, g_param_spec_double( - "width", _("Width"), - _("The width of the widget."), - -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_HEIGHT, g_param_spec_double( - "height", _("Height"), - _("The height of the widget."), - -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_ANCHOR, g_param_spec_enum( - "anchor", _("Anchor"), - _("The anchor point of the widget."), - GTK_TYPE_ANCHOR_TYPE, - GTK_ANCHOR_NW, - G_PARAM_READWRITE)); - - g_object_class_install_property( - gobject_class, PROP_SIZE_PIXELS, g_param_spec_boolean( - "size-pixels", ("Size is in pixels"), - _("Specifies whether the widget size is specified in pixels or" - " canvas units. If it is in pixels, then the widget will not" - " be scaled when the canvas zoom factor changes. Otherwise," - " it will be scaled."), - FALSE, - G_PARAM_READWRITE)); - - object_class->destroy = ganv_widget_destroy; - - item_class->update = ganv_widget_update; - item_class->point = ganv_widget_point; - item_class->bounds = ganv_widget_bounds; - item_class->draw = ganv_widget_draw; -} diff --git a/waflib/COPYING b/waflib/COPYING deleted file mode 100644 index a4147d2..0000000 --- a/waflib/COPYING +++ /dev/null @@ -1,25 +0,0 @@ -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/waflib/waf b/waflib/waf deleted file mode 100755 index e22930a..0000000 --- a/waflib/waf +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python - -# Minimal waf script for projects that include waflib directly - -from waflib import Context, Scripting - -import inspect -import os - -def main(): - script_path = os.path.abspath(inspect.getfile(inspect.getmodule(main))) - project_path = os.path.dirname(script_path) - Scripting.waf_entry_point(os.getcwd(), Context.WAFVERSION, project_path) - -if __name__ == '__main__': - main() diff --git a/wscript b/wscript deleted file mode 100644 index da4fdbd..0000000 --- a/wscript +++ /dev/null @@ -1,247 +0,0 @@ -#!/usr/bin/env python - -import os - -from waflib import Options, Utils -from waflib.extras import autowaf - -# Library and package version (UNIX style major, minor, micro) -# major increment <=> incompatible changes -# minor increment <=> compatible changes (additions) -# micro increment <=> no interface changes -GANV_VERSION = '1.5.4' -GANV_MAJOR_VERSION = '1' - -# Mandatory waf variables -APPNAME = 'ganv' # Package name for waf dist -VERSION = GANV_VERSION # Package version for waf dist -top = '.' # Source directory -out = 'build' # Build directory - -def options(ctx): - ctx.load('compiler_c') - ctx.load('compiler_cxx') - autowaf.set_options(ctx, test=True) - opt = ctx.get_option_group('Configuration options') - autowaf.add_flags( - opt, - {'no-graphviz': 'do not compile with graphviz support', - 'light-theme': 'use light coloured theme', - 'no-fdgl': 'use experimental force-directed graph layout', - 'no-nls': 'disable i18n (native language support)', - 'gir': 'build GObject introspection data'}) - -def configure(conf): - autowaf.display_header('Ganv Configuration') - conf.load('compiler_c', cache=True) - conf.load('compiler_cxx', cache=True) - conf.load('autowaf', cache=True) - autowaf.set_c_lang(conf, 'c99') - - autowaf.check_pkg(conf, 'gtk+-2.0', uselib_store='GTK', - atleast_version='2.0.0', mandatory=True) - autowaf.check_pkg(conf, 'gtkmm-2.4', uselib_store='GTKMM', - atleast_version='2.10.0', mandatory=True) - - if Options.options.gir: - autowaf.check_pkg(conf, 'gobject-introspection-1.0', - uselib_store='GIR', mandatory=False) - conf.find_program('g-ir-doc-tool', var='G_IR_DOC_TOOL', mandatory=False) - conf.find_program('yelp-build', var='YELP_BUILD', mandatory=False) - - if not Options.options.no_graphviz: - autowaf.check_pkg(conf, 'libgvc', uselib_store='AGRAPH', - atleast_version='2.30', mandatory=False) - - if not Options.options.no_fdgl: - autowaf.define(conf, 'GANV_FDGL', 1) - - if Options.options.light_theme: - autowaf.define(conf, 'GANV_USE_LIGHT_THEME', 1) - - if not Options.options.no_nls: - autowaf.check_function(conf, 'cxx', 'dgettext', - header_name = 'libintl.h', - lib = 'intl', - define_name = 'ENABLE_NLS', - mandatory = False) - - autowaf.set_lib_env(conf, 'ganv', GANV_VERSION) - conf.write_config_header('ganv_config.h', remove=False) - - autowaf.display_summary( - conf, - {'Static (Graphviz) arrange': bool(conf.env.HAVE_AGRAPH_2_20), - 'Interactive force-directed arrange': bool(conf.env.GANV_FDGL), - 'Native language support': bool(conf.env.ENABLE_NLS), - 'GObject introspection': bool(conf.env.HAVE_GIR), - 'Unit tests': bool(conf.env.BUILD_TESTS)}) - -ganv_source = [ - 'src/Canvas.cpp', - 'src/Port.cpp', - 'src/box.c', - 'src/circle.c', - 'src/edge.c', - 'src/ganv-marshal.c', - 'src/group.c', - 'src/item.c', - 'src/module.c', - 'src/node.c', - 'src/port.c', - 'src/text.c', - 'src/widget.c' -] - -def declare_doc_files(task): - bld = task.generator.bld - path = bld.path.get_bld().find_or_declare('doc-html') - for i in path.ant_glob('*', remove=False): - i.sig = Utils.h_file(i.abspath()) - -def build(bld): - # Headers - includedir = '${INCLUDEDIR}/ganv-%s/ganv' % GANV_MAJOR_VERSION - bld.install_files(includedir, bld.path.ant_glob('ganv/*.h*')) - - # Pkgconfig file - autowaf.build_pc(bld, 'GANV', GANV_VERSION, GANV_MAJOR_VERSION, - 'GTKMM AGRAPH', - {'GANV_MAJOR_VERSION' : GANV_MAJOR_VERSION}) - - bld(rule = 'glib-genmarshal --prefix=ganv_marshal --header ${SRC} > ${TGT}', - source = 'src/ganv-marshal.list', - target = 'src/ganv-marshal.h') - - bld(rule = 'glib-genmarshal --prefix=ganv_marshal --body ${SRC} > ${TGT}', - source = 'src/ganv-marshal.list', - target = 'src/ganv-marshal.c.in') - - bld(rule = 'cat ${SRC} > ${TGT}', - source = ['src/ganv-marshal.h', 'src/ganv-marshal.c.in'], - target = 'src/ganv-marshal.c') - - # Library - lib = bld(features = 'c cshlib cxx cxxshlib', - export_includes = ['.'], - source = ganv_source, - includes = ['.', './src'], - name = 'libganv', - target = 'ganv-%s' % GANV_MAJOR_VERSION, - uselib = 'GTKMM AGRAPH', - vnum = GANV_VERSION, - install_path = '${LIBDIR}') - if bld.is_defined('ENABLE_NLS'): - lib.lib = ['intl'] - - # Benchmark program (C++) - bld(features = 'cxx cxxprogram', - source = 'src/ganv_bench.cpp', - includes = ['.', './src'], - use = 'libganv', - uselib = 'GTKMM AGRAPH', - target = 'src/ganv_bench') - - if bld.env.BUILD_TESTS: - test_libs = [] - test_cflags = [''] - test_linkflags = [''] - if not bld.env.NO_COVERAGE: - test_cflags += ['--coverage'] - test_linkflags += ['--coverage'] - - # Static library for test program - bld(features = 'c cstlib cxx cxxshlib', - source = ganv_source, - includes = ['.', './src'], - name = 'libganv_profiled', - target = 'ganv_profiled', - uselib = 'GTKMM AGRAPH', - install_path = '', - cflags = test_cflags, - linkflags = test_linkflags) - - # Test program (C) - bld(features = 'cxx cxxprogram', - source = 'src/ganv_test.c', - includes = ['.', './src'], - use = 'libganv_profiled', - lib = test_libs, - uselib = 'GTKMM AGRAPH', - target = 'src/ganv_test', - cflags = test_cflags, - linkflags = test_linkflags) - - # Documentation - #autowaf.build_dox(bld, 'GANV', GANV_VERSION, top, out) - - if bld.env.HAVE_GIR: - bld.add_group() - - bld_dir = os.path.join(out, APPNAME) - if not (len(bld.stack_path) > 1): # not top-level - bld_dir = out - - pc_path = os.path.abspath(os.path.join(bld_dir, 'ganv-1.pc')) - - bld(name = 'ganv-gir', - source = ganv_source + bld.path.ant_glob('ganv/*.h'), - target = 'Ganv-1.0.gir', - install_path = '${LIBDIR}/girepository-1.0', - rule = 'g-ir-scanner --warn-all -n Ganv --nsversion=1.0' - ' --no-libtool ' + - ('--pkg=%s' % pc_path) + - (' -I%s' % bld.path.bldpath()) + - ''.join([' -I' + path for path in bld.env.INCLUDES_GTK]) + - (' -L%s' % bld_dir) + - ' --library=ganv-1' - ' --include=GObject-2.0 --include=Gdk-2.0 --include Gtk-2.0' - ' -o ${TGT} ${SRC}') - - bld(name = 'ganv-typelib', - after = 'ganv-gir', - source = 'Ganv-1.0.gir', - target = 'Ganv-1.0.typelib', - install_path = '${LIBDIR}/girepository-1.0', - rule = 'g-ir-compiler ${SRC} -o ${TGT}') - - if bld.env.DOCS and bld.env['G_IR_DOC_TOOL'] and bld.env['YELP_BUILD']: - # The source and target files used here aren't exclusive, - # but are declared so waf can track dependencies - bld(rule = '${G_IR_DOC_TOOL} --language C -o doc-xml ${SRC}', - source = 'Ganv-1.0.gir', - target = 'doc-xml/index.page') - bld(name = 'yelp-build', - rule = '${YELP_BUILD} html -o doc-html doc-xml', - source = 'doc-xml/index.page', - target = 'doc-html/index.html') - bld(name = 'find-docs', - always = True, - rule = declare_doc_files, - after = 'yelp-build') - - bld.install_files( - os.path.join('${DOCDIR}', 'ganv-0', 'html'), - bld.path.get_bld().ant_glob('doc-html/*')) - - bld.add_post_fun(autowaf.run_ldconfig) - -def test(ctx): - autowaf.pre_test(ctx, APPNAME) - autowaf.run_tests(ctx, APPNAME, ['src/ganv_test'], dirs=['./src']) - autowaf.post_test(ctx, APPNAME) - -def i18n(bld): - autowaf.build_i18n(bld, '..', 'ganv', APPNAME, ganv_source, - 'David Robillard') - -def posts(ctx): - path = str(ctx.path.abspath()) - autowaf.news_to_posts( - os.path.join(path, 'NEWS'), - {'title' : 'Ganv', - 'description' : autowaf.get_blurb(os.path.join(path, 'README')), - 'dist_pattern' : 'http://download.drobilla.net/ganv-%s.tar.bz2'}, - { 'Author' : 'drobilla', - 'Tags' : 'Hacking, LAD, LV2, Ganv' }, - os.path.join(out, 'posts')) |