diff --git a/common.pri b/common.pri index 28f63c91..1a23b61a 100644 --- a/common.pri +++ b/common.pri @@ -16,3 +16,4 @@ include(sparkle.pri) include(harfbuzz.pri) include(freetype.pri) include(fontconfig.pri) +include(scintilla.pri) diff --git a/openscad.pro b/openscad.pro index 62fdbdf3..50d7aca6 100644 --- a/openscad.pro +++ b/openscad.pro @@ -1,14 +1,14 @@ # Environment variables which can be set to specify library locations: -# MPIRDIR -# MPFRDIR -# BOOSTDIR -# CGALDIR -# EIGENDIR -# GLEWDIR -# OPENCSGDIR -# OPENSCAD_LIBRARIES +# MPIRDIR +# MPFRDIR +# BOOSTDIR +# CGALDIR +# EIGENDIR +# GLEWDIR +# OPENCSGDIR +# OPENSCAD_LIBRARIES # -# Please see the 'Building' sections of the OpenSCAD user manual +# Please see the 'Building' sections of the OpenSCAD user manual # for updated tips & workarounds. # # http://en.wikibooks.org/wiki/OpenSCAD_User_Manual @@ -135,13 +135,13 @@ netbsd* { } # Prevent LD_LIBRARY_PATH problems when running the openscad binary -# on systems where uni-build-dependencies.sh was used. +# on systems where uni-build-dependencies.sh was used. # Will not affect 'normal' builds. !isEmpty(OPENSCAD_LIBDIR) { unix:!macx { QMAKE_LFLAGS = -Wl,-R$$OPENSCAD_LIBDIR/lib $$QMAKE_LFLAGS # need /lib64 beause GLEW installs itself there on 64 bit machines - QMAKE_LFLAGS = -Wl,-R$$OPENSCAD_LIBDIR/lib64 $$QMAKE_LFLAGS + QMAKE_LFLAGS = -Wl,-R$$OPENSCAD_LIBDIR/lib64 $$QMAKE_LFLAGS } } @@ -179,8 +179,8 @@ CONFIG += harfbuzz CONFIG += freetype CONFIG += fontconfig -#Uncomment the following line to enable QCodeEdit -#CONFIG += qcodeedit +#Uncomment the following line to enable the QScintilla editor +CONFIG += scintilla # Make experimental features available experimental { @@ -208,7 +208,7 @@ win* { RESOURCES = openscad.qrc -FORMS += src/MainWindow.ui \ +FORMS += src/MainWindow.ui \ src/Preferences.ui \ src/OpenCSGWarningDialog.ui \ src/AboutDialog.ui \ @@ -283,9 +283,9 @@ HEADERS += src/typedefs.h \ src/GeometryEvaluator.h \ src/CSGTermEvaluator.h \ src/Tree.h \ - src/DrawingCallback.h \ - src/FreetypeRenderer.h \ - src/FontCache.h \ +src/DrawingCallback.h \ +src/FreetypeRenderer.h \ +src/FontCache.h \ src/mathc99.h \ src/memory.h \ src/linalg.h \ @@ -305,7 +305,8 @@ HEADERS += src/typedefs.h \ src/system-gl.h \ src/CsgInfo.h \ \ - src/AutoUpdater.h + src/AutoUpdater.h \ + src/legacyeditor.h SOURCES += src/version_check.cc \ src/ProgressWidget.cc \ @@ -360,9 +361,9 @@ SOURCES += src/version_check.cc \ src/ModuleCache.cc \ src/GeometryCache.cc \ src/Tree.cc \ - src/DrawingCallback.cc \ - src/FreetypeRenderer.cc \ - src/FontCache.cc \ +src/DrawingCallback.cc \ +src/FreetypeRenderer.cc \ +src/FontCache.cc \ \ src/rendersettings.cc \ src/highlighter.cc \ @@ -391,7 +392,8 @@ SOURCES += src/version_check.cc \ \ src/openscad.cc \ src/mainwin.cc \ - src/FontListDialog.cc + src/FontListDialog.cc \ + src/legacyeditor.cc # ClipperLib SOURCES += src/polyclipping/clipper.cpp @@ -488,4 +490,3 @@ INSTALLS += man CONFIG(winconsole) { include(winconsole.pri) } - diff --git a/openscad.pro.user b/openscad.pro.user index 087d6e65..ef6a7d28 100644 --- a/openscad.pro.user +++ b/openscad.pro.user @@ -1,6 +1,6 @@ - + ProjectExplorer.Project.ActiveTarget @@ -11,22 +11,24 @@ true false + true Cpp - CppGlobal + CppGlobal QmlJS - QmlJSGlobal + QmlJSGlobal 2 - System + UTF-8 false 4 + false true 1 true @@ -49,135 +51,34 @@ ProjectExplorer.Project.Target.0 - Desktop - Desktop - Qt4ProjectManager.Target.DesktopTarget - 1 + Qt 4.8.6 (qt4) + Qt 4.8.6 (qt4) + {90222843-28c9-4a66-ac82-99bd31ae7263} + 0 0 0 - INVALID + + true qmake QtProjectManager.QMakeBuildStep false false - - false - - - Make - - Qt4ProjectManager.MakeStep - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - Make - - Qt4ProjectManager.MakeStep - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - OPENSCAD_LIBRARIES=$$PWD/../libraries/install - - MacPorts QT4 Release - - Qt4ProjectManager.Qt4BuildConfiguration - 0 - $$PWD/../openscad-build-desktop - -1 - true - - - ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-macos-generic-mach_o-64bit./usr/bin/gdb - - - qmake - - QtProjectManager.QMakeBuildStep - false - false - -spec macx-g++ - false - - - Make - - Qt4ProjectManager.MakeStep - false - -j4 - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - Make - - Qt4ProjectManager.MakeStep - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - OPENSCAD_LIBRARIES=$$PWD/../libraries/install - CCACHE_BASEDIR=$$PWD/.. - PATH=/opt/local/libexec/ccache:/usr/bin:$QTDIR/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/local/bin - EIGEN2DIR=$$PWD/../libraries/install/include/eigen2 - - Desktop Qt 4.7.4 for GCC (Qt SDK) Debug - - Qt4ProjectManager.Qt4BuildConfiguration - 2 - $$PWD - 3 - false - - - INVALID - - - qmake - - QtProjectManager.QMakeBuildStep - false - false - + CONFIG+=experimental false + true Make Qt4ProjectManager.MakeStep + + -w + -r + false @@ -189,9 +90,14 @@ + true Make Qt4ProjectManager.MakeStep + + -w + -r + true clean @@ -204,117 +110,13 @@ 2 false - 4.7.4 Debug - - Qt4ProjectManager.Qt4BuildConfiguration - 2 - $$PWD/../openscad-build-desktop - -1 - true - - - INVALID - - - qmake - - QtProjectManager.QMakeBuildStep - false - false - - false - - - Make - - Qt4ProjectManager.MakeStep - false - - - - 2 - Build - - ProjectExplorer.BuildSteps.Build - - - - Make - - Qt4ProjectManager.MakeStep - true - clean - - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - 4.7.4 Release + Release Qt4ProjectManager.Qt4BuildConfiguration 0 - $$PWD/../openscad-build-desktop - -1 true - - ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-macos-generic-mach_o-64bit./usr/bin/gdb - - - qmake - Clone of qmake - QtProjectManager.QMakeBuildStep - false - false - -spec macx-g++ - false - - - Make - Clone of Make - Qt4ProjectManager.MakeStep - false - - - - 2 - Build - Clone of Build - ProjectExplorer.BuildSteps.Build - - - - Make - Clone of Make - Qt4ProjectManager.MakeStep - true - clean - - - 1 - Clean - Clone of Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - OPENSCAD_LIBRARIES=$$PWD/../libraries/install - - Desktop Qt 4.7.4 for GCC (Qt SDK) Debug - Desktop Qt 4.7.4 for GCC (Qt SDK) - Qt4ProjectManager.Qt4BuildConfiguration - 0 - $$PWD/../openscad-release-desktop - 3 - true - - 5 + 1 0 @@ -323,39 +125,29 @@ ProjectExplorer.BuildSteps.Deploy 1 - No deployment + Deploy locally ProjectExplorer.DefaultDeployConfiguration 1 + - true - true - false - false - false false false - false - false false true - true - 0.01 0.01 10 - 10 true - true - 25 + 1 25 - + 1 + true + false true - true - valgrind valgrind 0 @@ -374,37 +166,22 @@ 13 14 - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - + 2 + openscad - Qt4ProjectManager.Qt4RunConfiguration - 2 + Qt4ProjectManager.Qt4RunConfiguration:/home/shaina/letsbegin/openscad/openscad.pro openscad.pro false false - 3768 true + false + false false - false + true 1 @@ -415,10 +192,10 @@ ProjectExplorer.Project.Updater.EnvironmentId - {b7a15081-01e1-47e4-b2e5-20f6404deb62} + {56f57d1a-fe9b-42b2-a96b-3ac76cf7565f} ProjectExplorer.Project.Updater.FileVersion - 10 + 15 diff --git a/qscintilla2.prf b/qscintilla2.prf new file mode 100644 index 00000000..a3043f91 --- /dev/null +++ b/qscintilla2.prf @@ -0,0 +1,12 @@ +greaterThan(QT_MAJOR_VERSION, 4) { + QT += widgets printsupport + + greaterThan(QT_MINOR_VERSION, 1) { + macx:QT += macextras + } +} + +INCLUDEPATH += $$[QT_INSTALL_HEADERS] + +LIBS += -L$$[QT_INSTALL_LIBS] +LIBS += -lqscintilla2 diff --git a/scintilla.pri b/scintilla.pri new file mode 100644 index 00000000..aebb1262 --- /dev/null +++ b/scintilla.pri @@ -0,0 +1,11 @@ +scintilla { + HEADERS += src/scintillaeditor.h src/scadlexer.h + SOURCES += src/scintillaeditor.cpp src/scadlexer.cpp + + DEFINES += USE_SCINTILLA_EDITOR + + # The qscintilla2.prf which ships with QScintilla is broken for Mac/Windows + # debug builds, so we supply our own + win32|macx: include(qscintilla2.prf) + else: CONFIG += qscintilla2 +} diff --git a/scripts/common-build-dependencies.sh b/scripts/common-build-dependencies.sh index 3e60a775..87a2bed0 100644 --- a/scripts/common-build-dependencies.sh +++ b/scripts/common-build-dependencies.sh @@ -55,6 +55,7 @@ build_libxml2() build_fontconfig() { version=$1 + extra_config_flags="$2" if [ -e $DEPLOYDIR/include/fontconfig ]; then echo "fontconfig already installed. not building" @@ -70,10 +71,10 @@ build_fontconfig() tar xzf "fontconfig-$version.tar.gz" cd "fontconfig-$version" export PKG_CONFIG_PATH="$DEPLOYDIR/lib/pkgconfig" - ./configure --prefix="$DEPLOYDIR" --enable-libxml2 --disable-docs + ./configure --prefix=/ --enable-libxml2 --disable-docs $extra_config_flags unset PKG_CONFIG_PATH - make -j$NUMCPU - make install + DESTDIR="$DEPLOYDIR" make -j$NUMCPU + DESTDIR="$DEPLOYDIR" make install } build_libffi() diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh index 355239d0..575e76f5 100755 --- a/scripts/macosx-build-dependencies.sh +++ b/scripts/macosx-build-dependencies.sh @@ -133,6 +133,22 @@ build_qt5() make -j"$NUMCPU" install } +build_qscintilla() +{ + version=$1 + echo "Building QScintilla" $version "..." + cd $BASEDIR/src + rm -rf QScintilla-gpl-$version + if [ ! -f QScintilla-gpl-$version.tar.gz ]; then + curl -LO http://downloads.sourceforge.net/project/pyqt/QScintilla2/QScintilla-$version/QScintilla-gpl-$version.tar.gz + fi + tar xzf QScintilla-gpl-$version.tar.gz + cd QScintilla-gpl-$version/Qt4Qt5 + qmake qscintilla.pro + make -j6 install + install_name_tool -id $DEPLOYDIR/lib/libqscintilla2.dylib $DEPLOYDIR/lib/libqscintilla2.dylib +} + # Hack warning: gmplib is built separately in 32-bit and 64-bit mode # and then merged afterwards. gmplib's header files are dependent on # the CPU architecture on which configure was run and will be patched accordingly. @@ -754,6 +770,7 @@ fi echo "Using basedir:" $BASEDIR mkdir -p $SRCDIR $DEPLOYDIR build_qt5 5.3.1 +build_qscintilla 2.8.3 # NB! For eigen, also update the path in the function build_eigen 3.2.1 build_gmp 5.1.3 diff --git a/scripts/mingw-x-build-dependencies.sh b/scripts/mingw-x-build-dependencies.sh index 95f971d1..23519801 100755 --- a/scripts/mingw-x-build-dependencies.sh +++ b/scripts/mingw-x-build-dependencies.sh @@ -65,14 +65,14 @@ if [ "`echo $* | grep 64`" ]; then if [ "`echo $* | grep download`" ]; then PACKAGES='download-mpfr download-eigen download-opencsg download-cgal download-qtbase download-glib download-freetype download-fontconfig download-harfbuzz' else - PACKAGES='qtbase mpfr eigen opencsg cgal glib freetype fontconfig harfbuzz' + PACKAGES='qtbase qscintilla2 mpfr eigen opencsg cgal glib freetype fontconfig harfbuzz' fi else MXE_TARGETS='i686-w64-mingw32.static' if [ "`echo $* | grep download`" ]; then PACKAGES='download-mpfr download-eigen download-opencsg download-cgal download-qtbase download-nsis download-glib download-freetype download-fontconfig download-harfbuzz' else - PACKAGES='qtbase mpfr eigen opencsg cgal nsis glib freetype fontconfig harfbuzz' + PACKAGES='qtbase qscintilla2 mpfr eigen opencsg cgal nsis glib freetype fontconfig harfbuzz' fi fi echo make $PACKAGES MXE_TARGETS=$MXE_TARGETS -j $NUMCPU JOBS=$NUMJOBS diff --git a/scripts/openscad-linux b/scripts/openscad-linux index 1246199c..3ca48611 100755 --- a/scripts/openscad-linux +++ b/scripts/openscad-linux @@ -4,5 +4,6 @@ cd "$( dirname "$( type -p $0 )" )" libdir=$PWD/../lib/openscad/ cd "$OLDPWD" +export LIBGL_DRIVERS_PATH="$libdir"/dri export LD_LIBRARY_PATH="$libdir${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" exec $libdir/openscad "$@" diff --git a/scripts/release-common.sh b/scripts/release-common.sh index 337dab9b..80402ef2 100755 --- a/scripts/release-common.sh +++ b/scripts/release-common.sh @@ -455,12 +455,26 @@ case $OS in gcc -o chrpath_linux -DSIZEOF_VOID_P=4 scripts/chrpath_linux.c fi ./chrpath_linux -d openscad-$VERSION/lib/openscad/openscad - ldd openscad | sed -re 's,.* => ,,; s,[\t ].*,,;' -e '/Qt|boost/ { p; d; };' \ - -e '/lib(icu.*|stdc.*|audio|CGAL|GLEW|opencsg|png|gmp|gmpxx|mpfr)\.so/ { p; d; };' \ - -e 'd;' | xargs cp -vt openscad-$VERSION/lib/openscad/ + + QTLIBDIR=$(dirname $(ldd openscad | grep Qt5Gui | head -n 1 | awk '{print $3;}')) + ( ldd openscad ; ldd "$QTLIBDIR"/qt5/plugins/platforms/libqxcb.so ) \ + | sed -re 's,.* => ,,; s,[\t ].*,,;' -e '/^$/d' -e '/libc\.so|libm\.so|libdl\.so|libgcc_|libpthread\.so/d' \ + | sort -u \ + | xargs cp -vt "openscad-$VERSION/lib/openscad/" + PLATFORMDIR="openscad-$VERSION/lib/openscad/platforms/" + mkdir -p "$PLATFORMDIR" + cp -av "$QTLIBDIR"/qt5/plugins/platforms/libqxcb.so "$PLATFORMDIR" + DRIDRIVERDIR=$(find /usr/lib -xdev -type d -name dri) + if [ -d "$DRIDRIVERDIR" ] + then + DRILIB="openscad-$VERSION/lib/openscad/dri/" + mkdir -p "$DRILIB" + cp -av "$DRIDRIVERDIR"/swrast_dri.so "$DRILIB" + fi + strip openscad-$VERSION/lib/openscad/* mkdir -p openscad-$VERSION/share/appdata - cp openscad.appdata.xml openscad-$VERSION/share/appdata + cp icons/openscad.{desktop,png,xml} openscad-$VERSION/share/appdata cp scripts/installer-linux.sh openscad-$VERSION/install.sh chmod 755 -R openscad-$VERSION/ PACKAGEFILE=openscad-$VERSION.x86-$ARCH.tar.gz diff --git a/scripts/uni-build-dependencies.sh b/scripts/uni-build-dependencies.sh index 00f3ffdd..5ee34919 100755 --- a/scripts/uni-build-dependencies.sh +++ b/scripts/uni-build-dependencies.sh @@ -131,6 +131,56 @@ build_qt4() echo "----------" } +build_qt5() +{ + version=$1 + + if [ -f $DEPLOYDIR/lib/libQt5Core.a ]; then + echo "Qt5 already installed. not building" + return + fi + + echo "Building Qt" $version "..." + cd $BASEDIR/src + rm -rf qt-everywhere-opensource-src-$version + v=`echo "$version" | sed -e 's/\.[0-9]$//'` + if [ ! -f qt-everywhere-opensource-src-$version.tar.gz ]; then + curl -O -L http://download.qt-project.org/official_releases/qt/$v/$version/single/qt-everywhere-opensource-src-$version.tar.gz + fi + tar xzf qt-everywhere-opensource-src-$version.tar.gz + cd qt-everywhere-opensource-src-$version + ./configure -prefix $DEPLOYDIR -release -static -opensource -confirm-license \ + -nomake examples -nomake tests \ + -qt-xcb -no-c++11 -no-glib -no-harfbuzz -no-sql-db2 -no-sql-ibase -no-sql-mysql -no-sql-oci -no-sql-odbc \ + -no-sql-psql -no-sql-sqlite2 -no-sql-tds -no-cups -no-qml-debug \ + -skip activeqt -skip connectivity -skip declarative -skip doc \ + -skip enginio -skip graphicaleffects -skip location -skip multimedia \ + -skip quick1 -skip quickcontrols -skip script -skip sensors -skip serialport \ + -skip svg -skip webkit -skip webkit-examples -skip websockets -skip xmlpatterns + make -j"$NUMCPU" install +} + +build_qt5scintilla2() +{ + version=$1 + + if [ -d $DEPLOYDIR/lib/libqt5scintilla2.a ]; then + echo "Qt5Scintilla2 already installed. not building" + return + fi + + echo "Building Qt5Scintilla2" $version "..." + cd $BASEDIR/src + #rm -rf QScintilla-gpl-$version.tar.gz + if [ ! -f QScintilla-gpl-$version.tar.gz ]; then + curl -L -o "QScintilla-gpl-$version.tar.gz" "http://downloads.sourceforge.net/project/pyqt/QScintilla2/QScintilla-$version/QScintilla-gpl-$version.tar.gz?use_mirror=switch" + fi + tar xzf QScintilla-gpl-$version.tar.gz + cd QScintilla-gpl-$version/Qt4Qt5/ + qmake CONFIG+=staticlib + make -j"$NUMCPU" install +} + build_bison() { version=$1 @@ -210,7 +260,7 @@ build_gmp() cd $BASEDIR/src rm -rf gmp-$version if [ ! -f gmp-$version.tar.bz2 ]; then - curl --insecure -O ftp://ftp.gmplib.org/pub/gmp-$version/gmp-$version.tar.bz2 + curl --insecure -O https://gmplib.org/download/gmp/gmp-$version.tar.bz2 fi tar xjf gmp-$version.tar.bz2 cd gmp-$version @@ -315,6 +365,7 @@ build_cgal() echo "Building CGAL" $version "..." cd $BASEDIR/src rm -rf CGAL-$version + ver4_4="curl --insecure -O https://gforge.inria.fr/frs/download.php/file/33524/CGAL-4.4.tar.bz2" ver4_2="curl --insecure -O https://gforge.inria.fr/frs/download.php/32360/CGAL-4.2.tar.bz2" ver4_1="curl --insecure -O https://gforge.inria.fr/frs/download.php/31640/CGAL-4.1.tar.bz2" ver4_0_2="curl --insecure -O https://gforge.inria.fr/frs/download.php/31174/CGAL-4.0.2.tar.bz2" @@ -509,6 +560,7 @@ build_eigen() cd $BASEDIR/src rm -rf eigen-$version EIGENDIR="none" + if [ $version = "3.2.2" ]; then EIGENDIR=eigen-eigen-1306d75b4a21; fi if [ $version = "3.1.1" ]; then EIGENDIR=eigen-eigen-43d9075b23ef; fi if [ $EIGENDIR = "none" ]; then echo Unknown eigen version. Please edit script. @@ -697,7 +749,7 @@ if [ $1 ]; then exit $? fi if [ $1 = "cgal" ]; then - build_cgal 4.0.2 use-sys-libs + build_cgal 4.4 use-sys-libs exit $? fi if [ $1 = "opencsg" ]; then @@ -709,6 +761,11 @@ if [ $1 ]; then build_qt4 4.8.4 exit $? fi + if [ $1 = "qt5" ]; then + build_qt5 5.3.1 + build_qt5scintilla2 2.8.3 + exit $? + fi if [ $1 = "glu" ]; then # Mesa and GLU split in late 2012, so it's not on some systems build_glu 9.0.0 @@ -741,21 +798,21 @@ fi # # Some of these are defined in scripts/common-build-dependencies.sh -build_eigen 3.1.1 +build_eigen 3.2.2 build_gmp 5.0.5 build_mpfr 3.1.1 -build_boost 1.53.0 +build_boost 1.56.0 # NB! For CGAL, also update the actual download URL in the function -build_cgal 4.0.2 +build_cgal 4.4 build_glew 1.9.0 build_opencsg 1.3.2 build_gettext 0.18.3.1 build_glib2 2.38.2 # the following are only needed for text() -build_freetype 2.5.0.1 +build_freetype 2.5.0.1 --without-png build_libxml2 2.9.1 -build_fontconfig 2.11.0 +build_fontconfig 2.11.0 --with-add-fonts=/usr/X11R6/lib/X11/fonts,/usr/local/share/fonts build_ragel 6.8 build_harfbuzz 0.9.23 --with-glib=yes diff --git a/scripts/uni-get-dependencies.sh b/scripts/uni-get-dependencies.sh index 16cfa93a..92e17d65 100755 --- a/scripts/uni-get-dependencies.sh +++ b/scripts/uni-get-dependencies.sh @@ -57,7 +57,7 @@ get_mageia_deps() get_debian_deps() { - for pkg in build-essential libqt4-dev libqt4-opengl-dev \ + for pkg in build-essential curl libffi-dev qtbase5-dev \ libxmu-dev cmake bison flex git-core libboost-all-dev \ libXi-dev libmpfr-dev libboost-dev libglew-dev \ libeigen3-dev libcgal-dev libopencsg-dev libgmp3-dev libgmp-dev \ @@ -65,6 +65,15 @@ get_debian_deps() libharfbuzz-dev gtk-doc-tools libglib2.0-dev gettext; do sudo apt-get -y install $pkg; done + + # The following packages are only needed to build the static + # Qt5 version for release builds / older distributions. + for pkg in libdbus-1-dev \ + libxcb1-dev libx11-xcb-dev libxcb-keysyms1-dev libxcb-image0-dev \ + libxcb-shm0-dev libxcb-icccm4-dev libxcb-sync0-dev libxcb-xfixes0-dev \ + libxrender-dev libxcb-shape0-dev libxcb-randr0-dev libxcb-glx0-dev; do + sudo apt-get -y install $pkg; + done } unknown() diff --git a/setenv_mac-qt4.sh b/setenv_mac-qt4.sh index 1616245d..22ccbb69 100644 --- a/setenv_mac-qt4.sh +++ b/setenv_mac-qt4.sh @@ -1,4 +1,4 @@ -export OPENSCAD_LIBRARIES=$PWD/../libraries/install +export OPENSCAD_LIBRARIES=$PWD/../libraries/install-qt4 export DYLD_LIBRARY_PATH=$OPENSCAD_LIBRARIES/lib export DYLD_FRAMEWORK_PATH=$OPENSCAD_LIBRARIES/lib export QMAKESPEC=unsupported/macx-clang diff --git a/src/LibraryInfo.cc b/src/LibraryInfo.cc index 443b4e10..b15cb7e4 100644 --- a/src/LibraryInfo.cc +++ b/src/LibraryInfo.cc @@ -1,6 +1,9 @@ #include "LibraryInfo.h" #include #include +#ifdef USE_SCINTILLA_EDITOR +#include +#endif #include "version_check.h" #define STRINGIFY(x) #x @@ -82,6 +85,9 @@ std::string LibraryInfo::info() << "\nCGAL version, kernels: " << TOSTRING(CGAL_VERSION) << ", " << cgal_3d_kernel << ", " << cgal_2d_kernel << ", " << cgal_2d_kernelEx << "\nOpenCSG version: " << OPENCSG_VERSION_STRING << "\nQt version: " << qtVersion +#ifdef USE_SCINTILLA_EDITOR + << "\nQScintilla version: " << QSCINTILLA_VERSION_STR +#endif << "\nMingW build: " << mingwstatus << "\nGLib version: " << GLIB_MAJOR_VERSION << "." << GLIB_MINOR_VERSION << "." << GLIB_MICRO_VERSION << "\nOPENSCADPATH: " << (env_path == NULL ? "" : env_path) diff --git a/src/MainWindow.h b/src/MainWindow.h index be4e338b..2843102d 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -7,6 +7,7 @@ #include "module.h" #include "Tree.h" #include "memory.h" +#include "editor.h" #include #include #include @@ -65,6 +66,9 @@ public: static const int maxRecentFiles = 10; QAction *actionRecentFile[maxRecentFiles]; QMap knownFileExtensions; + + QString editortype; + bool useScintilla; MainWindow(const QString &filename); ~MainWindow(); @@ -105,6 +109,8 @@ private: void show_examples(); void setDockWidgetTitle(QDockWidget *dockWidget, QString prefix, bool topLevel); + EditorInterface *editor; + class QMessageBox *openglbox; class FontListDialog *font_list_dialog; @@ -135,14 +141,13 @@ private slots: private slots: void selectFindType(int); void find(); + void findString(QString); void findAndReplace(); void findNext(); void findPrev(); - void useSelectionForFind(); void replace(); void replaceAll(); protected: - bool findOperation(QTextDocument::FindFlags options = 0); virtual bool eventFilter(QObject* obj, QEvent *event); private slots: diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 31d6d49a..6ae8c7c2 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -179,7 +179,6 @@ - @@ -295,6 +294,15 @@ 0 + + 0 + + + 0 + + + 0 + @@ -361,25 +369,6 @@ - - - - - 100 - 100 - - - - - Monaco - 8 - - - - Qt::WheelFocus - - - @@ -461,7 +450,7 @@ Ctrl+Z - Qt::WidgetWithChildrenShortcut + Qt::WindowShortcut @@ -472,7 +461,7 @@ Ctrl+Shift+Z - Qt::WidgetWithChildrenShortcut + Qt::WindowShortcut @@ -483,7 +472,7 @@ Ctrl+X - Qt::WidgetWithChildrenShortcut + Qt::WindowShortcut @@ -494,7 +483,7 @@ Ctrl+C - Qt::WidgetWithChildrenShortcut + Qt::WindowShortcut @@ -505,7 +494,7 @@ Ctrl+V - Qt::WidgetWithChildrenShortcut + Qt::WindowShortcut @@ -776,9 +765,6 @@ Center - - Ctrl+P - @@ -975,15 +961,8 @@
QGLView.h
1 - - Editor - QWidget -
editor.h
-
- - - + fileActionClose diff --git a/src/PlatformUtils.cc b/src/PlatformUtils.cc index eb348c3d..a7f6c61a 100644 --- a/src/PlatformUtils.cc +++ b/src/PlatformUtils.cc @@ -3,6 +3,9 @@ #include "PlatformUtils.h" #include "boosty.h" #include +#ifdef USE_SCINTILLA_EDITOR +#include +#endif extern std::vector librarypath; extern std::vector fontpath; diff --git a/src/Preferences.cc b/src/Preferences.cc index a0bf5b49..5a47d880 100644 --- a/src/Preferences.cc +++ b/src/Preferences.cc @@ -66,6 +66,7 @@ Preferences::Preferences(QWidget *parent) : QMainWindow(parent) this->defaultmap["editor/fontfamily"] = found_family; this->defaultmap["editor/fontsize"] = 12; this->defaultmap["editor/syntaxhighlight"] = "For Light Background"; + this->defaultmap["editor/editortype"] = "Simple Editor"; #if defined (Q_OS_MAC) this->defaultmap["editor/ctrlmousewheelzoom"] = false; @@ -85,9 +86,12 @@ Preferences::Preferences(QWidget *parent) : QMainWindow(parent) connect(this->fontSize, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(on_fontSize_editTextChanged(const QString &))); + connect(this->editorType, SIGNAL(currentIndexChanged(const QString&)), + this, SLOT(on_editorType_editTextChanged(const QString &))); + // reset GUI fontsize if fontSize->addItem emitted signals that changed it. this->fontSize->setEditText( QString("%1").arg( savedsize ) ); - + // Setup default settings this->defaultmap["advanced/opencsg_show_warning"] = true; this->defaultmap["advanced/enable_opencsg_opengl1x"] = true; @@ -261,6 +265,12 @@ void Preferences::on_fontSize_editTextChanged(const QString &size) emit fontChanged(getValue("editor/fontfamily").toString(), intsize); } +void Preferences::on_editorType_editTextChanged(const QString &type) +{ + QSettings settings; + settings.setValue("editor/editortype", type); +} + void Preferences::on_syntaxHighlight_currentIndexChanged(const QString &s) { QSettings settings; @@ -430,6 +440,10 @@ void Preferences::updateGUI() int shidx = this->syntaxHighlight->findText(shighlight); if (shidx >= 0) this->syntaxHighlight->setCurrentIndex(shidx); + QString editortypevar = getValue("editor/editortype").toString(); + int edidx = this->editorType->findText(editortypevar); + if (edidx >=0) this->editorType->setCurrentIndex(edidx); + this->mouseWheelZoomBox->setChecked(getValue("editor/ctrlmousewheelzoom").toBool()); if (AutoUpdater *updater = AutoUpdater::updater()) { diff --git a/src/Preferences.h b/src/Preferences.h index 4aad048d..be951ade 100644 --- a/src/Preferences.h +++ b/src/Preferences.h @@ -35,7 +35,7 @@ public slots: void on_mdiCheckBox_toggled(bool); void on_undockCheckBox_toggled(bool); void on_checkNowButton_clicked(); - + void on_editorType_editTextChanged(const QString &); signals: void requestRedraw() const; void updateMdiMode(bool mdi) const; @@ -44,6 +44,7 @@ signals: void colorSchemeChanged(const QString &scheme) const; void openCSGSettingsChanged() const; void syntaxHighlightChanged(const QString &s); + void editorTypeChanged(const QString &type); private: Preferences(QWidget *parent = NULL); diff --git a/src/Preferences.ui b/src/Preferences.ui index 80cff0cf..f880fb57 100644 --- a/src/Preferences.ui +++ b/src/Preferences.ui @@ -6,8 +6,8 @@ 0 0 - 823 - 440 + 584 + 403
@@ -23,26 +23,32 @@ true - - - - - 4 - - - + + + + 10 + 10 + 470 + 899 + + + + 1 + + + + + - + + + + + Color scheme: + + + - - - - - Color scheme: - - - - @@ -92,64 +98,330 @@ - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - + - Qt::Vertical + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 645 + + + + + + + + + + + + + + + 75 + true + + + + Editor Type + + + + + + + + Simple Editor + + + + + QScintilla Editor + + + + + + + + + 10 + 50 + false + + + + (requires restart) + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding QSizePolicy::Expanding - 20 - 645 + 30 + 20 - - - + + + - - - - - - 75 - true - - + + + + 75 + true + + + + Font + + + false + + + + + + + + Helvetica + 12 + + + + + + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + + + + 75 + true + + + + Color syntax highlighting + + + + + + + + 0 + 0 + + + + + For Light Background + + + + + For Dark Background + + + + + Monokai + + + + + Solarized + + + + + Off + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 30 + 20 + + + + + + + + + + 5 + + + + + + 75 + true + + + + Use Ctrl/Cmd-Mouse-wheel to zoom text + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 723 + + + + + + + + + + + + + + - Font + Automatically check for updates - - false + + true - - + + + + Include development snapshots + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + + + Qt::Horizontal @@ -161,25 +433,15 @@ - - - - - DejaVu Sans - 12 - + + + + Check Now - - - - true - - - - - + + Qt::Horizontal @@ -194,10 +456,7 @@ - - - 0 - + @@ -241,46 +500,31 @@ Qt::Horizontal - - QSizePolicy::Expanding - - 30 + 40 20 - - - - - - 5 - - + + + false + - 75 - true + 11 - Use Ctrl/Cmd-Mouse-wheel to zoom text + Last checked: - - - - - - - - + Qt::Horizontal @@ -294,367 +538,223 @@ - - - - Qt::Vertical - - - - 20 - 77 - - - - - - - - - - - - - - - Automatically check for updates - - - true - - - - - - - Include development snapshots - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Check Now - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - false - - - - 11 - - - - Last checked: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Qt::Vertical - - - - 20 - 89 - - - - - - - - - - 0 + + + + + Qt::Vertical - - - - - - - 75 - true - - - - Features - - - - - - - QFrame::NoFrame - - - QFrame::Plain - - - Qt::ScrollBarAlwaysOff - - - true - - - - - 0 - 0 - 803 - 325 - - - - - - - 8 - - - - - - - Qt::Vertical - - - - 20 - 282 - - - - + + + 20 + 89 + + + + + + + + + + 0 + + + + + + + + 75 + true + + + + Features + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 83 + 36 + + + + + + + 8 + - - - - + + + + + Qt::Vertical + + + + 20 + 282 + + + + + + + - - - - - - - OpenCSG - - + + + + + + + + + OpenCSG + + + + + + Show capability warning + + + true + + + + + + + Enable for OpenGL 1.x + + + + + - + - Show capability warning - - - true + Turn off rendering at - - - Enable for OpenGL 1.x - - + - - - - - Turn off rendering at - - - - - - - - - - elements - - - - - - - + - Force Goldfeather + elements - - + + + + + Force Goldfeather + + + + + + + + - - - - - CGAL Cache size - - - - - - - - - - bytes - - - - - - - - - - - PolySet Cache size - - - - - - - - - - bytes - - - - - - - - - Qt::Vertical - - - - 20 - 11 - - - - - - + - Allow to open multiple documents + CGAL Cache size - + + + + - Enable undocking of Editor and Console + bytes - - - - + + + + + + + PolySet Cache size + + + + + + + + + + bytes + + + + + + + + + Qt::Vertical + + + + 20 + 11 + + + + + + + + Allow to open multiple documents + + + + + + + Enable undocking of Editor and Console + + + + + + diff --git a/src/editor.cc b/src/editor.cc index c870db6a..b9d528d0 100644 --- a/src/editor.cc +++ b/src/editor.cc @@ -1,173 +1,16 @@ #include "editor.h" #include "Preferences.h" -Editor::Editor(QWidget *parent) : QTextEdit(parent) -{ - setAcceptRichText(false); - // This needed to avoid QTextEdit accepting filename drops as we want - // to handle these ourselves in MainWindow - setAcceptDrops(false); - this->highlighter = new Highlighter(this->document()); -} - -void Editor::indentSelection() -{ - QTextCursor cursor = textCursor(); - int p1 = cursor.selectionStart(); - QString txt = cursor.selectedText(); - - txt.replace(QString(QChar(8233)), QString(QChar(8233)) + QString("\t")); - if (txt.endsWith(QString(QChar(8233)) + QString("\t"))) - txt.chop(1); - txt = QString("\t") + txt; - - cursor.insertText(txt); - int p2 = cursor.position(); - cursor.setPosition(p1, QTextCursor::MoveAnchor); - cursor.setPosition(p2, QTextCursor::KeepAnchor); - setTextCursor(cursor); -} - -void Editor::unindentSelection() -{ - QTextCursor cursor = textCursor(); - int p1 = cursor.selectionStart(); - QString txt = cursor.selectedText(); - - txt.replace(QString(QChar(8233)) + QString("\t"), QString(QChar(8233))); - if (txt.startsWith(QString("\t"))) - txt.remove(0, 1); - - cursor.insertText(txt); - int p2 = cursor.position(); - cursor.setPosition(p1, QTextCursor::MoveAnchor); - cursor.setPosition(p2, QTextCursor::KeepAnchor); - setTextCursor(cursor); -} - -void Editor::commentSelection() -{ - QTextCursor cursor = textCursor(); - int p1 = cursor.selectionStart(); - QString txt = cursor.selectedText(); - - txt.replace(QString(QChar(8233)), QString(QChar(8233)) + QString("//")); - if (txt.endsWith(QString(QChar(8233)) + QString("//"))) - txt.chop(2); - txt = QString("//") + txt; - - cursor.insertText(txt); - int p2 = cursor.position(); - cursor.setPosition(p1, QTextCursor::MoveAnchor); - cursor.setPosition(p2, QTextCursor::KeepAnchor); - setTextCursor(cursor); -} - -void Editor::uncommentSelection() -{ - QTextCursor cursor = textCursor(); - int p1 = cursor.selectionStart(); - QString txt = cursor.selectedText(); - - txt.replace(QString(QChar(8233)) + QString("//"), QString(QChar(8233))); - if (txt.startsWith(QString("//"))) - txt.remove(0, 2); - - cursor.insertText(txt); - int p2 = cursor.position(); - cursor.setPosition(p1, QTextCursor::MoveAnchor); - cursor.setPosition(p2, QTextCursor::KeepAnchor); - setTextCursor(cursor); -} - -void Editor::zoomIn() -{ - // See also QT's implementation in QEditor.cpp - QSettings settings; - QFont tmp_font = this->font() ; - if ( font().pointSize() >= 1 ) - tmp_font.setPointSize( 1 + font().pointSize() ); - else - tmp_font.setPointSize( 1 ); - settings.setValue("editor/fontsize", tmp_font.pointSize()); - this->setFont( tmp_font ); -} - -void Editor::zoomOut() -{ - QSettings settings; - QFont tmp_font = this->font(); - if ( font().pointSize() >= 2 ) - tmp_font.setPointSize( -1 + font().pointSize() ); - else - tmp_font.setPointSize( 1 ); - settings.setValue("editor/fontsize", tmp_font.pointSize()); - this->setFont( tmp_font ); -} - -void Editor::wheelEvent ( QWheelEvent * event ) +void EditorInterface::wheelEvent(QWheelEvent *event) { QSettings settings; bool wheelzoom_enabled = Preferences::inst()->getValue("editor/ctrlmousewheelzoom").toBool(); - if ((event->modifiers() == Qt::ControlModifier) && wheelzoom_enabled ) { - if (event->delta() > 0 ) + if ((event->modifiers() == Qt::ControlModifier) && wheelzoom_enabled) { + if (event->delta() > 0) zoomIn(); - else if (event->delta() < 0 ) + else if (event->delta() < 0) zoomOut(); } else { - QTextEdit::wheelEvent( event ); + QWidget::wheelEvent(event); } } - -void Editor::setPlainText(const QString &text) -{ - int y = verticalScrollBar()->sliderPosition(); - // Save current cursor position - QTextCursor cursor = textCursor(); - int n = cursor.position(); - QTextEdit::setPlainText(text); - // Restore cursor position - if (n < text.length()) { - cursor.setPosition(n); - setTextCursor(cursor); - verticalScrollBar()->setSliderPosition(y); - } -} - -void Editor::highlightError(int error_pos) -{ - highlighter->highlightError( error_pos ); - QTextCursor cursor = this->textCursor(); - cursor.setPosition( error_pos ); - this->setTextCursor( cursor ); -} - -void Editor::unhighlightLastError() -{ - highlighter->unhighlightLastError(); -} - -void Editor::setHighlightScheme(const QString &name) -{ - highlighter->assignFormatsToTokens( name ); - highlighter->rehighlight(); // slow on large files -} - -QSize Editor::sizeHint() const -{ - if (initialSizeHint.width() <= 0) { - return QTextEdit::sizeHint(); - } else { - return initialSizeHint; - } -} - -void Editor::setInitialSizeHint(const QSize &size) -{ - initialSizeHint = size; -} - -Editor::~Editor() -{ - delete highlighter; -} diff --git a/src/editor.h b/src/editor.h index 8abb20af..6aa20472 100644 --- a/src/editor.h +++ b/src/editor.h @@ -1,35 +1,52 @@ +#pragma once + #include #include #include #include #include #include -#include "highlighter.h" -class Editor : public QTextEdit +class EditorInterface : public QWidget { Q_OBJECT public: - Editor(QWidget *parent); - ~Editor(); - QSize sizeHint() const; - void setInitialSizeHint(const QSize &size); + EditorInterface(QWidget *parent) : QWidget(parent) {} + virtual ~EditorInterface() {} + virtual QSize sizeHint(){ QSize size; return size;} + virtual void setInitialSizeHint(const QSize&) { } + virtual void wheelEvent(QWheelEvent*); + virtual QString toPlainText() = 0; + virtual QTextDocument *document(){QTextDocument *t = new QTextDocument; return t;} + virtual QString selectedText() = 0; + virtual bool find(const QString &, bool findNext = false, bool findBackwards = false) = 0; + virtual void replaceSelectedText(const QString &) = 0; + +signals: + void contentsChanged(); + void modificationChanged(bool); + public slots: - void zoomIn(); - void zoomOut(); - void setLineWrapping(bool on) { if(on) setWordWrapMode(QTextOption::WrapAnywhere); } - void setContentModified(bool y) { document()->setModified(y); } - bool isContentModified() { return document()->isModified(); } - void indentSelection(); - void unindentSelection(); - void commentSelection(); - void uncommentSelection(); - void setPlainText(const QString &text); - void highlightError(int error_pos); - void unhighlightLastError(); - void setHighlightScheme(const QString &name); + virtual void zoomIn() = 0; + virtual void zoomOut() = 0; + virtual void setContentModified(bool) = 0; + virtual bool isContentModified() = 0; + virtual void indentSelection() = 0; + virtual void unindentSelection() = 0; + virtual void commentSelection() = 0; + virtual void uncommentSelection() = 0; + virtual void setPlainText(const QString &) = 0; + virtual void highlightError(int) = 0; + virtual void unhighlightLastError() = 0; + virtual void setHighlightScheme(const QString&) = 0; + virtual void insert(const QString&) = 0; + virtual void undo() = 0; + virtual void redo() = 0; + virtual void cut() = 0; + virtual void copy() = 0; + virtual void paste() = 0; + virtual void initFont(const QString&, uint) = 0; + private: - void wheelEvent ( QWheelEvent * event ); - Highlighter *highlighter; - QSize initialSizeHint; + QSize initialSizeHint; }; diff --git a/src/legacyeditor.cc b/src/legacyeditor.cc new file mode 100644 index 00000000..d9259339 --- /dev/null +++ b/src/legacyeditor.cc @@ -0,0 +1,267 @@ +#include "legacyeditor.h" +#include "Preferences.h" +#include "highlighter.h" + +LegacyEditor::LegacyEditor(QWidget *parent) : EditorInterface(parent) +{ + QVBoxLayout *legacyeditorLayout = new QVBoxLayout(this); + legacyeditorLayout->setContentsMargins(0, 0, 0, 0); + this->textedit = new QTextEdit(this); + legacyeditorLayout->addWidget(this->textedit); + this->textedit->setAcceptRichText(false); + // This needed to avoid the editor accepting filename drops as we want + // to handle these ourselves in MainWindow + this->textedit->setAcceptDrops(false); + this->textedit->setWordWrapMode(QTextOption::WrapAnywhere); + this->textedit->setTabStopWidth(30); + + this->highlighter = new Highlighter(this->textedit->document()); + + connect(this->textedit, SIGNAL(textChanged()), this, SIGNAL(contentsChanged())); + connect(this->textedit->document(), SIGNAL(modificationChanged(bool)), this, SIGNAL(modificationChanged(bool))); +} + +void LegacyEditor::indentSelection() +{ + QTextCursor cursor = textedit->textCursor(); + int p1 = cursor.selectionStart(); + QString txt = cursor.selectedText(); + + txt.replace(QString(QChar(8233)), QString(QChar(8233)) + QString("\t")); + if (txt.endsWith(QString(QChar(8233)) + QString("\t"))) + txt.chop(1); + txt = QString("\t") + txt; + + cursor.insertText(txt); + int p2 = cursor.position(); + cursor.setPosition(p1, QTextCursor::MoveAnchor); + cursor.setPosition(p2, QTextCursor::KeepAnchor); + textedit->setTextCursor(cursor); +} + +void LegacyEditor::unindentSelection() +{ + QTextCursor cursor = textedit->textCursor(); + int p1 = cursor.selectionStart(); + QString txt = cursor.selectedText(); + + txt.replace(QString(QChar(8233)) + QString("\t"), QString(QChar(8233))); + if (txt.startsWith(QString("\t"))) + txt.remove(0, 1); + + cursor.insertText(txt); + int p2 = cursor.position(); + cursor.setPosition(p1, QTextCursor::MoveAnchor); + cursor.setPosition(p2, QTextCursor::KeepAnchor); + textedit->setTextCursor(cursor); +} + +void LegacyEditor::commentSelection() +{ + QTextCursor cursor = textedit->textCursor(); + int p1 = cursor.selectionStart(); + QString txt = cursor.selectedText(); + + txt.replace(QString(QChar(8233)), QString(QChar(8233)) + QString("//")); + if (txt.endsWith(QString(QChar(8233)) + QString("//"))) + txt.chop(2); + txt = QString("//") + txt; + + cursor.insertText(txt); + int p2 = cursor.position(); + cursor.setPosition(p1, QTextCursor::MoveAnchor); + cursor.setPosition(p2, QTextCursor::KeepAnchor); + textedit->setTextCursor(cursor); + +} + +void LegacyEditor::uncommentSelection() +{ + QTextCursor cursor = textedit->textCursor(); + int p1 = cursor.selectionStart(); + QString txt = cursor.selectedText(); + + txt.replace(QString(QChar(8233)) + QString("//"), QString(QChar(8233))); + if (txt.startsWith(QString("//"))) + txt.remove(0, 2); + + cursor.insertText(txt); + int p2 = cursor.position(); + cursor.setPosition(p1, QTextCursor::MoveAnchor); + cursor.setPosition(p2, QTextCursor::KeepAnchor); + textedit->setTextCursor(cursor); +} + +void LegacyEditor::zoomIn() +{ + // See also QT's implementation in QLegacyEditor.cpp + QSettings settings; + QFont tmp_font = this->font() ; + if (font().pointSize() >= 1) + tmp_font.setPointSize(1 + font().pointSize()); + else + tmp_font.setPointSize(1); + settings.setValue("editor/fontsize", tmp_font.pointSize()); + this->setFont(tmp_font); +} + +void LegacyEditor::zoomOut() +{ + + QSettings settings; + QFont tmp_font = this->font(); + if (font().pointSize() >= 2) + tmp_font.setPointSize(-1 + font().pointSize()); + else + tmp_font.setPointSize(1); + settings.setValue("editor/fontsize", tmp_font.pointSize()); + this->setFont(tmp_font); + +} + +void LegacyEditor::setPlainText(const QString &text) +{ + + int y = textedit->verticalScrollBar()->sliderPosition(); + // Save current cursor position + QTextCursor cursor = textedit->textCursor(); + int n = cursor.position(); + textedit->setPlainText(text); + // Restore cursor position + if (n < text.length()) { + cursor.setPosition(n); + textedit->setTextCursor(cursor); + textedit->verticalScrollBar()->setSliderPosition(y); + } +} + +void LegacyEditor::highlightError(int error_pos) +{ + highlighter->highlightError(error_pos); + QTextCursor cursor = this->textedit->textCursor(); + cursor.setPosition(error_pos); + this->textedit->setTextCursor(cursor); + +} + +void LegacyEditor::unhighlightLastError() +{ + highlighter->unhighlightLastError(); +} + +void LegacyEditor::setHighlightScheme(const QString &name) +{ + highlighter->assignFormatsToTokens(name); + highlighter->rehighlight(); // slow on large files +} + +QSize LegacyEditor::sizeHint() const +{ + if (initialSizeHint.width() <= 0) { + return textedit->sizeHint(); + } else { + return initialSizeHint; + } +} + +void LegacyEditor::setInitialSizeHint(const QSize &size) +{ + initialSizeHint = size; +} + +QString LegacyEditor::toPlainText() +{ + return textedit->toPlainText(); +} + +void LegacyEditor::insert(const QString &text) +{ + textedit->insertPlainText(text); +} + +void LegacyEditor::undo() +{ + textedit->undo(); +} + +void LegacyEditor::redo() +{ + textedit->redo(); +} + +void LegacyEditor::cut() +{ + textedit->cut(); +} + +void LegacyEditor::copy() +{ + textedit->copy(); +} + +void LegacyEditor::paste() +{ + textedit->paste(); +} + +LegacyEditor::~LegacyEditor() +{ + delete highlighter; +} + +void LegacyEditor::replaceSelectedText(const QString &newText) +{ + QTextCursor cursor = this->textedit->textCursor(); + if (cursor.selectedText() != newText) { + cursor.insertText(newText); + } +} + +bool LegacyEditor::findString(const QString & exp, bool findBackwards) const +{ + return textedit->find(exp, findBackwards ? QTextDocument::FindBackward : QTextDocument::FindFlags(0)); +} + +bool LegacyEditor::find(const QString &newText, bool findNext, bool findBackwards) +{ + bool success = this->findString(newText, findBackwards); + if (!success) { // Implement wrap-around search behavior + QTextCursor old_cursor = this->textedit->textCursor(); + QTextCursor tmp_cursor = old_cursor; + tmp_cursor.movePosition(findBackwards ? QTextCursor::End : QTextCursor::Start); + this->textedit->setTextCursor(tmp_cursor); + bool success = this->findString(newText, findBackwards); + if (!success) { + this->textedit->setTextCursor(old_cursor); + } + return success; + } + return true; + +} + +void LegacyEditor::initFont(const QString& family, uint size) +{ + QFont font; + if (!family.isEmpty()) font.setFamily(family); + else font.setFixedPitch(true); + if (size > 0) font.setPointSize(size); + font.setStyleHint(QFont::TypeWriter); + this->setFont(font); + +} + +QString LegacyEditor::selectedText() +{ + return textedit->textCursor().selectedText(); +} + +void LegacyEditor::setContentModified(bool y) +{ + textedit->document()->setModified(y); +} + +bool LegacyEditor::isContentModified() +{ + return textedit->document()->isModified(); +} diff --git a/src/legacyeditor.h b/src/legacyeditor.h new file mode 100644 index 00000000..eb8e7b41 --- /dev/null +++ b/src/legacyeditor.h @@ -0,0 +1,43 @@ +#pragma once + +#include "editor.h" + +class LegacyEditor : public EditorInterface +{ + Q_OBJECT +public: + LegacyEditor(class QWidget *parent); + virtual ~LegacyEditor(); + QSize sizeHint() const; + void setInitialSizeHint(const QSize&); + QString toPlainText(); + QString selectedText(); + bool find(const QString &, bool findNext = false, bool findBackwards = false); + void replaceSelectedText(const QString &newText); + bool findString(const QString & exp, bool findBackwards) const; + +public slots: + void zoomIn(); + void zoomOut(); + void setContentModified(bool); + bool isContentModified(); + void indentSelection(); + void unindentSelection(); + void commentSelection(); + void uncommentSelection(); + void setPlainText(const QString&); + void highlightError(int); + void unhighlightLastError(); + void setHighlightScheme(const QString&); + void insert(const QString&); + void undo(); + void redo(); + void cut(); + void copy(); + void paste(); + void initFont(const QString&, uint); +private: + class QTextEdit *textedit; + class Highlighter *highlighter; + QSize initialSizeHint; +}; diff --git a/src/mainwin.cc b/src/mainwin.cc index 3a142ebc..4e8d2928 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -23,7 +23,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ - #include "GeometryCache.h" #include "ModuleCache.h" #include "MainWindow.h" @@ -40,6 +39,10 @@ #include "expression.h" #include "progress.h" #include "dxfdim.h" +#include "legacyeditor.h" +#ifdef USE_SCINTILLA_EDITOR +#include "scintillaeditor.h" +#endif #include "AboutDialog.h" #include "FontListDialog.h" #ifdef ENABLE_OPENCSG @@ -166,6 +169,20 @@ MainWindow::MainWindow(const QString &filename) : root_inst("group"), font_list_dialog(NULL), tempFile(NULL), progresswidget(NULL) { setupUi(this); + + editortype = Preferences::inst()->getValue("editor/editortype").toString(); + + useScintilla = (editortype == "QScintilla Editor"); +#ifdef USE_SCINTILLA_EDITOR + if (useScintilla) { + editor = new ScintillaEditor(editorDockContents); + } + else +#endif + editor = new LegacyEditor(editorDockContents); + + editorDockContents->layout()->addWidget(editor); + setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea); setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea); @@ -219,8 +236,6 @@ MainWindow::MainWindow(const QString &filename) connect(this, SIGNAL(highlightError(int)), editor, SLOT(highlightError(int))); connect(this, SIGNAL(unhighlightLastError()), editor, SLOT(unhighlightLastError())); - editor->setTabStopWidth(30); - editor->setLineWrapping(true); // Not designable this->qglview->statusLabel = new QLabel(this); statusBar()->addWidget(this->qglview->statusLabel); @@ -315,7 +330,6 @@ MainWindow::MainWindow(const QString &filename) connect(this->editActionFindAndReplace, SIGNAL(triggered()), this, SLOT(findAndReplace())); connect(this->editActionFindNext, SIGNAL(triggered()), this, SLOT(findNext())); connect(this->editActionFindPrevious, SIGNAL(triggered()), this, SLOT(findPrev())); - connect(this->editActionUseSelectionForFind, SIGNAL(triggered()), this, SLOT(useSelectionForFind())); // Design menu connect(this->designActionAutoReload, SIGNAL(toggled(bool)), this, SLOT(autoReloadSet(bool))); @@ -397,15 +411,15 @@ MainWindow::MainWindow(const QString &filename) } updateRecentFileActions(); - connect(editor->document(), SIGNAL(contentsChanged()), this, SLOT(animateUpdateDocChanged())); - connect(editor->document(), SIGNAL(modificationChanged(bool)), this, SLOT(setWindowModified(bool))); + connect(editor, SIGNAL(contentsChanged()), this, SLOT(animateUpdateDocChanged())); + connect(editor, SIGNAL(modificationChanged(bool)), this, SLOT(setWindowModified(bool))); connect(this->qglview, SIGNAL(doAnimateUpdate()), this, SLOT(animateUpdate())); connect(Preferences::inst(), SIGNAL(requestRedraw()), this->qglview, SLOT(updateGL())); connect(Preferences::inst(), SIGNAL(updateMdiMode(bool)), this, SLOT(updateMdiMode(bool))); connect(Preferences::inst(), SIGNAL(updateUndockMode(bool)), this, SLOT(updateUndockMode(bool))); connect(Preferences::inst(), SIGNAL(fontChanged(const QString&,uint)), - this, SLOT(setFont(const QString&,uint))); + editor, SLOT(initFont(const QString&,uint))); connect(Preferences::inst(), SIGNAL(openCSGSettingsChanged()), this, SLOT(openCSGSettingsChanged())); connect(Preferences::inst(), SIGNAL(syntaxHighlightChanged(const QString&)), @@ -417,7 +431,9 @@ MainWindow::MainWindow(const QString &filename) QString cs = Preferences::inst()->getValue("3dview/colorscheme").toString(); this->setColorScheme(cs); + //find and replace panel connect(this->findTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(selectFindType(int))); + connect(this->findInputField, SIGNAL(textChanged(QString)), this, SLOT(findString(QString))); connect(this->findInputField, SIGNAL(returnPressed()), this->nextButton, SLOT(animateClick())); find_panel->installEventFilter(this); @@ -470,8 +486,7 @@ MainWindow::MainWindow(const QString &filename) clearCurrentOutput(); } -void -MainWindow::loadViewSettings(){ +void MainWindow::loadViewSettings(){ QSettings settings; if (settings.value("view/showEdges").toBool()) { viewActionShowEdges->setChecked(true); @@ -498,8 +513,7 @@ MainWindow::loadViewSettings(){ updateUndockMode(settings.value("advanced/undockableWindows").toBool()); } -void -MainWindow::loadDesignSettings() +void MainWindow::loadDesignSettings() { QSettings settings; if (settings.value("design/autoReload").toBool()) { @@ -591,8 +605,8 @@ void MainWindow::requestOpenFile(const QString &filename) one is not empty. Otherwise the current window content is overwritten. Any check whether to replace the content have to be made before. */ -void -MainWindow::openFile(const QString &new_filename) + +void MainWindow::openFile(const QString &new_filename) { if (MainWindow::mdiMode) { if (!editor->toPlainText().isEmpty()) { @@ -622,8 +636,7 @@ MainWindow::openFile(const QString &new_filename) clearCurrentOutput(); } -void -MainWindow::setFileName(const QString &filename) +void MainWindow::setFileName(const QString &filename) { if (filename.isEmpty()) { this->fileName.clear(); @@ -1091,6 +1104,7 @@ void MainWindow::show_examples() { bool found_example = false; QStringList categories; + //categories in File menu item - Examples categories << "Basics" << "Shapes" << "Extrusion" << "Advanced"; foreach (const QString &cat, categories){ @@ -1243,19 +1257,17 @@ void MainWindow::actionReload() void MainWindow::pasteViewportTranslation() { - QTextCursor cursor = editor->textCursor(); QString txt; txt.sprintf("[ %.2f, %.2f, %.2f ]", -qglview->cam.object_trans.x(), -qglview->cam.object_trans.y(), -qglview->cam.object_trans.z()); - cursor.insertText(txt); + this->editor->insert(txt); } void MainWindow::pasteViewportRotation() { - QTextCursor cursor = editor->textCursor(); QString txt; txt.sprintf("[ %.2f, %.2f, %.2f ]", fmodf(360 - qglview->cam.object_rot.x() + 90, 360), fmodf(360 - qglview->cam.object_rot.y(), 360), fmodf(360 - qglview->cam.object_rot.z(), 360)); - cursor.insertText(txt); + this->editor->insert(txt); } void MainWindow::find() @@ -1265,10 +1277,16 @@ void MainWindow::find() replaceButton->hide(); replaceAllButton->hide(); find_panel->show(); + findInputField->setText(editor->selectedText()); findInputField->setFocus(); findInputField->selectAll(); } +void MainWindow::findString(QString textToFind) +{ + editor->find(textToFind, false, false); +} + void MainWindow::findAndReplace() { findTypeComboBox->setCurrentIndex(1); @@ -1285,55 +1303,25 @@ void MainWindow::selectFindType(int type) { if (type == 1) findAndReplace(); } -bool MainWindow::findOperation(QTextDocument::FindFlags options) { - bool success = editor->find(findInputField->text(), options); - if (!success) { // Implement wrap-around search behavior - QTextCursor old_cursor = editor->textCursor(); - QTextCursor tmp_cursor = old_cursor; - tmp_cursor.movePosition((options & QTextDocument::FindBackward) ? QTextCursor::End : QTextCursor::Start); - editor->setTextCursor(tmp_cursor); - bool success = editor->find(findInputField->text(), options); - if (!success) { - editor->setTextCursor(old_cursor); - } - return success; - } - return true; -} - void MainWindow::replace() { - QTextCursor cursor = editor->textCursor(); - QString selectedText = cursor.selectedText(); - if (selectedText == findInputField->text()) { - cursor.insertText(replaceInputField->text()); - } - findNext(); + this->editor->replaceSelectedText(this->replaceInputField->text()); + this->editor->find(this->findInputField->text()); } void MainWindow::replaceAll() { - QTextCursor old_cursor = editor->textCursor(); - QTextCursor tmp_cursor = old_cursor; - tmp_cursor.movePosition(QTextCursor::Start); - editor->setTextCursor(tmp_cursor); - while (editor->find(findInputField->text())) { - editor->textCursor().insertText(replaceInputField->text()); + while (this->editor->find(this->findInputField->text(), true)) { + this->editor->replaceSelectedText(this->replaceInputField->text()); } - editor->setTextCursor(old_cursor); } void MainWindow::findNext() { - findOperation(); + editor->find(this->findInputField->text(), true); } void MainWindow::findPrev() { - findOperation(QTextDocument::FindBackward); -} - -void MainWindow::useSelectionForFind() -{ - findInputField->setText(editor->textCursor().selectedText()); + editor->find(this->findInputField->text(), true, true); } bool MainWindow::eventFilter(QObject* obj, QEvent *event) @@ -1473,6 +1461,7 @@ void MainWindow::compileTopLevelDocument() resetPrintedDeprecations(); this->last_compiled_doc = editor->toPlainText(); + std::string fulltext = std::string(this->last_compiled_doc.toLocal8Bit().constData()) + "\n" + commandline_commands; @@ -1481,10 +1470,8 @@ void MainWindow::compileTopLevelDocument() this->root_module = NULL; this->root_module = parse(fulltext.c_str(), - this->fileName.isEmpty() ? - "" : - QFileInfo(this->fileName).absolutePath().toLocal8Bit(), - false); + this->fileName.isEmpty() ? "" : + QFileInfo(this->fileName).absolutePath().toLocal8Bit(), false); updateCamera(); } @@ -1921,8 +1908,9 @@ void MainWindow::actionExportCSG() } QString csg_filename = QFileDialog::getSaveFileName(this, "Export CSG File", - this->fileName.isEmpty() ? "Untitled.csg" : QFileInfo(this->fileName).baseName()+".csg", - "CSG Files (*.csg)"); + this->fileName.isEmpty() ? "Untitled.csg" : QFileInfo(this->fileName).baseName()+".csg", + "CSG Files (*.csg)"); + if (csg_filename.isEmpty()) { PRINT("No filename specified. CSG export aborted."); clearCurrentOutput(); @@ -2071,7 +2059,7 @@ void MainWindow::viewModeAnimate() void MainWindow::animateUpdateDocChanged() { - QString current_doc = editor->toPlainText(); + QString current_doc = editor->toPlainText(); if (current_doc != last_compiled_doc) animateUpdate(); } @@ -2260,7 +2248,7 @@ void MainWindow::handleFileDrop(const QString &filename) } openFile(filename); } else { - editor->insertPlainText(cmd.arg(filename)); + editor->insert(cmd.arg(filename)); } } @@ -2402,7 +2390,8 @@ void MainWindow::consoleOutput(const std::string &msg, void *userdata) // originates in a worker thread. MainWindow *thisp = static_cast(userdata); QMetaObject::invokeMethod(thisp->console, "append", Qt::QueuedConnection, - Q_ARG(QString, QString::fromLocal8Bit(msg.c_str()))); + Q_ARG(QString, QString::fromLocal8Bit(msg.c_str()))); + if (thisp->procevents) QApplication::processEvents(); } @@ -2419,6 +2408,7 @@ void MainWindow::clearCurrentOutput() void MainWindow::openCSGSettingsChanged() { #ifdef ENABLE_OPENCSG - OpenCSG::setOption(OpenCSG::AlgorithmSetting, Preferences::inst()->getValue("advanced/forceGoldfeather").toBool() ? OpenCSG::Goldfeather : OpenCSG::Automatic); + OpenCSG::setOption(OpenCSG::AlgorithmSetting, Preferences::inst()->getValue("advanced/forceGoldfeather").toBool() ? + OpenCSG::Goldfeather : OpenCSG::Automatic); #endif } diff --git a/src/scadlexer.cpp b/src/scadlexer.cpp new file mode 100644 index 00000000..ff774dff --- /dev/null +++ b/src/scadlexer.cpp @@ -0,0 +1,38 @@ +#include "scadlexer.h" + +ScadLexer::ScadLexer(QObject *parent) + : QsciLexerCPP(parent) +{ } + +ScadLexer::~ScadLexer() +{ } + +const char *ScadLexer::language() const +{ + return "SCAD"; +} + +const char *ScadLexer::keywords(int set) const +{ + + if (set == 1) + return "if else for module function intersection_for assign echo search " + " str let true false "; // -> Style: Keyword + + if (set == 2) + return " abs sign acos asin atan atan2 sin cos tan floor round ceil len ln " + " log lookup min max pow sqrt exp rands version version_num " + " group difference union intersection render translate rotate scale multmatrix color " + " projection hull resize mirror minkowski glide subdiv child " + " include use dxf_dim dxf_cross " + " linear_extrude rotate_extrude "; // -> Style: KeywordSet2 + + if (set == 3) + return " param author "; // -> used in comments only like /*! \cube */ + + if (set == 4) + return "cube circle cylinder polygon polyhedron square sphere " + "surface import "; // -> Style: GlobalClass + + return 0; +} diff --git a/src/scadlexer.h b/src/scadlexer.h new file mode 100644 index 00000000..50e6347a --- /dev/null +++ b/src/scadlexer.h @@ -0,0 +1,19 @@ +#pragma once + +#include + +#include +#include + +class ScadLexer : public QsciLexerCPP +{ +public: + ScadLexer(QObject *parent); + virtual ~ScadLexer(); + const char *language() const; + const char *keywords(int set) const; + +private: + ScadLexer(const ScadLexer &); + ScadLexer &operator=(const ScadLexer &); +}; diff --git a/src/scintillaeditor.cpp b/src/scintillaeditor.cpp new file mode 100644 index 00000000..e41b66b4 --- /dev/null +++ b/src/scintillaeditor.cpp @@ -0,0 +1,349 @@ +#include +#include +#include +#include "scintillaeditor.h" +#include +#include "Preferences.h" + +ScintillaEditor::ScintillaEditor(QWidget *parent) : EditorInterface(parent) +{ + scintillaLayout = new QVBoxLayout(this); + qsci = new QsciScintilla(this); + + + // + // Remapping some scintilla key binding which conflict with OpenSCAD global + // key bindings, as well as some minor scintilla bugs + // + QsciCommand *c; +#ifdef Q_OS_MAC + // Alt-Backspace should delete left word (Alt-Delete already deletes right word) + c= qsci->standardCommands()->find(QsciCommand::DeleteWordLeft); + c->setKey(Qt::Key_Backspace | Qt::ALT); +#endif + // Cmd/Ctrl-T is handled by the menu + c = qsci->standardCommands()->boundTo(Qt::Key_T | Qt::CTRL); + c->setKey(0); + // Cmd/Ctrl-D is handled by the menu + c = qsci->standardCommands()->boundTo(Qt::Key_D | Qt::CTRL); + c->setKey(0); + // Ctrl-Shift-Z should redo on all platforms + c= qsci->standardCommands()->find(QsciCommand::Redo); + c->setKey(Qt::Key_Z | Qt::CTRL | Qt::SHIFT); + + scintillaLayout->setContentsMargins(0, 0, 0, 0); + scintillaLayout->addWidget(qsci); + + qsci->setBraceMatching (QsciScintilla::SloppyBraceMatch); + qsci->setWrapMode(QsciScintilla::WrapCharacter); + qsci->setWrapVisualFlags(QsciScintilla::WrapFlagByBorder, QsciScintilla::WrapFlagNone, 0); + qsci->setAutoIndent(true); + qsci->indicatorDefine(QsciScintilla::RoundBoxIndicator, indicatorNumber); + qsci->markerDefine(QsciScintilla::Circle, markerNumber); + qsci->setUtf8(true); + lexer = new ScadLexer(this); + initLexer(); + initMargin(); + qsci->setFolding(QsciScintilla::BoxedTreeFoldStyle, 4); + qsci->setCaretLineVisible(true); + this->setHighlightScheme(Preferences::inst()->getValue("editor/syntaxhighlight").toString()); + + connect(qsci, SIGNAL(textChanged()), this, SIGNAL(contentsChanged())); + connect(qsci, SIGNAL(modificationChanged(bool)), this, SIGNAL(modificationChanged(bool))); +} + +void ScintillaEditor::setPlainText(const QString &text) +{ + qsci->setText(text); + setContentModified(false); +} + +QString ScintillaEditor::toPlainText() +{ + return qsci->text(); +} + +void ScintillaEditor::setContentModified(bool modified) +{ + qsci->setModified(modified); +} + +bool ScintillaEditor::isContentModified() +{ + return qsci->isModified(); +} + +void ScintillaEditor::highlightError(int error_pos) +{ + int line, index; + qsci->lineIndexFromPosition(error_pos, &line, &index); + qsci->fillIndicatorRange(line, index, line, index+1, indicatorNumber); + qsci->setIndicatorForegroundColor(QColor(255,0,0,100)); + qsci->markerAdd(line, markerNumber); +} + +void ScintillaEditor::unhighlightLastError() +{ + int totalLength = qsci->text().length(); + int line, index; + qsci->lineIndexFromPosition(totalLength, &line, &index); + qsci->clearIndicatorRange(0, 0, line, index, indicatorNumber); + qsci->markerDeleteAll(markerNumber); +} + +//Editor themes +void ScintillaEditor::forLightBackground() +{ + lexer->setPaper("#fff"); + lexer->setColor(QColor("#272822")); // -> Style: Default text + lexer->setColor(QColor("Green"), QsciLexerCPP::Keyword); // -> Style: Keyword + lexer->setColor(QColor("Green"), QsciLexerCPP::KeywordSet2); // -> Style: KeywordSet2 + lexer->setColor(Qt::blue, QsciLexerCPP::CommentDocKeyword); // -> used in comments only like /*! \cube */ + lexer->setColor(QColor("DarkBlue"), QsciLexerCPP::GlobalClass); // -> Style: GlobalClass + lexer->setColor(Qt::blue, QsciLexerCPP::Operator); + lexer->setColor(Qt::darkMagenta, QsciLexerCPP::DoubleQuotedString); + lexer->setColor(Qt::darkCyan, QsciLexerCPP::Comment); + lexer->setColor(Qt::darkCyan, QsciLexerCPP::CommentLine); + lexer->setColor(QColor("DarkRed"), QsciLexerCPP::Number); + qsci->setMarkerBackgroundColor(QColor(255, 0, 0, 100), markerNumber); + qsci->setCaretLineBackgroundColor(QColor("#ffe4e4")); + qsci->setMarginsBackgroundColor(QColor("#ccc")); + qsci->setMarginsForegroundColor(QColor("#111")); + qsci->setMatchedBraceBackgroundColor(QColor("#333")); + qsci->setMatchedBraceForegroundColor(QColor("#fff")); +} + +void ScintillaEditor::forDarkBackground() +{ + lexer->setPaper(QColor("#272822")); + lexer->setColor(QColor(Qt::white)); + lexer->setColor(QColor("#f12971"), QsciLexerCPP::Keyword); + lexer->setColor(QColor("#56dbf0"),QsciLexerCPP::KeywordSet2); + lexer->setColor(QColor("#ccdf32"), QsciLexerCPP::CommentDocKeyword); + lexer->setColor(QColor("#56d8f0"), QsciLexerCPP::GlobalClass); + lexer->setColor(QColor("#d8d8d8"), QsciLexerCPP::Operator); + lexer->setColor(QColor("#e6db74"), QsciLexerCPP::DoubleQuotedString); + lexer->setColor(QColor("#e6db74"), QsciLexerCPP::CommentLine); + lexer->setColor(QColor("#af7dff"), QsciLexerCPP::Number); + qsci->setCaretLineBackgroundColor(QColor(104,225,104, 127)); + qsci->setMarkerBackgroundColor(QColor(255, 0, 0, 100), markerNumber); + qsci->setMarginsBackgroundColor(QColor("20,20,20,150")); + qsci->setMarginsForegroundColor(QColor("#fff")); + qsci->setCaretWidth(2); + qsci->setCaretForegroundColor(QColor("#ffff00")); +} + +void ScintillaEditor::Monokai() +{ + lexer->setPaper("#272822"); + lexer->setColor(QColor("#f8f8f2")); // -> Style: Default text + lexer->setColor(QColor("#66c3b3"), QsciLexerCPP::Keyword); // -> Style: Keyword + lexer->setColor(QColor("#79abff"), QsciLexerCPP::KeywordSet2); // -> Style: KeywordSet2 + lexer->setColor(QColor("#ccdf32"), QsciLexerCPP::CommentDocKeyword); // -> used in comments only like /*! \cube */ + lexer->setColor(QColor("#ffffff"), QsciLexerCPP::GlobalClass); // -> Style: GlobalClass + lexer->setColor(QColor("#d8d8d8"), QsciLexerCPP::Operator); + lexer->setColor(QColor("#e6db74"), QsciLexerCPP::DoubleQuotedString); + lexer->setColor(QColor("#75715e"), QsciLexerCPP::CommentLine); + lexer->setColor(QColor("#7fb347"), QsciLexerCPP::Number); + qsci->setMarkerBackgroundColor(QColor(255, 0, 0, 100), markerNumber); + qsci->setCaretLineBackgroundColor(QColor("#3e3d32")); + qsci->setMarginsBackgroundColor(QColor("#757575")); + qsci->setMarginsForegroundColor(QColor("#f8f8f2")); + qsci->setCaretWidth(2); + qsci->setCaretForegroundColor(QColor("#ffff00")); +} + +void ScintillaEditor::Solarized_light() +{ + lexer->setPaper("#fdf6e3"); + lexer->setColor(QColor("#657b83")); // -> Style: Default text + lexer->setColor(QColor("#268ad1"), QsciLexerCPP::Keyword); // -> Style: Keyword + lexer->setColor(QColor("#6c71c4"), QsciLexerCPP::KeywordSet2); // -> Style: KeywordSet2 + lexer->setColor(QColor("#b58900"), QsciLexerCPP::CommentDocKeyword); // -> used in comments only like /*! \cube */ + lexer->setColor(QColor("#b58800"), QsciLexerCPP::GlobalClass); // -> Style: GlobalClass + lexer->setColor(QColor("#859900"), QsciLexerCPP::Operator); + lexer->setColor(QColor("#2aa198"), QsciLexerCPP::DoubleQuotedString); + lexer->setColor(QColor("#b58800"), QsciLexerCPP::CommentLine); + lexer->setColor(QColor("#cb4b16"), QsciLexerCPP::Number); + qsci->setMarkerBackgroundColor(QColor(255, 0, 0, 100), markerNumber); + qsci->setCaretLineBackgroundColor(QColor("#eeead5")); + qsci->setMarginsBackgroundColor(QColor("#eee8d5")); + qsci->setMarginsForegroundColor(QColor("#93a1a1")); + qsci->setMatchedBraceBackgroundColor(QColor("#0000ff")); + qsci->setMatchedBraceBackgroundColor(QColor("#333")); + qsci->setMatchedBraceForegroundColor(QColor("#fff")); +} + +void ScintillaEditor::noColor() +{ + lexer->setPaper(Qt::white); + lexer->setColor(Qt::black); + qsci->setMarginsBackgroundColor(QColor("#ccc")); + qsci->setMarginsForegroundColor(QColor("#111")); + +} + +void ScintillaEditor::setHighlightScheme(const QString &name) +{ + if(name == "For Light Background") { + forLightBackground(); + } + else if(name == "For Dark Background") { + forDarkBackground(); + } + else if(name == "Monokai") { + Monokai(); + } + else if(name == "Solarized") { + Solarized_light(); + } + else if(name == "Off") { + noColor(); + } +} + +void ScintillaEditor::insert(const QString &text) +{ + qsci->insert(text); +} + +void ScintillaEditor::undo() +{ + qsci->undo(); +} + +void ScintillaEditor::redo() +{ + qsci->redo(); +} + +void ScintillaEditor::cut() +{ + qsci->cut(); +} + +void ScintillaEditor::copy() +{ + qsci->copy(); +} + +void ScintillaEditor::paste() +{ + qsci->paste(); +} + +void ScintillaEditor::zoomIn() +{ + qsci->zoomIn(); +} + +void ScintillaEditor::zoomOut() +{ + qsci->zoomOut(); +} + +void ScintillaEditor::initFont(const QString& fontName, uint size) +{ + QFont font(fontName, size); + font.setFixedPitch(true); + lexer->setFont(font); +} + +void ScintillaEditor::initLexer() +{ + qsci->setLexer(lexer); +} + +void ScintillaEditor::initMargin() +{ + QFontMetrics fontmetrics = QFontMetrics(qsci->font()); + qsci->setMarginsFont(qsci->font()); + qsci->setMarginWidth(1, fontmetrics.width(QString::number(qsci->lines())) + 6); + qsci->setMarginLineNumbers(1, true); + + connect(qsci, SIGNAL(textChanged()), this, SLOT(onTextChanged())); +} + +void ScintillaEditor::onTextChanged() +{ + QFontMetrics fontmetrics = qsci->fontMetrics(); + qsci->setMarginWidth(1, fontmetrics.width(QString::number(qsci->lines())) + 6); +} + +bool ScintillaEditor::find(const QString &expr, bool findNext, bool findBackwards) +{ + int startline = -1, startindex = -1; + + // If findNext, start from the end of the current selection + if (qsci->hasSelectedText()) { + int lineFrom, indexFrom, lineTo, indexTo; + qsci->getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo); + + startline = !(findBackwards xor findNext) ? std::min(lineFrom, lineTo) : std::max(lineFrom, lineTo); + startindex = !(findBackwards xor findNext) ? std::min(indexFrom, indexTo) : std::max(indexFrom, indexTo); + } + + return qsci->findFirst(expr, false, false, false, true, + !findBackwards, startline, startindex); +} + +void ScintillaEditor::replaceSelectedText(const QString &newText) +{ + if (qsci->selectedText() != newText) qsci->replaceSelectedText(newText); +} + +void ScintillaEditor::get_range(int *lineFrom, int *lineTo) +{ + int indexFrom, indexTo; + if (qsci->hasSelectedText()) { + qsci->getSelection(lineFrom, &indexFrom, lineTo, &indexTo); + } else { + qsci->getCursorPosition(lineFrom, &indexFrom); + *lineTo = *lineFrom; + } +} + +void ScintillaEditor::indentSelection() +{ + int lineFrom, lineTo; + get_range(&lineFrom, &lineTo); + for (int line = lineFrom;line <= lineTo;line++) { + qsci->indent(line); + } +} + +void ScintillaEditor::unindentSelection() +{ + int lineFrom, lineTo; + get_range(&lineFrom, &lineTo); + for (int line = lineFrom;line <= lineTo;line++) { + qsci->unindent(line); + } +} + +void ScintillaEditor::commentSelection() +{ + int lineFrom, lineTo; + get_range(&lineFrom, &lineTo); + for (int line = lineFrom;line <= lineTo;line++) { + qsci->insertAt("//", line, 0); + } +} + +void ScintillaEditor::uncommentSelection() +{ + int lineFrom, lineTo; + get_range(&lineFrom, &lineTo); + for (int line = lineFrom;line <= lineTo;line++) { + QString lineText = qsci->text(line); + if (lineText.startsWith("//")) { + qsci->setSelection(line, 0, line, 2); + qsci->removeSelectedText(); + } + } +} + +QString ScintillaEditor::selectedText() +{ + return qsci->selectedText(); +} diff --git a/src/scintillaeditor.h b/src/scintillaeditor.h new file mode 100644 index 00000000..14287f5b --- /dev/null +++ b/src/scintillaeditor.h @@ -0,0 +1,62 @@ +#pragma once + +#include +#include +#include +#include +#include +#include "editor.h" +#include "scadlexer.h" + +class ScintillaEditor : public EditorInterface +{ + Q_OBJECT; +public: + ScintillaEditor(QWidget *parent); + virtual ~ScintillaEditor() {} + QsciScintilla *qsci; + QString toPlainText(); + void initMargin(); + void initLexer(); + void forLightBackground(); + void forDarkBackground(); + void Monokai(); + void Solarized_light(); + void noColor(); + QString selectedText(); + bool find(const QString &, bool findNext = false, bool findBackwards = false); + void replaceSelectedText(const QString&); + +private: + void get_range(int *lineFrom, int *lineTo); + +public slots: + void zoomIn(); + void zoomOut(); + void setPlainText(const QString&); + void setContentModified(bool); + bool isContentModified(); + void highlightError(int); + void unhighlightLastError(); + void setHighlightScheme(const QString&); + void indentSelection(); + void unindentSelection(); + void commentSelection(); + void uncommentSelection(); + void insert(const QString&); + void undo(); + void redo(); + void cut(); + void copy(); + void paste(); + void initFont(const QString&, uint); + +private slots: + void onTextChanged(); + +private: + QVBoxLayout *scintillaLayout; + static const int indicatorNumber = 1; + static const int markerNumber = 2; + ScadLexer *lexer; +};