diff --git a/.gitignore b/.gitignore index 9074570fcb06..5b5391c64b23 100644 --- a/.gitignore +++ b/.gitignore @@ -132,3 +132,10 @@ libbitcoinconsensus.pc .idea CMakeLists.txt cmake-build-debug + +moc_* +*.tmp +ui_* +build* +pivxd.* +pivxd-new-gui.* \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 78b598b47141..5b2482755c9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -139,7 +139,7 @@ jobs: name: 'x86_64 Linux [GOAL: install] [bionic] [uses qt5 dev package instead of depends Qt to speed up build and avoid timeout]' env: >- HOST=x86_64-unknown-linux-gnu - PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" + PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libqt5svg5-dev libqt5charts5-dev libqrencode-dev protobuf-compiler libdbus-1-dev libharfbuzz-dev libprotobuf-dev" DEP_OPTS="NO_QT=1 NO_UPNP=1 DEBUG=1 ALLOW_HOST_PACKAGES=1" RUN_FUNCTIONAL_TESTS=true #TEST_RUNNER_EXTRA="--coverage --extended" # Run extended tests so that coverage does not fail, but exclude the very slow dbcrash @@ -151,7 +151,7 @@ jobs: env: >- HOST=x86_64-unknown-linux-gnu DOCKER_NAME_TAG=ubuntu:14.04 - PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libicu-dev libpng-dev libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.1++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" + PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libqt5svg5-dev libicu-dev libpng-dev libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.1++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" NO_DEPENDS=1 RUN_FUNCTIONAL_TESTS=false GOAL="install" @@ -162,7 +162,7 @@ jobs: env: >- HOST=x86_64-unknown-linux-gnu DOCKER_NAME_TAG=ubuntu:16.04 - PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" + PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libqt5svg5-dev libssl-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" NO_DEPENDS=1 GOAL="install" BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER --disable-hardening --disable-asm" @@ -171,7 +171,7 @@ jobs: name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs]' env: >- HOST=x86_64-unknown-linux-gnu - PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" + PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libqt5svg5-dev libqt5charts5-dev libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" NO_DEPENDS=1 GOAL="install" BITCOIN_CONFIG="--enable-zmq --with-incompatible-bdb --with-gui=qt5 CPPFLAGS=-DDEBUG_LOCKORDER" @@ -180,7 +180,7 @@ jobs: # name: 'x86_64 Linux [GOAL: install] [bionic] [no depends, only system libs, sanitizers: fuzzer,address]' # env: >- # HOST=x86_64-unknown-linux-gnu -# PACKAGES="clang python3-zmq qtbase5-dev qttools5-dev-tools libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" +# PACKAGES="clang python3-zmq qtbase5-dev qttools5-dev-tools libqt5svg5-dev libqt5charts5-dev libssl1.0-dev libevent-dev bsdmainutils libboost-system-dev libboost-filesystem-dev libboost-chrono-dev libboost-program-options-dev libboost-test-dev libboost-thread-dev libdb5.3++-dev libminiupnpc-dev libzmq3-dev libprotobuf-dev protobuf-compiler libqrencode-dev libgmp-dev" # NO_DEPENDS=1 # RUN_UNIT_TESTS=false # RUN_FUNCTIONAL_TESTS=false diff --git a/build-aux/m4/bitcoin_qt.m4 b/build-aux/m4/bitcoin_qt.m4 index c0c87dafd824..b1fcf9c317f3 100644 --- a/build-aux/m4/bitcoin_qt.m4 +++ b/build-aux/m4/bitcoin_qt.m4 @@ -68,6 +68,7 @@ AC_DEFUN([BITCOIN_QT_INIT],[ AC_ARG_WITH([qt-libdir],[AS_HELP_STRING([--with-qt-libdir=LIB_DIR],[specify qt lib path (overridden by pkgconfig)])], [qt_lib_path=$withval], []) AC_ARG_WITH([qt-plugindir],[AS_HELP_STRING([--with-qt-plugindir=PLUGIN_DIR],[specify qt plugin path (overridden by pkgconfig)])], [qt_plugin_path=$withval], []) AC_ARG_WITH([qt-translationdir],[AS_HELP_STRING([--with-qt-translationdir=PLUGIN_DIR],[specify qt translation path (overridden by pkgconfig)])], [qt_translation_path=$withval], []) + AC_ARG_WITH([qt-svgdir],[AS_HELP_STRING([--with-qt-svgdir=PLUGIN_DIR],[specify qt svg path (overridden by pkgconfig)])], [qt_svg_path=$withval], []) AC_ARG_WITH([qt-bindir],[AS_HELP_STRING([--with-qt-bindir=BIN_DIR],[specify qt bin path])], [qt_bin_path=$withval], []) AC_ARG_WITH([qtdbus], @@ -136,6 +137,8 @@ AC_DEFUN([BITCOIN_QT_CONFIGURE],[ fi _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QMinimalIntegrationPlugin)],[-lqminimal]) AC_DEFINE(QT_QPA_PLATFORM_MINIMAL, 1, [Define this symbol if the minimal qt platform exists]) + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QSvgPlugin)],[-lqsvg]) + _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QSvgIconPlugin)],[-lqsvgicon]) if test "x$TARGET_OS" = xwindows; then _BITCOIN_QT_CHECK_STATIC_PLUGINS([Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)],[-lqwindows]) AC_DEFINE(QT_QPA_PLATFORM_WINDOWS, 1, [Define this symbol if the qt platform is windows]) @@ -355,7 +358,7 @@ dnl Inputs: qt_plugin_path. optional. dnl Outputs: QT_LIBS is appended AC_DEFUN([_BITCOIN_QT_FIND_STATIC_PLUGINS],[ if test "x$qt_plugin_path" != x; then - QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms" + QT_LIBS="$QT_LIBS -L$qt_plugin_path/platforms -L$qt_plugin_path/imageformats -L$qt_plugin_path/iconengines" if test -d "$qt_plugin_path/accessible"; then QT_LIBS="$QT_LIBS -L$qt_plugin_path/accessible" fi @@ -382,6 +385,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_STATIC_PLUGINS],[ PKG_CHECK_MODULES([QTGRAPHICS], [Qt5GraphicsSupport], [QT_LIBS="-lQt5GraphicsSupport $QT_LIBS"]) PKG_CHECK_MODULES([QTCGL], [Qt5CglSupport], [QT_LIBS="-lQt5CglSupport $QT_LIBS"]) fi + @echo "QT_LIBS: $(QT_LIBS)" ]) else if test "x$TARGET_OS" = xwindows; then @@ -428,7 +432,7 @@ dnl Outputs: have_qt_test and have_qt_dbus are set (if applicable) to yes|no. AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITH_PKGCONFIG],[ m4_ifdef([PKG_CHECK_MODULES],[ QT_LIB_PREFIX=Qt5 - qt5_modules="Qt5Core Qt5Gui Qt5Network Qt5Widgets" + qt5_modules="Qt5Core Qt5Gui Qt5Network Qt5Widgets Qt5Svg" BITCOIN_QT_CHECK([ PKG_CHECK_MODULES([QT5], [$qt5_modules], [QT_INCLUDES="$QT5_CFLAGS"; QT_LIBS="$QT5_LIBS" have_qt=yes],[have_qt=no]) @@ -460,7 +464,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ TEMP_LIBS="$LIBS" BITCOIN_QT_CHECK([ if test "x$qt_include_path" != x; then - QT_INCLUDES="-I$qt_include_path -I$qt_include_path/QtCore -I$qt_include_path/QtGui -I$qt_include_path/QtWidgets -I$qt_include_path/QtNetwork -I$qt_include_path/QtTest -I$qt_include_path/QtDBus" + QT_INCLUDES="-I$qt_include_path -I$qt_include_path/QtCore -I$qt_include_path/QtGui -I$qt_include_path/QtWidgets -I$qt_include_path/QtNetwork -I$qt_include_path/QtTest -I$qt_include_path/QtDBus -I$qt_include_path/QtSvg -I$qt_include_path/QtCharts" CPPFLAGS="$QT_INCLUDES $CPPFLAGS" fi ]) @@ -468,6 +472,8 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ BITCOIN_QT_CHECK([AC_CHECK_HEADER([QtPlugin],,BITCOIN_QT_FAIL(QtCore headers missing))]) BITCOIN_QT_CHECK([AC_CHECK_HEADER([QApplication],, BITCOIN_QT_FAIL(QtGui headers missing))]) BITCOIN_QT_CHECK([AC_CHECK_HEADER([QLocalSocket],, BITCOIN_QT_FAIL(QtNetwork headers missing))]) + BITCOIN_QT_CHECK([AC_CHECK_HEADER([QtSvg],, BITCOIN_QT_FAIL(QtSvg headers missing))]) + BITCOIN_QT_CHECK([AC_CHECK_HEADER([QtCharts],, BITCOIN_QT_FAIL(QtCharts headers missing))]) BITCOIN_QT_CHECK([ if test "x$bitcoin_qt_want_version" = xauto; then @@ -502,6 +508,7 @@ AC_DEFUN([_BITCOIN_QT_FIND_LIBS_WITHOUT_PKGCONFIG],[ BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Gui] ,[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Gui not found))) BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Network],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Network not found))) BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Widgets],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Widgets not found))) + BITCOIN_QT_CHECK(AC_CHECK_LIB([${QT_LIB_PREFIX}Svg],[main],,BITCOIN_QT_FAIL(lib${QT_LIB_PREFIX}Svg not found))) QT_LIBS="$LIBS" LIBS="$TEMP_LIBS" diff --git a/configure.ac b/configure.ac index 5672fc2b1cd0..83b2b9a8cea8 100644 --- a/configure.ac +++ b/configure.ac @@ -138,11 +138,11 @@ AC_ARG_ENABLE([extended-functional-tests], [use_extended_functional_tests=$enableval], [use_extended_functional_tests=no]) -AC_ARG_WITH([qrencode], - [AS_HELP_STRING([--with-qrencode], - [enable QR code support (default is yes if qt is enabled and libqrencode is found)])], - [use_qr=$withval], - [use_qr=auto]) +AC_ARG_WITH([qtcharts], + [AS_HELP_STRING([--with-qtcharts], + [enable QTCHARTS code support (default is yes if qt is enabled and qtchartview is found)])], + [use_qtcharts=$withval], + [use_qtcharts=auto]) AC_ARG_ENABLE([hardening], [AS_HELP_STRING([--disable-hardening], @@ -1024,9 +1024,12 @@ if test x$use_pkgconfig = xyes; then PKG_CHECK_MODULES([SSL], [libssl],, [AC_MSG_ERROR(openssl not found.)]) PKG_CHECK_MODULES([CRYPTO], [libcrypto],,[AC_MSG_ERROR(libcrypto not found.)]) BITCOIN_QT_CHECK([PKG_CHECK_MODULES([PROTOBUF], [protobuf], [have_protobuf=yes], [BITCOIN_QT_FAIL(libprotobuf not found)])]) - if test x$use_qr != xno; then - BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])]) + BITCOIN_QT_CHECK([PKG_CHECK_MODULES([QR], [libqrencode], [have_qrencode=yes], [have_qrencode=no])]) + if test x$use_qtcharts != xno; then + BITCOIN_QT_CHECK([PKG_CHECK_MODULES([CHARTS], [Qt5Charts],[have_qtcharts=yes], [have_qtcharts=no])]) fi + BITCOIN_QT_CHECK([PKG_CHECK_MODULES([SVG], [Qt5Svg],,[BITCOIN_QT_FAIL(qtsvg not found)])]) + if test x$build_bitcoin_utils$build_bitcoind$bitcoin_enable_qt$use_tests != xnononono; then PKG_CHECK_MODULES([EVENT], [libevent],, [AC_MSG_ERROR(libevent not found.)]) if test x$TARGET_OS != xwindows; then @@ -1084,9 +1087,14 @@ else fi BITCOIN_QT_CHECK(AC_CHECK_LIB([protobuf] ,[main],[PROTOBUF_LIBS=-lprotobuf], BITCOIN_QT_FAIL(libprotobuf not found))) - if test x$use_qr != xno; then - BITCOIN_QT_CHECK([AC_CHECK_LIB([qrencode], [main],[QR_LIBS=-lqrencode], [have_qrencode=no])]) - BITCOIN_QT_CHECK([AC_CHECK_HEADER([qrencode.h],, have_qrencode=no)]) + BITCOIN_QT_CHECK([AC_CHECK_LIB([Qt5Svg], [main],[SVG_LIBS=-lQt5Svg], BITCOIN_QT_FAIL(svg not found))]) + BITCOIN_QT_CHECK([AC_CHECK_LIB([Qt5Charts], [main],[CHARTS_LIBS=-lQt5Charts], BITCOIN_QT_FAIL(charts not found))]) + + BITCOIN_QT_CHECK([AC_CHECK_LIB([qrencode], [main],[QR_LIBS=-lqrencode], [have_qrencode=no])]) + BITCOIN_QT_CHECK([AC_CHECK_HEADER([qrencode.h],, have_qrencode=no)]) + if test x$use_qtcharts != xno; then + BITCOIN_QT_CHECK([AC_CHECK_LIB([Qt5Charts], [main],[CHARTS_LIBS=-lQt5Charts], [have_qtcharts=no])]) + BITCOIN_QT_CHECK([AC_CHECK_HEADER([qchartview.h],, have_qtcharts=no)]) fi fi @@ -1265,18 +1273,18 @@ if test x$bitcoin_enable_qt != xno; then fi AC_MSG_RESULT($bitcoin_enable_qt_dbus) - dnl enable qr support - AC_MSG_CHECKING([whether to build GUI with support for QR codes]) - if test x$have_qrencode = xno; then - if test x$use_qr = xyes; then - AC_MSG_ERROR("QR support requested but cannot be built. use --without-qrencode") + dnl enable qtcharts support + AC_MSG_CHECKING([whether to build GUI with support for qtcharts codes]) + if test x$have_qtcharts = xno; then + if test x$use_qtcharts = xyes; then + AC_MSG_ERROR("QTCharts support requested but cannot be built. use --without-qtcharts") fi AC_MSG_RESULT(no) else - if test x$use_qr != xno; then + if test x$use_qtcharts != xno; then AC_MSG_RESULT(yes) - AC_DEFINE([USE_QRCODE],[1],[Define if QR support should be compiled in]) - use_qr=yes + AC_DEFINE([USE_QTCHARTS],[1],[Define if QTCHARTS support should be compiled in]) + use_qtcharts=yes else AC_MSG_RESULT(no) fi @@ -1341,7 +1349,7 @@ AM_CONDITIONAL([ENABLE_TESTS],[test x$BUILD_TEST = xyes]) AM_CONDITIONAL([ENABLE_QT],[test x$bitcoin_enable_qt = xyes]) AM_CONDITIONAL([ENABLE_QT_TESTS],[test x$BUILD_TEST_QT = xyes]) AM_CONDITIONAL([ENABLE_BENCH],[test x$use_bench = xyes]) -AM_CONDITIONAL([USE_QRCODE], [test x$use_qr = xyes]) +AM_CONDITIONAL([USE_QTCHARTS], [test x$use_qtcharts = xyes]) AM_CONDITIONAL([USE_LCOV],[test x$use_lcov = xyes]) AM_CONDITIONAL([GLIBC_BACK_COMPAT],[test x$use_glibc_compat = xyes]) AM_CONDITIONAL([HARDEN],[test x$use_hardening = xyes]) @@ -1390,7 +1398,7 @@ AC_SUBST(AVX2_CXXFLAGS) AC_SUBST(SHANI_CXXFLAGS) AC_SUBST(LIBTOOL_APP_LDFLAGS) AC_SUBST(USE_UPNP) -AC_SUBST(USE_QRCODE) +AC_SUBST(USE_QTCHARTS) AC_SUBST(BOOST_LIBS) AC_SUBST(TESTDEFS) AC_SUBST(LEVELDB_TARGET_FLAGS) @@ -1469,7 +1477,7 @@ echo "Options used to compile and link:" echo " with wallet = $enable_wallet" echo " with gui / qt = $bitcoin_enable_qt" if test x$bitcoin_enable_qt != xno; then - echo " with qr = $use_qr" + echo " with QTCHARTS = $use_qtcharts" fi echo " with zmq = $use_zmq" echo " with bignum = $set_bignum" @@ -1494,4 +1502,8 @@ echo " LDFLAGS = $PTHREAD_CFLAGS $HARDENED_LDFLAGS $GPROF_LDFLAGS $LDFLAG echo " ARFLAGS = $ARFLAGS" echo " PIC_FLAGS = $PIC_FLAGS" echo " QT_PIE_FLAGS = $QT_PIE_FLAGS" +echo " SVG_LIBS = $SVG_LIBS " +echo " SVG_CFLAGS = $SVG_CFLAGS " +echo " CHARTS_LIBS = $CHARTS_LIBS " +echo " CHARTS_CFLAGS = $CHARTS_CFLAGS " echo diff --git a/contrib/macdeploy/macdeployqtplus b/contrib/macdeploy/macdeployqtplus index a64ef2d2de29..c4321b5ee10a 100755 --- a/contrib/macdeploy/macdeployqtplus +++ b/contrib/macdeploy/macdeployqtplus @@ -424,7 +424,11 @@ def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose): elif pluginPath == "imageformats/libqsvg.dylib" or pluginPath == "iconengines/libqsvgicon.dylib": # Deploy the svg plugins only if QtSvg is in use if not deploymentInfo.usesFramework("QtSvg"): + print ("qtSVG NOT FOUND") continue + else: + print ("qtSVG FOUND!") + #a = deploymentInfo.usesFramework("QtSvg") elif pluginPath == "accessible/libqtaccessiblecompatwidgets.dylib": # Deploy accessibility for Qt3Support only if the Qt3Support is in use if not deploymentInfo.usesFramework("Qt3Support"): diff --git a/contrib/pivx-qt.pro b/contrib/pivx-qt.pro index 26f1a674f202..24e5a965e378 100644 --- a/contrib/pivx-qt.pro +++ b/contrib/pivx-qt.pro @@ -658,3 +658,6 @@ TRANSLATIONS += src/qt/locale/pivx_bg.ts \ src/qt/locale/pivx_vi.ts \ src/qt/locale/pivx_zh_CN.ts \ src/qt/locale/pivx_zh_TW.ts + +DISTFILES += \ + README.md diff --git a/depends/config.site.in b/depends/config.site.in index e63375206653..d6e39be254b4 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -13,6 +13,9 @@ fi if test -z $with_qt_translationdir; then with_qt_translationdir=$depends_prefix/translations fi +if test -z $with_qt_svgdir; then + with_qt_svgdir=$depends_prefix/svg +fi if test -z $with_qt_bindir && test -z "@no_qt@"; then with_qt_bindir=$depends_prefix/native/bin fi diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 8d2cb1936156..d281e3f7b7cd 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -16,8 +16,16 @@ $(package)_qttranslations_sha256_hash=b36da7d93c3ab6fca56b32053bb73bc619c8b192bb $(package)_qttools_file_name=qttools-$($(package)_suffix) $(package)_qttools_sha256_hash=d62e0f70d99645d6704dbb8976fb2222443061743689943d40970c52c49367a1 +$(package)_qtsvg_file_name=qtsvg-$($(package)_suffix) +$(package)_qtsvg_sha256_hash=628f22b8472e96ed8033d5491286ce2ab5b2c7b9fe0fe468acd78b458dc75564 + +$(package)_qtcharts_file_name=qtcharts-$($(package)_suffix) +$(package)_qtcharts_sha256_hash=16cd367241b2e0cd3bc8aea6f874598cd18ad83b72eed89f2713b777272572e6 + $(package)_extra_sources = $($(package)_qttranslations_file_name) $(package)_extra_sources += $($(package)_qttools_file_name) +$(package)_extra_sources += $($(package)_qtsvg_file_name) +$(package)_extra_sources += $($(package)_qtcharts_file_name) define $(package)_set_vars $(package)_config_opts_release = -release @@ -121,7 +129,9 @@ endef define $(package)_fetch_cmds $(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ $(call fetch_file,$(package),$($(package)_download_path),$($(package)_qttranslations_file_name),$($(package)_qttranslations_file_name),$($(package)_qttranslations_sha256_hash)) && \ -$(call fetch_file,$(package),$($(package)_download_path),$($(package)_qttools_file_name),$($(package)_qttools_file_name),$($(package)_qttools_sha256_hash)) +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_qttools_file_name),$($(package)_qttools_file_name),$($(package)_qttools_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_qtsvg_file_name),$($(package)_qtsvg_file_name),$($(package)_qtsvg_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_qtcharts_file_name),$($(package)_qtcharts_file_name),$($(package)_qtcharts_sha256_hash)) endef define $(package)_extract_cmds @@ -129,13 +139,19 @@ define $(package)_extract_cmds echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ echo "$($(package)_qttranslations_sha256_hash) $($(package)_source_dir)/$($(package)_qttranslations_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ echo "$($(package)_qttools_sha256_hash) $($(package)_source_dir)/$($(package)_qttools_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_qtsvg_sha256_hash) $($(package)_source_dir)/$($(package)_qtsvg_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_qtcharts_sha256_hash) $($(package)_source_dir)/$($(package)_qtcharts_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ mkdir qtbase && \ tar --no-same-owner --strip-components=1 -xf $($(package)_source) -C qtbase && \ mkdir qttranslations && \ tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \ mkdir qttools && \ - tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools + tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools && \ + mkdir qtsvg && \ + tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qtsvg_file_name) -C qtsvg && \ + mkdir qtcharts && \ + tar --no-same-owner --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qtcharts_file_name) -C qtcharts endef define $(package)_preprocess_cmds @@ -151,6 +167,11 @@ define $(package)_preprocess_cmds cp -f qtbase/mkspecs/macx-clang/Info.plist.app qtbase/mkspecs/macx-clang-linux/ &&\ cp -f qtbase/mkspecs/macx-clang/qplatformdefs.h qtbase/mkspecs/macx-clang-linux/ &&\ cp -f $($(package)_patch_dir)/mac-qmake.conf qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + echo "!host_build: QMAKE_INCDIR += $(host_prefix)/native/include/c++/v1" >> qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + sed -i.old "s|QMAKE_AR = \$$$$\$$$${CROSS_COMPILE}|QMAKE_AR = $(host_prefix)/native/bin/\$$$$\$$$${CROSS_COMPILE}|" qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + sed -i.old "s|QMAKE_RANLIB=\$$$$\$$$${CROSS_COMPILE}|QMAKE_RANLIB=$(host_prefix)/native/bin/\$$$$\$$$${CROSS_COMPILE}|" qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + sed -i.old "s|QMAKE_LIBTOOL=\$$$$\$$$${CROSS_COMPILE}|QMAKE_LIBTOOL=$(host_prefix)/native/bin/\$$$$\$$$${CROSS_COMPILE}|" qtbase/mkspecs/macx-clang-linux/qmake.conf && \ + sed -i.old "s|QMAKE_INSTALL_NAME_TOOL=\$$$$\$$$${CROSS_COMPILE}|QMAKE_INSTALL_NAME_TOOL=$(host_prefix)/native/bin/\$$$$\$$$${CROSS_COMPILE}|" qtbase/mkspecs/macx-clang-linux/qmake.conf && \ cp -r qtbase/mkspecs/linux-arm-gnueabi-g++ qtbase/mkspecs/pivx-linux-g++ && \ sed -i.old "s/arm-linux-gnueabi-/$(host)-/g" qtbase/mkspecs/pivx-linux-g++/qmake.conf && \ patch -p1 -i $($(package)_patch_dir)/fix_qt_pkgconfig.patch &&\ @@ -181,20 +202,33 @@ define $(package)_config_cmds cd ../qttranslations && ../qtbase/bin/qmake qttranslations.pro -o Makefile && \ cd translations && ../../qtbase/bin/qmake translations.pro -o Makefile && cd ../.. && \ cd qttools/src/linguist/lrelease/ && ../../../../qtbase/bin/qmake lrelease.pro -o Makefile && \ - cd ../lupdate/ && ../../../../qtbase/bin/qmake lupdate.pro -o Makefile && cd ../../../.. + cd ../lupdate/ && ../../../../qtbase/bin/qmake lupdate.pro -o Makefile && cd ../../../.. && \ + cd qtsvg && ../qtbase/bin/qmake qtsvg.pro -o Makefile && \ + cd src/svg && ../../../qtbase/bin/qmake svg.pro -o Makefile && cd ../../.. && \ + cd qtsvg/src/plugins && ../../../qtbase/bin/qmake plugins.pro -o Makefile && cd ../../.. && \ + cd qtsvg/src/plugins/imageformats && ../../../../qtbase/bin/qmake imageformats.pro -o Makefile && cd ../../../.. && \ + cd qtsvg/src/plugins/imageformats/svg && ../../../../../qtbase/bin/qmake svg.pro -o Makefile && cd ../../../../.. && \ + cd qtcharts && ../qtbase/bin/qmake qtcharts.pro -o Makefile endef define $(package)_build_cmds + export PATH=$(build_prefix)/bin:$(PATH) && \ $(MAKE) -C src $(addprefix sub-,$($(package)_qt_libs)) && \ $(MAKE) -C ../qttools/src/linguist/lrelease && \ $(MAKE) -C ../qttools/src/linguist/lupdate && \ - $(MAKE) -C ../qttranslations + $(MAKE) -C ../qttranslations && \ + $(MAKE) -C ../qtsvg/ && \ + $(MAKE) -C ../qtsvg/src/svg && \ + $(MAKE) -C ../qtsvg/src/plugins/imageformats && \ + $(MAKE) -C ../qtcharts/ endef define $(package)_stage_cmds $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && cd .. && \ $(MAKE) -C qttools/src/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install_target && \ $(MAKE) -C qttools/src/linguist/lupdate INSTALL_ROOT=$($(package)_staging_dir) install_target && \ + $(MAKE) -C qtsvg INSTALL_ROOT=$($(package)_staging_dir) install_subtargets && \ + $(MAKE) -C qtcharts INSTALL_ROOT=$($(package)_staging_dir) install_subtargets && \ $(MAKE) -C qttranslations INSTALL_ROOT=$($(package)_staging_dir) install_subtargets && \ if `test -f qtbase/src/plugins/platforms/xcb/xcb-static/libxcb-static.a`; then \ cp qtbase/src/plugins/platforms/xcb/xcb-static/libxcb-static.a $($(package)_staging_prefix_dir)/lib; \ diff --git a/doc/build-unix.md b/doc/build-unix.md index f959a4da2050..bda447f24e56 100644 --- a/doc/build-unix.md +++ b/doc/build-unix.md @@ -44,7 +44,6 @@ Optional dependencies: libdb4.8 | Berkeley DB | Wallet storage (only needed when wallet enabled) qt | GUI | GUI toolkit (only needed when GUI enabled) protobuf | Payments in GUI | Data interchange format used for payment protocol (only needed when GUI enabled) - libqrencode | QR codes in GUI | Optional for generating QR codes (only needed when GUI enabled) univalue | Utility | JSON parsing and encoding (bundled version will be used unless --with-system-univalue passed to configure) libzmq3 | ZMQ notification | Optional, allows generating ZMQ notifications (requires ZMQ version >= 4.0.0) @@ -115,11 +114,7 @@ To build without GUI pass `--without-gui`. To build with Qt 5 you need the following: - sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler - -libqrencode (optional) can be installed with: - - sudo apt-get install libqrencode-dev + sudo apt-get install libqt5gui5 libqt5core5a libqt5dbus5 libqt5svg5-dev libqt5charts5-dev qttools5-dev qttools5-dev-tools libprotobuf-dev protobuf-compiler libqrencode-dev Once these are installed, they will be found by configure and a pivx-qt executable will be built by default. @@ -139,11 +134,7 @@ Optional: To build with Qt 5 you need the following: - sudo dnf install qt5-qttools-devel qt5-qtbase-devel protobuf-devel - -libqrencode (optional) can be installed with: - - sudo dnf install qrencode-devel + sudo dnf install qt5-qttools-devel qt5-qtbase-devel protobuf-devel qrencode-devel Notes ----- diff --git a/pivxd-new-gui.config b/pivxd-new-gui.config new file mode 100644 index 000000000000..e0284f42573a --- /dev/null +++ b/pivxd-new-gui.config @@ -0,0 +1,2 @@ +// Add predefined macros for your project here. For example: +// #define THE_ANSWER 42 diff --git a/pivxd-new-gui.creator b/pivxd-new-gui.creator new file mode 100644 index 000000000000..e94cbbd3027d --- /dev/null +++ b/pivxd-new-gui.creator @@ -0,0 +1 @@ +[General] diff --git a/pivxd-new-gui.creator.user b/pivxd-new-gui.creator.user new file mode 100644 index 000000000000..19f49181d271 --- /dev/null +++ b/pivxd-new-gui.creator.user @@ -0,0 +1,202 @@ + + + + + + EnvironmentId + {a3b9609a-d7d6-4afe-935c-407d31c78f25} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + true + + + + ProjectExplorer.Project.Target.0 + + Desktop Qt 5.9.6 clang 64bit + Desktop Qt 5.9.6 clang 64bit + qt.596.clang_64_kit + 0 + 0 + 0 + + /Users/furszy/Documents/pivx_wallet/PIVX_core_new_gui + + + + all + + false + + + true + Make + + GenericProjectManager.GenericMakeStep + + 1 + Build + + ProjectExplorer.BuildSteps.Build + + + + + clean + + false + + + true + Make + + GenericProjectManager.GenericMakeStep + + 1 + Clean + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Default + Default + GenericProjectManager.GenericBuildConfiguration + + 1 + + + 0 + Deploy + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deploy Configuration + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + -testnet -datadir="/Users/furszy/Desktop/pivx_testnet_remove_me" + /Users/furszy/Documents/pivx_wallet/PIVX_core_new_gui/src/qt/pivx-qt + + + Custom Executable + + ProjectExplorer.CustomExecutableRunConfiguration + 3768 + false + true + false + false + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 18 + + + Version + 18 + + diff --git a/pivxd-new-gui.files b/pivxd-new-gui.files new file mode 100644 index 000000000000..9e3435d654a6 --- /dev/null +++ b/pivxd-new-gui.files @@ -0,0 +1,1067 @@ +cmake-build-debug/CMakeFiles/3.10.3/CompilerIdC/CMakeCCompilerId.c +cmake-build-debug/CMakeFiles/3.10.3/CompilerIdCXX/CMakeCXXCompilerId.cpp +cmake-build-debug/CMakeFiles/feature_tests.c +cmake-build-debug/CMakeFiles/feature_tests.cxx +src/accumulatorcheckpoints.cpp +src/accumulatorcheckpoints.h +src/accumulatorcheckpoints.json.h +src/accumulatormap.cpp +src/accumulatormap.h +src/accumulators.cpp +src/accumulators.h +src/activemasternode.cpp +src/activemasternode.h +src/addrman.cpp +src/addrman.h +src/alert.cpp +src/alert.h +src/allocators.cpp +src/allocators.h +src/amount.cpp +src/amount.h +src/base58.cpp +src/base58.h +src/bip38.cpp +src/bip38.h +src/blocksignature.cpp +src/blocksignature.h +src/bloom.cpp +src/bloom.h +src/chain.cpp +src/chain.h +src/chainparams.cpp +src/chainparams.h +src/chainparamsbase.cpp +src/chainparamsbase.h +src/chainparamsseeds.h +src/checkpoints.cpp +src/checkpoints.h +src/checkqueue.h +src/clientversion.cpp +src/clientversion.h +src/coincontrol.h +src/coins.cpp +src/coins.h +src/compat.h +src/compat/byteswap.h +src/compat/endian.h +src/compat/glibc_compat.cpp +src/compat/glibc_sanity.cpp +src/compat/glibcxx_sanity.cpp +src/compat/sanity.h +src/compat/strnlen.cpp +src/compressor.cpp +src/compressor.h +src/concurrentqueue.h +src/config/pivx-config.h +src/core_io.h +src/core_read.cpp +src/core_write.cpp +src/crypter.cpp +src/crypter.h +src/crypto/aes_helper.c +src/crypto/blake.c +src/crypto/bmw.c +src/crypto/common.h +src/crypto/cubehash.c +src/crypto/echo.c +src/crypto/groestl.c +src/crypto/hmac_sha256.cpp +src/crypto/hmac_sha256.h +src/crypto/hmac_sha512.cpp +src/crypto/hmac_sha512.h +src/crypto/jh.c +src/crypto/keccak.c +src/crypto/luffa.c +src/crypto/rfc6979_hmac_sha256.cpp +src/crypto/rfc6979_hmac_sha256.h +src/crypto/ripemd160.cpp +src/crypto/ripemd160.h +src/crypto/scrypt.cpp +src/crypto/scrypt.h +src/crypto/sha1.cpp +src/crypto/sha1.h +src/crypto/sha256.cpp +src/crypto/sha256.h +src/crypto/sha512.cpp +src/crypto/sha512.h +src/crypto/shavite.c +src/crypto/simd.c +src/crypto/skein.c +src/crypto/sph_blake.h +src/crypto/sph_bmw.h +src/crypto/sph_cubehash.h +src/crypto/sph_echo.h +src/crypto/sph_groestl.h +src/crypto/sph_jh.h +src/crypto/sph_keccak.h +src/crypto/sph_luffa.h +src/crypto/sph_shavite.h +src/crypto/sph_simd.h +src/crypto/sph_skein.h +src/crypto/sph_types.h +src/db.cpp +src/db.h +src/denomination_functions.cpp +src/denomination_functions.h +src/genwit.cpp +src/genwit.h +src/hash.cpp +src/hash.h +src/httprpc.cpp +src/httprpc.h +src/httpserver.cpp +src/httpserver.h +src/init.cpp +src/init.h +src/invalid.cpp +src/invalid.h +src/invalid_outpoints.json.h +src/invalid_serials.json.h +src/kernel.cpp +src/kernel.h +src/key.cpp +src/key.h +src/keystore.cpp +src/keystore.h +src/leveldb/db/autocompact_test.cc +src/leveldb/db/builder.cc +src/leveldb/db/builder.h +src/leveldb/db/c.cc +src/leveldb/db/c_test.c +src/leveldb/db/corruption_test.cc +src/leveldb/db/db_bench.cc +src/leveldb/db/db_impl.cc +src/leveldb/db/db_impl.h +src/leveldb/db/db_iter.cc +src/leveldb/db/db_iter.h +src/leveldb/db/db_test.cc +src/leveldb/db/dbformat.cc +src/leveldb/db/dbformat.h +src/leveldb/db/dbformat_test.cc +src/leveldb/db/dumpfile.cc +src/leveldb/db/fault_injection_test.cc +src/leveldb/db/filename.cc +src/leveldb/db/filename.h +src/leveldb/db/filename_test.cc +src/leveldb/db/leveldbutil.cc +src/leveldb/db/log_format.h +src/leveldb/db/log_reader.cc +src/leveldb/db/log_reader.h +src/leveldb/db/log_test.cc +src/leveldb/db/log_writer.cc +src/leveldb/db/log_writer.h +src/leveldb/db/memtable.cc +src/leveldb/db/memtable.h +src/leveldb/db/recovery_test.cc +src/leveldb/db/repair.cc +src/leveldb/db/skiplist.h +src/leveldb/db/skiplist_test.cc +src/leveldb/db/snapshot.h +src/leveldb/db/table_cache.cc +src/leveldb/db/table_cache.h +src/leveldb/db/version_edit.cc +src/leveldb/db/version_edit.h +src/leveldb/db/version_edit_test.cc +src/leveldb/db/version_set.cc +src/leveldb/db/version_set.h +src/leveldb/db/version_set_test.cc +src/leveldb/db/write_batch.cc +src/leveldb/db/write_batch_internal.h +src/leveldb/db/write_batch_test.cc +src/leveldb/doc/bench/db_bench_sqlite3.cc +src/leveldb/doc/bench/db_bench_tree_db.cc +src/leveldb/helpers/memenv/memenv.cc +src/leveldb/helpers/memenv/memenv.h +src/leveldb/helpers/memenv/memenv_test.cc +src/leveldb/include/leveldb/c.h +src/leveldb/include/leveldb/cache.h +src/leveldb/include/leveldb/comparator.h +src/leveldb/include/leveldb/db.h +src/leveldb/include/leveldb/dumpfile.h +src/leveldb/include/leveldb/env.h +src/leveldb/include/leveldb/filter_policy.h +src/leveldb/include/leveldb/iterator.h +src/leveldb/include/leveldb/options.h +src/leveldb/include/leveldb/slice.h +src/leveldb/include/leveldb/status.h +src/leveldb/include/leveldb/table.h +src/leveldb/include/leveldb/table_builder.h +src/leveldb/include/leveldb/write_batch.h +src/leveldb/issues/issue178_test.cc +src/leveldb/issues/issue200_test.cc +src/leveldb/port/atomic_pointer.h +src/leveldb/port/port.h +src/leveldb/port/port_example.h +src/leveldb/port/port_posix.cc +src/leveldb/port/port_posix.h +src/leveldb/port/port_posix_sse.cc +src/leveldb/port/port_win.cc +src/leveldb/port/port_win.h +src/leveldb/port/thread_annotations.h +src/leveldb/port/win/stdint.h +src/leveldb/table/block.cc +src/leveldb/table/block.h +src/leveldb/table/block_builder.cc +src/leveldb/table/block_builder.h +src/leveldb/table/filter_block.cc +src/leveldb/table/filter_block.h +src/leveldb/table/filter_block_test.cc +src/leveldb/table/format.cc +src/leveldb/table/format.h +src/leveldb/table/iterator.cc +src/leveldb/table/iterator_wrapper.h +src/leveldb/table/merger.cc +src/leveldb/table/merger.h +src/leveldb/table/table.cc +src/leveldb/table/table_builder.cc +src/leveldb/table/table_test.cc +src/leveldb/table/two_level_iterator.cc +src/leveldb/table/two_level_iterator.h +src/leveldb/util/arena.cc +src/leveldb/util/arena.h +src/leveldb/util/arena_test.cc +src/leveldb/util/bloom.cc +src/leveldb/util/bloom_test.cc +src/leveldb/util/cache.cc +src/leveldb/util/cache_test.cc +src/leveldb/util/coding.cc +src/leveldb/util/coding.h +src/leveldb/util/coding_test.cc +src/leveldb/util/comparator.cc +src/leveldb/util/crc32c.cc +src/leveldb/util/crc32c.h +src/leveldb/util/crc32c_test.cc +src/leveldb/util/env.cc +src/leveldb/util/env_posix.cc +src/leveldb/util/env_posix_test.cc +src/leveldb/util/env_posix_test_helper.h +src/leveldb/util/env_test.cc +src/leveldb/util/env_win.cc +src/leveldb/util/filter_policy.cc +src/leveldb/util/hash.cc +src/leveldb/util/hash.h +src/leveldb/util/hash_test.cc +src/leveldb/util/histogram.cc +src/leveldb/util/histogram.h +src/leveldb/util/logging.cc +src/leveldb/util/logging.h +src/leveldb/util/mutexlock.h +src/leveldb/util/options.cc +src/leveldb/util/posix_logger.h +src/leveldb/util/random.h +src/leveldb/util/status.cc +src/leveldb/util/testharness.cc +src/leveldb/util/testharness.h +src/leveldb/util/testutil.cc +src/leveldb/util/testutil.h +src/leveldbwrapper.cpp +src/leveldbwrapper.h +src/libzerocoin/Accumulator.cpp +src/libzerocoin/Accumulator.h +src/libzerocoin/AccumulatorProofOfKnowledge.cpp +src/libzerocoin/AccumulatorProofOfKnowledge.h +src/libzerocoin/Coin.cpp +src/libzerocoin/Coin.h +src/libzerocoin/CoinSpend.cpp +src/libzerocoin/CoinSpend.h +src/libzerocoin/Commitment.cpp +src/libzerocoin/Commitment.h +src/libzerocoin/Denominations.cpp +src/libzerocoin/Denominations.h +src/libzerocoin/ParamGeneration.cpp +src/libzerocoin/ParamGeneration.h +src/libzerocoin/Params.cpp +src/libzerocoin/Params.h +src/libzerocoin/SerialNumberSignatureOfKnowledge.cpp +src/libzerocoin/SerialNumberSignatureOfKnowledge.h +src/libzerocoin/SpendType.h +src/libzerocoin/ZerocoinDefines.h +src/libzerocoin/bignum.h +src/libzerocoin/paramgen.cpp +src/lightzpivthread.cpp +src/lightzpivthread.h +src/limitedmap.h +src/main.cpp +src/main.h +src/masternode-budget.cpp +src/masternode-budget.h +src/masternode-payments.cpp +src/masternode-payments.h +src/masternode-sync.cpp +src/masternode-sync.h +src/masternode.cpp +src/masternode.h +src/masternodeconfig.cpp +src/masternodeconfig.h +src/masternodeman.cpp +src/masternodeman.h +src/merkleblock.cpp +src/merkleblock.h +src/miner.cpp +src/miner.h +src/mintpool.cpp +src/mintpool.h +src/mruset.h +src/net.cpp +src/net.h +src/netbase.cpp +src/netbase.h +src/noui.cpp +src/noui.h +src/obfuscation-relay.cpp +src/obfuscation-relay.h +src/obfuscation.cpp +src/obfuscation.h +src/obj/build.h +src/pivx-cli.cpp +src/pivx-tx.cpp +src/pivxd.cpp +src/pow.cpp +src/pow.h +src/primitives/block.cpp +src/primitives/block.h +src/primitives/deterministicmint.cpp +src/primitives/deterministicmint.h +src/primitives/transaction.cpp +src/primitives/transaction.h +src/primitives/zerocoin.cpp +src/primitives/zerocoin.h +src/protocol.cpp +src/protocol.h +src/pubkey.cpp +src/pubkey.h +src/qt/addressbookpage.cpp +src/qt/addressbookpage.cpp +src/qt/addressbookpage.h +src/qt/addressbookpage.h +src/qt/addresstablemodel.cpp +src/qt/addresstablemodel.cpp +src/qt/addresstablemodel.h +src/qt/addresstablemodel.h +src/qt/askpassphrasedialog.cpp +src/qt/askpassphrasedialog.cpp +src/qt/askpassphrasedialog.h +src/qt/askpassphrasedialog.h +src/qt/bantablemodel.cpp +src/qt/bantablemodel.cpp +src/qt/bantablemodel.h +src/qt/bantablemodel.h +src/qt/bip38tooldialog.cpp +src/qt/bip38tooldialog.cpp +src/qt/bip38tooldialog.h +src/qt/bip38tooldialog.h +src/qt/bitcoinaddressvalidator.cpp +src/qt/bitcoinaddressvalidator.cpp +src/qt/bitcoinaddressvalidator.h +src/qt/bitcoinaddressvalidator.h +src/qt/bitcoinamountfield.cpp +src/qt/bitcoinamountfield.cpp +src/qt/bitcoinamountfield.h +src/qt/bitcoinamountfield.h +src/qt/bitcoingui.cpp +src/qt/bitcoingui.cpp +src/qt/bitcoingui.h +src/qt/bitcoingui.h +src/qt/bitcoinunits.cpp +src/qt/bitcoinunits.cpp +src/qt/bitcoinunits.h +src/qt/bitcoinunits.h +src/qt/blockexplorer.cpp +src/qt/blockexplorer.cpp +src/qt/blockexplorer.h +src/qt/blockexplorer.h +src/qt/clientmodel.cpp +src/qt/clientmodel.cpp +src/qt/clientmodel.h +src/qt/clientmodel.h +src/qt/coincontroldialog.cpp +src/qt/coincontroldialog.cpp +src/qt/coincontroldialog.h +src/qt/coincontroldialog.h +src/qt/coincontroltreewidget.cpp +src/qt/coincontroltreewidget.cpp +src/qt/coincontroltreewidget.h +src/qt/coincontroltreewidget.h +src/qt/csvmodelwriter.cpp +src/qt/csvmodelwriter.cpp +src/qt/csvmodelwriter.h +src/qt/csvmodelwriter.h +src/qt/editaddressdialog.cpp +src/qt/editaddressdialog.cpp +src/qt/editaddressdialog.h +src/qt/editaddressdialog.h +src/qt/forms/addressbookpage.ui +src/qt/forms/askpassphrasedialog.ui +src/qt/forms/bip38tooldialog.ui +src/qt/forms/blockexplorer.ui +src/qt/forms/coincontroldialog.ui +src/qt/forms/editaddressdialog.ui +src/qt/forms/governancepage.ui +src/qt/forms/helpmessagedialog.ui +src/qt/forms/intro.ui +src/qt/forms/masternodelist.ui +src/qt/forms/multisenddialog.ui +src/qt/forms/multisigdialog.ui +src/qt/forms/obfuscationconfig.ui +src/qt/forms/openuridialog.ui +src/qt/forms/optionsdialog.ui +src/qt/forms/overviewpage.ui +src/qt/forms/privacydialog.ui +src/qt/forms/receivecoinsdialog.ui +src/qt/forms/receiverequestdialog.ui +src/qt/forms/rpcconsole.ui +src/qt/forms/sendcoinsdialog.ui +src/qt/forms/sendcoinsentry.ui +src/qt/forms/signverifymessagedialog.ui +src/qt/forms/tradingdialog.ui +src/qt/forms/transactiondescdialog.ui +src/qt/forms/ui_addressbookpage.h +src/qt/forms/ui_addressbookpage.h +src/qt/forms/ui_askpassphrasedialog.h +src/qt/forms/ui_askpassphrasedialog.h +src/qt/forms/ui_bip38tooldialog.h +src/qt/forms/ui_bip38tooldialog.h +src/qt/forms/ui_blockexplorer.h +src/qt/forms/ui_blockexplorer.h +src/qt/forms/ui_coincontroldialog.h +src/qt/forms/ui_coincontroldialog.h +src/qt/forms/ui_editaddressdialog.h +src/qt/forms/ui_editaddressdialog.h +src/qt/forms/ui_governancepage.h +src/qt/forms/ui_governancepage.h +src/qt/forms/ui_helpmessagedialog.h +src/qt/forms/ui_helpmessagedialog.h +src/qt/forms/ui_intro.h +src/qt/forms/ui_intro.h +src/qt/forms/ui_masternodelist.h +src/qt/forms/ui_masternodelist.h +src/qt/forms/ui_multisenddialog.h +src/qt/forms/ui_multisenddialog.h +src/qt/forms/ui_multisigdialog.h +src/qt/forms/ui_multisigdialog.h +src/qt/forms/ui_obfuscationconfig.h +src/qt/forms/ui_obfuscationconfig.h +src/qt/forms/ui_openuridialog.h +src/qt/forms/ui_openuridialog.h +src/qt/forms/ui_optionsdialog.h +src/qt/forms/ui_optionsdialog.h +src/qt/forms/ui_overviewpage.h +src/qt/forms/ui_overviewpage.h +src/qt/forms/ui_privacydialog.h +src/qt/forms/ui_privacydialog.h +src/qt/forms/ui_receivecoinsdialog.h +src/qt/forms/ui_receivecoinsdialog.h +src/qt/forms/ui_receiverequestdialog.h +src/qt/forms/ui_receiverequestdialog.h +src/qt/forms/ui_rpcconsole.h +src/qt/forms/ui_rpcconsole.h +src/qt/forms/ui_sendcoinsdialog.h +src/qt/forms/ui_sendcoinsdialog.h +src/qt/forms/ui_sendcoinsentry.h +src/qt/forms/ui_sendcoinsentry.h +src/qt/forms/ui_signverifymessagedialog.h +src/qt/forms/ui_signverifymessagedialog.h +src/qt/forms/ui_transactiondescdialog.h +src/qt/forms/ui_transactiondescdialog.h +src/qt/forms/ui_zpivcontroldialog.h +src/qt/forms/ui_zpivcontroldialog.h +src/qt/forms/zpivcontroldialog.ui +src/qt/governancepage.cpp +src/qt/governancepage.cpp +src/qt/governancepage.h +src/qt/governancepage.h +src/qt/guiconstants.h +src/qt/guiconstants.h +src/qt/guiutil.cpp +src/qt/guiutil.cpp +src/qt/guiutil.h +src/qt/guiutil.h +src/qt/intro.cpp +src/qt/intro.cpp +src/qt/intro.h +src/qt/intro.h +src/qt/macdockiconhandler.h +src/qt/macdockiconhandler.h +src/qt/macnotificationhandler.h +src/qt/macnotificationhandler.h +src/qt/masternodelist.cpp +src/qt/masternodelist.cpp +src/qt/masternodelist.h +src/qt/masternodelist.h +src/qt/moc_addressbookpage.cpp +src/qt/moc_addressbookpage.cpp +src/qt/moc_addresstablemodel.cpp +src/qt/moc_addresstablemodel.cpp +src/qt/moc_askpassphrasedialog.cpp +src/qt/moc_askpassphrasedialog.cpp +src/qt/moc_bantablemodel.cpp +src/qt/moc_bantablemodel.cpp +src/qt/moc_bip38tooldialog.cpp +src/qt/moc_bip38tooldialog.cpp +src/qt/moc_bitcoinaddressvalidator.cpp +src/qt/moc_bitcoinaddressvalidator.cpp +src/qt/moc_bitcoinamountfield.cpp +src/qt/moc_bitcoinamountfield.cpp +src/qt/moc_bitcoingui.cpp +src/qt/moc_bitcoingui.cpp +src/qt/moc_bitcoinunits.cpp +src/qt/moc_bitcoinunits.cpp +src/qt/moc_blockexplorer.cpp +src/qt/moc_blockexplorer.cpp +src/qt/moc_clientmodel.cpp +src/qt/moc_clientmodel.cpp +src/qt/moc_coincontroldialog.cpp +src/qt/moc_coincontroldialog.cpp +src/qt/moc_coincontroltreewidget.cpp +src/qt/moc_coincontroltreewidget.cpp +src/qt/moc_csvmodelwriter.cpp +src/qt/moc_csvmodelwriter.cpp +src/qt/moc_editaddressdialog.cpp +src/qt/moc_editaddressdialog.cpp +src/qt/moc_governancepage.cpp +src/qt/moc_governancepage.cpp +src/qt/moc_guiutil.cpp +src/qt/moc_guiutil.cpp +src/qt/moc_intro.cpp +src/qt/moc_intro.cpp +src/qt/moc_macdockiconhandler.cpp +src/qt/moc_macdockiconhandler.cpp +src/qt/moc_macnotificationhandler.cpp +src/qt/moc_macnotificationhandler.cpp +src/qt/moc_masternodelist.cpp +src/qt/moc_masternodelist.cpp +src/qt/moc_multisenddialog.cpp +src/qt/moc_multisenddialog.cpp +src/qt/moc_multisigdialog.cpp +src/qt/moc_multisigdialog.cpp +src/qt/moc_notificator.cpp +src/qt/moc_notificator.cpp +src/qt/moc_obfuscationconfig.cpp +src/qt/moc_obfuscationconfig.cpp +src/qt/moc_openuridialog.cpp +src/qt/moc_openuridialog.cpp +src/qt/moc_optionsdialog.cpp +src/qt/moc_optionsdialog.cpp +src/qt/moc_optionsmodel.cpp +src/qt/moc_optionsmodel.cpp +src/qt/moc_overviewpage.cpp +src/qt/moc_overviewpage.cpp +src/qt/moc_paymentserver.cpp +src/qt/moc_paymentserver.cpp +src/qt/moc_peertablemodel.cpp +src/qt/moc_peertablemodel.cpp +src/qt/moc_privacydialog.cpp +src/qt/moc_privacydialog.cpp +src/qt/moc_proposalframe.cpp +src/qt/moc_proposalframe.cpp +src/qt/moc_qvalidatedlineedit.cpp +src/qt/moc_qvalidatedlineedit.cpp +src/qt/moc_qvaluecombobox.cpp +src/qt/moc_qvaluecombobox.cpp +src/qt/moc_receivecoinsdialog.cpp +src/qt/moc_receivecoinsdialog.cpp +src/qt/moc_receiverequestdialog.cpp +src/qt/moc_receiverequestdialog.cpp +src/qt/moc_recentrequeststablemodel.cpp +src/qt/moc_recentrequeststablemodel.cpp +src/qt/moc_rpcconsole.cpp +src/qt/moc_rpcconsole.cpp +src/qt/moc_sendcoinsdialog.cpp +src/qt/moc_sendcoinsdialog.cpp +src/qt/moc_sendcoinsentry.cpp +src/qt/moc_sendcoinsentry.cpp +src/qt/moc_signverifymessagedialog.cpp +src/qt/moc_signverifymessagedialog.cpp +src/qt/moc_splashscreen.cpp +src/qt/moc_splashscreen.cpp +src/qt/moc_trafficgraphwidget.cpp +src/qt/moc_trafficgraphwidget.cpp +src/qt/moc_transactiondesc.cpp +src/qt/moc_transactiondesc.cpp +src/qt/moc_transactiondescdialog.cpp +src/qt/moc_transactiondescdialog.cpp +src/qt/moc_transactionfilterproxy.cpp +src/qt/moc_transactionfilterproxy.cpp +src/qt/moc_transactiontablemodel.cpp +src/qt/moc_transactiontablemodel.cpp +src/qt/moc_transactionview.cpp +src/qt/moc_transactionview.cpp +src/qt/moc_utilitydialog.cpp +src/qt/moc_utilitydialog.cpp +src/qt/moc_walletframe.cpp +src/qt/moc_walletframe.cpp +src/qt/moc_walletmodel.cpp +src/qt/moc_walletmodel.cpp +src/qt/moc_walletview.cpp +src/qt/moc_walletview.cpp +src/qt/moc_zpivcontroldialog.cpp +src/qt/moc_zpivcontroldialog.cpp +src/qt/multisenddialog.cpp +src/qt/multisenddialog.cpp +src/qt/multisenddialog.h +src/qt/multisenddialog.h +src/qt/multisigdialog.cpp +src/qt/multisigdialog.cpp +src/qt/multisigdialog.h +src/qt/multisigdialog.h +src/qt/networkstyle.cpp +src/qt/networkstyle.cpp +src/qt/networkstyle.h +src/qt/networkstyle.h +src/qt/notificator.cpp +src/qt/notificator.cpp +src/qt/notificator.h +src/qt/notificator.h +src/qt/obfuscationconfig.cpp +src/qt/obfuscationconfig.cpp +src/qt/obfuscationconfig.h +src/qt/obfuscationconfig.h +src/qt/openuridialog.cpp +src/qt/openuridialog.cpp +src/qt/openuridialog.h +src/qt/openuridialog.h +src/qt/optionsdialog.cpp +src/qt/optionsdialog.cpp +src/qt/optionsdialog.h +src/qt/optionsdialog.h +src/qt/optionsmodel.cpp +src/qt/optionsmodel.cpp +src/qt/optionsmodel.h +src/qt/optionsmodel.h +src/qt/overviewpage.cpp +src/qt/overviewpage.cpp +src/qt/overviewpage.h +src/qt/overviewpage.h +src/qt/paymentrequest.pb.cc +src/qt/paymentrequest.pb.cc +src/qt/paymentrequest.pb.h +src/qt/paymentrequest.pb.h +src/qt/paymentrequestplus.cpp +src/qt/paymentrequestplus.cpp +src/qt/paymentrequestplus.h +src/qt/paymentrequestplus.h +src/qt/paymentserver.cpp +src/qt/paymentserver.cpp +src/qt/paymentserver.h +src/qt/paymentserver.h +src/qt/peertablemodel.cpp +src/qt/peertablemodel.cpp +src/qt/peertablemodel.h +src/qt/peertablemodel.h +src/qt/pivx.cpp +src/qt/pivx.cpp +src/qt/pivx.qrc +src/qt/pivx/PIVXGUI.cpp +src/qt/pivx/PIVXGUI.cpp +src/qt/pivx/PIVXGUI.cpp +src/qt/pivx/PIVXGUI.h +src/qt/pivx/PIVXGUI.h +src/qt/pivx/PIVXGUI.h +src/qt/pivx/forms/lockunlock.ui +src/qt/pivx/forms/navmenuwidget.ui +src/qt/pivx/forms/receivedialog.ui +src/qt/pivx/forms/topbar.ui +src/qt/pivx/forms/walletpassworddialog.ui +src/qt/pivx/lockunlock.cpp +src/qt/pivx/lockunlock.cpp +src/qt/pivx/lockunlock.h +src/qt/pivx/lockunlock.h +src/qt/pivx/navmenuwidget.cpp +src/qt/pivx/navmenuwidget.cpp +src/qt/pivx/navmenuwidget.h +src/qt/pivx/navmenuwidget.h +src/qt/pivx/qtutils.cpp +src/qt/pivx/qtutils.cpp +src/qt/pivx/qtutils.h +src/qt/pivx/qtutils.h +src/qt/pivx/receivedialog.cpp +src/qt/pivx/receivedialog.cpp +src/qt/pivx/receivedialog.h +src/qt/pivx/receivedialog.h +src/qt/pivx/receivewidget.cpp +src/qt/pivx/receivewidget.h +src/qt/pivx/send.cpp +src/qt/pivx/settings/forms/settingsconsolewidget.ui +src/qt/pivx/topbar.cpp +src/qt/pivx/topbar.cpp +src/qt/pivx/topbar.h +src/qt/pivx/topbar.h +src/qt/pivx/txrow.cpp +src/qt/pivx/txrow.h +src/qt/pivx/txviewholder.cpp +src/qt/pivx/txviewholder.h +src/qt/pivx/walletpassworddialog.cpp +src/qt/pivx/walletpassworddialog.cpp +src/qt/pivx/walletpassworddialog.h +src/qt/pivx/walletpassworddialog.h +src/qt/pivxstrings.cpp +src/qt/pivxstrings.cpp +src/qt/platformstyle.cpp +src/qt/platformstyle.cpp +src/qt/platformstyle.h +src/qt/platformstyle.h +src/qt/privacydialog.cpp +src/qt/privacydialog.cpp +src/qt/privacydialog.h +src/qt/privacydialog.h +src/qt/proposalframe.cpp +src/qt/proposalframe.cpp +src/qt/proposalframe.h +src/qt/proposalframe.h +src/qt/qrc_pivx.cpp +src/qt/qrc_pivx.cpp +src/qt/qrc_pivx_locale.cpp +src/qt/qrc_pivx_locale.cpp +src/qt/qvalidatedlineedit.cpp +src/qt/qvalidatedlineedit.cpp +src/qt/qvalidatedlineedit.h +src/qt/qvalidatedlineedit.h +src/qt/qvaluecombobox.cpp +src/qt/qvaluecombobox.cpp +src/qt/qvaluecombobox.h +src/qt/qvaluecombobox.h +src/qt/receivecoinsdialog.cpp +src/qt/receivecoinsdialog.cpp +src/qt/receivecoinsdialog.h +src/qt/receivecoinsdialog.h +src/qt/receiverequestdialog.cpp +src/qt/receiverequestdialog.cpp +src/qt/receiverequestdialog.h +src/qt/receiverequestdialog.h +src/qt/recentrequeststablemodel.cpp +src/qt/recentrequeststablemodel.cpp +src/qt/recentrequeststablemodel.h +src/qt/recentrequeststablemodel.h +src/qt/rpcconsole.cpp +src/qt/rpcconsole.cpp +src/qt/rpcconsole.h +src/qt/rpcconsole.h +src/qt/sendcoinsdialog.cpp +src/qt/sendcoinsdialog.cpp +src/qt/sendcoinsdialog.h +src/qt/sendcoinsdialog.h +src/qt/sendcoinsentry.cpp +src/qt/sendcoinsentry.cpp +src/qt/sendcoinsentry.h +src/qt/sendcoinsentry.h +src/qt/signverifymessagedialog.cpp +src/qt/signverifymessagedialog.cpp +src/qt/signverifymessagedialog.h +src/qt/signverifymessagedialog.h +src/qt/splashscreen.cpp +src/qt/splashscreen.cpp +src/qt/splashscreen.h +src/qt/splashscreen.h +src/qt/test/moc_paymentservertests.cpp +src/qt/test/moc_paymentservertests.cpp +src/qt/test/moc_uritests.cpp +src/qt/test/moc_uritests.cpp +src/qt/test/paymentrequestdata.h +src/qt/test/paymentrequestdata.h +src/qt/test/paymentservertests.cpp +src/qt/test/paymentservertests.cpp +src/qt/test/paymentservertests.h +src/qt/test/paymentservertests.h +src/qt/test/test_main.cpp +src/qt/test/test_main.cpp +src/qt/test/uritests.cpp +src/qt/test/uritests.cpp +src/qt/test/uritests.h +src/qt/test/uritests.h +src/qt/trafficgraphwidget.cpp +src/qt/trafficgraphwidget.cpp +src/qt/trafficgraphwidget.h +src/qt/trafficgraphwidget.h +src/qt/transactiondesc.cpp +src/qt/transactiondesc.cpp +src/qt/transactiondesc.h +src/qt/transactiondesc.h +src/qt/transactiondescdialog.cpp +src/qt/transactiondescdialog.cpp +src/qt/transactiondescdialog.h +src/qt/transactiondescdialog.h +src/qt/transactionfilterproxy.cpp +src/qt/transactionfilterproxy.cpp +src/qt/transactionfilterproxy.h +src/qt/transactionfilterproxy.h +src/qt/transactionrecord.cpp +src/qt/transactionrecord.cpp +src/qt/transactionrecord.h +src/qt/transactionrecord.h +src/qt/transactiontablemodel.cpp +src/qt/transactiontablemodel.cpp +src/qt/transactiontablemodel.h +src/qt/transactiontablemodel.h +src/qt/transactionview.cpp +src/qt/transactionview.cpp +src/qt/transactionview.h +src/qt/transactionview.h +src/qt/utilitydialog.cpp +src/qt/utilitydialog.cpp +src/qt/utilitydialog.h +src/qt/utilitydialog.h +src/qt/walletframe.cpp +src/qt/walletframe.cpp +src/qt/walletframe.h +src/qt/walletframe.h +src/qt/walletmodel.cpp +src/qt/walletmodel.cpp +src/qt/walletmodel.h +src/qt/walletmodel.h +src/qt/walletmodeltransaction.cpp +src/qt/walletmodeltransaction.cpp +src/qt/walletmodeltransaction.h +src/qt/walletmodeltransaction.h +src/qt/walletview.cpp +src/qt/walletview.cpp +src/qt/walletview.h +src/qt/walletview.h +src/qt/winshutdownmonitor.cpp +src/qt/winshutdownmonitor.cpp +src/qt/winshutdownmonitor.h +src/qt/winshutdownmonitor.h +src/qt/zpivcontroldialog.cpp +src/qt/zpivcontroldialog.cpp +src/qt/zpivcontroldialog.h +src/qt/zpivcontroldialog.h +src/random.cpp +src/random.h +src/rest.cpp +src/reverse_iterate.h +src/reverselock.h +src/rpc/blockchain.cpp +src/rpc/budget.cpp +src/rpc/client.cpp +src/rpc/client.h +src/rpc/masternode.cpp +src/rpc/mining.cpp +src/rpc/misc.cpp +src/rpc/net.cpp +src/rpc/protocol.cpp +src/rpc/protocol.h +src/rpc/rawtransaction.cpp +src/rpc/server.cpp +src/rpc/server.h +src/rpcdump.cpp +src/rpcwallet.cpp +src/scheduler.cpp +src/scheduler.h +src/script/bitcoinconsensus.cpp +src/script/bitcoinconsensus.h +src/script/interpreter.cpp +src/script/interpreter.h +src/script/script.cpp +src/script/script.h +src/script/script_error.cpp +src/script/script_error.h +src/script/sigcache.cpp +src/script/sigcache.h +src/script/sign.cpp +src/script/sign.h +src/script/standard.cpp +src/script/standard.h +src/secp256k1/contrib/lax_der_parsing.c +src/secp256k1/contrib/lax_der_parsing.h +src/secp256k1/contrib/lax_der_privatekey_parsing.c +src/secp256k1/contrib/lax_der_privatekey_parsing.h +src/secp256k1/include/secp256k1.h +src/secp256k1/include/secp256k1_ecdh.h +src/secp256k1/include/secp256k1_recovery.h +src/secp256k1/src/basic-config.h +src/secp256k1/src/bench.h +src/secp256k1/src/bench_ecdh.c +src/secp256k1/src/bench_ecmult.c +src/secp256k1/src/bench_internal.c +src/secp256k1/src/bench_recover.c +src/secp256k1/src/bench_sign.c +src/secp256k1/src/bench_verify.c +src/secp256k1/src/ecdsa.h +src/secp256k1/src/ecdsa_impl.h +src/secp256k1/src/eckey.h +src/secp256k1/src/eckey_impl.h +src/secp256k1/src/ecmult.h +src/secp256k1/src/ecmult_const.h +src/secp256k1/src/ecmult_const_impl.h +src/secp256k1/src/ecmult_gen.h +src/secp256k1/src/ecmult_gen_impl.h +src/secp256k1/src/ecmult_impl.h +src/secp256k1/src/ecmult_static_context.h +src/secp256k1/src/field.h +src/secp256k1/src/field_10x26.h +src/secp256k1/src/field_10x26_impl.h +src/secp256k1/src/field_5x52.h +src/secp256k1/src/field_5x52_asm_impl.h +src/secp256k1/src/field_5x52_impl.h +src/secp256k1/src/field_5x52_int128_impl.h +src/secp256k1/src/field_impl.h +src/secp256k1/src/gen_context.c +src/secp256k1/src/group.h +src/secp256k1/src/group_impl.h +src/secp256k1/src/hash.h +src/secp256k1/src/hash_impl.h +src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c +src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h +src/secp256k1/src/java/org_bitcoin_Secp256k1Context.c +src/secp256k1/src/java/org_bitcoin_Secp256k1Context.h +src/secp256k1/src/libsecp256k1-config.h +src/secp256k1/src/modules/ecdh/main_impl.h +src/secp256k1/src/modules/ecdh/tests_impl.h +src/secp256k1/src/modules/recovery/main_impl.h +src/secp256k1/src/modules/recovery/tests_impl.h +src/secp256k1/src/num.h +src/secp256k1/src/num_gmp.h +src/secp256k1/src/num_gmp_impl.h +src/secp256k1/src/num_impl.h +src/secp256k1/src/scalar.h +src/secp256k1/src/scalar_4x64.h +src/secp256k1/src/scalar_4x64_impl.h +src/secp256k1/src/scalar_8x32.h +src/secp256k1/src/scalar_8x32_impl.h +src/secp256k1/src/scalar_impl.h +src/secp256k1/src/scalar_low.h +src/secp256k1/src/scalar_low_impl.h +src/secp256k1/src/scratch.h +src/secp256k1/src/scratch_impl.h +src/secp256k1/src/secp256k1.c +src/secp256k1/src/testrand.h +src/secp256k1/src/testrand_impl.h +src/secp256k1/src/tests.c +src/secp256k1/src/tests_exhaustive.c +src/secp256k1/src/util.h +src/serialize.h +src/spork.cpp +src/spork.h +src/sporkdb.cpp +src/sporkdb.h +src/stakeinput.cpp +src/stakeinput.h +src/streams.h +src/support/cleanse.cpp +src/support/cleanse.h +src/swifttx.cpp +src/swifttx.h +src/sync.cpp +src/sync.h +src/test/Checkpoints_tests.cpp +src/test/DoS_tests.cpp +src/test/accounting_tests.cpp +src/test/alert_tests.cpp +src/test/allocator_tests.cpp +src/test/arith_uint256_tests.cpp +src/test/base32_tests.cpp +src/test/base58_tests.cpp +src/test/base64_tests.cpp +src/test/benchmark_zerocoin.cpp +src/test/bip32_tests.cpp +src/test/bloom_tests.cpp +src/test/budget_tests.cpp +src/test/checkblock_tests.cpp +src/test/coins_tests.cpp +src/test/compress_tests.cpp +src/test/crypto_tests.cpp +src/test/data/alertTests.raw.h +src/test/data/base58_encode_decode.json.h +src/test/data/base58_keys_invalid.json.h +src/test/data/base58_keys_valid.json.h +src/test/data/script_invalid.json.h +src/test/data/script_valid.json.h +src/test/data/sig_canonical.json.h +src/test/data/sig_noncanonical.json.h +src/test/data/sighash.json.h +src/test/data/tx_invalid.json.h +src/test/data/tx_valid.json.h +src/test/getarg_tests.cpp +src/test/hash_tests.cpp +src/test/key_tests.cpp +src/test/libzerocoin_tests.cpp +src/test/main_tests.cpp +src/test/mempool_tests.cpp +src/test/miner_tests.cpp +src/test/mruset_tests.cpp +src/test/multisig_tests.cpp +src/test/netbase_tests.cpp +src/test/pmt_tests.cpp +src/test/reverselock_tests.cpp +src/test/rpc_tests.cpp +src/test/rpc_wallet_tests.cpp +src/test/sanity_tests.cpp +src/test/scheduler_tests.cpp +src/test/script_P2SH_tests.cpp +src/test/script_tests.cpp +src/test/scriptnum_tests.cpp +src/test/serialize_tests.cpp +src/test/sighash_tests.cpp +src/test/sigopcount_tests.cpp +src/test/skiplist_tests.cpp +src/test/test_pivx.cpp +src/test/test_zerocoin.cpp +src/test/timedata_tests.cpp +src/test/torcontrol_tests.cpp +src/test/transaction_tests.cpp +src/test/tutorial_zerocoin.cpp +src/test/uint256_tests.cpp +src/test/univalue_tests.cpp +src/test/util_tests.cpp +src/test/wallet_tests.cpp +src/test/zerocoin_coinspend_tests.cpp +src/test/zerocoin_denomination_tests.cpp +src/test/zerocoin_implementation_tests.cpp +src/test/zerocoin_transactions_tests.cpp +src/threadsafety.h +src/timedata.cpp +src/timedata.h +src/tinyformat.h +src/torcontrol.cpp +src/torcontrol.h +src/txdb.cpp +src/txdb.h +src/txmempool.cpp +src/txmempool.h +src/ui_interface.h +src/uint256.cpp +src/uint256.h +src/uint512.h +src/undo.h +src/univalue/gen/gen.cpp +src/univalue/include/univalue.h +src/univalue/lib/univalue.cpp +src/univalue/lib/univalue_escapes.h +src/univalue/lib/univalue_read.cpp +src/univalue/lib/univalue_utffilter.h +src/univalue/lib/univalue_write.cpp +src/univalue/test/no_nul.cpp +src/univalue/test/object.cpp +src/univalue/test/test_json.cpp +src/univalue/test/unitester.cpp +src/univalue/univalue-config.h +src/util.cpp +src/util.h +src/utilmoneystr.cpp +src/utilmoneystr.h +src/utilstrencodings.cpp +src/utilstrencodings.h +src/utiltime.cpp +src/utiltime.h +src/validationinterface.cpp +src/validationinterface.h +src/version.h +src/wallet.cpp +src/wallet.h +src/wallet_ismine.cpp +src/wallet_ismine.h +src/walletdb.cpp +src/walletdb.h +src/zmq/zmqabstractnotifier.cpp +src/zmq/zmqabstractnotifier.h +src/zmq/zmqconfig.h +src/zmq/zmqnotificationinterface.cpp +src/zmq/zmqnotificationinterface.h +src/zmq/zmqpublishnotifier.cpp +src/zmq/zmqpublishnotifier.h +src/zpivchain.cpp +src/zpivchain.h +src/zpivtracker.cpp +src/zpivtracker.h +src/zpivwallet.cpp +src/zpivwallet.h diff --git a/pivxd-new-gui.includes b/pivxd-new-gui.includes new file mode 100644 index 000000000000..b34ade118290 --- /dev/null +++ b/pivxd-new-gui.includes @@ -0,0 +1,34 @@ +src +src/compat +src/config +src/crypto +src/leveldb/db +src/leveldb/helpers/memenv +src/leveldb/include/leveldb +src/leveldb/port +src/leveldb/port/win +src/leveldb/table +src/leveldb/util +src/libzerocoin +src/obj +src/primitives +src/qt +src/qt/forms +src/qt/test +src/rpc +src/script +src/secp256k1/contrib +src/secp256k1/include +src/secp256k1/src +src/secp256k1/src/java +src/secp256k1/src/modules/ecdh +src/secp256k1/src/modules/recovery +src/support +src/test/data +src/univalue +src/univalue/include +src/univalue/lib +src/zmq +src/qt/pivx +src/qt/pivx/forms +src/qt/pivx/settings/forms diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include old mode 100755 new mode 100644 index 7867269eb159..4be9ff05bcc4 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -65,7 +65,56 @@ QT_FORMS_UI = \ qt/forms/sendcoinsentry.ui \ qt/forms/signverifymessagedialog.ui \ qt/forms/transactiondescdialog.ui \ - qt/forms/zpivcontroldialog.ui + qt/pivx/forms/loadingdialog.ui \ + qt/forms/zpivcontroldialog.ui \ + qt/pivx/forms/snackbar.ui \ + qt/pivx/forms/navmenuwidget.ui \ + qt/pivx/forms/lockunlock.ui \ + qt/pivx/forms/expandablebutton.ui \ + qt/pivx/forms/receivedialog.ui \ + qt/pivx/forms/walletpassworddialog.ui \ + qt/pivx/forms/topbar.ui \ + qt/pivx/forms/txrow.ui \ + qt/pivx/forms/dashboardwidget.ui \ + qt/pivx/forms/coincontrolpivwidget.ui \ + qt/pivx/forms/addresslabelrow.ui \ + qt/pivx/forms/contactdropdownrow.ui \ + qt/pivx/forms/mninfodialog.ui \ + qt/pivx/forms/optionbutton.ui \ + qt/pivx/forms/masternodewizarddialog.ui \ + qt/pivx/forms/mnrow.ui \ + qt/pivx/forms/masternodeswidget.ui \ + qt/pivx/forms/myaddressrow.ui \ + qt/pivx/forms/sendchangeaddressdialog.ui \ + qt/pivx/forms/sendconfirmdialog.ui \ + qt/pivx/forms/sendcustomfeedialog.ui \ + qt/pivx/forms/sendchangeaddressdialog.ui \ + qt/pivx/forms/sendmultirow.ui \ + qt/pivx/forms/send.ui \ + qt/pivx/forms/addnewaddressdialog.ui \ + qt/pivx/forms/addnewcontactdialog.ui \ + qt/pivx/forms/requestdialog.ui \ + qt/pivx/forms/receivewidget.ui \ + qt/pivx/forms/tooltipmenu.ui \ + qt/pivx/forms/addresseswidget.ui \ + qt/pivx/forms/defaultdialog.ui \ + qt/pivx/forms/denomgenerationdialog.ui \ + qt/pivx/forms/privacywidget.ui \ + qt/pivx/settings/forms/settingsbackupwallet.ui \ + qt/pivx/settings/forms/settingsbittoolwidget.ui \ + qt/pivx/settings/forms/settingsconsolewidget.ui \ + qt/pivx/settings/forms/settingsdisplayoptionswidget.ui \ + qt/pivx/settings/forms/settingsfaqwidget.ui \ + qt/pivx/settings/forms/settingsinformationwidget.ui \ + qt/pivx/settings/forms/settingsmainoptionswidget.ui \ + qt/pivx/settings/forms/settingsmultisenddialog.ui \ + qt/pivx/settings/forms/settingsmultisendwidget.ui \ + qt/pivx/settings/forms/settingssignmessagewidgets.ui \ + qt/pivx/settings/forms/settingswalletoptionswidget.ui \ + qt/pivx/settings/forms/settingswalletrepairwidget.ui \ + qt/pivx/settings/forms/settingswidget.ui \ + qt/pivx/forms/welcomecontentwidget.ui \ + qt/pivx/forms/splash.ui QT_MOC_CPP = \ qt/moc_addressbookpage.cpp \ @@ -76,6 +125,7 @@ QT_MOC_CPP = \ qt/moc_bitcoinaddressvalidator.cpp \ qt/moc_bitcoinamountfield.cpp \ qt/moc_bitcoingui.cpp \ + qt/pivx/moc_pivxgui.cpp \ qt/moc_bitcoinunits.cpp \ qt/moc_blockexplorer.cpp \ qt/moc_clientmodel.cpp \ @@ -120,7 +170,60 @@ QT_MOC_CPP = \ qt/moc_walletframe.cpp \ qt/moc_walletmodel.cpp \ qt/moc_walletview.cpp \ - qt/moc_zpivcontroldialog.cpp + qt/pivx/moc_loadingdialog.cpp \ + qt/moc_zpivcontroldialog.cpp \ + qt/pivx/moc_pwidget.cpp \ + qt/pivx/moc_snackbar.cpp \ + qt/pivx/moc_navmenuwidget.cpp \ + qt/pivx/moc_lockunlock.cpp \ + qt/pivx/moc_expandablebutton.cpp \ + qt/pivx/moc_furabstractlistitemdelegate.cpp \ + qt/pivx/moc_receivedialog.cpp \ + qt/pivx/moc_walletpassworddialog.cpp \ + qt/pivx/moc_topbar.cpp \ + qt/pivx/moc_txrow.cpp \ + qt/pivx/moc_dashboardwidget.cpp \ + qt/pivx/moc_coincontrolpivwidget.cpp \ + qt/pivx/moc_addresslabelrow.cpp \ + qt/pivx/moc_contactdropdownrow.cpp \ + qt/pivx/moc_mninfodialog.cpp \ + qt/pivx/moc_optionbutton.cpp \ + qt/pivx/moc_mnmodel.cpp \ + qt/pivx/moc_masternodewizarddialog.cpp \ + qt/pivx/moc_mnrow.cpp \ + qt/pivx/moc_masternodeswidget.cpp \ + qt/pivx/moc_myaddressrow.cpp \ + qt/pivx/moc_contactsdropdown.cpp \ + qt/pivx/moc_sendchangeaddressdialog.cpp \ + qt/pivx/moc_sendconfirmdialog.cpp \ + qt/pivx/moc_sendcustomfeedialog.cpp \ + qt/pivx/moc_sendchangeaddressdialog.cpp \ + qt/pivx/moc_sendmultirow.cpp \ + qt/pivx/moc_send.cpp \ + qt/pivx/moc_addnewaddressdialog.cpp \ + qt/pivx/moc_addnewcontactdialog.cpp \ + qt/pivx/moc_requestdialog.cpp \ + qt/pivx/moc_receivewidget.cpp \ + qt/pivx/moc_tooltipmenu.cpp \ + qt/pivx/moc_addresseswidget.cpp \ + qt/pivx/moc_defaultdialog.cpp \ + qt/pivx/moc_denomgenerationdialog.cpp \ + qt/pivx/moc_privacywidget.cpp \ + qt/pivx/settings/moc_settingsbackupwallet.cpp \ + qt/pivx/settings/moc_settingsbittoolwidget.cpp \ + qt/pivx/settings/moc_settingsconsolewidget.cpp \ + qt/pivx/settings/moc_settingsdisplayoptionswidget.cpp \ + qt/pivx/settings/moc_settingsfaqwidget.cpp \ + qt/pivx/settings/moc_settingsinformationwidget.cpp \ + qt/pivx/settings/moc_settingsmainoptionswidget.cpp \ + qt/pivx/settings/moc_settingsmultisenddialog.cpp \ + qt/pivx/settings/moc_settingsmultisendwidget.cpp \ + qt/pivx/settings/moc_settingssignmessagewidgets.cpp \ + qt/pivx/settings/moc_settingswalletoptionswidget.cpp \ + qt/pivx/settings/moc_settingswalletrepairwidget.cpp \ + qt/pivx/settings/moc_settingswidget.cpp \ + qt/pivx/moc_welcomecontentwidget.cpp \ + qt/pivx/moc_splash.cpp BITCOIN_MM = \ qt/macdockiconhandler.mm \ @@ -151,6 +254,7 @@ BITCOIN_QT_H = \ qt/bitcoinaddressvalidator.h \ qt/bitcoinamountfield.h \ qt/bitcoingui.h \ + qt/pivx/pivxgui.h \ qt/bitcoinunits.h \ qt/blockexplorer.h \ qt/clientmodel.h \ @@ -200,9 +304,67 @@ BITCOIN_QT_H = \ qt/walletframe.h \ qt/walletmodel.h \ qt/walletmodeltransaction.h \ + qt/pivx/prunnable.h \ + qt/pivx/loadingdialog.h \ qt/walletview.h \ qt/winshutdownmonitor.h \ - qt/zpivcontroldialog.h + qt/zpivcontroldialog.h \ + qt/pivx/pwidget.h \ + qt/pivx/snackbar.h \ + qt/pivx/navmenuwidget.h \ + qt/pivx/lockunlock.h \ + qt/pivx/receivedialog.h \ + qt/pivx/furlistrow.h \ + qt/pivx/furabstractlistitemdelegate.h \ + qt/pivx/txviewholder.h \ + qt/pivx/qtutils.h \ + qt/pivx/expandablebutton.h \ + qt/pivx/walletpassworddialog.h \ + qt/pivx/topbar.h \ + qt/pivx/txrow.h \ + qt/pivx/addressfilterproxymodel.h \ + qt/pivx/dashboardwidget.h \ + qt/pivx/coincontrolpivwidget.h \ + qt/pivx/addresslabelrow.h \ + qt/pivx/contactdropdownrow.h \ + qt/pivx/mninfodialog.h \ + qt/pivx/optionbutton.h \ + qt/pivx/mnmodel.h \ + qt/pivx/masternodewizarddialog.h \ + qt/pivx/mnrow.h \ + qt/pivx/masternodeswidget.h \ + qt/pivx/myaddressrow.h \ + qt/pivx/contactsdropdown.h \ + qt/pivx/sendchangeaddressdialog.h \ + qt/pivx/sendconfirmdialog.h \ + qt/pivx/sendcustomfeedialog.h \ + qt/pivx/sendchangeaddressdialog.h \ + qt/pivx/sendmultirow.h \ + qt/pivx/send.h \ + qt/pivx/addnewaddressdialog.h \ + qt/pivx/addnewcontactdialog.h \ + qt/pivx/requestdialog.h \ + qt/pivx/receivewidget.h \ + qt/pivx/tooltipmenu.h \ + qt/pivx/addresseswidget.h \ + qt/pivx/defaultdialog.h \ + qt/pivx/denomgenerationdialog.h \ + qt/pivx/privacywidget.h \ + qt/pivx/settings/settingsbackupwallet.h \ + qt/pivx/settings/settingsbittoolwidget.h \ + qt/pivx/settings/settingsconsolewidget.h \ + qt/pivx/settings/settingsdisplayoptionswidget.h \ + qt/pivx/settings/settingsfaqwidget.h \ + qt/pivx/settings/settingsinformationwidget.h \ + qt/pivx/settings/settingsmainoptionswidget.h \ + qt/pivx/settings/settingsmultisenddialog.h \ + qt/pivx/settings/settingsmultisendwidget.h \ + qt/pivx/settings/settingssignmessagewidgets.h \ + qt/pivx/settings/settingswalletoptionswidget.h \ + qt/pivx/settings/settingswalletrepairwidget.h \ + qt/pivx/settings/settingswidget.h \ + qt/pivx/welcomecontentwidget.h \ + qt/pivx/splash.h RES_ICONS = \ qt/res/icons/add.png \ @@ -264,6 +426,10 @@ RES_ICONS = \ qt/res/icons/tx_input.png \ qt/res/icons/tx_output.png \ qt/res/icons/tx_mined.png \ + qt/res/icons/ic-transaction-received.svg \ + qt/res/icons/ic-transaction-mint.svg \ + qt/res/icons/ic-transaction-sent.svg \ + qt/res/icons/ic-transaction-staked.svg \ qt/res/icons/unit_pivx.png \ qt/res/icons/unit_mpivx.png \ qt/res/icons/unit_upivx.png \ @@ -272,13 +438,202 @@ RES_ICONS = \ qt/res/icons/unit_tupivx.png \ qt/res/icons/yesvote.png \ qt/res/icons/novote.png \ - qt/res/icons/abstainvote.png + qt/res/icons/abstainvote.png \ + qt/pivx/res/img/bg-dashboard-banner.png \ + qt/pivx/res/img/bg-multi-number-dark.svg \ + qt/pivx/res/img/ic-check-locked.svg \ + qt/pivx/res/img/ic-nav-address.svg \ + qt/pivx/res/img/ic-update.svg \ + qt/pivx/res/img/bg-multi-number.svg \ + qt/pivx/res/img/ic-check-mint-off.svg \ + qt/pivx/res/img/ic-nav-dashboard-active.svg \ + qt/pivx/res/img/ic-wallet-status-locked.svg \ + qt/pivx/res/img/bg-splash.svg \ + qt/pivx/res/img/bg-splash.png \ + qt/pivx/res/img/ic-check-mint.svg \ + qt/pivx/res/img/ic-nav-dashboard-hover.svg \ + qt/pivx/res/img/ic-wallet-status-staking.svg \ + qt/pivx/res/img/ic-check-peers-off.svg \ + qt/pivx/res/img/ic-nav-dashboard.svg \ + qt/pivx/res/img/ic-wallet-status-unlocked.svg \ + qt/pivx/res/img/ic-check-peers.svg \ + qt/pivx/res/img/ic-nav-master-active.svg \ + qt/pivx/res/img/ic-watch-password-white.svg \ + qt/pivx/res/img/bg-welcome-container.jpg \ + qt/pivx/res/img/bg-welcome-container.png \ + qt/pivx/res/img/bg-welcome-container.svg \ + qt/pivx/res/img/bg-welcome-container@2x.png \ + qt/pivx/res/img/bg-welcome-container@3x.png \ + qt/pivx/res/img/ic-check-staking-off.svg \ + qt/pivx/res/img/ic-nav-master-hover.svg \ + qt/pivx/res/img/ic-watch-password.svg \ + qt/pivx/res/img/bg-welcome.jpg \ + qt/pivx/res/img/bg-welcome.svg \ + qt/pivx/res/img/bg-welcome@2x.jpg \ + qt/pivx/res/img/bg-welcome@3x.jpg \ + qt/pivx/res/img/bg-welcome.png \ + qt/pivx/res/img/ic-check-staking.svg \ + qt/pivx/res/img/ic-nav-master.svg \ + qt/pivx/res/img/img-dashboard-banner.jpg \ + qt/pivx/res/img/btn-radio-active.svg \ + qt/pivx/res/img/ic-check-sync-off.svg \ + qt/pivx/res/img/ic-nav-privacy-active.svg \ + qt/pivx/res/img/img-empty-contacts.svg \ + qt/pivx/res/img/btn-radio-off.svg \ + qt/pivx/res/img/ic-check-sync.png \ + qt/pivx/res/img/ic-nav-privacy-hover.svg \ + qt/pivx/res/img/img-empty-dark-contacts.svg \ + qt/pivx/res/img/ic-contact-arrow-down.svg \ + qt/pivx/res/img/ic-contact-arrow-down-white.svg \ + qt/pivx/res/img/ic-check-sync.svg \ + qt/pivx/res/img/ic-check-faq.svg \ + qt/pivx/res/img/ic-nav-privacy.svg \ + qt/pivx/res/img/img-empty-dark-error.svg \ + qt/pivx/res/img/ic-add-label.svg \ + qt/pivx/res/img/ic-pending.svg \ + qt/pivx/res/img/ic-check-theme-dark.svg \ + qt/pivx/res/img/ic-nav-receive-active.svg \ + qt/pivx/res/img/img-empty-dark-masternode.svg \ + qt/pivx/res/img/ic-add-liliac.svg \ + qt/pivx/res/img/ic-check-theme-light.svg \ + qt/pivx/res/img/ic-nav-receive-hover.svg \ + qt/pivx/res/img/img-empty-dark-multisend.svg \ + qt/pivx/res/img/ic-add-purple.svg \ + qt/pivx/res/img/ic-check-white.svg \ + qt/pivx/res/img/ic-nav-receive.svg \ + qt/pivx/res/img/img-empty-dark-peers.svg \ + qt/pivx/res/img/ic-add.svg \ + qt/pivx/res/img/ic-check.svg \ + qt/pivx/res/img/ic-nav-send-active.svg \ + qt/pivx/res/img/img-empty-dark-staking-off.svg \ + qt/pivx/res/img/img-empty-dark-staking-on.svg \ + qt/pivx/res/img/ic-address-book-grey.svg \ + qt/pivx/res/img/ic-chevron-left.svg \ + qt/pivx/res/img/ic-nav-send-hover.svg \ + qt/pivx/res/img/img-empty-dark-transactions.svg \ + qt/pivx/res/img/ic-address-book-white.svg \ + qt/pivx/res/img/ic-chevron-right.svg \ + qt/pivx/res/img/ic-nav-send.svg \ + qt/pivx/res/img/img-empty-error.svg \ + qt/pivx/res/img/ic-address-book.svg \ + qt/pivx/res/img/ic-clear-liliac.svg \ + qt/pivx/res/img/ic-nav-settings-active.svg \ + qt/pivx/res/img/img-empty-masternode.svg \ + qt/pivx/res/img/ic-address-send-white.svg \ + qt/pivx/res/img/ic-clear-purple.svg \ + qt/pivx/res/img/ic-nav-settings-hover.svg \ + qt/pivx/res/img/img-empty-multisend.svg \ + qt/pivx/res/img/ic-address-send.svg \ + qt/pivx/res/img/ic-close-white.svg \ + qt/pivx/res/img/ic-nav-settings.svg \ + qt/pivx/res/img/img-empty-peers.svg \ + qt/pivx/res/img/img-empty-privacy.svg \ + qt/pivx/res/img/img-empty-privacy-dark.svg \ + qt/pivx/res/img/ic-arrow-drop-down-white.svg \ + qt/pivx/res/img/ic-close.svg \ + qt/pivx/res/img/ic-radio-liliac-on.svg \ + qt/pivx/res/img/img-empty-staking-off.svg \ + qt/pivx/res/img/ic-arrow-drop-down.svg \ + qt/pivx/res/img/ic-coin-piv.svg \ + qt/pivx/res/img/ic-receive-off.svg \ + qt/pivx/res/img/img-empty-staking-on.svg \ + qt/pivx/res/img/ic-arrow-drop-up-white.svg \ + qt/pivx/res/img/ic-coin-zpiv.png \ + qt/pivx/res/img/ic-receive-on.svg \ + qt/pivx/res/img/img-empty-transactions.svg \ + qt/pivx/res/img/ic-arrow-drop-up.svg \ + qt/pivx/res/img/ic-coin-zpiv.svg \ + qt/pivx/res/img/ic-received.svg \ + qt/pivx/res/img/img-logo-pivx.png \ + qt/pivx/res/img/ic-arrow-drop-white-down.svg \ + qt/pivx/res/img/ic-combo-box.svg \ + qt/pivx/res/img/ic-send.svg \ + qt/pivx/res/img/img-logo-pivx@2x.png \ + qt/pivx/res/img/ic-arrow-purple-down.svg \ + qt/pivx/res/img/ic-connect.svg \ + qt/pivx/res/img/ic-submenu-lock.svg \ + qt/pivx/res/img/img-logo-pivx@3x.png \ + qt/pivx/res/img/img-logo-pivx.svg \ + qt/pivx/res/img/ic-arrow-right-white.svg \ + qt/pivx/res/img/ic-arrow-left-white.svg \ + qt/pivx/res/img/ic-arrow-left.svg \ + qt/pivx/res/img/ic-copy-liliac.svg \ + qt/pivx/res/img/ic-submenu-staking.svg \ + qt/pivx/res/img/img-nav-logo-pivx.png \ + qt/pivx/res/img/ic-arrow-right.svg \ + qt/pivx/res/img/ic-copy.svg \ + qt/pivx/res/img/ic-copy-big.svg \ + qt/pivx/res/img/ic-copy-big-white.svg \ + qt/pivx/res/img/ic-submenu-unlock.svg \ + qt/pivx/res/img/img-nav-logo.png \ + qt/pivx/res/img/ic-arrow-white-left.svg \ + qt/pivx/res/img/ic-exit.svg \ + qt/pivx/res/img/ic-switch-liliac-on.svg \ + qt/pivx/res/img/img-nav-logo.svg \ + qt/pivx/res/img/ic-arrow-white-right.svg \ + qt/pivx/res/img/ic-expand.svg \ + qt/pivx/res/img/ic-switch-off.svg \ + qt/pivx/res/img/img-qr-test-big.png \ + qt/pivx/res/img/ic-check-active.svg \ + qt/pivx/res/img/ic-folder.svg \ + qt/pivx/res/img/ic-switch-on.svg \ + qt/pivx/res/img/img-qr-test.png \ + qt/pivx/res/img/ic-check-box.svg \ + qt/pivx/res/img/ic-check-box-dark-active.svg \ + qt/pivx/res/img/ic-check-box-indeterminate.svg \ + qt/pivx/res/img/ic-check-box-liliac-indeterminate.svg \ + qt/pivx/res/img/ic-label-liliac.svg \ + qt/pivx/res/img/ic-transaction-warning.svg \ + qt/pivx/res/img/ic-transaction-mint.svg \ + qt/pivx/res/img/ic-transaction-mint-inactive.svg \ + qt/pivx/res/img/img-qr.svg \ + qt/pivx/res/img/ic-check-connect-off.svg \ + qt/pivx/res/img/ic-label.svg \ + qt/pivx/res/img/ic-transaction-received.svg \ + qt/pivx/res/img/dark/ic-transaction-received.svg \ + qt/pivx/res/img/dark/ic-transaction-warning.svg \ + qt/pivx/res/img/dark/ic-transaction-mint.svg \ + qt/pivx/res/img/dark/ic-transaction-mint-inactive.svg \ + qt/pivx/res/img/ic-transaction-received-inactive.svg \ + qt/pivx/res/img/dark/ic-transaction-received-inactive.svg \ + qt/pivx/res/img/img-welcome-step1.png \ + qt/pivx/res/img/ic-check-connect.svg \ + qt/pivx/res/img/ic-menu-hover.svg \ + qt/pivx/res/img/ic-transaction-sent.svg \ + qt/pivx/res/img/ic-transaction-sent-inactive.svg \ + qt/pivx/res/img/dark/ic-transaction-sent.svg \ + qt/pivx/res/img/dark/ic-transaction-sent-inactive.svg \ + qt/pivx/res/img/img-welcome-step2.png \ + qt/pivx/res/img/ic-check-dark.svg \ + qt/pivx/res/img/ic-mint.svg \ + qt/pivx/res/img/ic-transaction-staked.svg \ + qt/pivx/res/img/ic-transaction-staked-inactive.svg \ + qt/pivx/res/img/dark/ic-transaction-staked.svg \ + qt/pivx/res/img/dark/ic-transaction-staked-inactive.svg \ + qt/pivx/res/img/img-welcome-step3.png \ + qt/pivx/res/img/ic-check-liliac-on.svg \ + qt/pivx/res/img/ic-nav-address-active.svg \ + qt/pivx/res/img/ic-unlock-staking.svg \ + qt/pivx/res/img/img-welcome-step4.png \ + qt/pivx/res/img/ic-check-locked-off.svg \ + qt/pivx/res/img/ic-nav-address-hover.svg \ + qt/pivx/res/img/ic-update-liliac.svg \ + qt/pivx/res/img/ic-arrow-drop-down-purple.svg \ + qt/pivx/res/img/ic-arrow-drop-up-purple.svg \ + qt/pivx/res/img/ic-check-liliac-indeterminate.svg \ + qt/pivx/res/img/ic-check-box-liliac-indeterminate.svg \ + qt/pivx/res/img/ic-check-box-indeterminate.svg \ + qt/pivx/res/img/ani-loading-dark.gif \ + qt/pivx/res/img/ani-loading.gif + + BITCOIN_QT_BASE_CPP = \ qt/bantablemodel.cpp \ qt/bitcoinaddressvalidator.cpp \ qt/bitcoinamountfield.cpp \ qt/bitcoingui.cpp \ + qt/pivx/pivxgui.cpp \ qt/bitcoinunits.cpp \ qt/blockexplorer.cpp \ qt/clientmodel.cpp \ @@ -336,7 +691,64 @@ BITCOIN_QT_WALLET_CPP = \ qt/walletmodel.cpp \ qt/walletmodeltransaction.cpp \ qt/walletview.cpp \ - qt/zpivcontroldialog.cpp + qt/pivx/loadingdialog.cpp \ + qt/zpivcontroldialog.cpp \ + qt/pivx/pwidget.cpp \ + qt/pivx/snackbar.cpp \ + qt/pivx/navmenuwidget.cpp \ + qt/pivx/lockunlock.cpp \ + qt/pivx/receivedialog.cpp \ + qt/pivx/furabstractlistitemdelegate.cpp \ + qt/pivx/txviewholder.cpp \ + qt/pivx/qtutils.cpp \ + qt/pivx/expandablebutton.cpp \ + qt/pivx/walletpassworddialog.cpp \ + qt/pivx/topbar.cpp \ + qt/pivx/txrow.cpp \ + qt/pivx/addressfilterproxymodel.cpp \ + qt/pivx/dashboardwidget.cpp \ + qt/pivx/coincontrolpivwidget.cpp \ + qt/pivx/addresslabelrow.cpp \ + qt/pivx/contactdropdownrow.cpp \ + qt/pivx/contactsdropdown.cpp \ + qt/pivx/optionbutton.cpp \ + qt/pivx/mninfodialog.cpp \ + qt/pivx/mnmodel.cpp \ + qt/pivx/masternodewizarddialog.cpp \ + qt/pivx/mnrow.cpp \ + qt/pivx/masternodeswidget.cpp \ + qt/pivx/myaddressrow.cpp \ + qt/pivx/sendchangeaddressdialog.cpp \ + qt/pivx/sendconfirmdialog.cpp \ + qt/pivx/sendcustomfeedialog.cpp \ + qt/pivx/sendchangeaddressdialog.cpp \ + qt/pivx/sendmultirow.cpp \ + qt/pivx/send.cpp \ + qt/pivx/addnewaddressdialog.cpp \ + qt/pivx/addnewcontactdialog.cpp \ + qt/pivx/requestdialog.cpp \ + qt/pivx/receivewidget.cpp \ + qt/pivx/tooltipmenu.cpp \ + qt/pivx/addresseswidget.cpp \ + qt/pivx/defaultdialog.cpp \ + qt/pivx/denomgenerationdialog.cpp \ + qt/pivx/privacywidget.cpp \ + qt/pivx/settings/settingsbackupwallet.cpp \ + qt/pivx/settings/settingsbittoolwidget.cpp \ + qt/pivx/settings/settingsconsolewidget.cpp \ + qt/pivx/settings/settingsdisplayoptionswidget.cpp \ + qt/pivx/settings/settingsfaqwidget.cpp \ + qt/pivx/settings/settingsinformationwidget.cpp \ + qt/pivx/settings/settingsmainoptionswidget.cpp \ + qt/pivx/settings/settingsmultisenddialog.cpp \ + qt/pivx/settings/settingsmultisendwidget.cpp \ + qt/pivx/settings/settingssignmessagewidgets.cpp \ + qt/pivx/settings/settingswalletoptionswidget.cpp \ + qt/pivx/settings/settingswalletrepairwidget.cpp \ + qt/pivx/settings/settingswidget.cpp \ + qt/pivx/welcomecontentwidget.cpp \ + qt/pivx/splash.cpp + BITCOIN_QT_CPP = $(BITCOIN_QT_BASE_CPP) if TARGET_WINDOWS @@ -362,7 +774,9 @@ RES_IMAGES = \ qt/res/images/qtreeview_selected.png RES_CSS = \ - qt/res/css/default.css + qt/res/css/default.css \ + qt/pivx/res/css/style_dark.css \ + qt/pivx/res/css/style_light.css RES_MOVIES = $(wildcard $(srcdir)/qt/res/movies/spinner-*.png) @@ -372,7 +786,7 @@ BITCOIN_QT_INCLUDES = -I$(builddir)/qt -I$(srcdir)/qt -I$(srcdir)/qt/forms \ -I$(builddir)/qt/forms qt_libbitcoinqt_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ - $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) + $(QT_INCLUDES) $(QT_DBUS_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) $(SVG_CFLAGS) $(CHARTS_CFLAGS) qt_libbitcoinqt_a_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS) @@ -397,7 +811,7 @@ $(QT_MOC_CPP): $(PROTOBUF_H) # pivx-qt binary # qt_pivx_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDES) \ - $(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) + $(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS) $(SVG_CFLAGS) $(CHARTS_CFLAGS) qt_pivx_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS) qt_pivx_qt_SOURCES = qt/pivx.cpp @@ -415,7 +829,7 @@ if ENABLE_ZMQ qt_pivx_qt_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) endif qt_pivx_qt_LDADD += $(LIBBITCOIN_CLI) $(LIBBITCOIN_COMMON) $(LIBBITCOIN_UTIL) $(LIBBITCOIN_CRYPTO) $(LIBUNIVALUE) $(LIBBITCOIN_ZEROCOIN) $(LIBLEVELDB) $(LIBLEVELDB_SSE42) $(LIBMEMENV) \ - $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ + $(BOOST_LIBS) $(QT_LIBS) $(QT_DBUS_LIBS) $(QR_LIBS) $(PROTOBUF_LIBS) $(SVG_LIBS) $(CHARTS_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(LIBSECP256K1) \ $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS) qt_pivx_qt_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(QT_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) qt_pivx_qt_LIBTOOLFLAGS = $(AM_LIBTOOLFLAGS) --tag CXX diff --git a/src/clientversion.cpp b/src/clientversion.cpp index 8b407def3cfd..e90f02546450 100644 --- a/src/clientversion.cpp +++ b/src/clientversion.cpp @@ -91,6 +91,11 @@ std::string FormatFullVersion() return CLIENT_BUILD; } +std::string FormatVersionFriendly() +{ + return FormatVersion(CLIENT_VERSION); +} + /** * Format the subversion field according to BIP 14 spec (https://github.com/bitcoin/bips/blob/master/bip-0014.mediawiki) */ diff --git a/src/clientversion.h b/src/clientversion.h index ec857702c644..ff4bde40bab2 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -50,6 +50,9 @@ extern const std::string CLIENT_DATE; std::string FormatFullVersion(); std::string FormatSubVersion(const std::string& name, int nClientVersion, const std::vector& comments); +// Returns a friendly formatted version string to show in the UI +std::string FormatVersionFriendly(); + #endif // WINDRES_PREPROC #endif // BITCOIN_CLIENTVERSION_H diff --git a/src/coincontrol.h b/src/coincontrol.h index 0e9ffdfca8b5..9fc26ba57987 100644 --- a/src/coincontrol.h +++ b/src/coincontrol.h @@ -14,7 +14,7 @@ class CCoinControl { public: - CTxDestination destChange; + CTxDestination destChange = CNoDestination(); bool useObfuScation; bool useSwiftTX; bool fSplitBlock; diff --git a/src/guiinterface.h b/src/guiinterface.h index 69167386b84c..c5a6a2abbeb2 100644 --- a/src/guiinterface.h +++ b/src/guiinterface.h @@ -73,7 +73,8 @@ class CClientUIInterface /** Predefined combinations for certain default usage cases */ MSG_INFORMATION = ICON_INFORMATION, MSG_WARNING = (ICON_WARNING | BTN_OK | MODAL), - MSG_ERROR = (ICON_ERROR | BTN_OK | MODAL) + MSG_ERROR = (ICON_ERROR | BTN_OK | MODAL), + MSG_INFORMATION_SNACK = 1U << 2 }; /** Show message box. */ diff --git a/src/masternode.cpp b/src/masternode.cpp index 984d93d2d37e..1bec0db3e984 100644 --- a/src/masternode.cpp +++ b/src/masternode.cpp @@ -316,6 +316,8 @@ std::string CMasternode::GetStatus() return "WATCHDOG_EXPIRED"; case CMasternode::MASTERNODE_POSE_BAN: return "POSE_BAN"; + case CMasternode::MASTERNODE_MISSING: + return "MISSING"; default: return "UNKNOWN"; } diff --git a/src/masternode.h b/src/masternode.h index b5acbd05b036..3c08a4b0c801 100644 --- a/src/masternode.h +++ b/src/masternode.h @@ -120,7 +120,8 @@ class CMasternode MASTERNODE_WATCHDOG_EXPIRED, MASTERNODE_POSE_BAN, MASTERNODE_VIN_SPENT, - MASTERNODE_POS_ERROR + MASTERNODE_POS_ERROR, + MASTERNODE_MISSING }; CTxIn vin; @@ -276,6 +277,7 @@ class CMasternode if (activeState == CMasternode::MASTERNODE_VIN_SPENT) strStatus = "VIN_SPENT"; if (activeState == CMasternode::MASTERNODE_REMOVE) strStatus = "REMOVE"; if (activeState == CMasternode::MASTERNODE_POS_ERROR) strStatus = "POS_ERROR"; + if (activeState == CMasternode::MASTERNODE_MISSING) strStatus = "MISSING"; return strStatus; } diff --git a/src/masternodeconfig.cpp b/src/masternodeconfig.cpp index c2d469566f86..7c25d9a9f013 100644 --- a/src/masternodeconfig.cpp +++ b/src/masternodeconfig.cpp @@ -11,10 +11,23 @@ CMasternodeConfig masternodeConfig; -void CMasternodeConfig::add(std::string alias, std::string ip, std::string privKey, std::string txHash, std::string outputIndex) +CMasternodeConfig::CMasternodeEntry* CMasternodeConfig::add(std::string alias, std::string ip, std::string privKey, std::string txHash, std::string outputIndex) { CMasternodeEntry cme(alias, ip, privKey, txHash, outputIndex); entries.push_back(cme); + return &(entries[entries.size()-1]); +} + +void CMasternodeConfig::remove(std::string alias) { + int pos = -1; + for (int i = 0; i < ((int) entries.size()); ++i) { + CMasternodeEntry e = entries[i]; + if (e.getAlias() == alias) { + pos = i; + break; + } + } + entries.erase(entries.begin() + pos); } bool CMasternodeConfig::read(std::string& strErr) @@ -28,7 +41,8 @@ bool CMasternodeConfig::read(std::string& strErr) if (configFile != NULL) { std::string strHeader = "# Masternode config file\n" "# Format: alias IP:port masternodeprivkey collateral_output_txid collateral_output_index\n" - "# Example: mn1 127.0.0.2:51472 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0\n"; + "# Example: mn1 127.0.0.2:51472 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0" + "#\n"; fwrite(strHeader.c_str(), std::strlen(strHeader.c_str()), 1, configFile); fclose(configFile); } diff --git a/src/masternodeconfig.h b/src/masternodeconfig.h index 40c171d45210..920bc439863a 100644 --- a/src/masternodeconfig.h +++ b/src/masternodeconfig.h @@ -97,7 +97,8 @@ class CMasternodeConfig void clear(); bool read(std::string& strErr); - void add(std::string alias, std::string ip, std::string privKey, std::string txHash, std::string outputIndex); + CMasternodeConfig::CMasternodeEntry* add(std::string alias, std::string ip, std::string privKey, std::string txHash, std::string outputIndex); + void remove(std::string alias); std::vector& getEntries() { diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index 7f04e0ed5c53..96fc5db02116 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -304,6 +304,11 @@ unsigned int CTransaction::CalculateModifiedSize(unsigned int nTxSize) const return nTxSize; } +unsigned int CTransaction::GetTotalSize() const +{ + return ::GetSerializeSize(*this, SER_NETWORK, PROTOCOL_VERSION); +} + std::string CTransaction::ToString() const { std::string str; diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index 30cd527433b3..438f25c6d7cf 100644 --- a/src/primitives/transaction.h +++ b/src/primitives/transaction.h @@ -294,6 +294,8 @@ class CTransaction return a.hash != b.hash; } + unsigned int GetTotalSize() const; + std::string ToString() const; }; diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 92c9f843b99d..0ef9b4057489 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -32,10 +32,11 @@ struct AddressTableEntry { QString label; QString address; QString pubcoin; + uint creationTime; AddressTableEntry() {} AddressTableEntry(Type type, const QString &pubcoin): type(type), pubcoin(pubcoin) {} - AddressTableEntry(Type type, const QString& label, const QString& address) : type(type), label(label), address(address) {} + AddressTableEntry(Type type, const QString& label, const QString& address, const uint _creationTime) : type(type), label(label), address(address), creationTime(_creationTime) {} }; struct AddressTableEntryLessThan { @@ -73,6 +74,8 @@ class AddressTablePriv public: CWallet* wallet; QList cachedAddressTable; + int sendNum = 0; + int recvNum = 0; AddressTableModel* parent; AddressTablePriv(CWallet* wallet, AddressTableModel* parent) : wallet(wallet), parent(parent) {} @@ -88,9 +91,22 @@ class AddressTablePriv AddressTableEntry::Type addressType = translateTransactionType( QString::fromStdString(item.second.purpose), fMine); const std::string& strName = item.second.name; - cachedAddressTable.append(AddressTableEntry(addressType, - QString::fromStdString(strName), - QString::fromStdString(address.ToString()))); + + uint creationTime = 0; + if(item.second.purpose == "receive"){ + creationTime = static_cast(wallet->GetKeyCreationTime(address)); + recvNum++; + }else if(item.second.purpose == "send"){ + sendNum++; + } + + cachedAddressTable.append( + AddressTableEntry(addressType, + QString::fromStdString(strName), + QString::fromStdString(address.ToString()), + creationTime + ) + ); } } // qLowerBound() and qUpperBound() require our cachedAddressTable list to be sorted in asc order @@ -112,16 +128,24 @@ class AddressTablePriv AddressTableEntry::Type newEntryType = translateTransactionType(purpose, isMine); switch (status) { - case CT_NEW: + case CT_NEW: { if (inModel) { qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_NEW, but entry is already in model"; break; } + uint creationTime = 0; + if (purpose == "receive") { + creationTime = static_cast(wallet->GetKeyCreationTime(CBitcoinAddress(address.toStdString()))); + recvNum++; + } else if (purpose == "send") { + sendNum++; + } parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); - cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, label, address)); + cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, label, address, creationTime)); parent->endInsertRows(); break; - case CT_UPDATED: + } + case CT_UPDATED: { if (!inModel) { qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_UPDATED, but entry is not in model"; break; @@ -130,7 +154,8 @@ class AddressTablePriv lower->label = label; parent->emitDataChanged(lowerIndex); break; - case CT_DELETED: + } + case CT_DELETED: { if (!inModel) { qWarning() << "AddressTablePriv::updateEntry : Warning: Got CT_DELETED, but entry is not in model"; break; @@ -138,7 +163,13 @@ class AddressTablePriv parent->beginRemoveRows(QModelIndex(), lowerIndex, upperIndex - 1); cachedAddressTable.erase(lower, upper); parent->endRemoveRows(); + if (purpose == "receive") { + recvNum--; + } else if (purpose == "send") { + sendNum--; + } break; + } } } @@ -161,7 +192,7 @@ class AddressTablePriv qWarning() << "AddressTablePriv_ZC::updateEntry : Warning: Got CT_NEW, but entry is already in model"; } parent->beginInsertRows(QModelIndex(), lowerIndex, lowerIndex); - cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, isUsed, pubCoin)); + cachedAddressTable.insert(lowerIndex, AddressTableEntry(newEntryType, isUsed, pubCoin, 0)); parent->endInsertRows(); break; case CT_UPDATED: @@ -184,6 +215,14 @@ class AddressTablePriv return cachedAddressTable.size(); } + int sizeSend(){ + return sendNum; + } + + int sizeRecv(){ + return recvNum; + } + AddressTableEntry* index(int idx) { if (idx >= 0 && idx < cachedAddressTable.size()) { @@ -196,7 +235,7 @@ class AddressTablePriv AddressTableModel::AddressTableModel(CWallet* wallet, WalletModel* parent) : QAbstractTableModel(parent), walletModel(parent), wallet(wallet), priv(0) { - columns << tr("Label") << tr("Address"); + columns << tr("Label") << tr("Address") << tr("Date"); priv = new AddressTablePriv(wallet, this); priv->refreshAddressTable(); } @@ -218,6 +257,13 @@ int AddressTableModel::columnCount(const QModelIndex& parent) const return columns.length(); } +int AddressTableModel::sizeSend() const{ + return priv->sizeSend(); +} +int AddressTableModel::sizeRecv() const{ + return priv->sizeRecv(); +} + QVariant AddressTableModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) @@ -235,6 +281,8 @@ QVariant AddressTableModel::data(const QModelIndex& index, int role) const } case Address: return rec->address; + case Date: + return rec->creationTime; } } else if (role == Qt::FontRole) { QFont font; @@ -420,9 +468,8 @@ bool AddressTableModel::removeRows(int row, int count, const QModelIndex& parent } { LOCK(wallet->cs_wallet); - wallet->DelAddressBook(CBitcoinAddress(rec->address.toStdString()).Get()); + return wallet->DelAddressBook(CBitcoinAddress(rec->address.toStdString()).Get()); } - return true; } /* Look up label for address in address book, if not found return empty string. @@ -451,6 +498,28 @@ int AddressTableModel::lookupAddress(const QString& address) const } } +/** + * Return last created unused address --> TODO: complete "unused".. + * @return + */ +QString AddressTableModel::getLastUnusedAddress() const{ + LOCK(wallet->cs_wallet); + if(!wallet->mapAddressBook.empty()) { + for (std::map::iterator it = wallet->mapAddressBook.end(); it != wallet->mapAddressBook.begin(); --it) { + if(it != wallet->mapAddressBook.end()) { + if (it->second.purpose == "receive") { + const CBitcoinAddress &address = it->first; + bool fMine = IsMine(*wallet, address.Get()); + if (fMine) { + return QString::fromStdString(address.ToString()); + } + } + } + } + } + return QString(); +} + void AddressTableModel::emitDataChanged(int idx) { emit dataChanged(index(idx, 0, QModelIndex()), index(idx, columns.length() - 1, QModelIndex())); diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 81eb7149a93d..1dac43b9d6d3 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -27,7 +27,8 @@ class AddressTableModel : public QAbstractTableModel enum ColumnIndex { Label = 0, /**< User specified label */ - Address = 1 /**< Bitcoin address */ + Address = 1, /**< Bitcoin address */ + Date = 2 /**< Address creation date */ }; enum RoleIndex { @@ -52,6 +53,8 @@ class AddressTableModel : public QAbstractTableModel @{*/ int rowCount(const QModelIndex& parent) const; int columnCount(const QModelIndex& parent) const; + int sizeSend() const; + int sizeRecv() const; QVariant data(const QModelIndex& index, int role) const; bool setData(const QModelIndex& index, const QVariant& value, int role); QVariant headerData(int section, Qt::Orientation orientation, int role) const; @@ -74,6 +77,11 @@ class AddressTableModel : public QAbstractTableModel */ int lookupAddress(const QString& address) const; + /** + * Return last unused address + */ + QString getLastUnusedAddress() const; + EditStatus getEditStatus() const { return editStatus; } private: diff --git a/src/qt/askpassphrasedialog.cpp b/src/qt/askpassphrasedialog.cpp index 3da13dcfed92..6dcef532af7f 100644 --- a/src/qt/askpassphrasedialog.cpp +++ b/src/qt/askpassphrasedialog.cpp @@ -6,12 +6,16 @@ #include "askpassphrasedialog.h" #include "ui_askpassphrasedialog.h" +#include #include "guiconstants.h" #include "guiutil.h" #include "walletmodel.h" - -#include "allocators.h" +#include "qt/pivx/qtutils.h" +#include "qt/pivx/loadingdialog.h" +#include "qt/pivx/defaultdialog.h" +#include "qt/pivx/pivxgui.h" +#include #include #include @@ -23,11 +27,40 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel mode(mode), model(model), context(context), - fCapsLock(false) + fCapsLock(false), + btnWatch(new QCheckBox()) { ui->setupUi(this); this->setStyleSheet(GUIUtil::loadStyleSheet()); + ui->left->setProperty("cssClass", "container-dialog"); + + ui->labelTitle->setText("Change passphrase"); + ui->labelTitle->setProperty("cssClass", "text-title-screen"); + + ui->warningLabel->setProperty("cssClass", "text-subtitle"); + + ui->btnEsc->setText(""); + ui->btnEsc->setProperty("cssClass", "ic-close"); + + ui->pushButtonOk->setText("OK"); + ui->pushButtonOk->setProperty("cssClass", "btn-primary"); + + initCssEditLine(ui->passEdit1); + initCssEditLine(ui->passEdit2); + initCssEditLine(ui->passEdit3); + + ui->passLabel1->setText("Current passphrase"); + ui->passLabel1->setProperty("cssClass", "text-title"); + + ui->passLabel2->setText("New passphrase"); + ui->passLabel2->setProperty("cssClass", "text-title"); + + ui->passLabel3->setText("Repeat passphrase"); + ui->passLabel3->setProperty("cssClass", "text-title"); + + ui->capsLabel->setVisible(false); + ui->passEdit1->setMinimumSize(ui->passEdit1->sizeHint()); ui->passEdit2->setMinimumSize(ui->passEdit2->sizeHint()); ui->passEdit3->setMinimumSize(ui->passEdit3->sizeHint()); @@ -36,6 +69,9 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE); ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE); + setShadow(ui->layoutEdit); + setShadow(ui->layoutEdit2); + // Setup Caps Lock detection. ui->passEdit1->installEventFilter(this); ui->passEdit2->installEventFilter(this); @@ -43,54 +79,69 @@ AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel this->model = model; + QString title; switch (mode) { case Mode::Encrypt: // Ask passphrase x2 ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.
Please use a passphrase of ten or more random characters, or eight or more words.")); ui->passLabel1->hide(); ui->passEdit1->hide(); - setWindowTitle(tr("Encrypt wallet")); + ui->layoutEdit->hide(); + title = tr("Encrypt wallet"); + initWatch(ui->layoutEdit2); break; case Mode::UnlockAnonymize: - ui->anonymizationCheckBox->show(); + ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet.")); + ui->passLabel2->hide(); + ui->passEdit2->hide(); + ui->layoutEdit2->hide(); + ui->passLabel3->hide(); + ui->passEdit3->hide(); + title = tr("Unlock wallet\nfor staking"); + initWatch(ui->layoutEdit); + break; case Mode::Unlock: // Ask passphrase ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet.")); ui->passLabel2->hide(); ui->passEdit2->hide(); + ui->layoutEdit2->hide(); ui->passLabel3->hide(); ui->passEdit3->hide(); - setWindowTitle(tr("Unlock wallet")); + title = tr("Unlock wallet"); + initWatch(ui->layoutEdit); break; case Mode::Decrypt: // Ask passphrase ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet.")); ui->passLabel2->hide(); ui->passEdit2->hide(); + ui->layoutEdit2->hide(); ui->passLabel3->hide(); ui->passEdit3->hide(); - setWindowTitle(tr("Decrypt wallet")); + title = tr("Decrypt wallet"); + initWatch(ui->layoutEdit); break; case Mode::ChangePass: // Ask old passphrase + new passphrase x2 - setWindowTitle(tr("Change passphrase")); + title = tr("Change passphrase"); ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet.")); + initWatch(ui->layoutEdit); break; } - // Set checkbox "For anonymization, automint, and staking only" depending on from where we were called - if (context == Context::Unlock_Menu || context == Context::Mint_zPIV || context == Context::BIP_38 || context == Context::UI_Vote) { - ui->anonymizationCheckBox->setChecked(true); - } - else { - ui->anonymizationCheckBox->setChecked(false); - } - - // It doesn't make sense to show the checkbox for sending PIV because you wouldn't check it anyway. - if (context == Context::Send_PIV || context == Context::Send_zPIV) { - ui->anonymizationCheckBox->hide(); - } + ui->labelTitle->setText(title); textChanged(); + connect(btnWatch, SIGNAL(clicked()), this, SLOT(onWatchClicked())); connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged())); + connect(ui->pushButtonOk, SIGNAL(clicked()), this, SLOT(accept())); + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); +} + +void AskPassphraseDialog::onWatchClicked(){ + int state = btnWatch->checkState(); + ui->passEdit3->setEchoMode(state == Qt::Checked ? QLineEdit::Normal : QLineEdit::Password ); + ui->passEdit2->setEchoMode(state== Qt::Checked ? QLineEdit::Normal : QLineEdit::Password ); + ui->passEdit1->setEchoMode(state == Qt::Checked ? QLineEdit::Normal : QLineEdit::Password ); } AskPassphraseDialog::~AskPassphraseDialog() @@ -102,6 +153,11 @@ AskPassphraseDialog::~AskPassphraseDialog() delete ui; } +void AskPassphraseDialog::showEvent(QShowEvent *event) +{ + if (ui->passEdit1) ui->passEdit1->setFocus(); +} + void AskPassphraseDialog::accept() { SecureString oldpass, newpass1, newpass2; @@ -122,30 +178,19 @@ void AskPassphraseDialog::accept() // Cannot encrypt with empty passphrase break; } - QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"), - tr("Warning: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR PIV!") + "

" + tr("Are you sure you wish to encrypt your wallet?"), - QMessageBox::Yes | QMessageBox::Cancel, - QMessageBox::Cancel); - if (retval == QMessageBox::Yes) { + hide(); + bool ret = openStandardDialog( + tr("Confirm wallet encryption"), + tr("Warning: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR PIV!") + "

" + tr("Are you sure you wish to encrypt your wallet?"), + tr("ENCRYPT"), tr("CANCEL") + ); + if (ret) { if (newpass1 == newpass2) { - if (model->setWalletEncrypted(true, newpass1)) { - QMessageBox::warning(this, tr("Wallet encrypted"), - "" + - tr("PIVX will close now to finish the encryption process. " - "Remember that encrypting your wallet cannot fully protect " - "your PIVs from being stolen by malware infecting your computer.") + - "

" + - tr("IMPORTANT: Any previous backups you have made of your wallet file " - "should be replaced with the newly generated, encrypted wallet file. " - "For security reasons, previous backups of the unencrypted wallet file " - "will become useless as soon as you start using the new, encrypted wallet.") + - "
"); - QApplication::quit(); - } else { - QMessageBox::critical(this, tr("Wallet encryption failed"), - tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted.")); - } - QDialog::accept(); // Success + newpassCache = newpass1; + PIVXGUI* window = static_cast(parentWidget()); + LoadingDialog *dialog = new LoadingDialog(window); + dialog->execute(this, 1); + openDialogWithOpaqueBackgroundFullScreen(dialog, window); } else { QMessageBox::critical(this, tr("Wallet encryption failed"), tr("The supplied passphrases do not match.")); @@ -155,8 +200,15 @@ void AskPassphraseDialog::accept() } } break; case Mode::UnlockAnonymize: + if (!model->setWalletLocked(false, oldpass, true)) { + QMessageBox::critical(this, tr("Wallet unlock failed"), + tr("The passphrase entered for the wallet decryption was incorrect.")); + } else { + QDialog::accept(); // Success + } + break; case Mode::Unlock: - if (!model->setWalletLocked(false, oldpass, ui->anonymizationCheckBox->isChecked())) { + if (!model->setWalletLocked(false, oldpass, false)) { QMessageBox::critical(this, tr("Wallet unlock failed"), tr("The passphrase entered for the wallet decryption was incorrect.")); } else { @@ -174,8 +226,8 @@ void AskPassphraseDialog::accept() case Mode::ChangePass: if (newpass1 == newpass2) { if (model->changePassphrase(oldpass, newpass1)) { - QMessageBox::information(this, tr("Wallet encrypted"), - tr("Wallet passphrase was successfully changed.")); + hide(); + openStandardDialog(tr("Wallet encrypted"),tr("Wallet passphrase was successfully changed.")); QDialog::accept(); // Success } else { QMessageBox::critical(this, tr("Wallet encryption failed"), @@ -206,7 +258,7 @@ void AskPassphraseDialog::textChanged() acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty(); break; } - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable); + ui->pushButtonOk->setEnabled(acceptable); } bool AskPassphraseDialog::event(QEvent* event) @@ -219,8 +271,10 @@ bool AskPassphraseDialog::event(QEvent* event) } if (fCapsLock) { ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!")); + ui->capsLabel->setVisible(true); } else { ui->capsLabel->clear(); + ui->capsLabel->setVisible(false); } } return QWidget::event(event); @@ -243,11 +297,81 @@ bool AskPassphraseDialog::eventFilter(QObject* object, QEvent* event) if ((fShift && *psz >= 'a' && *psz <= 'z') || (!fShift && *psz >= 'A' && *psz <= 'Z')) { fCapsLock = true; ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!")); + ui->capsLabel->setVisible(true); } else if (psz->isLetter()) { fCapsLock = false; ui->capsLabel->clear(); + ui->capsLabel->setVisible(false); } } } return QDialog::eventFilter(object, event); } + +bool AskPassphraseDialog::openStandardDialog(QString title, QString body, QString okBtn, QString cancelBtn){ + PIVXGUI* gui = static_cast(parentWidget()); + DefaultDialog *confirmDialog = new DefaultDialog(gui); + confirmDialog->setText(title, body, okBtn, cancelBtn); + confirmDialog->adjustSize(); + openDialogWithOpaqueBackground(confirmDialog, gui); + bool ret = confirmDialog->isOk; + confirmDialog->deleteLater(); + return ret; +} + +void AskPassphraseDialog::warningMessage() { + hide(); + static_cast(parentWidget())->showHide(true); + openStandardDialog( + tr("Wallet encrypted"), + "" + + tr("PIVX will close now to finish the encryption process. " + "Remember that encrypting your wallet cannot fully protect " + "your PIVs from being stolen by malware infecting your computer.") + + "

" + + tr("IMPORTANT: Any previous backups you have made of your wallet file " + "should be replaced with the newly generated, encrypted wallet file. " + "For security reasons, previous backups of the unencrypted wallet file " + "will become useless as soon as you start using the new, encrypted wallet.") + + "
", + tr("OK") + ); + QApplication::quit(); +} + +void AskPassphraseDialog::errorEncryptingWallet() { + QMessageBox::critical(this, tr("Wallet encryption failed"), + tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted.")); +} + +void AskPassphraseDialog::run(int type){ + if (type == 1) { + if (!newpassCache.empty()) { + QMetaObject::invokeMethod(this, "hide", Qt::QueuedConnection); + if (model->setWalletEncrypted(true, newpassCache)) { + QMetaObject::invokeMethod(this, "warningMessage", Qt::QueuedConnection); + } else { + QMetaObject::invokeMethod(this, "errorEncryptingWallet", Qt::QueuedConnection); + } + newpassCache.clear(); + QDialog::accept(); // Success + } + } +} +void AskPassphraseDialog::onError(int type, QString error){ + newpassCache = ""; +} + +void AskPassphraseDialog::initWatch(QWidget *parent) { + btnWatch = new QCheckBox(parent); + setCssProperty(btnWatch, "btn-watch-password"); + btnWatch->setChecked(false); + QSize BUTTON_CONTACT_SIZE = QSize(24, 24); + btnWatch->setMinimumSize(BUTTON_CONTACT_SIZE); + btnWatch->setMaximumSize(BUTTON_CONTACT_SIZE); + btnWatch->show(); + btnWatch->raise(); + + int posYY = 8; + btnWatch->move(450, posYY); +} \ No newline at end of file diff --git a/src/qt/askpassphrasedialog.h b/src/qt/askpassphrasedialog.h index fd44ba77a063..5f28a97d8df2 100644 --- a/src/qt/askpassphrasedialog.h +++ b/src/qt/askpassphrasedialog.h @@ -7,17 +7,22 @@ #define BITCOIN_QT_ASKPASSPHRASEDIALOG_H #include +#include "qt/pivx/prunnable.h" +#include "allocators.h" +#include class WalletModel; +class PIVXGUI; namespace Ui { class AskPassphraseDialog; +class QCheckBox; } /** Multifunctional dialog to ask for passphrases. Used for encryption, unlocking, and changing the passphrase. */ -class AskPassphraseDialog : public QDialog +class AskPassphraseDialog : public QDialog, public Runnable { Q_OBJECT @@ -50,7 +55,8 @@ class AskPassphraseDialog : public QDialog explicit AskPassphraseDialog(Mode mode, QWidget* parent, WalletModel* model, Context context); ~AskPassphraseDialog(); - void accept(); + void showEvent(QShowEvent *event) override; + void accept() override; private: Ui::AskPassphraseDialog* ui; @@ -58,13 +64,24 @@ class AskPassphraseDialog : public QDialog WalletModel* model; Context context; bool fCapsLock; + SecureString newpassCache = ""; + + void run(int type) override; + void onError(int type, QString error) override; + QCheckBox *btnWatch; + + void initWatch(QWidget *parent); private slots: + void onWatchClicked(); void textChanged(); + void warningMessage(); + void errorEncryptingWallet(); + bool openStandardDialog(QString title = "", QString body = "", QString okBtn = "OK", QString cancelBtn = ""); protected: - bool event(QEvent* event); - bool eventFilter(QObject* object, QEvent* event); + bool event(QEvent* event) override ; + bool eventFilter(QObject* object, QEvent* event) override; }; #endif // BITCOIN_QT_ASKPASSPHRASEDIALOG_H diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index 339bb9e32621..89b1471b7877 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -11,6 +11,8 @@ #include #include +#include + BitcoinUnits::BitcoinUnits(QObject* parent) : QAbstractListModel(parent), unitlist(availableUnits()) { @@ -51,27 +53,29 @@ QString BitcoinUnits::id(int unit) } } -QString BitcoinUnits::name(int unit) +QString BitcoinUnits::name(int unit, bool isZpiv) { + QString z = ""; + if(isZpiv) z = "z"; if (Params().NetworkID() == CBaseChainParams::MAIN) { switch (unit) { case PIV: - return QString("PIV"); + return z + QString("PIV"); case mPIV: - return QString("mPIV"); + return z + QString("mPIV"); case uPIV: - return QString::fromUtf8("μPIV"); + return z + QString::fromUtf8("μPIV"); default: return QString("???"); } } else { switch (unit) { case PIV: - return QString("tPIV"); + return z + QString("tPIV"); case mPIV: - return QString("mtPIV"); + return z + QString("mtPIV"); case uPIV: - return QString::fromUtf8("μtPIV"); + return z + QString::fromUtf8("μtPIV"); default: return QString("???"); } @@ -133,12 +137,13 @@ int BitcoinUnits::decimals(int unit) } } -QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators) +QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, SeparatorStyle separators, bool cleanRemainderZeros) { // Note: not using straight sprintf here because we do NOT want // localized number formatting. - if (!valid(unit)) + if (!valid(unit)){ return QString(); // Refuse to format invalid unit + } qint64 n = (qint64)nIn; qint64 coin = factor(unit); int num_decimals = decimals(unit); @@ -164,6 +169,18 @@ QString BitcoinUnits::format(int unit, const CAmount& nIn, bool fPlus, Separator if (num_decimals <= 0) return quotient_str; + if(cleanRemainderZeros) { + // Clean remainder + QString cleanRemainder = remainder_str; + for (int i = (remainder_str.length() - 1); i > 1; i--) { + if (remainder_str.at(i) == QChar('0')) { + cleanRemainder = cleanRemainder.left(cleanRemainder.lastIndexOf("0")); + } else + break; + } + return quotient_str + QString(".") + cleanRemainder; + } + return quotient_str + QString(".") + remainder_str; } @@ -191,25 +208,34 @@ QString BitcoinUnits::formatWithUnit(int unit, const CAmount& amount, bool pluss QString BitcoinUnits::formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators) { QString str(formatWithUnit(unit, amount, plussign, separators)); - str.replace(QChar(THIN_SP_CP), QString(THIN_SP_HTML)); + str.replace(QChar(THIN_SP_CP), QString(COMMA_HTML)); return QString("%1").arg(str); } -QString BitcoinUnits::floorWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators) +QString BitcoinUnits::floorWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators, bool cleanRemainderZeros, bool isZPIV) { QSettings settings; int digits = settings.value("digits").toInt(); - QString result = format(unit, amount, plussign, separators); - if (decimals(unit) > digits) result.chop(decimals(unit) - digits); + QString result = format(unit, amount, plussign, separators, cleanRemainderZeros); + if(decimals(unit) > digits) { + if (!cleanRemainderZeros) { + result.chop(decimals(unit) - digits); + } else { + int lenght = result.mid(result.indexOf("."), result.length() - 1).length() - 1; + if (lenght > digits) { + result.chop(lenght - digits); + } + } + } - return result + QString(" ") + name(unit); + return result + QString(" ") + name(unit, isZPIV); } -QString BitcoinUnits::floorHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators) +QString BitcoinUnits::floorHtmlWithUnit(int unit, const CAmount& amount, bool plussign, SeparatorStyle separators, bool cleanRemainderZeros, bool isZPIV) { - QString str(floorWithUnit(unit, amount, plussign, separators)); - str.replace(QChar(THIN_SP_CP), QString(THIN_SP_HTML)); + QString str(floorWithUnit(unit, amount, plussign, separators, cleanRemainderZeros, isZPIV)); + str.replace(QChar(THIN_SP_CP), QString(COMMA_HTML)); return QString("%1").arg(str); } diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h index 583a3a1d9943..2c113b93514e 100644 --- a/src/qt/bitcoinunits.h +++ b/src/qt/bitcoinunits.h @@ -17,6 +17,10 @@ #define REAL_THIN_SP_UTF8 "\xE2\x80\x89" #define REAL_THIN_SP_HTML " " +#define COMMA_CP 0x2C +#define COMMA_UTF8 "\x2C" +#define COMMA_HTML "," + // U+200A HAIR SPACE = UTF-8 E2 80 8A #define HAIR_SP_CP 0x200A #define HAIR_SP_UTF8 "\xE2\x80\x8A" @@ -79,7 +83,7 @@ class BitcoinUnits : public QAbstractListModel //! Identifier, e.g. for image names static QString id(int unit); //! Short name - static QString name(int unit); + static QString name(int unit, bool isZpiv = false); //! Longer description static QString description(int unit); //! Number of Satoshis (1e-8) per unit @@ -87,14 +91,14 @@ class BitcoinUnits : public QAbstractListModel //! Number of decimals left static int decimals(int unit); //! Format as string - static QString format(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = separatorStandard); + static QString format(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = separatorStandard, bool cleanRemainderZeros = true); static QString simpleFormat(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = separatorStandard); //! Format as string (with unit) static QString formatWithUnit(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = separatorStandard); static QString formatHtmlWithUnit(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = separatorStandard); //! Format as string (with unit) but floor value up to "digits" settings - static QString floorWithUnit(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = separatorStandard); - static QString floorHtmlWithUnit(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = separatorStandard); + static QString floorWithUnit(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = separatorStandard, bool cleanRemainderZeros = false, bool isZPIV = false); + static QString floorHtmlWithUnit(int unit, const CAmount& amount, bool plussign = false, SeparatorStyle separators = separatorStandard, bool cleanRemainderZeros = false, bool isZPIV = false); //! Parse string to coin amount static bool parse(int unit, const QString& value, CAmount* val_out); //! Gets title for amount column including current display unit if optionsModel reference available */ diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 9fc60ac9aae1..2e9f957107aa 100644 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -50,11 +50,60 @@ CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : Q model(0) { ui->setupUi(this); - this->fMultisigEnabled = fMultisigEnabled; /* Open CSS when configured */ this->setStyleSheet(GUIUtil::loadStyleSheet()); + ui->frameContainer->setProperty("cssClass", "container-dialog"); + ui->layoutAmount->setProperty("cssClass", "container-border-purple"); + ui->layoutAfter->setProperty("cssClass", "container-border-purple"); + ui->layoutBytes->setProperty("cssClass", "container-border-purple"); + ui->layoutChange->setProperty("cssClass", "container-border-purple"); + ui->layoutDust->setProperty("cssClass", "container-border-purple"); + ui->layoutFee->setProperty("cssClass", "container-border-purple"); + ui->layoutQuantity->setProperty("cssClass", "container-border-purple"); + + // Title + + ui->labelTitle->setText("Select PIV Denominations to Spend"); + ui->labelTitle->setProperty("cssClass", "text-title-dialog"); + + // Label Style + + ui->labelCoinControlAfterFeeText->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlAmountText->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlBytesText->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlChangeText->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlLowOutputText->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlFeeText->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlQuantityText->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlAfterFeeText->setProperty("cssClass", "text-main-purple"); + + ui->labelCoinControlAfterFee->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlAmount->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlBytes->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlChange->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlLowOutput->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlFee->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlQuantity->setProperty("cssClass", "text-main-purple"); + ui->labelCoinControlAfterFee->setProperty("cssClass", "text-main-purple"); + + ui->groupBox_2->setProperty("cssClass", "group-box"); + ui->treeWidget->setProperty("cssClass", "table-tree"); + ui->labelLocked->setProperty("cssClass", "text-main-purple"); + + // Buttons + ui->pushButtonSelectAll->setProperty("cssClass", "btn-check"); + ui->pushButtonToggleLock->setProperty("cssClass", "btn-check"); + + ui->btnEsc->setText(""); + ui->btnEsc->setProperty("cssClass", "ic-close"); + ui->pushButtonOk->setProperty("cssClass", "btn-primary"); + + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); + + this->fMultisigEnabled = fMultisigEnabled; + // context menu actions QAction* copyAddressAction = new QAction(tr("Copy address"), this); QAction* copyLabelAction = new QAction(tr("Copy label"), this); @@ -106,10 +155,15 @@ CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : Q ui->labelCoinControlFee->addAction(clipboardFeeAction); ui->labelCoinControlAfterFee->addAction(clipboardAfterFeeAction); ui->labelCoinControlBytes->addAction(clipboardBytesAction); - ui->labelCoinControlPriority->addAction(clipboardPriorityAction); ui->labelCoinControlLowOutput->addAction(clipboardLowOutputAction); ui->labelCoinControlChange->addAction(clipboardChangeAction); + if (ui->pushButtonSelectAll->isChecked()){ + ui->pushButtonSelectAll->setText(tr("Unselect all")); + }else{ + ui->pushButtonSelectAll->setText(tr("Select all")); + } + // toggle tree/list mode connect(ui->radioTreeMode, SIGNAL(toggled(bool)), this, SLOT(radioTreeMode(bool))); connect(ui->radioListMode, SIGNAL(toggled(bool)), this, SLOT(radioListMode(bool))); @@ -122,7 +176,7 @@ CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : Q connect(ui->treeWidget->header(), SIGNAL(sectionClicked(int)), this, SLOT(headerSectionClicked(int))); // ok button - connect(ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonBoxClicked(QAbstractButton*))); + connect(ui->pushButtonOk, SIGNAL(clicked()), this, SLOT(accept())); // (un)select all connect(ui->pushButtonSelectAll, SIGNAL(clicked()), this, SLOT(buttonSelectAllClicked())); @@ -135,22 +189,28 @@ CoinControlDialog::CoinControlDialog(QWidget* parent, bool fMultisigEnabled) : Q ui->treeWidget->headerItem()->setText(COLUMN_CHECKBOX, QString()); ui->treeWidget->setColumnWidth(COLUMN_CHECKBOX, 84); - ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 100); + ui->treeWidget->setColumnWidth(COLUMN_AMOUNT, 120); ui->treeWidget->setColumnWidth(COLUMN_LABEL, 170); - ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 190); - ui->treeWidget->setColumnWidth(COLUMN_DATE, 80); + ui->treeWidget->setColumnWidth(COLUMN_ADDRESS, 310); + ui->treeWidget->setColumnWidth(COLUMN_DATE, 100); ui->treeWidget->setColumnWidth(COLUMN_CONFIRMATIONS, 100); - ui->treeWidget->setColumnWidth(COLUMN_PRIORITY, 100); ui->treeWidget->setColumnHidden(COLUMN_TXHASH, true); // store transacton hash in this column, but dont show it ui->treeWidget->setColumnHidden(COLUMN_VOUT_INDEX, true); // store vout index in this column, but dont show it + ui->treeWidget->header()->setStretchLastSection(true); // default view is sorted by amount desc sortView(COLUMN_AMOUNT, Qt::DescendingOrder); // restore list mode and sortorder as a convenience feature QSettings settings; - if (settings.contains("nCoinControlMode") && !settings.value("nCoinControlMode").toBool()) + if (settings.contains("nCoinControlMode") && !settings.value("nCoinControlMode").toBool()) { + ui->radioTreeMode->setChecked(true); + ui->treeWidget->setRootIsDecorated(true); ui->radioTreeMode->click(); + }else{ + ui->radioListMode->setChecked(true); + ui->treeWidget->setRootIsDecorated(false); + } if (settings.contains("nCoinControlSortColumn") && settings.contains("nCoinControlSortOrder")) sortView(settings.value("nCoinControlSortColumn").toInt(), ((Qt::SortOrder)settings.value("nCoinControlSortOrder").toInt())); } @@ -177,13 +237,6 @@ void CoinControlDialog::setModel(WalletModel* model) } } -// ok button -void CoinControlDialog::buttonBoxClicked(QAbstractButton* button) -{ - if (ui->buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) - done(QDialog::Accepted); // closes the dialog -} - // (un)select all void CoinControlDialog::buttonSelectAllClicked() { @@ -199,8 +252,12 @@ void CoinControlDialog::buttonSelectAllClicked() if (ui->treeWidget->topLevelItem(i)->checkState(COLUMN_CHECKBOX) != state) ui->treeWidget->topLevelItem(i)->setCheckState(COLUMN_CHECKBOX, state); ui->treeWidget->setEnabled(true); - if (state == Qt::Unchecked) + if (state == Qt::Unchecked) { coinControl->UnSelectAll(); // just to be sure + ui->pushButtonSelectAll->setText(tr("Select all")); + }else{ + ui->pushButtonSelectAll->setText(tr("Unselect all")); + } CoinControlDialog::updateLabels(model, this); updateDialogLabels(); } @@ -215,9 +272,6 @@ void CoinControlDialog::buttonToggleLockClicked() for (int i = 0; i < ui->treeWidget->topLevelItemCount(); i++) { item = ui->treeWidget->topLevelItem(i); - if (item->text(COLUMN_TYPE) == "MultiSig") - continue; - COutPoint outpt(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt()); if (model->isLockedCoin(uint256(item->text(COLUMN_TXHASH).toStdString()), item->text(COLUMN_VOUT_INDEX).toUInt())) { model->unlockCoin(outpt); @@ -355,12 +409,6 @@ void CoinControlDialog::clipboardBytes() GUIUtil::setClipboard(ui->labelCoinControlBytes->text().replace("~", "")); } -// copy label "Priority" to clipboard -void CoinControlDialog::clipboardPriority() -{ - GUIUtil::setClipboard(ui->labelCoinControlPriority->text()); -} - // copy label "Dust" to clipboard void CoinControlDialog::clipboardLowOutput() { @@ -515,9 +563,9 @@ void CoinControlDialog::updateDialogLabels() // Amount nAmount += out.tx->vout[out.i].nValue; } - MultisigDialog* multisigDialog = (MultisigDialog*)this->parentWidget(); - multisigDialog->updateCoinControl(nAmount, nQuantity); + //MultisigDialog* multisigDialog = (MultisigDialog*)this->parentWidget(); + //multisigDialog->updateCoinControl(nAmount, nQuantity); } void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) @@ -649,7 +697,6 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) QLabel* l3 = dialog->findChild("labelCoinControlFee"); QLabel* l4 = dialog->findChild("labelCoinControlAfterFee"); QLabel* l5 = dialog->findChild("labelCoinControlBytes"); - QLabel* l6 = dialog->findChild("labelCoinControlPriority"); QLabel* l7 = dialog->findChild("labelCoinControlLowOutput"); QLabel* l8 = dialog->findChild("labelCoinControlChange"); @@ -665,7 +712,6 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) l3->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nPayFee)); // Fee l4->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nAfterFee)); // After Fee l5->setText(((nBytes > 0) ? "~" : "") + QString::number(nBytes)); // Bytes - l6->setText(sPriorityLabel); // Priority l7->setText(fDust ? tr("yes") : tr("no")); // Dust l8->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, nChange)); // Change if (nPayFee > 0 && !(payTxFee.GetFeePerK() > 0 && fPayAtLeastCustomFee && nBytes < 1000)) { @@ -677,7 +723,6 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) // turn labels "red" l5->setStyleSheet((nBytes >= MAX_FREE_TRANSACTION_CREATE_SIZE) ? "color:red;" : ""); // Bytes >= 1000 - l6->setStyleSheet((dPriority > 0 && !fAllowFree) ? "color:red;" : ""); // Priority < "medium" l7->setStyleSheet((fDust) ? "color:red;" : ""); // Dust = "yes" // tool tips @@ -702,13 +747,11 @@ void CoinControlDialog::updateLabels(WalletModel* model, QDialog* dialog) l3->setToolTip(toolTip4); l4->setToolTip(toolTip4); l5->setToolTip(toolTip1); - l6->setToolTip(toolTip2); l7->setToolTip(toolTip3); l8->setToolTip(toolTip4); dialog->findChild("labelCoinControlFeeText")->setToolTip(l3->toolTip()); dialog->findChild("labelCoinControlAfterFeeText")->setToolTip(l4->toolTip()); dialog->findChild("labelCoinControlBytesText")->setToolTip(l5->toolTip()); - dialog->findChild("labelCoinControlPriorityText")->setToolTip(l6->toolTip()); dialog->findChild("labelCoinControlLowOutputText")->setToolTip(l7->toolTip()); dialog->findChild("labelCoinControlChangeText")->setToolTip(l8->toolTip()); @@ -725,14 +768,19 @@ void CoinControlDialog::updateView() bool treeMode = ui->radioTreeMode->isChecked(); + if(treeMode){ + ui->treeWidget->setRootIsDecorated(true); + }else{ + ui->treeWidget->setRootIsDecorated(false); + } + ui->treeWidget->clear(); ui->treeWidget->setEnabled(false); // performance, otherwise updateLabels would be called for every checked checkbox - ui->treeWidget->setAlternatingRowColors(!treeMode); QFlags flgCheckbox = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable; QFlags flgTristate = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsTristate; int nDisplayUnit = model->getOptionsModel()->getDisplayUnit(); - double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget); +// double mempoolEstimatePriority = mempool.estimatePriority(nTxConfirmTarget); std::map> mapCoins; model->listCoins(mapCoins); @@ -785,7 +833,6 @@ void CoinControlDialog::updateView() //MultiSig if (fMultiSigUTXO) { - itemOutput->setText(COLUMN_TYPE, "MultiSig"); if (!fMultisigEnabled) { COutPoint outpt(out.tx->GetHash(), out.i); @@ -793,8 +840,6 @@ void CoinControlDialog::updateView() itemOutput->setDisabled(true); itemOutput->setIcon(COLUMN_CHECKBOX, QIcon(":/icons/lock_closed")); } - } else { - itemOutput->setText(COLUMN_TYPE, "Personal"); } // address @@ -843,9 +888,6 @@ void CoinControlDialog::updateView() itemOutput->setData(COLUMN_CONFIRMATIONS, Qt::UserRole, QVariant((qlonglong) out.nDepth)); // priority - double dPriority = ((double)out.tx->vout[out.i].nValue / (nInputSize + 78)) * (out.nDepth + 1); // 78 = 2 * 34 + 10 - itemOutput->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPriority, mempoolEstimatePriority)); - itemOutput->setData(COLUMN_PRIORITY, Qt::UserRole, QVariant((qlonglong) dPriority)); dPrioritySum += (double)out.tx->vout[out.i].nValue * (out.nDepth + 1); nInputSum += nInputSize; @@ -876,8 +918,6 @@ void CoinControlDialog::updateView() itemWalletAddress->setText(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); itemWalletAddress->setToolTip(COLUMN_AMOUNT, BitcoinUnits::format(nDisplayUnit, nSum)); itemWalletAddress->setData(COLUMN_AMOUNT, Qt::UserRole, QVariant((qlonglong) nSum)); - itemWalletAddress->setText(COLUMN_PRIORITY, CoinControlDialog::getPriorityLabel(dPrioritySum, mempoolEstimatePriority)); - itemWalletAddress->setData(COLUMN_PRIORITY, Qt::UserRole, QVariant((qlonglong) dPrioritySum)); } } diff --git a/src/qt/coincontroldialog.h b/src/qt/coincontroldialog.h index 8817cf23a9a9..0bee2504bf99 100644 --- a/src/qt/coincontroldialog.h +++ b/src/qt/coincontroldialog.h @@ -78,10 +78,8 @@ class CoinControlDialog : public QDialog COLUMN_AMOUNT, COLUMN_LABEL, COLUMN_ADDRESS, - COLUMN_TYPE, COLUMN_DATE, COLUMN_CONFIRMATIONS, - COLUMN_PRIORITY, COLUMN_TXHASH, COLUMN_VOUT_INDEX, }; @@ -100,14 +98,12 @@ private slots: void clipboardFee(); void clipboardAfterFee(); void clipboardBytes(); - void clipboardPriority(); void clipboardLowOutput(); void clipboardChange(); void radioTreeMode(bool); void radioListMode(bool); void viewItemChanged(QTreeWidgetItem*, int); void headerSectionClicked(int); - void buttonBoxClicked(QAbstractButton*); void buttonSelectAllClicked(); void buttonToggleLockClicked(); void updateLabelLocked(); diff --git a/src/qt/forms/askpassphrasedialog.ui b/src/qt/forms/askpassphrasedialog.ui index eb545bb44808..677a34d18eb0 100644 --- a/src/qt/forms/askpassphrasedialog.ui +++ b/src/qt/forms/askpassphrasedialog.ui @@ -6,8 +6,8 @@ 0 0 - 598 - 222 + 550 + 565 @@ -22,155 +22,333 @@ 0 + + + 550 + 16777215 + + Passphrase Dialog - - QLayout::SetMinimumSize - - - - - Placeholder text - - - Qt::RichText - - - true - - - - - - - QLayout::SetMinimumSize - - - QFormLayout::AllNonFixedFieldsGrow - - - - - Enter passphrase - - - - - - - QLineEdit::Password - - - - - - - New passphrase - - - - - - - QLineEdit::Password - - - - - - - Repeat new passphrase - - - - - - - QLineEdit::Password - - - - - - - - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - true - - - Serves to disable the trivial sendmoney when OS account compromised. Provides no real security. - - - For anonymization, automint, and staking only - - - false - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 20 + + + 20 + + + 20 + + + 20 + + + 20 + + + + + 0 + + + + + padding-left:24px; + + + + 5 + + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + + + + 24 + 16777215 + + + + + + + + + + + + + + 0 + 0 + + + + + 400 + 0 + + + + Placeholder text + + + Qt::RichText + + + Qt::AlignCenter + + + true + + + + + + + 0 + + + + + 5 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + QLineEdit::Password + + + + + + + + + + + + + + 5 + + + + + TextLabel + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + QLineEdit::Password + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + + + 5 + + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + QLineEdit::Password + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + 75 + true + + + + + + + Qt::AlignCenter + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + PushButton + + + + + + - - - buttonBox - accepted() - AskPassphraseDialog - accept() - - - 20 - 20 - - - 20 - 20 - - - - - buttonBox - rejected() - AskPassphraseDialog - reject() - - - 20 - 20 - - - 20 - 20 - - - - + diff --git a/src/qt/forms/coincontroldialog.ui b/src/qt/forms/coincontroldialog.ui index 885e9f331808..aa079ac464da 100644 --- a/src/qt/forms/coincontroldialog.ui +++ b/src/qt/forms/coincontroldialog.ui @@ -6,526 +6,649 @@ 0 0 - 954 - 500 + 1000 + 650 + + + 950 + 650 + + Coin Selection + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - + + 0 - - 10 - - - - - 10 - - - 10 - - - 6 - - - 6 - - - - - - 75 - true - - - - Quantity: - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0 - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 75 - true - - - - Bytes: - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0 - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - 10 - - - 10 - - - 6 - - - 6 - - - - - - 75 - true - - - - Amount: - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0.00 PIV - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 75 - true - - - - Priority: - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - medium - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - 10 - - - 10 - - - 6 - - - 6 - - - - - - 75 - true - - - - Fee: - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0.00 PIV - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - false - - - - 75 - true - - - - Dust: - - - - - - - false - - - IBeamCursor - - - Qt::ActionsContextMenu - - - no - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - 10 - - - 10 - - - 6 - - - 6 - - - - - - 75 - true - - - - After Fee: - - - - - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0.00 PIV - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - false - - - - 75 - true - - - - Change: - - - - - - - false - - - IBeamCursor - - - Qt::ActionsContextMenu - - - 0.00 PIV - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - - - - - 0 - 40 - - QFrame::StyledPanel - QFrame::Sunken + QFrame::Raised - + + + 0 + + + 0 + + + 20 + - + - 14 + 0 + + + 20 + + + 30 - - - - 0 - 0 - + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:30px; - (un)select all + Transaction Details - - false + + Qt::AlignCenter + + + 7 - - - - 0 - 0 - + + + Qt::Horizontal - - toggle lock state + + + 40 + 20 + - - false + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PushButton + + + + + + 20 + + + 20 + + + + + + + + Amount + + + + + + + 0.00 PIV + + + + + + - - - - 0 - 0 - + + + Qt::Horizontal - - Tree mode + + QSizePolicy::Fixed + + + 40 + 20 + + + + + + + + + + + Quantity: + + + + + + + 0 + + + + - - - - 0 - 0 - + + + Qt::Horizontal - - List mode + + QSizePolicy::Fixed - - true + + + 40 + 20 + + + + + + + + + + Fee: + + + + + + + 0.00 PIV + + + + + + + + + + + 0 + 40 + + + + #frame { + border:0; +} + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + 0 + + + 20 + + + 0 + + + 20 + + + 0 + + + + + 20 + + + + + + 0 + 0 + + + + + 160 + 40 + + + + + 16777215 + 40 + + + + Select all + + + true + + + false + + + false + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + + 0 + 0 + + + + + 160 + 40 + + + + + 16777215 + 40 + + + + Toggle lock state + + + true + + + false + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 30 + 20 + + + + + + + + #groupBox_2 { + background-color:transparent; + border-radius:0; +} + + + + + + + + + + 0 + 0 + + + + Tree mode + + + + + + + + 0 + 0 + + + + List mode + + + false + + + + + + + + + + (1 locked) + + + + + + + + + + + + 20 + + + 20 + - - - (1 locked) + + + Qt::NoFocus + + Qt::CustomContextMenu + + + + + + false + + + 6 + + + true + + + false + + + + + + + + + Amount + + + + + Received with label + + + + + Received with address + + + + + Date + + + + + Confirmations + + + Confirmed + + + + + + + + 20 + + + 20 + + + 20 + + + + + + + + Bytes: + + + + + + + 0 + + + + + + + + + + + + + Dust: + + + + + + + no + + + + + + + + + + + + + Change: + + + + + + + 0 + + + + + + + + + + + + + After Fee: + + + + + + + 0.00 PIV + + + + + + + + + + + + 0 + + + 20 + + + 26 + - + Qt::Horizontal - 40 + 558 20 + + + + + 150 + 35 + + + + OK + + + - - - - Qt::CustomContextMenu - - - false - - - 10 - - - true - - - false - - - - - - - - - Amount - - - - - Received with label - - - - - Received with address - - - - - Type - - - - - Date - - - - - Confirmations - - - Confirmed - - - - - Priority - - - - - - - - - - - - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - QDialogButtonBox::Ok - - - diff --git a/src/qt/forms/helpmessagedialog.ui b/src/qt/forms/helpmessagedialog.ui index a0cdaaba3fca..6475d1494130 100644 --- a/src/qt/forms/helpmessagedialog.ui +++ b/src/qt/forms/helpmessagedialog.ui @@ -6,10 +6,16 @@ 0 0 - 585 - 488 + 600 + 500 + + + 600 + 500 + + 10 @@ -18,119 +24,232 @@ PIVX Core - Command-line options - + + #HelpMessageDialog { + background-color:#FFFFFF; +} + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - + - + 0 - 0 + 100 - - :/images/about + + + 0 + 200 + - - - - - - - - true - - - - - - - Qt::ScrollBarAlwaysOn - - - true - - - - - 0 - 0 - 479 - 213 - + + #helpContainer{ + background-color:white; + padding:9px; +} + + + + 0 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + 0 + 0 + + + + + 0 + 100 + + + + :/images/about - - - - - IBeamCursor + + + + + + 100 + + + + + + 0 + 0 + + + + #helpMessage { +background-color:#FFFFFF; + color:#707070; +} + + + true + + + + + + + #scrollArea { +background-color:#FFFFFF; +} + + + Qt::ScrollBarAlwaysOn + + + true + + + + + 0 + 0 + 564 + 263 + - - Qt::PlainText + + #scrollAreaWidgetContents { +background-color:#FFFFFF; +} - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + 0 + 245 + + + + IBeamCursor + + + #aboutMessage { +background-color:#FFFFFF; + color:#707070; +} + + + Qt::PlainText + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + + + + + + 0 + 50 + + + + + 0 + 60 + + + + + 0 - - true + + 0 - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + 0 - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Ok - - - - + + 0 + + + + + Qt::Horizontal + + + + 421 + 20 + + + + + + + + + 150 + 50 + + + + OK + + + + + + + + + + - - - - - - okButton - accepted() - HelpMessageDialog - accept() - - - 20 - 20 - - - 20 - 20 - - - - - okButton - rejected() - HelpMessageDialog - reject() - - - 20 - 20 - - - 20 - 20 - - - - + + diff --git a/src/qt/forms/intro.ui b/src/qt/forms/intro.ui index 5aa82c3d3a3b..d4a94d4caadd 100644 --- a/src/qt/forms/intro.ui +++ b/src/qt/forms/intro.ui @@ -6,261 +6,504 @@ 0 0 - 674 - 363 + 1200 + 750 Welcome + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - QLabel { font-style:italic; } - - - Welcome to PIVX Core. - - - true - - - - - - - Qt::Vertical - - - QSizePolicy::Minimum - - - - 20 - 15 - - - - - - - - As this is the first time the program is launched, you can choose where PIVX Core will store its data. - - - true - - - - - - - PIVX Core will download and store a copy of the PIVX block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. - - - true - - - - - - - Use the default data directory - - - - - - - Use a custom data directory: - - - - - - - 0 - - - QLayout::SetDefaultConstraint - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 60 - 20 - - - - - - - - QLayout::SetDefaultConstraint - - - - - - - - - - - 0 - 0 - - - - - 30 - 16777215 - - - - ... - - - false - - - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 5 - - - - - - - - - 1 - 0 - - - - - - - true - - - - - - - Qt::Vertical + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 820 + 520 + + + + + 820 + 520 + + + + + 0 - - QSizePolicy::Fixed + + 1 - - - 20 - 5 - + + 1 - - - - - - - 0 - 0 - + + 1 - - Qt::RichText + + 1 - - true - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - + + + + + 10 + + + 30 + + + 30 + + + 30 + + + 30 + + + + + QLabel { font-style:italic; } + + + Welcome to PIVX Core. + + + Qt::AlignCenter + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 15 + + + + + + + + + 0 + 0 + + + + As this is the first time the program is launched, you can choose where PIVX Core will store its data. + + + Qt::AlignCenter + + + true + + + + + + + #sizeWarningLabel { + padding:0 80px; +} + + + PIVX Core will download and store a copy of the PIVX block chain. At least %1GB of data will be stored in this directory, and it will grow over time. The wallet will also be stored in this directory. + + + Qt::AlignCenter + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + Use the default data directory + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + Use a custom data directory + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + 0 + + + QLayout::SetDefaultConstraint + + + + + 6 + + + QLayout::SetDefaultConstraint + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 725 + 40 + + + + + 725 + 40 + + + + + + + + 0 + + + 2 + + + + + + 0 + 0 + + + + + 50 + 40 + + + + + 50 + 16777215 + + + + ... + + + false + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 6 + + + + + + + + + 1 + 0 + + + + + 500 + 0 + + + + + + + + + + false + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 5 + + + + + + + + + 0 + 0 + + + + + 600 + 0 + + + + + + + Qt::RichText + + + false + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 50 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 535 + 20 + + + + + + + + + 100 + 40 + + + + CANCEL + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 100 + 40 + + + + OK + + + + + + + + + + + + + - - - buttonBox - accepted() - Intro - accept() - - - 20 - 20 - - - 20 - 20 - - - - - buttonBox - rejected() - Intro - reject() - - - 20 - 20 - - - 20 - 20 - - - - + diff --git a/src/qt/forms/openuridialog.ui b/src/qt/forms/openuridialog.ui index 114a3639439e..699f176f7bc4 100644 --- a/src/qt/forms/openuridialog.ui +++ b/src/qt/forms/openuridialog.ui @@ -7,68 +7,192 @@ 0 0 564 - 109 + 260 Open URI + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + - - - Open payment request from URI or file + + + QFrame::StyledPanel - - - - - - - - URI: - - - - - - - - - - Select payment request file - - - ... - - - false - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + QFrame::Raised + + + 5 + + + 20 + + + 20 + + + 20 + + + 16 + + + + + Open payment request from URI or file + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + TextLabel + + + + + + + 0 + + + + + #uriEdit{ + border-top-right-radius:0px; + border-bottom-right-radius:0px; +} + + + + + + + + 0 + 41 + + + + Select payment request file + + + #selectFileButton{ + border-top-left-radius:0px; + border-bottom-left-radius:0px; +} + + + ... + + + false + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 50 + + + + + + + Qt::Horizontal + + + + 289 + 20 + + + + + + + + + 100 + 40 + + + + CANCEL + + + + + + + + 100 + 40 + + + + OK + + + + + + + @@ -81,38 +205,5 @@ - - - buttonBox - accepted() - OpenURIDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - OpenURIDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - + diff --git a/src/qt/forms/zpivcontroldialog.ui b/src/qt/forms/zpivcontroldialog.ui index fe106a301a14..4d2524273b60 100644 --- a/src/qt/forms/zpivcontroldialog.ui +++ b/src/qt/forms/zpivcontroldialog.ui @@ -1,240 +1,431 @@ - ZPivControlDialog - - - - 0 - 0 - 781 - 450 - - - - - 781 - 450 - - - - Select zPIV to Spend - - - - - - -1 - - - 10 - - - - - 10 - - - 10 - - - 6 - - - 6 - - - - - Quantity - - - - - - - 0 - - - - - - - zPIV - - - - - - - 0 - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 14 - - - 10 - - - - - Select/Deselect All - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 0 - 0 - - - - - 0 - 250 - - - - true - - - true - - - 5 - - - 100 - - - - Select + ZPivControlDialog + + + + 0 + 0 + 681 + 550 + - - - - Denomination + + + 681 + 550 + - - - - ID + + Select zPIV to Spend - - - - Version - - - - - Precomputed - - - - - Confirmations - - - - - Spendable? - - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - ZPivControlDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - ZPivControlDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 12 + + + 0 + + + 20 + + + + + 0 + + + 20 + + + 30 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:30px; + + + Coin Control + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PushButton + + + + + + + + + -1 + + + 20 + + + 20 + + + 10 + + + + + + + + zPiv + + + + + + + 0.00 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + + Quantity: + + + + + + + 0 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 0 + + + 20 + + + 20 + + + 10 + + + + + + 180 + 40 + + + + Select/Deselect All + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + 20 + + + 20 + + + + + + 0 + 0 + + + + + 0 + 250 + + + + true + + + true + + + 6 + + + 100 + + + + Select + + + + + Denomination + + + + + zPIV ID + + + + + zPIV Version + + + + + Confirmations + + + + + Is Spendable + + + + + + + + + + 0 + + + 20 + + + 26 + + + + + Qt::Horizontal + + + + 558 + 20 + + + + + + + + + 0 + 0 + + + + + 150 + 35 + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + + + + + + buttonBox + accepted() + ZPivControlDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + ZPivControlDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + diff --git a/src/qt/guiutil.cpp b/src/qt/guiutil.cpp index b59a7abbf04b..621ef3a3fb9b 100644 --- a/src/qt/guiutil.cpp +++ b/src/qt/guiutil.cpp @@ -95,6 +95,37 @@ QFont bitcoinAddressFont() return font; } +/** + * Parse a string into a number of base monetary units and + * return validity. + * @note Must return 0 if !valid. + */ +CAmount parseValue(const QString& text, int displayUnit, bool* valid_out) +{ + CAmount val = 0; + bool valid = BitcoinUnits::parse(displayUnit, text, &val); + if (valid) { + if (val < 0 || val > BitcoinUnits::maxMoney()) + valid = false; + } + if (valid_out) + *valid_out = valid; + return valid ? val : 0; +} + +QString formatBalance(CAmount amount, int nDisplayUnit, bool isZpiv){ + return (amount == 0) ? ("0.00 " + BitcoinUnits::name(nDisplayUnit, isZpiv)) : BitcoinUnits::floorHtmlWithUnit(nDisplayUnit, amount, false, BitcoinUnits::separatorAlways, true, isZpiv); +} + +bool requestUnlock(WalletModel* walletModel, AskPassphraseDialog::Context context, bool relock){ + // Request unlock if wallet was locked or unlocked for mixing: + WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); + if (encStatus == walletModel->Locked) { + return WalletModel::UnlockContext(walletModel->requestUnlock(context, relock)).isValid(); + } + return true; +} + void setupAddressWidget(QValidatedLineEdit* widget, QWidget* parent) { parent->setFocusProxy(widget); @@ -339,40 +370,44 @@ bool isObscured(QWidget* w) return !(checkPoint(QPoint(0, 0), w) && checkPoint(QPoint(w->width() - 1, 0), w) && checkPoint(QPoint(0, w->height() - 1), w) && checkPoint(QPoint(w->width() - 1, w->height() - 1), w) && checkPoint(QPoint(w->width() / 2, w->height() / 2), w)); } -void openDebugLogfile() +bool openDebugLogfile() { boost::filesystem::path pathDebug = GetDataDir() / "debug.log"; /* Open debug.log with the associated application */ if (boost::filesystem::exists(pathDebug)) - QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathDebug))); + return QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathDebug))); + return false; } -void openConfigfile() +bool openConfigfile() { boost::filesystem::path pathConfig = GetConfigFile(); /* Open pivx.conf with the associated application */ if (boost::filesystem::exists(pathConfig)) - QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig))); + return QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig))); + return false; } -void openMNConfigfile() +bool openMNConfigfile() { boost::filesystem::path pathConfig = GetMasternodeConfigFile(); /* Open masternode.conf with the associated application */ if (boost::filesystem::exists(pathConfig)) - QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig))); + return QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathConfig))); + return false; } -void showBackups() +bool showBackups() { boost::filesystem::path pathBackups = GetDataDir() / "backups"; /* Open folder with default browser */ if (boost::filesystem::exists(pathBackups)) - QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathBackups))); + return QDesktopServices::openUrl(QUrl::fromLocalFile(boostPathToQString(pathBackups))); + return false; } void SubstituteFonts(const QString& language) @@ -802,7 +837,7 @@ bool isExternal(QString theme) if (theme.isEmpty()) return false; - return (theme.operator!=("default")); + return (theme.operator!=("default") && theme.operator!=("default-dark")); } // Open CSS when configured diff --git a/src/qt/guiutil.h b/src/qt/guiutil.h index e52867ab0395..447654e29c39 100644 --- a/src/qt/guiutil.h +++ b/src/qt/guiutil.h @@ -7,6 +7,7 @@ #define BITCOIN_QT_GUIUTIL_H #include "amount.h" +#include "askpassphrasedialog.h" #include #include @@ -42,6 +43,15 @@ QString dateTimeStr(qint64 nTime); // Render PIVX addresses in monospace font QFont bitcoinAddressFont(); +// Parse string into a CAmount value +CAmount parseValue(const QString& text, int displayUnit, bool* valid_out = 0); + +// Format an amount +QString formatBalance(CAmount amount, int nDisplayUnit = 0, bool isZpiv = false); + +// Request wallet unlock +bool requestUnlock(WalletModel* walletModel, AskPassphraseDialog::Context context, bool relock); + // Set up widgets for address and amounts void setupAddressWidget(QValidatedLineEdit* widget, QWidget* parent); void setupAmountWidget(QLineEdit* widget, QWidget* parent); @@ -110,16 +120,16 @@ Qt::ConnectionType blockingGUIThreadConnection(); bool isObscured(QWidget* w); // Open debug.log -void openDebugLogfile(); +bool openDebugLogfile(); // Open pivx.conf -void openConfigfile(); +bool openConfigfile(); // Open masternode.conf -void openMNConfigfile(); +bool openMNConfigfile(); // Browse backup folder -void showBackups(); +bool showBackups(); // Replace invalid default fonts with known good ones void SubstituteFonts(const QString& language); diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index cad7485dd6de..312c9319ece5 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -10,6 +10,7 @@ #include "guiutil.h" #include "util.h" +#include "qt/pivx/qtutils.h" #include @@ -109,6 +110,27 @@ Intro::Intro(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::W signalled(false) { ui->setupUi(this); + this->setStyleSheet(GUIUtil::loadStyleSheet()); + + setCssProperty(ui->frame, "container-welcome-step2"); + setCssProperty(ui->container, "container-welcome-stack"); + setCssProperty(ui->frame_2, "container-welcome"); + setCssProperty(ui->label_2, "text-title-welcome"); + setCssProperty(ui->label_4, "text-intro-white"); + setCssProperty(ui->sizeWarningLabel, "text-intro-white"); + setCssProperty(ui->freeSpace, "text-intro-white"); + setCssProperty(ui->errorMessage, "text-intro-white"); + + setCssProperty({ui->dataDirDefault, ui->dataDirCustom}, "radio-welcome"); + setCssProperty(ui->dataDirectory, "edit-primary-welcome"); + ui->dataDirectory->setAttribute(Qt::WA_MacShowFocusRect, 0); + setCssProperty(ui->ellipsisButton, "btn-dots-welcome"); + setCssBtnPrimary(ui->pushButtonOk); + setCssBtnSecondary(ui->pushButtonCancel); + + connect(ui->pushButtonOk, SIGNAL(clicked()), this, SLOT(accept())); + connect(ui->pushButtonCancel, SIGNAL(clicked()), this, SLOT(close())); + ui->sizeWarningLabel->setText(ui->sizeWarningLabel->text().arg(BLOCK_CHAIN_SIZE / GB_BYTES)); startThread(); } @@ -133,10 +155,12 @@ void Intro::setDataDirectory(const QString& dataDir) ui->dataDirDefault->setChecked(true); ui->dataDirectory->setEnabled(false); ui->ellipsisButton->setEnabled(false); + updateDataDirStatus(false); } else { ui->dataDirCustom->setChecked(true); ui->dataDirectory->setEnabled(true); ui->ellipsisButton->setEnabled(true); + updateDataDirStatus(true); } } @@ -158,15 +182,16 @@ bool Intro::pickDataDirectory() /* 2) Allow QSettings to override default dir */ dataDir = settings.value("strDataDir", dataDir).toString(); + if (!fs::exists(GUIUtil::qstringToBoostPath(dataDir)) || GetBoolArg("-choosedatadir", false)) { - /* If current default data directory does not exist, let the user choose one */ + // If current default data directory does not exist, let the user choose one Intro intro; intro.setDataDirectory(dataDir); intro.setWindowIcon(QIcon(":icons/bitcoin")); while (true) { if (!intro.exec()) { - /* Cancel clicked */ + // Cancel clicked return false; } dataDir = intro.getDataDirectory(); @@ -176,16 +201,18 @@ bool Intro::pickDataDirectory() } catch (fs::filesystem_error& e) { QMessageBox::critical(0, tr("PIVX Core"), tr("Error: Specified data directory \"%1\" cannot be created.").arg(dataDir)); - /* fall through, back to choosing screen */ + // fall through, back to choosing screen } } settings.setValue("strDataDir", dataDir); } + /* Only override -datadir if different from the default, to make it possible to * override -datadir in the pivx.conf file in the default data directory * (to be consistent with pivxd behavior) */ + if (dataDir != getDefaultDataDirectory()) SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting return true; @@ -200,7 +227,7 @@ void Intro::setStatus(int status, const QString& message, quint64 bytesAvailable break; case FreespaceChecker::ST_ERROR: ui->errorMessage->setText(tr("Error") + ": " + message); - ui->errorMessage->setStyleSheet("QLabel { color: #800000 }"); + ui->errorMessage->setStyleSheet("QLabel { color: #f84444 }"); break; } /* Indicate number of bytes available */ @@ -217,13 +244,22 @@ void Intro::setStatus(int status, const QString& message, quint64 bytesAvailable ui->freeSpace->setText(freeString + "."); } /* Don't allow confirm in ERROR state */ - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status != FreespaceChecker::ST_ERROR); + ui->pushButtonOk->setEnabled(status != FreespaceChecker::ST_ERROR); +} + +void Intro::updateDataDirStatus(bool enabled){ + if(enabled){ + setCssProperty(ui->dataDirectory, "edit-primary-welcome", true); + } else { + setCssProperty(ui->dataDirectory, "edit-primary-welcome-disabled", true); + + } } void Intro::on_dataDirectory_textChanged(const QString& dataDirStr) { /* Disable OK button until check result comes in */ - ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + ui->pushButtonOk->setEnabled(false); checkPath(dataDirStr); } @@ -237,12 +273,14 @@ void Intro::on_ellipsisButton_clicked() void Intro::on_dataDirDefault_clicked() { setDataDirectory(getDefaultDataDirectory()); + updateDataDirStatus(false); } void Intro::on_dataDirCustom_clicked() { ui->dataDirectory->setEnabled(true); ui->ellipsisButton->setEnabled(true); + updateDataDirStatus(true); } void Intro::startThread() diff --git a/src/qt/intro.h b/src/qt/intro.h index ee998f094285..d958a0793699 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -73,6 +73,7 @@ private slots: void startThread(); void checkPath(const QString& dataDir); QString getPathToCheck(); + void updateDataDirStatus(bool enabled); friend class FreespaceChecker; }; diff --git a/src/qt/openuridialog.cpp b/src/qt/openuridialog.cpp index 733a0f453e95..b7f7eb6a6822 100644 --- a/src/qt/openuridialog.cpp +++ b/src/qt/openuridialog.cpp @@ -1,6 +1,4 @@ -// Copyright (c) 2011-2014 The Bitcoin developers -// Copyright (c) 2014-2015 The Dash developers -// Copyright (c) 2015-2018 The PIVX developers +// Copyright (c) 2019 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,6 +7,7 @@ #include "guiutil.h" #include "walletmodel.h" +#include "qt/pivx/qtutils.h" #include @@ -16,7 +15,26 @@ OpenURIDialog::OpenURIDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystem ui(new Ui::OpenURIDialog) { ui->setupUi(this); + this->setStyleSheet(parent->styleSheet()); ui->uriEdit->setPlaceholderText("pivx:"); + + ui->labelSubtitle->setText("URI"); + setCssProperty(ui->labelSubtitle, "text-title2-dialog"); + setCssProperty(ui->frame, "container-dialog"); + setCssProperty(ui->labelTitle, "text-title-dialog"); + + setCssBtnPrimary(ui->pushButtonOK); + setCssBtnPrimary(ui->selectFileButton); + setCssProperty(ui->pushButtonCancel, "btn-dialog-cancel"); + + initCssEditLine(ui->uriEdit, true); + connect(ui->pushButtonOK, SIGNAL(clicked()), this, SLOT(accept())); + connect(ui->pushButtonCancel, SIGNAL(clicked()), this, SLOT(close())); +} + +void OpenURIDialog::showEvent(QShowEvent *event) +{ + ui->uriEdit->setFocus(); } OpenURIDialog::~OpenURIDialog() @@ -36,7 +54,7 @@ void OpenURIDialog::accept() /* Only accept value URIs */ QDialog::accept(); } else { - ui->uriEdit->setValid(false); + setCssEditLineDialog(ui->uriEdit, false, true); } } diff --git a/src/qt/openuridialog.h b/src/qt/openuridialog.h index abe548035894..aab3ff3c4f93 100644 --- a/src/qt/openuridialog.h +++ b/src/qt/openuridialog.h @@ -1,5 +1,4 @@ -// Copyright (c) 2011-2013 The Bitcoin developers -// Copyright (c) 2017-2018 The PIVX developers +// Copyright (c) 2019 The PIVX developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -22,9 +21,10 @@ class OpenURIDialog : public QDialog ~OpenURIDialog(); QString getURI(); + void showEvent(QShowEvent *event) override; protected slots: - void accept(); + void accept() override; private slots: void on_selectFileButton_clicked(); diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp index 3018a9625ac4..90e6e9b945a2 100644 --- a/src/qt/optionsdialog.cpp +++ b/src/qt/optionsdialog.cpp @@ -47,7 +47,7 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet) : QDialog(paren ui->threadsScriptVerif->setMinimum(-(int)boost::thread::hardware_concurrency()); ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS); -/* Network elements init */ + /* Network elements init */ #ifndef USE_UPNP ui->mapPortUpnp->setEnabled(false); #endif diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 0c4653367317..2eebc29a54be 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -27,7 +27,6 @@ #endif #include -#include #include OptionsModel::OptionsModel(QObject* parent) : QAbstractListModel(parent) @@ -52,29 +51,15 @@ void OptionsModel::Init() // These are Qt-only settings: // Window - if (!settings.contains("fMinimizeToTray")) - settings.setValue("fMinimizeToTray", false); - fMinimizeToTray = settings.value("fMinimizeToTray").toBool(); - - if (!settings.contains("fMinimizeOnClose")) - settings.setValue("fMinimizeOnClose", false); - fMinimizeOnClose = settings.value("fMinimizeOnClose").toBool(); + setWindowDefaultOptions(settings); // Display - if (!settings.contains("nDisplayUnit")) - settings.setValue("nDisplayUnit", BitcoinUnits::PIV); - nDisplayUnit = settings.value("nDisplayUnit").toInt(); - - if (!settings.contains("strThirdPartyTxUrls")) - settings.setValue("strThirdPartyTxUrls", ""); - strThirdPartyTxUrls = settings.value("strThirdPartyTxUrls", "").toString(); - if (!settings.contains("fHideZeroBalances")) settings.setValue("fHideZeroBalances", true); fHideZeroBalances = settings.value("fHideZeroBalances").toBool(); if (!settings.contains("fHideOrphans")) - settings.setValue("fHideOrphans", false); + settings.setValue("fHideOrphans", true); fHideOrphans = settings.value("fHideOrphans").toBool(); if (!settings.contains("fCoinControlFeatures")) @@ -100,6 +85,27 @@ void OptionsModel::Init() if (!settings.contains("fShowMasternodesTab")) settings.setValue("fShowMasternodesTab", masternodeConfig.getCount()); + // Main + setMainDefaultOptions(settings); + +// Wallet +#ifdef ENABLE_WALLET + setWalletDefaultOptions(settings); +#endif + + // Network + setNetworkDefaultOptions(settings); + // Display + setDisplayDefaultOptions(settings); + + language = settings.value("language").toString(); +} + +void OptionsModel::refreshDataView(){ + emit dataChanged(index(0), index(rowCount(QModelIndex()) - 1)); +} + +void OptionsModel::setMainDefaultOptions(QSettings& settings, bool reset){ // These are shared with the core or have a command-line parameter // and we want command-line parameters to overwrite the GUI settings. // @@ -107,43 +113,51 @@ void OptionsModel::Init() // // If SoftSetArg() or SoftSetBoolArg() return false we were overridden // by command-line and show this in the UI. - // Main - if (!settings.contains("nDatabaseCache")) + if (!settings.contains("nDatabaseCache") || reset) settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache); if (!SoftSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString())) addOverriddenOption("-dbcache"); - if (!settings.contains("nThreadsScriptVerif")) + if (!settings.contains("nThreadsScriptVerif") || reset) settings.setValue("nThreadsScriptVerif", DEFAULT_SCRIPTCHECK_THREADS); if (!SoftSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString())) addOverriddenOption("-par"); -// Wallet -#ifdef ENABLE_WALLET - if (!settings.contains("bSpendZeroConfChange")) + if(reset){ + refreshDataView(); + } +} + +void OptionsModel::setWalletDefaultOptions(QSettings& settings, bool reset){ + if (!settings.contains("bSpendZeroConfChange") || reset) settings.setValue("bSpendZeroConfChange", false); if (!SoftSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool())) addOverriddenOption("-spendzeroconfchange"); -#endif - if (!settings.contains("nStakeSplitThreshold")) - settings.setValue("nStakeSplitThreshold", 1); + if (!settings.contains("nStakeSplitThreshold") || reset) + settings.setValue("nStakeSplitThreshold", CWallet::STAKE_SPLIT_THRESHOLD); - // Network - if (!settings.contains("fUseUPnP")) + if (reset){ + setStakeSplitThreshold(CWallet::STAKE_SPLIT_THRESHOLD); + refreshDataView(); + } +} + +void OptionsModel::setNetworkDefaultOptions(QSettings& settings, bool reset){ + if (!settings.contains("fUseUPnP") || reset) settings.setValue("fUseUPnP", DEFAULT_UPNP); if (!SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool())) addOverriddenOption("-upnp"); - if (!settings.contains("fListen")) + if (!settings.contains("fListen") || reset) settings.setValue("fListen", DEFAULT_LISTEN); if (!SoftSetBoolArg("-listen", settings.value("fListen").toBool())) addOverriddenOption("-listen"); - if (!settings.contains("fUseProxy")) + if (!settings.contains("fUseProxy") || reset) settings.setValue("fUseProxy", false); - if (!settings.contains("addrProxy")) + if (!settings.contains("addrProxy") || reset) settings.setValue("addrProxy", "127.0.0.1:9050"); // Only try to set -proxy, if user has enabled fUseProxy if (settings.value("fUseProxy").toBool() && !SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString())) @@ -151,30 +165,58 @@ void OptionsModel::Init() else if (!settings.value("fUseProxy").toBool() && !GetArg("-proxy", "").empty()) addOverriddenOption("-proxy"); - // Display - if (!settings.contains("digits")) + if(reset){ + refreshDataView(); + } +} + +void OptionsModel::setWindowDefaultOptions(QSettings& settings, bool reset){ + if (!settings.contains("fMinimizeToTray") || reset) + settings.setValue("fMinimizeToTray", false); + fMinimizeToTray = settings.value("fMinimizeToTray").toBool(); + + if (!settings.contains("fMinimizeOnClose") || reset) + settings.setValue("fMinimizeOnClose", false); + fMinimizeOnClose = settings.value("fMinimizeOnClose").toBool(); + + if(reset){ + refreshDataView(); + } +} + +void OptionsModel::setDisplayDefaultOptions(QSettings& settings, bool reset){ + if (!settings.contains("nDisplayUnit") || reset) + settings.setValue("nDisplayUnit", BitcoinUnits::PIV); + nDisplayUnit = settings.value("nDisplayUnit").toInt(); + if (!settings.contains("digits") || reset) settings.setValue("digits", "2"); - if (!settings.contains("theme")) + if (!settings.contains("theme") || reset) settings.setValue("theme", ""); - if (!settings.contains("fCSSexternal")) + if (!settings.contains("fCSSexternal") || reset) settings.setValue("fCSSexternal", false); - if (!settings.contains("language")) + if (!settings.contains("language") || reset) settings.setValue("language", ""); if (!SoftSetArg("-lang", settings.value("language").toString().toStdString())) addOverriddenOption("-lang"); - if (settings.contains("fZeromintEnable")) + if (settings.contains("fZeromintEnable") || reset) SoftSetBoolArg("-enablezeromint", settings.value("fZeromintEnable").toBool()); - if (settings.contains("fEnableAutoConvert")) + if (settings.contains("fEnableAutoConvert") || reset) SoftSetBoolArg("-enableautoconvertaddress", settings.value("fEnableAutoConvert").toBool()); - if (settings.contains("nZeromintPercentage")) + if (settings.contains("nZeromintPercentage") || reset) SoftSetArg("-zeromintpercentage", settings.value("nZeromintPercentage").toString().toStdString()); - if (settings.contains("nPreferredDenom")) + if (settings.contains("nPreferredDenom") || reset) SoftSetArg("-preferredDenom", settings.value("nPreferredDenom").toString().toStdString()); - if (settings.contains("nAnonymizePivxAmount")) + if (settings.contains("nAnonymizePivxAmount") || reset) SoftSetArg("-anonymizepivxamount", settings.value("nAnonymizePivxAmount").toString().toStdString()); - language = settings.value("language").toString(); + if (!settings.contains("strThirdPartyTxUrls") || reset) + settings.setValue("strThirdPartyTxUrls", ""); + strThirdPartyTxUrls = settings.value("strThirdPartyTxUrls", "").toString(); + + if(reset){ + refreshDataView(); + } } void OptionsModel::Reset() diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 096e3fbfca4a..13f4a5771e74 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -9,12 +9,13 @@ #include "amount.h" #include +#include QT_BEGIN_NAMESPACE class QNetworkProxy; QT_END_NAMESPACE -/** Interface from Qt to configuration data structure for Bitcoin client. +/** Interface from Qt to configuration data structure for PIVX client. To Qt, the options are presented as a list with the different options laid out vertically. This can be changed to a tree once the settings become sufficiently @@ -63,6 +64,7 @@ class OptionsModel : public QAbstractListModel int rowCount(const QModelIndex& parent = QModelIndex()) const; QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); + void refreshDataView(); /** Updates current unit in memory, settings and emits displayUnitChanged(newUnit) signal */ void setDisplayUnit(const QVariant& value); /* Update StakeSplitThreshold's value in wallet */ @@ -82,6 +84,13 @@ class OptionsModel : public QAbstractListModel bool isRestartRequired(); bool resetSettings; + // Reset + void setMainDefaultOptions(QSettings& settings, bool reset = false); + void setWalletDefaultOptions(QSettings& settings, bool reset = false); + void setNetworkDefaultOptions(QSettings& settings, bool reset = false); + void setWindowDefaultOptions(QSettings& settings, bool reset = false); + void setDisplayDefaultOptions(QSettings& settings, bool reset = false); + private: /* Qt-only settings */ bool fMinimizeToTray; diff --git a/src/qt/pivx.cpp b/src/qt/pivx.cpp index 830e8941e0ec..3be19b6834ed 100644 --- a/src/qt/pivx.cpp +++ b/src/qt/pivx.cpp @@ -8,7 +8,7 @@ #include "config/pivx-config.h" #endif -#include "bitcoingui.h" +#include "qt/pivx/pivxgui.h" #include "clientmodel.h" #include "guiconstants.h" @@ -17,7 +17,8 @@ #include "net.h" #include "networkstyle.h" #include "optionsmodel.h" -#include "splashscreen.h" +#include "qt/pivx/splash.h" +#include "qt/pivx/welcomecontentwidget.h" #include "utilitydialog.h" #include "winshutdownmonitor.h" @@ -65,6 +66,8 @@ Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); #elif defined(QT_QPA_PLATFORM_COCOA) Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin); #endif +Q_IMPORT_PLUGIN(QSvgPlugin); +Q_IMPORT_PLUGIN(QSvgIconPlugin); #endif // Declare meta types used for QMetaObject::invokeMethod @@ -191,6 +194,9 @@ class BitcoinApplication : public QApplication /// Create splash screen void createSplashScreen(const NetworkStyle* networkStyle); + /// Create tutorial screen + bool createTutorialScreen(); + /// Request core initialization void requestInitialize(); /// Request core shutdown @@ -199,7 +205,7 @@ class BitcoinApplication : public QApplication /// Get process return value int getReturnValue() { return returnValue; } - /// Get window identifier of QMainWindow (BitcoinGUI) + /// Get window identifier of QMainWindow (PIVXGUI) WId getMainWinId() const; public slots: @@ -207,6 +213,7 @@ public slots: void shutdownResult(int retval); /// Handle runaway exceptions. Shows a message box with the problem and quits the program. void handleRunawayException(const QString& message); + void updateTranslation(); signals: void requestedInitialize(); @@ -219,13 +226,14 @@ public slots: QThread* coreThread; OptionsModel* optionsModel; ClientModel* clientModel; - BitcoinGUI* window; + PIVXGUI* window; QTimer* pollShutdownTimer; #ifdef ENABLE_WALLET PaymentServer* paymentServer; WalletModel* walletModel; #endif int returnValue; + QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; void startThread(); }; @@ -348,7 +356,7 @@ void BitcoinApplication::createOptionsModel() void BitcoinApplication::createWindow(const NetworkStyle* networkStyle) { - window = new BitcoinGUI(networkStyle, 0); + window = new PIVXGUI(networkStyle, 0); pollShutdownTimer = new QTimer(window); connect(pollShutdownTimer, SIGNAL(timeout()), window, SLOT(detectShutdown())); @@ -357,7 +365,7 @@ void BitcoinApplication::createWindow(const NetworkStyle* networkStyle) void BitcoinApplication::createSplashScreen(const NetworkStyle* networkStyle) { - SplashScreen* splash = new SplashScreen(0, networkStyle); + Splash* splash = new Splash(0); // We don't hold a direct pointer to the splash screen after creation, so use // Qt::WA_DeleteOnClose to make sure that the window will be deleted eventually. splash->setAttribute(Qt::WA_DeleteOnClose); @@ -365,6 +373,27 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle* networkStyle) connect(this, SIGNAL(splashFinished(QWidget*)), splash, SLOT(slotFinish(QWidget*))); } +bool BitcoinApplication::createTutorialScreen() +{ + WelcomeContentWidget* widget = new WelcomeContentWidget(); + //widget->setOptionsModel(optionsModel); + + connect(widget, &WelcomeContentWidget::onLanguageSelected, [this](){ + std::cout << "updating translations.." << std::endl; + updateTranslation(); + }); + + widget->exec(); + bool ret = widget->isOk; + widget->deleteLater(); + return ret; +} + +void BitcoinApplication::updateTranslation(){ + // Re-initialize translations after change them + initTranslations(this->qtTranslatorBase, this->qtTranslator, this->translatorBase, this->translator); +} + void BitcoinApplication::startThread() { if (coreThread) @@ -435,8 +464,8 @@ void BitcoinApplication::initializeResult(int retval) if (pwalletMain) { walletModel = new WalletModel(pwalletMain, optionsModel); - window->addWallet(BitcoinGUI::DEFAULT_WALLET, walletModel); - window->setCurrentWallet(BitcoinGUI::DEFAULT_WALLET); + window->addWallet(PIVXGUI::DEFAULT_WALLET, walletModel); + window->setCurrentWallet(PIVXGUI::DEFAULT_WALLET); connect(walletModel, SIGNAL(coinsSent(CWallet*, SendCoinsRecipient, QByteArray)), paymentServer, SLOT(fetchPaymentACK(CWallet*, const SendCoinsRecipient&, QByteArray))); @@ -475,7 +504,7 @@ void BitcoinApplication::shutdownResult(int retval) void BitcoinApplication::handleRunawayException(const QString& message) { - QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. PIVX can no longer continue safely and will quit.") + QString("\n\n") + message); + QMessageBox::critical(0, "Runaway exception", PIVXGUI::tr("A fatal error occurred. PIVX can no longer continue safely and will quit.") + QString("\n\n") + message); ::exit(1); } @@ -530,8 +559,8 @@ int main(int argc, char* argv[]) /// 4. Initialization of translations, so that intro dialog is in user's language // Now that QSettings are accessible, initialize translations - QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator; - initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); + //initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); + app.updateTranslation(); uiInterface.Translate.connect(Translate); // Show help message immediately after parsing command-line options (for "-lang") and setting locale, @@ -583,7 +612,7 @@ int main(int argc, char* argv[]) // Allow for separate UI settings for testnets QApplication::setApplicationName(networkStyle->getAppName()); // Re-initialize translations after changing application name (language in network-specific settings can be different) - initTranslations(qtTranslatorBase, qtTranslator, translatorBase, translator); + app.updateTranslation(); #ifdef ENABLE_WALLET /// 7a. parse masternode.conf @@ -623,6 +652,27 @@ int main(int argc, char* argv[]) // Subscribe to global signals from core uiInterface.InitMessage.connect(InitMessage); + bool ret = true; +#ifdef ENABLE_WALLET + // Check if the wallet exists or need to be created + std::string strWalletFile = GetArg("-wallet", "wallet.dat"); + std::string strDataDir = GetDataDir().string(); + // Wallet file must be a plain filename without a directory + if (strWalletFile != boost::filesystem::basename(strWalletFile) + boost::filesystem::extension(strWalletFile)){ + throw std::runtime_error(strprintf(_("Wallet %s resides outside data directory %s"), strWalletFile, strDataDir)); + } + + boost::filesystem::path pathBootstrap = GetDataDir() / strWalletFile; + if (!boost::filesystem::exists(pathBootstrap)) { + // wallet doesn't exist, popup tutorial screen. + ret = app.createTutorialScreen(); + } +#endif + if(!ret){ + // wallet not loaded. + return 0; + } + if (GetBoolArg("-splash", true) && !GetBoolArg("-min", false)) app.createSplashScreen(networkStyle.data()); diff --git a/src/qt/pivx.qrc b/src/qt/pivx.qrc index 73e6db6889da..5435e6ce5683 100644 --- a/src/qt/pivx.qrc +++ b/src/qt/pivx.qrc @@ -1,4 +1,4 @@ - + res/icons/bitcoin.png res/icons/address-book.png @@ -39,6 +39,10 @@ res/icons/export.png res/icons/synced.png res/icons/remove.png + res/icons/ic-transaction-mint.svg + res/icons/ic-transaction-received.svg + res/icons/ic-transaction-sent.svg + res/icons/ic-transaction-staked.svg res/icons/tx_mined.png res/icons/tx_input.png res/icons/tx_output.png @@ -67,7 +71,9 @@ res/icons/onion.png - res/css/default.css + res/css/default.css + pivx/res/css/style_dark.css + pivx/res/css/style_light.css res/images/about.png @@ -121,4 +127,183 @@ res/movies/spinner-033.png res/movies/spinner-034.png + + pivx/res/img/bg-splash.svg + pivx/res/img/bg-splash.png + pivx/res/img/img-logo-pivx.png + pivx/res/img/img-logo-pivx@2x.png + pivx/res/img/img-logo-pivx@3x.png + pivx/res/img/img-nav-logo-pivx.png + pivx/res/img/img-qr-test-big.png + pivx/res/img/img-qr-test.png + pivx/res/img/img-welcome-step1.png + pivx/res/img/img-welcome-step2.png + pivx/res/img/img-welcome-step3.png + pivx/res/img/img-welcome-step4.png + pivx/res/img/bg-multi-number-dark.svg + pivx/res/img/bg-multi-number.svg + pivx/res/img/btn-radio-active.svg + pivx/res/img/btn-radio-off.svg + pivx/res/img/ic-add-label.svg + pivx/res/img/ic-add-liliac.svg + pivx/res/img/ic-add-purple.svg + pivx/res/img/ic-add.svg + pivx/res/img/ic-address-book-grey.svg + pivx/res/img/ic-address-book-white.svg + pivx/res/img/ic-address-book.svg + pivx/res/img/ic-address-send-white.svg + pivx/res/img/ic-address-send.svg + pivx/res/img/ic-arrow-drop-down-white.svg + pivx/res/img/ic-arrow-drop-down.svg + pivx/res/img/ic-arrow-drop-up-white.svg + pivx/res/img/ic-arrow-drop-up.svg + pivx/res/img/ic-arrow-drop-white-down.svg + pivx/res/img/ic-arrow-purple-down.svg + pivx/res/img/ic-arrow-right-white.svg + pivx/res/img/ic-arrow-right.svg + pivx/res/img/ic-arrow-left-white.svg + pivx/res/img/ic-arrow-left.svg + pivx/res/img/ic-arrow-white-left.svg + pivx/res/img/ic-arrow-white-right.svg + pivx/res/img/ic-check-active.svg + pivx/res/img/ic-check-box.svg + pivx/res/img/ic-check-box-liliac-indeterminate.svg + pivx/res/img/ic-check-connect-off.svg + pivx/res/img/ic-check-connect.svg + pivx/res/img/ic-check-dark.svg + pivx/res/img/ic-check-liliac-on.svg + pivx/res/img/ic-check-locked-off.svg + pivx/res/img/ic-check-locked.svg + pivx/res/img/ic-check-mint-off.svg + pivx/res/img/ic-check-mint.svg + pivx/res/img/ic-check-peers-off.svg + pivx/res/img/ic-check-peers.svg + pivx/res/img/ic-check-staking-off.svg + pivx/res/img/ic-check-staking.svg + pivx/res/img/ic-check-sync-off.svg + pivx/res/img/ic-check-sync.svg + pivx/res/img/ic-check-faq.svg + pivx/res/img/ic-check-theme-dark.svg + pivx/res/img/ic-check-theme-light.svg + pivx/res/img/ic-check-white.svg + pivx/res/img/ic-check.svg + pivx/res/img/ic-chevron-left.svg + pivx/res/img/ic-chevron-right.svg + pivx/res/img/ic-clear-liliac.svg + pivx/res/img/ic-clear-purple.svg + pivx/res/img/ic-close-white.svg + pivx/res/img/ic-close.svg + pivx/res/img/ic-coin-piv.svg + pivx/res/img/ic-coin-zpiv.svg + pivx/res/img/ic-combo-box.svg + pivx/res/img/ic-connect.svg + pivx/res/img/ic-copy-liliac.svg + pivx/res/img/ic-copy.svg + pivx/res/img/ic-copy-big.svg + pivx/res/img/ic-copy-big-white.svg + pivx/res/img/ic-exit.svg + pivx/res/img/ic-expand.svg + pivx/res/img/ic-folder.svg + pivx/res/img/ic-label-liliac.svg + pivx/res/img/ic-label.svg + pivx/res/img/ic-menu-hover.svg + pivx/res/img/ic-mint.svg + pivx/res/img/ic-nav-address-active.svg + pivx/res/img/ic-nav-address-hover.svg + pivx/res/img/ic-nav-address.svg + pivx/res/img/ic-nav-dashboard-active.svg + pivx/res/img/ic-nav-dashboard-hover.svg + pivx/res/img/ic-nav-dashboard.svg + pivx/res/img/ic-nav-master-active.svg + pivx/res/img/ic-nav-master-hover.svg + pivx/res/img/ic-nav-master.svg + pivx/res/img/ic-nav-privacy-active.svg + pivx/res/img/ic-nav-privacy-hover.svg + pivx/res/img/ic-nav-privacy.svg + pivx/res/img/ic-nav-receive-active.svg + pivx/res/img/ic-nav-receive-hover.svg + pivx/res/img/ic-nav-receive.svg + pivx/res/img/ic-nav-send-active.svg + pivx/res/img/ic-nav-send-hover.svg + pivx/res/img/ic-nav-send.svg + pivx/res/img/ic-nav-settings-active.svg + pivx/res/img/ic-nav-settings-hover.svg + pivx/res/img/ic-nav-settings.svg + pivx/res/img/ic-radio-liliac-on.svg + pivx/res/img/ic-receive-off.svg + pivx/res/img/ic-receive-on.svg + pivx/res/img/ic-received.svg + pivx/res/img/ic-send.svg + pivx/res/img/ic-submenu-lock.svg + pivx/res/img/ic-submenu-staking.svg + pivx/res/img/ic-submenu-unlock.svg + pivx/res/img/ic-switch-liliac-on.svg + pivx/res/img/ic-switch-off.svg + pivx/res/img/ic-switch-on.svg + pivx/res/img/ic-transaction-warning.svg + pivx/res/img/ic-transaction-mint.svg + pivx/res/img/ic-transaction-received.svg + pivx/res/img/ic-transaction-sent.svg + pivx/res/img/ic-transaction-staked.svg + pivx/res/img/dark/ic-transaction-mint.svg + pivx/res/img/dark/ic-transaction-received.svg + pivx/res/img/dark/ic-transaction-sent.svg + pivx/res/img/dark/ic-transaction-staked.svg + pivx/res/img/ic-transaction-mint-inactive.svg + pivx/res/img/ic-transaction-received-inactive.svg + pivx/res/img/ic-transaction-sent-inactive.svg + pivx/res/img/ic-transaction-staked-inactive.svg + pivx/res/img/dark/ic-transaction-mint-inactive.svg + pivx/res/img/dark/ic-transaction-received-inactive.svg + pivx/res/img/dark/ic-transaction-sent-inactive.svg + pivx/res/img/dark/ic-transaction-staked-inactive.svg + pivx/res/img/ic-unlock-staking.svg + pivx/res/img/ic-update-liliac.svg + pivx/res/img/ic-update.svg + pivx/res/img/ic-wallet-status-locked.svg + pivx/res/img/ic-wallet-status-staking.svg + pivx/res/img/ic-wallet-status-unlocked.svg + pivx/res/img/ic-watch-password-white.svg + pivx/res/img/ic-watch-password.svg + pivx/res/img/img-empty-contacts.svg + pivx/res/img/img-empty-dark-contacts.svg + pivx/res/img/img-empty-dark-error.svg + pivx/res/img/img-empty-dark-masternode.svg + pivx/res/img/img-empty-dark-multisend.svg + pivx/res/img/img-empty-dark-peers.svg + pivx/res/img/img-empty-dark-staking-on.svg + pivx/res/img/img-empty-dark-staking-off.svg + pivx/res/img/img-empty-dark-transactions.svg + pivx/res/img/img-empty-privacy-dark.svg + pivx/res/img/img-empty-error.svg + pivx/res/img/img-empty-masternode.svg + pivx/res/img/img-empty-multisend.svg + pivx/res/img/img-empty-peers.svg + pivx/res/img/img-empty-privacy.svg + pivx/res/img/img-empty-staking-off.svg + pivx/res/img/img-empty-staking-on.svg + pivx/res/img/img-empty-transactions.svg + pivx/res/img/img-nav-logo.svg + pivx/res/img/img-qr.svg + pivx/res/img/ic-contact-arrow-down.svg + pivx/res/img/ic-contact-arrow-down-white.svg + pivx/res/img/ic-arrow-drop-down-purple.svg + pivx/res/img/ic-arrow-drop-up-purple.svg + pivx/res/img/bg-welcome@2x.jpg + pivx/res/img/bg-welcome@3x.jpg + pivx/res/img/img-logo-pivx.svg + pivx/res/img/bg-welcome.svg + pivx/res/img/bg-welcome-container.svg + pivx/res/img/bg-welcome.png + pivx/res/img/bg-welcome-container.png + pivx/res/img/bg-welcome-container@2x.png + pivx/res/img/bg-welcome-container@3x.png + pivx/res/img/bg-dashboard-banner.png + pivx/res/img/ic-check-box-dark-active.svg + pivx/res/img/ic-check-box-indeterminate.svg + pivx/res/img/ic-check-liliac-indeterminate.svg + pivx/res/img/ani-loading-dark.gif + pivx/res/img/ani-loading.gif + pivx/res/img/ic-pending.svg + diff --git a/src/qt/pivx/addnewaddressdialog.cpp b/src/qt/pivx/addnewaddressdialog.cpp new file mode 100644 index 000000000000..f8076244f1ab --- /dev/null +++ b/src/qt/pivx/addnewaddressdialog.cpp @@ -0,0 +1,36 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/addnewaddressdialog.h" +#include "qt/pivx/forms/ui_addnewaddressdialog.h" + +AddNewAddressDialog::AddNewAddressDialog(QWidget *parent) : + QWidget(parent), + ui(new Ui::AddNewAddressDialog) +{ + ui->setupUi(this); + + // Stylesheet + this->setStyleSheet(parent->styleSheet()); + + // Container + + ui->frameContainer->setProperty("cssClass", "container-dialog"); + + // Title + + ui->labelTitle->setText("New Address"); + ui->labelTitle->setProperty("cssClass", "text-title-dialog"); + + // Buttons + + ui->btnCancel->setProperty("cssClass", "btn-dialog-cancel"); + ui->btnSave->setText("SAVE"); + ui->btnSave->setProperty("cssClass", "btn-primary"); +} + +AddNewAddressDialog::~AddNewAddressDialog() +{ + delete ui; +} diff --git a/src/qt/pivx/addnewaddressdialog.h b/src/qt/pivx/addnewaddressdialog.h new file mode 100644 index 000000000000..7f3bcc777eae --- /dev/null +++ b/src/qt/pivx/addnewaddressdialog.h @@ -0,0 +1,26 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ADDNEWADDRESSDIALOG_H +#define ADDNEWADDRESSDIALOG_H + +#include + +namespace Ui { +class AddNewAddressDialog; +} + +class AddNewAddressDialog : public QWidget +{ + Q_OBJECT + +public: + explicit AddNewAddressDialog(QWidget *parent = nullptr); + ~AddNewAddressDialog(); + +private: + Ui::AddNewAddressDialog *ui; +}; + +#endif // ADDNEWADDRESSDIALOG_H diff --git a/src/qt/pivx/addnewcontactdialog.cpp b/src/qt/pivx/addnewcontactdialog.cpp new file mode 100644 index 000000000000..329d851afe8e --- /dev/null +++ b/src/qt/pivx/addnewcontactdialog.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/addnewcontactdialog.h" +#include "qt/pivx/forms/ui_addnewcontactdialog.h" +#include "qt/pivx/qtutils.h" + +AddNewContactDialog::AddNewContactDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::AddNewContactDialog) +{ + ui->setupUi(this); + + // Stylesheet + this->setStyleSheet(parent->styleSheet()); + + ui->frame->setProperty("cssClass", "container-dialog"); + // Title + ui->labelTitle->setText(tr("Edit Contact")); + ui->labelTitle->setProperty("cssClass", "text-title-dialog"); + + ui->labelMessage->setText(tr("Set a label for the selected address")); + ui->labelMessage->setProperty("cssClass", "text-main-grey"); + + // Address + ui->lineEditName->setPlaceholderText(tr("Enter a name for the address (e.g Exchange)")); + initCssEditLine(ui->lineEditName, true); + + // Buttons + ui->btnEsc->setText(""); + ui->btnEsc->setProperty("cssClass", "ic-close"); + + ui->btnCancel->setProperty("cssClass", "btn-dialog-cancel"); + ui->btnOk->setText(tr("SAVE")); + ui->btnOk->setProperty("cssClass", "btn-primary"); + + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnOk, SIGNAL(clicked()), this, SLOT(ok())); +} + +void AddNewContactDialog::setTexts(QString title, const char* message) { + ui->labelTitle->setText(title); + this->message = message; +} + +void AddNewContactDialog::setData(QString address, QString label){ + ui->labelMessage->setText( + ( + !message ? + tr("Edit label for the selected address:\n%1").arg(address.toUtf8().constData()) : + tr(message).arg(address.toUtf8().constData()) + ) + ); + if (!label.isEmpty()) ui->lineEditName->setText(label); +} + +void AddNewContactDialog::ok() { + this->res = true; + accept(); +} + +QString AddNewContactDialog::getLabel(){ + return ui->lineEditName->text(); +} + +AddNewContactDialog::~AddNewContactDialog() +{ + delete ui; +} diff --git a/src/qt/pivx/addnewcontactdialog.h b/src/qt/pivx/addnewcontactdialog.h new file mode 100644 index 000000000000..827795448047 --- /dev/null +++ b/src/qt/pivx/addnewcontactdialog.h @@ -0,0 +1,35 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ADDNEWCONTACTDIALOG_H +#define ADDNEWCONTACTDIALOG_H + +#include + +namespace Ui { +class AddNewContactDialog; +} + +class AddNewContactDialog : public QDialog +{ + Q_OBJECT + +public: + explicit AddNewContactDialog(QWidget *parent = nullptr); + ~AddNewContactDialog(); + + void setTexts(QString title, const char* message = nullptr); + void setData(QString address, QString label); + QString getLabel(); + + bool res = false; + +public slots: + void ok(); +private: + Ui::AddNewContactDialog *ui; + const char* message = nullptr; +}; + +#endif // ADDNEWCONTACTDIALOG_H diff --git a/src/qt/pivx/addresseswidget.cpp b/src/qt/pivx/addresseswidget.cpp new file mode 100644 index 000000000000..44e0233c2139 --- /dev/null +++ b/src/qt/pivx/addresseswidget.cpp @@ -0,0 +1,263 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/addresseswidget.h" +#include "qt/pivx/forms/ui_addresseswidget.h" +#include "qt/pivx/addresslabelrow.h" +#include "qt/pivx/addnewaddressdialog.h" +#include "qt/pivx/tooltipmenu.h" + +#include "qt/pivx/addnewcontactdialog.h" +#include "qt/pivx/pivxgui.h" +#include "guiutil.h" +#include "qt/pivx/qtutils.h" +#include "walletmodel.h" + +#include +#include + +#define DECORATION_SIZE 60 +#define NUM_ITEMS 3 + +class ContactsHolder : public FurListRow +{ +public: + ContactsHolder(); + + explicit ContactsHolder(bool _isLightTheme) : FurListRow(), isLightTheme(_isLightTheme){} + + AddressLabelRow* createHolder(int pos) override{ + return new AddressLabelRow(isLightTheme, false); + } + + void init(QWidget* holder,const QModelIndex &index, bool isHovered, bool isSelected) const override{ + AddressLabelRow* row = static_cast(holder); + + row->updateState(isLightTheme, isHovered, isSelected); + + QString address = index.data(Qt::DisplayRole).toString(); + QModelIndex sibling = index.sibling(index.row(), AddressTableModel::Label); + QString label = sibling.data(Qt::DisplayRole).toString(); + + row->updateView(address, label); + } + + QColor rectColor(bool isHovered, bool isSelected) override{ + return getRowColor(isLightTheme, isHovered, isSelected); + } + + ~ContactsHolder() override{} + + bool isLightTheme; +}; + +#include "qt/pivx/moc_addresseswidget.cpp" + +AddressesWidget::AddressesWidget(PIVXGUI* parent) : + PWidget(parent), + ui(new Ui::AddressesWidget) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + delegate = new FurAbstractListItemDelegate( + DECORATION_SIZE, + new ContactsHolder(isLightTheme()), + this + ); + + /* Containers */ + setCssProperty(ui->left, "container"); + ui->left->setContentsMargins(0,20,0,20); + setCssProperty(ui->right, "container-right"); + ui->right->setContentsMargins(20,10,20,20); + setCssProperty(ui->listAddresses, "container"); + + // Title + ui->labelTitle->setText(tr("Contacts")); + ui->labelSubtitle1->setText(tr("You can add a new one in the options menu to the side.")); + setCssTitleScreen(ui->labelTitle); + setCssSubtitleScreen(ui->labelSubtitle1); + + // Change eddress option + ui->btnAddContact->setTitleClassAndText("btn-title-grey", "Add new contact"); + ui->btnAddContact->setSubTitleClassAndText("text-subtitle", "Generate a new address to receive tokens."); + ui->btnAddContact->setRightIconClass("ic-arrow-down"); + + // List Addresses + ui->listAddresses->setItemDelegate(delegate); + ui->listAddresses->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE)); + ui->listAddresses->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2)); + ui->listAddresses->setAttribute(Qt::WA_MacShowFocusRect, false); + ui->listAddresses->setSelectionBehavior(QAbstractItemView::SelectRows); + + //Empty List + ui->emptyContainer->setVisible(false); + setCssProperty(ui->pushImgEmpty, "img-empty-contacts"); + + ui->labelEmpty->setText(tr("No contacts yet")); + setCssProperty(ui->labelEmpty, "text-empty"); + + // Add Contact + setCssProperty(ui->layoutNewContact, "container-options"); + + // Name + ui->labelName->setText(tr("Contact name")); + setCssProperty(ui->labelName, "text-title"); + ui->lineEditName->setPlaceholderText(tr("e.g. John Doe")); + setCssEditLine(ui->lineEditName, true); + + // Address + ui->labelAddress->setText(tr("Enter a PIVX address")); + setCssProperty(ui->labelAddress, "text-title"); + ui->lineEditAddress->setPlaceholderText("e.g. D7VFR83SQbiezrW72hjc…"); + setCssEditLine(ui->lineEditAddress, true); + ui->lineEditAddress->setValidator(new QRegExpValidator(QRegExp("^[A-Za-z0-9]+"), ui->lineEditName)); + + // Buttons + ui->btnSave->setText(tr("SAVE")); + setCssBtnPrimary(ui->btnSave); + + connect(ui->listAddresses, SIGNAL(clicked(QModelIndex)), this, SLOT(handleAddressClicked(QModelIndex))); + connect(ui->btnSave, SIGNAL(clicked()), this, SLOT(onStoreContactClicked())); + connect(ui->btnAddContact, SIGNAL(clicked()), this, SLOT(onAddContactShowHideClicked())); +} + +void AddressesWidget::handleAddressClicked(const QModelIndex &index){ + ui->listAddresses->setCurrentIndex(index); + QRect rect = ui->listAddresses->visualRect(index); + QPoint pos = rect.topRight(); + pos.setX(pos.x() - (DECORATION_SIZE * 2)); + pos.setY(pos.y() + (DECORATION_SIZE)); + + QModelIndex rIndex = filter->mapToSource(index); + + if(!this->menu){ + this->menu = new TooltipMenu(window, this); + connect(this->menu, &TooltipMenu::message, this, &AddressesWidget::message); + connect(this->menu, SIGNAL(onEditClicked()), this, SLOT(onEditClicked())); + connect(this->menu, SIGNAL(onDeleteClicked()), this, SLOT(onDeleteClicked())); + connect(this->menu, SIGNAL(onCopyClicked()), this, SLOT(onCopyClicked())); + }else { + this->menu->hide(); + } + this->index = rIndex; + menu->move(pos); + menu->show(); +} + +void AddressesWidget::loadWalletModel(){ + if(walletModel) { + addressTablemodel = walletModel->getAddressTableModel(); + this->filter = new AddressFilterProxyModel(AddressTableModel::Send, this); + this->filter->setSourceModel(addressTablemodel); + ui->listAddresses->setModel(this->filter); + ui->listAddresses->setModelColumn(AddressTableModel::Address); + + updateListView(); + } +} + +void AddressesWidget::updateListView(){ + bool empty = addressTablemodel->sizeSend() == 0; + ui->emptyContainer->setVisible(empty); + ui->listAddresses->setVisible(!empty); +} + +void AddressesWidget::onStoreContactClicked(){ + if (walletModel) { + QString label = ui->lineEditName->text(); + QString address = ui->lineEditAddress->text(); + + if (!walletModel->validateAddress(address)) { + setCssEditLine(ui->lineEditAddress, false, true); + inform(tr("Invalid Contact Address")); + return; + } + + CBitcoinAddress pivAdd = CBitcoinAddress(address.toUtf8().constData()); + if (walletModel->isMine(pivAdd)) { + setCssEditLine(ui->lineEditAddress, false, true); + inform(tr("Cannot store your own address as contact")); + return; + } + + QString storedLabel = walletModel->getAddressTableModel()->labelForAddress(address); + + if(!storedLabel.isEmpty()){ + inform(tr("Address already stored, label: %1").arg("\'"+storedLabel+"\'")); + return; + } + + if (walletModel->updateAddressBookLabels(pivAdd.Get(), label.toUtf8().constData(), "send")) { + ui->lineEditAddress->setText(""); + ui->lineEditName->setText(""); + setCssEditLine(ui->lineEditAddress, true, true); + setCssEditLine(ui->lineEditName, true, true); + + if (ui->emptyContainer->isVisible()) { + ui->emptyContainer->setVisible(false); + ui->listAddresses->setVisible(true); + } + inform(tr("New Contact Stored")); + } else { + inform(tr("Error Storing Contact")); + } + } +} + +void AddressesWidget::onEditClicked(){ + QString address = index.data(Qt::DisplayRole).toString(); + QString currentLabel = index.sibling(index.row(), AddressTableModel::Label).data(Qt::DisplayRole).toString(); + showHideOp(true); + AddNewContactDialog *dialog = new AddNewContactDialog(window); + dialog->setData(address, currentLabel); + if(openDialogWithOpaqueBackground(dialog, window)){ + if(walletModel->updateAddressBookLabels( + CBitcoinAddress(address.toStdString()).Get(), dialog->getLabel().toStdString(), "send")){ + inform(tr("Contact edited")); + }else{ + inform(tr("Contact edit failed")); + } + } + dialog->deleteLater(); +} + +void AddressesWidget::onDeleteClicked(){ + if(walletModel) { + if (ask(tr("Delete Contact"), tr("You are just about to remove the contact:\n\n%1\n\nAre you sure?").arg(index.data(Qt::DisplayRole).toString().toUtf8().constData())) + ) { + if (this->walletModel->getAddressTableModel()->removeRows(index.row(), 1, index)) { + updateListView(); + inform(tr("Contact Deleted")); + } else { + inform(tr("Error deleting a contact")); + } + } + } +} + +void AddressesWidget::onCopyClicked(){ + GUIUtil::setClipboard(index.data(Qt::DisplayRole).toString()); + inform(tr("Address copied")); +} + +void AddressesWidget::onAddContactShowHideClicked(){ + if(!ui->layoutNewContact->isVisible()){ + ui->btnAddContact->setRightIconClass("btn-dropdown", true); + ui->layoutNewContact->setVisible(true); + }else { + ui->btnAddContact->setRightIconClass("ic-arrow", true); + ui->layoutNewContact->setVisible(false); + } +} + +void AddressesWidget::changeTheme(bool isLightTheme, QString& theme){ + static_cast(this->delegate->getRowFactory())->isLightTheme = isLightTheme; +} + +AddressesWidget::~AddressesWidget(){ + delete ui; +} diff --git a/src/qt/pivx/addresseswidget.h b/src/qt/pivx/addresseswidget.h new file mode 100644 index 000000000000..7801cce8a8bd --- /dev/null +++ b/src/qt/pivx/addresseswidget.h @@ -0,0 +1,65 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ADDRESSESWIDGET_H +#define ADDRESSESWIDGET_H + +#include "qt/pivx/pwidget.h" +#include "addresstablemodel.h" +#include "qt/pivx/tooltipmenu.h" +#include "furabstractlistitemdelegate.h" +#include "qt/pivx/addressfilterproxymodel.h" + +#include + +class AddressViewDelegate; +class TooltipMenu; +class PIVXGUI; +class WalletModel; + +namespace Ui { +class AddressesWidget; +} + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +class AddressesWidget : public PWidget +{ + Q_OBJECT + +public: + explicit AddressesWidget(PIVXGUI* parent); + ~AddressesWidget(); + + void loadWalletModel() override; + void onNewContactClicked(); + +private slots: + void handleAddressClicked(const QModelIndex &index); + void onStoreContactClicked(); + void onEditClicked(); + void onDeleteClicked(); + void onCopyClicked(); + void onAddContactShowHideClicked(); + + void changeTheme(bool isLightTheme, QString &theme) override; +private: + Ui::AddressesWidget *ui; + + FurAbstractListItemDelegate* delegate = nullptr; + AddressTableModel* addressTablemodel = nullptr; + AddressFilterProxyModel *filter = nullptr; + + bool isOnMyAddresses = true; + TooltipMenu* menu = nullptr; + + // Cached index + QModelIndex index; + + void updateListView(); +}; + +#endif // ADDRESSESWIDGET_H diff --git a/src/qt/pivx/addressfilterproxymodel.cpp b/src/qt/pivx/addressfilterproxymodel.cpp new file mode 100644 index 000000000000..028a14513499 --- /dev/null +++ b/src/qt/pivx/addressfilterproxymodel.cpp @@ -0,0 +1,29 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/addressfilterproxymodel.h" + +bool AddressFilterProxyModel::filterAcceptsRow(int row, const QModelIndex& parent) const +{ + auto model = sourceModel(); + auto label = model->index(row, AddressTableModel::Label, parent); + + if (model->data(label, AddressTableModel::TypeRole).toString() != m_type) { + return false; + } + + auto address = model->index(row, AddressTableModel::Address, parent); + + if (filterRegExp().indexIn(model->data(address).toString()) < 0 && + filterRegExp().indexIn(model->data(label).toString()) < 0) { + return false; + } + + return true; +} + +int AddressFilterProxyModel::rowCount(const QModelIndex& parent) const +{ + return QSortFilterProxyModel::rowCount(parent); +} diff --git a/src/qt/pivx/addressfilterproxymodel.h b/src/qt/pivx/addressfilterproxymodel.h new file mode 100644 index 000000000000..9eab4c3ea001 --- /dev/null +++ b/src/qt/pivx/addressfilterproxymodel.h @@ -0,0 +1,32 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef PIVX_CORE_NEW_GUI_ADDRESSFILTERPROXYMODEL_H +#define PIVX_CORE_NEW_GUI_ADDRESSFILTERPROXYMODEL_H + +#include +#include "addresstablemodel.h" + + +class AddressFilterProxyModel final : public QSortFilterProxyModel +{ + const QString m_type; + +public: + AddressFilterProxyModel(const QString& type, QObject* parent) + : QSortFilterProxyModel(parent) + , m_type(type) { + setDynamicSortFilter(true); + setFilterCaseSensitivity(Qt::CaseInsensitive); + setSortCaseSensitivity(Qt::CaseInsensitive); + } + + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + +protected: + bool filterAcceptsRow(int row, const QModelIndex& parent) const override; +}; + + +#endif //PIVX_CORE_NEW_GUI_ADDRESSFILTERPROXYMODEL_H diff --git a/src/qt/pivx/addresslabelrow.cpp b/src/qt/pivx/addresslabelrow.cpp new file mode 100644 index 000000000000..c7e146ea00b9 --- /dev/null +++ b/src/qt/pivx/addresslabelrow.cpp @@ -0,0 +1,48 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/addresslabelrow.h" +#include "qt/pivx/forms/ui_addresslabelrow.h" +#include "QFile" + +AddressLabelRow::AddressLabelRow(bool isLightTheme, bool isHover , QWidget *parent) : + QWidget(parent), + ui(new Ui::AddressLabelRow) +{ + ui->setupUi(this); + + ui->lblAddress->setProperty("cssClass", "text-list-body1"); + ui->lblLabel->setProperty("cssClass", "text-list-title1"); + + updateState(isLightTheme, isHover, false); +} + +void AddressLabelRow::updateView(QString address, QString label){ + ui->lblAddress->setText(address); + ui->lblLabel->setText(label); +} + +void AddressLabelRow::updateState(bool isLightTheme, bool isHovered, bool isSelected){ + if(isLightTheme) + ui->lblDivisory->setStyleSheet("background-color:#bababa"); + else + ui->lblDivisory->setStyleSheet("background-color:#40ffffff"); + + ui->btnMenu->setVisible(isHovered); +} + +void AddressLabelRow::enterEvent(QEvent *) { + ui->btnMenu->setVisible(true); + update(); +} + +void AddressLabelRow::leaveEvent(QEvent *) { + ui->btnMenu->setVisible(false); + update(); +} + +AddressLabelRow::~AddressLabelRow() +{ + delete ui; +} diff --git a/src/qt/pivx/addresslabelrow.h b/src/qt/pivx/addresslabelrow.h new file mode 100644 index 000000000000..8096a1eaf476 --- /dev/null +++ b/src/qt/pivx/addresslabelrow.h @@ -0,0 +1,32 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef ADDRESSLABELROW_H +#define ADDRESSLABELROW_H + +#include + +namespace Ui { +class AddressLabelRow; +} + +class AddressLabelRow : public QWidget +{ + Q_OBJECT + +public: + explicit AddressLabelRow(bool isLightTheme, bool isHover , QWidget *parent = nullptr); + ~AddressLabelRow(); + + void updateState(bool isLightTheme, bool isHovered, bool isSelected); + void updateView(QString address, QString label); +protected: + virtual void enterEvent(QEvent *); + virtual void leaveEvent(QEvent *); + +private: + Ui::AddressLabelRow *ui; +}; + +#endif // ADDRESSLABELROW_H diff --git a/src/qt/pivx/coincontrolpivwidget.cpp b/src/qt/pivx/coincontrolpivwidget.cpp new file mode 100644 index 000000000000..bb673015bfd3 --- /dev/null +++ b/src/qt/pivx/coincontrolpivwidget.cpp @@ -0,0 +1,89 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/coincontrolpivwidget.h" +#include "qt/pivx/forms/ui_coincontrolpivwidget.h" + +CoinControlPivWidget::CoinControlPivWidget(QWidget *parent) : + QDialog(parent), + ui(new Ui::CoinControlPivWidget) +{ + ui->setupUi(this); + + // Stylesheet + this->setStyleSheet(parent->styleSheet()); + + // Container + + ui->frameContainer->setProperty("cssClass", "container-dialog"); + ui->layoutAmount->setProperty("cssClass", "container-border-purple"); + ui->layoutAfter->setProperty("cssClass", "container-border-purple"); + ui->layoutBytes->setProperty("cssClass", "container-border-purple"); + ui->layoutChange->setProperty("cssClass", "container-border-purple"); + ui->layoutDust->setProperty("cssClass", "container-border-purple"); + ui->layoutFee->setProperty("cssClass", "container-border-purple"); + ui->layoutQuantity->setProperty("cssClass", "container-border-purple"); + + // Title + + ui->labelTitle->setText("Select PIV Outputs to Spend"); + ui->labelTitle->setProperty("cssClass", "text-title-dialog"); + + // Label Style + + ui->labelTitleAfter->setProperty("cssClass", "text-main-purple"); + ui->labelTitleAmount->setProperty("cssClass", "text-main-purple"); + ui->labelTitleAmount->setText("PIV"); + ui->labelTitleBytes->setProperty("cssClass", "text-main-purple"); + ui->labelTitleBytes->setProperty("cssClass", "text-main-purple"); + ui->labelTitleChange->setProperty("cssClass", "text-main-purple"); + ui->labelTitleType->setProperty("cssClass", "text-main-purple"); + ui->labelTitleConfirmations->setProperty("cssClass", "text-main-purple"); + ui->labelTitleDenom->setProperty("cssClass", "text-main-purple"); + ui->labelTitleDust->setProperty("cssClass", "text-main-purple"); + ui->labelTitleFee->setProperty("cssClass", "text-main-purple"); + ui->labelTitleId->setProperty("cssClass", "text-main-purple"); + ui->labelTitleQuantity->setProperty("cssClass", "text-main-purple"); + ui->labelTitleQuantity->setText("Quantity"); + ui->labelTitleSpen->setProperty("cssClass", "text-main-purple"); + ui->labelTitleVersion->setProperty("cssClass", "text-main-purple"); + + ui->labelValueAfter->setProperty("cssClass", "text-main-purple"); + ui->labelValueAmount->setProperty("cssClass", "text-main-purple"); + ui->labelValueBytes->setProperty("cssClass", "text-main-purple"); + ui->labelValueDust->setProperty("cssClass", "text-main-purple"); + ui->labelValueChange->setProperty("cssClass", "text-main-purple"); + ui->labelValueFee->setProperty("cssClass", "text-main-purple"); + ui->labelValueQuantity->setProperty("cssClass", "text-main-purple"); + + + // Values + + ui->labelValueAfter->setText("0.00 PIV"); + ui->labelValueAmount->setText("0"); + ui->labelValueBytes->setText("0"); + ui->labelValueDust->setText("No"); + ui->labelValueChange->setText("0.00 PIV"); + ui->labelValueFee->setText("0.00 PIV"); + ui->labelValueQuantity->setText("0"); + + // Buttons + + + ui->btnEsc->setText(""); + ui->btnEsc->setProperty("cssClass", "ic-close"); + + ui->btnCancel->setProperty("cssClass", "btn-dialog-cancel"); + ui->btnSave->setText("SAVE"); + ui->btnSave->setProperty("cssClass", "btn-primary"); + + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close())); + +} + +CoinControlPivWidget::~CoinControlPivWidget() +{ + delete ui; +} diff --git a/src/qt/pivx/coincontrolpivwidget.h b/src/qt/pivx/coincontrolpivwidget.h new file mode 100644 index 000000000000..0a9e86c38140 --- /dev/null +++ b/src/qt/pivx/coincontrolpivwidget.h @@ -0,0 +1,26 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef COINCONTROLPIVWIDGET_H +#define COINCONTROLPIVWIDGET_H + +#include + +namespace Ui { +class CoinControlPivWidget; +} + +class CoinControlPivWidget : public QDialog +{ + Q_OBJECT + +public: + explicit CoinControlPivWidget(QWidget *parent = nullptr); + ~CoinControlPivWidget(); + +private: + Ui::CoinControlPivWidget *ui; +}; + +#endif // COINCONTROLPIVWIDGET_H diff --git a/src/qt/pivx/contactdropdownrow.cpp b/src/qt/pivx/contactdropdownrow.cpp new file mode 100644 index 000000000000..2f52818ccce8 --- /dev/null +++ b/src/qt/pivx/contactdropdownrow.cpp @@ -0,0 +1,30 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/contactdropdownrow.h" +#include "qt/pivx/forms/ui_contactdropdownrow.h" + +ContactDropdownRow::ContactDropdownRow(bool isLightTheme, bool isHover, QWidget *parent) : + QWidget(parent), + ui(new Ui::ContactDropdownRow) +{ + ui->setupUi(this); + ui->lblAddress->setProperty("cssClass", "text-list-contact-body1"); + ui->lblLabel->setProperty("cssClass", "text-list-contact-title1"); + update(isLightTheme, isHover, false); +} + +void ContactDropdownRow::update(bool isLightTheme, bool isHover, bool isSelected){ + ui->lblDivisory->setStyleSheet("background-color:#bababa"); +} + +void ContactDropdownRow::setData(QString address, QString label){ + ui->lblAddress->setText(address); + ui->lblLabel->setText(label); +} + +ContactDropdownRow::~ContactDropdownRow() +{ + delete ui; +} diff --git a/src/qt/pivx/contactdropdownrow.h b/src/qt/pivx/contactdropdownrow.h new file mode 100644 index 000000000000..7b9017f78f95 --- /dev/null +++ b/src/qt/pivx/contactdropdownrow.h @@ -0,0 +1,29 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef CONTACTDROPDOWNROW_H +#define CONTACTDROPDOWNROW_H + +#include + +namespace Ui { +class ContactDropdownRow; +} + +class ContactDropdownRow : public QWidget +{ + Q_OBJECT + +public: + explicit ContactDropdownRow(bool isLightTheme, bool isHover, QWidget *parent = nullptr); + ~ContactDropdownRow(); + + void update(bool isLightTheme, bool isHover, bool isSelected); + void setData(QString address, QString label); + +private: + Ui::ContactDropdownRow *ui; +}; + +#endif // CONTACTDROPDOWNROW_H diff --git a/src/qt/pivx/contactsdropdown.cpp b/src/qt/pivx/contactsdropdown.cpp new file mode 100644 index 000000000000..0937e37f8606 --- /dev/null +++ b/src/qt/pivx/contactsdropdown.cpp @@ -0,0 +1,115 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/contactsdropdown.h" + +#include +#include +#include "qt/pivx/addresslabelrow.h" +#include "qt/pivx/contactdropdownrow.h" +#include "qt/pivx/qtutils.h" +#include "qt/pivx/furlistrow.h" +#include "walletmodel.h" +#include "addresstablemodel.h" + +#define DECORATION_SIZE 70 +#define NUM_ITEMS 3 + +class ContViewHolder : public FurListRow +{ +public: + ContViewHolder(); + + explicit ContViewHolder(bool _isLightTheme) : FurListRow(), isLightTheme(_isLightTheme){} + + ContactDropdownRow* createHolder(int pos) override{ + return new ContactDropdownRow(true, false); + } + + void init(QWidget* holder,const QModelIndex &index, bool isHovered, bool isSelected) const override{ + ContactDropdownRow* row = static_cast(holder); + row->update(isLightTheme, isHovered, isSelected); + QString address = index.data(Qt::DisplayRole).toString(); + QModelIndex sibling = index.sibling(index.row(), AddressTableModel::Label); + QString label = sibling.data(Qt::DisplayRole).toString(); + row->setData(address, label); + } + + QColor rectColor(bool isHovered, bool isSelected) override{ + return getRowColor(isLightTheme, isHovered, isSelected); + } + + ~ContViewHolder() override{} + + bool isLightTheme; +}; + +ContactsDropdown::ContactsDropdown(int minWidth, int minHeight, PWidget *parent) : + PWidget(parent) +{ + + this->setStyleSheet(parent->styleSheet()); + + delegate = new FurAbstractListItemDelegate( + DECORATION_SIZE, + new ContViewHolder(isLightTheme()), + this + ); + + setMinimumWidth(minWidth); + setMinimumHeight(minHeight); + setContentsMargins(0,0,0,0); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + frameList = new QFrame(this); + frameList->setProperty("cssClass", "container-border-light"); + frameList->setContentsMargins(10,10,10,10); + frameList->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + list = new QListView(frameList); + list->setMinimumWidth(minWidth); + list->setProperty("cssClass", "container-border-light"); + list->setItemDelegate(delegate); + list->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE)); + list->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2)); + list->setAttribute(Qt::WA_MacShowFocusRect, false); + list->setSelectionBehavior(QAbstractItemView::SelectRows); + + connect(list, SIGNAL(clicked(QModelIndex)), this, SLOT(handleClick(QModelIndex))); +} + +void ContactsDropdown::setWalletModel(WalletModel* _model, QString type){ + model = _model->getAddressTableModel(); + this->filter = new AddressFilterProxyModel(type, this); + this->filter->setSourceModel(model); + list->setModel(this->filter); + list->setModelColumn(AddressTableModel::Address); +} + +void ContactsDropdown::resizeList(int minWidth, int mintHeight){ + list->setMinimumWidth(minWidth); + setMinimumWidth(minWidth); + setMinimumHeight(mintHeight); + frameList->setMinimumHeight(mintHeight); + frameList->setMinimumWidth(minWidth); + list->setMinimumHeight(mintHeight); + list->resize(mintHeight,mintHeight); + list->adjustSize(); + frameList->resize(minWidth, mintHeight); + resize(minWidth, mintHeight); + adjustSize(); + update(); +} + +void ContactsDropdown::handleClick(const QModelIndex &index){ + QModelIndex rIndex = (filter) ? filter->mapToSource(index) : index; + QString address = rIndex.data(Qt::DisplayRole).toString(); + QModelIndex sibling = rIndex.sibling(rIndex.row(), AddressTableModel::Label); + QString label = sibling.data(Qt::DisplayRole).toString(); + emit contactSelected(address, label); + close(); +} + +void ContactsDropdown::changeTheme(bool isLightTheme, QString& theme){ + static_cast(this->delegate->getRowFactory())->isLightTheme = isLightTheme; +} diff --git a/src/qt/pivx/contactsdropdown.h b/src/qt/pivx/contactsdropdown.h new file mode 100644 index 000000000000..eeac0f40efab --- /dev/null +++ b/src/qt/pivx/contactsdropdown.h @@ -0,0 +1,48 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef CONTACTSDROPDOWN_H +#define CONTACTSDROPDOWN_H + +#include "addresstablemodel.h" +#include "qt/pivx/pwidget.h" +#include "qt/pivx/contactdropdownrow.h" +#include "qt/pivx/furabstractlistitemdelegate.h" +#include "qt/pivx/addressfilterproxymodel.h" +#include +#include +#include + + +class ContactsViewDelegate; +class ContViewHolder; +class WalletModel; + + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +class ContactsDropdown : public PWidget +{ + Q_OBJECT +public: + explicit ContactsDropdown(int minWidth, int minHeight, PWidget *parent = nullptr); + + void resizeList(int minWidth, int mintHeight); + void setWalletModel(WalletModel* _model, QString type); + void changeTheme(bool isLightTheme, QString& theme) override; +signals: + void contactSelected(QString address, QString label); +private: + FurAbstractListItemDelegate* delegate; + AddressTableModel* model; + AddressFilterProxyModel *filter = nullptr; + QListView *list; + QFrame *frameList; +private slots: + void handleClick(const QModelIndex &index); +}; + +#endif // CONTACTSDROPDOWN_H diff --git a/src/qt/pivx/dashboardwidget.cpp b/src/qt/pivx/dashboardwidget.cpp new file mode 100644 index 000000000000..28e03dabb8cc --- /dev/null +++ b/src/qt/pivx/dashboardwidget.cpp @@ -0,0 +1,781 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/dashboardwidget.h" +#include "qt/pivx/forms/ui_dashboardwidget.h" +#include "qt/pivx/sendconfirmdialog.h" +#include "qt/pivx/txrow.h" +#include "qt/pivx/qtutils.h" +#include "guiutil.h" +#include "walletmodel.h" +#include "clientmodel.h" +#include "optionsmodel.h" +#include "utiltime.h" +#include +#include +#include +#include + +#define DECORATION_SIZE 65 +#define NUM_ITEMS 3 +#define SHOW_EMPTY_CHART_VIEW_THRESHOLD 4000 +#define REQUEST_LOAD_TASK 1 +#define CHART_LOAD_MIN_TIME_INTERVAL 15 + +#include "moc_dashboardwidget.cpp" + +DashboardWidget::DashboardWidget(PIVXGUI* parent) : + PWidget(parent), + ui(new Ui::DashboardWidget) +{ + ui->setupUi(this); + + txHolder = new TxViewHolder(isLightTheme()); + txViewDelegate = new FurAbstractListItemDelegate( + DECORATION_SIZE, + txHolder, + this + ); + + this->setStyleSheet(parent->styleSheet()); + this->setContentsMargins(0,0,0,0); + + // Containers + setCssProperty({this, ui->left}, "container"); + ui->left->setContentsMargins(0,0,0,0); + setCssProperty(ui->right, "container-right"); + ui->right->setContentsMargins(20,20,20,0); + + // Title + ui->labelTitle2->setText(tr("Staking Rewards")); + setCssTitleScreen(ui->labelTitle); + setCssTitleScreen(ui->labelTitle2); + + /* Subtitle */ + ui->labelSubtitle->setText(tr("You can view your account's history")); + setCssSubtitleScreen(ui->labelSubtitle); + + // Staking Information + ui->labelMessage->setText(tr("Amount of PIV and zPIV staked.")); + setCssSubtitleScreen(ui->labelMessage); + setCssProperty(ui->labelSquarePiv, "square-chart-piv"); + setCssProperty(ui->labelSquarezPiv, "square-chart-zpiv"); + setCssProperty(ui->labelPiv, "text-chart-piv"); + setCssProperty(ui->labelZpiv, "text-chart-zpiv"); + + // Staking Amount + QFont fontBold; + fontBold.setWeight(QFont::Bold); + + setCssProperty(ui->labelChart, "legend-chart"); + + ui->labelAmountZpiv->setText("0 zPIV"); + ui->labelAmountPiv->setText("0 PIV"); + setCssProperty(ui->labelAmountPiv, "text-stake-piv-disable"); + setCssProperty(ui->labelAmountZpiv, "text-stake-zpiv-disable"); + + setCssProperty({ui->pushButtonAll, ui->pushButtonMonth, ui->pushButtonYear}, "btn-check-time"); + setCssProperty({ui->comboBoxMonths, ui->comboBoxYears}, "btn-combo-chart-selected"); + + ui->comboBoxMonths->setView(new QListView()); + ui->comboBoxMonths->setStyleSheet("selection-background-color:transparent; selection-color:transparent;"); + ui->comboBoxYears->setView(new QListView()); + ui->comboBoxYears->setStyleSheet("selection-background-color:transparent; selection-color:transparent;"); + ui->pushButtonYear->setChecked(true); + + setCssProperty(ui->pushButtonChartArrow, "btn-chart-arrow"); + + connect(ui->comboBoxYears, SIGNAL(currentIndexChanged(const QString&)), this,SLOT(onChartYearChanged(const QString&))); + + // Sort Transactions + SortEdit* lineEdit = new SortEdit(ui->comboBoxSort); + initComboBox(ui->comboBoxSort, lineEdit); + connect(lineEdit, &SortEdit::Mouse_Pressed, [this](){ui->comboBoxSort->showPopup();}); + ui->comboBoxSort->addItem("Date desc", SortTx::DATE_DESC); + ui->comboBoxSort->addItem("Date asc", SortTx::DATE_ASC); + ui->comboBoxSort->addItem("Amount desc", SortTx::AMOUNT_ASC); + ui->comboBoxSort->addItem("Amount asc", SortTx::AMOUNT_DESC); + connect(ui->comboBoxSort, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(onSortChanged(const QString&))); + + // Sort type + SortEdit* lineEditType = new SortEdit(ui->comboBoxSortType); + initComboBox(ui->comboBoxSortType, lineEditType); + connect(lineEditType, &SortEdit::Mouse_Pressed, [this](){ui->comboBoxSortType->showPopup();}); + + QSettings settings; + ui->comboBoxSortType->addItem(tr("All"), TransactionFilterProxy::ALL_TYPES); + ui->comboBoxSortType->addItem(tr("Received"), TransactionFilterProxy::TYPE(TransactionRecord::RecvWithAddress) | TransactionFilterProxy::TYPE(TransactionRecord::RecvFromOther)); + ui->comboBoxSortType->addItem(tr("Sent"), TransactionFilterProxy::TYPE(TransactionRecord::SendToAddress) | TransactionFilterProxy::TYPE(TransactionRecord::SendToOther)); + ui->comboBoxSortType->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated)); + ui->comboBoxSortType->addItem(tr("Minted"), TransactionFilterProxy::TYPE(TransactionRecord::StakeMint)); + ui->comboBoxSortType->addItem(tr("MN reward"), TransactionFilterProxy::TYPE(TransactionRecord::MNReward)); + ui->comboBoxSortType->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf)); + ui->comboBoxSortType->setCurrentIndex(0); + connect(ui->comboBoxSortType, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(onSortTypeChanged(const QString&))); + + // Transactions + setCssProperty(ui->listTransactions, "container"); + ui->listTransactions->setItemDelegate(txViewDelegate); + ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE)); + ui->listTransactions->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2)); + ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false); + ui->listTransactions->setSelectionBehavior(QAbstractItemView::SelectRows); + + // Sync Warning + ui->layoutWarning->setVisible(true); + ui->lblWarning->setText(tr("Please wait until the wallet is fully synced to see your correct balance")); + setCssProperty(ui->lblWarning, "text-warning"); + setCssProperty(ui->imgWarning, "ic-warning"); + + //Empty List + ui->emptyContainer->setVisible(false); + setCssProperty(ui->pushImgEmpty, "img-empty-transactions"); + + ui->labelEmpty->setText(tr("No transactions yet")); + setCssProperty(ui->labelEmpty, "text-empty"); + setCssProperty(ui->chartContainer, "container-chart"); + setCssProperty(ui->pushImgEmptyChart, "img-empty-staking-on"); + + ui->btnHowTo->setText(tr("How to get PIV or zPIV")); + setCssBtnSecondary(ui->btnHowTo); + + + setCssProperty(ui->labelEmptyChart, "text-empty"); + ui->labelMessageEmpty->setText(tr("You can verify the staking activity in the status bar at the top right of the wallet.\nIt will start automatically as soon as the wallet has enough confirmations on any unspent balances, and the wallet has synced.")); + setCssSubtitleScreen(ui->labelMessageEmpty); + + // Chart State + ui->layoutChart->setVisible(false); + ui->emptyContainerChart->setVisible(true); + setShadow(ui->layoutShadow); + + connect(ui->listTransactions, SIGNAL(clicked(QModelIndex)), this, SLOT(handleTransactionClicked(QModelIndex))); + if (window) + connect(window, SIGNAL(windowResizeEvent(QResizeEvent*)), this, SLOT(windowResizeEvent(QResizeEvent*))); + +bool hasCharts = false; +#ifdef USE_QTCHARTS + hasCharts = true; + setChartShow(YEAR); + connect(ui->pushButtonYear, &QPushButton::clicked, [this](){setChartShow(YEAR);}); + connect(ui->pushButtonMonth, &QPushButton::clicked, [this](){setChartShow(MONTH);}); + connect(ui->pushButtonAll, &QPushButton::clicked, [this](){setChartShow(ALL);}); +#endif + + if (hasCharts) { + ui->labelEmptyChart->setText(tr("You have no staking rewards")); + } else { + ui->labelEmptyChart->setText(tr("No charts library")); + } +} + +void DashboardWidget::handleTransactionClicked(const QModelIndex &index){ + + ui->listTransactions->setCurrentIndex(index); + QModelIndex rIndex = filter->mapToSource(index); + + window->showHide(true); + TxDetailDialog *dialog = new TxDetailDialog(window, false); + dialog->setData(walletModel, rIndex); + dialog->adjustSize(); + openDialogWithOpaqueBackgroundY(dialog, window, 3, 17); + + // Back to regular status + ui->listTransactions->scrollTo(index); + ui->listTransactions->clearSelection(); + ui->listTransactions->setFocus(); + dialog->deleteLater(); +} + +void DashboardWidget::loadWalletModel(){ + if (walletModel && walletModel->getOptionsModel()) { + txModel = walletModel->getTransactionTableModel(); + // Set up transaction list + filter = new TransactionFilterProxy(); + filter->setDynamicSortFilter(true); + filter->setSortCaseSensitivity(Qt::CaseInsensitive); + filter->setFilterCaseSensitivity(Qt::CaseInsensitive); + filter->setSortRole(Qt::EditRole); + filter->setSourceModel(txModel); + filter->sort(TransactionTableModel::Date, Qt::DescendingOrder); + txHolder->setFilter(filter); + ui->listTransactions->setModel(filter); + ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress); + + if(txModel->size() == 0){ + ui->emptyContainer->setVisible(true); + ui->listTransactions->setVisible(false); + ui->comboBoxSortType->setVisible(false); + ui->comboBoxSort->setVisible(false); + } + + connect(ui->pushImgEmpty, SIGNAL(clicked()), window, SLOT(openFAQ())); + connect(ui->btnHowTo, SIGNAL(clicked()), window, SLOT(openFAQ())); + connect(txModel, &TransactionTableModel::txArrived, this, &DashboardWidget::onTxArrived); + + // Notification pop-up for new transaction + connect(txModel, SIGNAL(rowsInserted(QModelIndex, int, int)), + this, SLOT(processNewTransaction(QModelIndex, int, int))); +#ifdef USE_QTCHARTS + // chart filter + stakesFilter = new TransactionFilterProxy(); + stakesFilter->setSourceModel(txModel); + stakesFilter->sort(TransactionTableModel::Date, Qt::AscendingOrder); + stakesFilter->setOnlyStakes(true); + loadChart(); +#endif + } + // update the display unit, to not use the default ("PIV") + updateDisplayUnit(); +} + +void DashboardWidget::onTxArrived(const QString& hash) { + showList(); +#ifdef USE_QTCHARTS + if (walletModel->isCoinStakeMine(hash)) + tryChartRefresh(); +#endif +} + +void DashboardWidget::showList(){ + if (ui->emptyContainer->isVisible()) { + ui->emptyContainer->setVisible(false); + ui->listTransactions->setVisible(true); + ui->comboBoxSortType->setVisible(true); + ui->comboBoxSort->setVisible(true); + } +} + +void DashboardWidget::updateDisplayUnit() { + if (walletModel && walletModel->getOptionsModel()) { + nDisplayUnit = walletModel->getOptionsModel()->getDisplayUnit(); + txHolder->setDisplayUnit(nDisplayUnit); + ui->listTransactions->update(); + } +} + +void DashboardWidget::onSortChanged(const QString& value){ + if (!filter) return; + int columnIndex = 0; + Qt::SortOrder order = Qt::DescendingOrder; + if(!value.isNull()) { + switch (ui->comboBoxSort->itemData(ui->comboBoxSort->currentIndex()).toInt()) { + case SortTx::DATE_ASC:{ + columnIndex = TransactionTableModel::Date; + order = Qt::AscendingOrder; + break; + } + case SortTx::DATE_DESC:{ + columnIndex = TransactionTableModel::Date; + break; + } + case SortTx::AMOUNT_ASC:{ + columnIndex = TransactionTableModel::Amount; + order = Qt::AscendingOrder; + break; + } + case SortTx::AMOUNT_DESC:{ + columnIndex = TransactionTableModel::Amount; + break; + } + + } + } + filter->sort(columnIndex, order); + ui->listTransactions->update(); +} + +void DashboardWidget::onSortTypeChanged(const QString& value){ + if (!filter) return; + int filterByType = ui->comboBoxSortType->itemData(ui->comboBoxSortType->currentIndex()).toInt(); + filter->setTypeFilter(filterByType); + ui->listTransactions->update(); + + if (filter->rowCount() == 0){ + ui->emptyContainer->setVisible(true); + ui->listTransactions->setVisible(false); + } else { + showList(); + } + + // Store settings + QSettings settings; + settings.setValue("transactionType", filterByType); +} + +void DashboardWidget::walletSynced(bool sync){ + if (this->isSync != sync) { + this->isSync = sync; + ui->layoutWarning->setVisible(!this->isSync); +#ifdef USE_QTCHARTS + tryChartRefresh(); +#endif + } +} + +void DashboardWidget::changeTheme(bool isLightTheme, QString& theme){ + static_cast(this->txViewDelegate->getRowFactory())->isLightTheme = isLightTheme; +#ifdef USE_QTCHARTS + if (chart) this->changeChartColors(); +#endif +} + +#ifdef USE_QTCHARTS + +void DashboardWidget::tryChartRefresh() { + if (hasStakes()) { + // Check for min update time to not reload the UI so often if the node is syncing. + int64_t now = GetTime(); + if (lastRefreshTime + CHART_LOAD_MIN_TIME_INTERVAL < now) { + lastRefreshTime = now; + refreshChart(); + } + } +} + +void DashboardWidget::setChartShow(ChartShowType type) { + this->chartShow = type; + if (chartShow == MONTH) { + ui->containerChartArrow->setVisible(true); + } else { + ui->containerChartArrow->setVisible(false); + } + if (isChartInitialized) refreshChart(); +} + +const QStringList monthsNames = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + +void DashboardWidget::loadChart(){ + if (hasStakes()) { + if (!chart) { + showHideEmptyChart(false, false); + initChart(); + QDate currentDate = QDate::currentDate(); + monthFilter = currentDate.month(); + yearFilter = currentDate.year(); + for (int i = 1; i < 13; ++i) ui->comboBoxMonths->addItem(QString(monthsNames[i-1]), QVariant(i)); + ui->comboBoxMonths->setCurrentIndex(monthFilter - 1); + connect(ui->comboBoxMonths, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(onChartMonthChanged(const QString&))); + connect(ui->pushButtonChartArrow, SIGNAL(clicked()), this, SLOT(onChartArrowClicked())); + } + refreshChart(); + changeChartColors(); + } else { + showHideEmptyChart(true, false); + } +} + +void DashboardWidget::showHideEmptyChart(bool showEmpty, bool loading, bool forceView) { + if (stakesFilter->rowCount() > SHOW_EMPTY_CHART_VIEW_THRESHOLD || forceView) { + if (!ui->layoutChart->isVisible()) { + ui->layoutChart->setVisible(!showEmpty); + ui->emptyContainerChart->setVisible(showEmpty); + } + } + ui->labelEmptyChart->setText(loading ? tr("Loading chart..") : tr("You have no staking rewards")); +} + +void DashboardWidget::initChart() { + chart = new QChart(); + axisX = new QBarCategoryAxis(); + axisY = new QValueAxis(); + + // Chart style + chart->legend()->setVisible(false); + chart->legend()->setAlignment(Qt::AlignTop); + chart->layout()->setContentsMargins(0, 0, 0, 0); + chart->setMargins({0, 0, 0, 0}); + chart->setBackgroundRoundness(0); + // Axis + chart->addAxis(axisX, Qt::AlignBottom); + chart->addAxis(axisY, Qt::AlignRight); + chart->setAnimationOptions(QChart::SeriesAnimations); + + chartView = new QChartView(chart); + chartView->setRenderHint(QPainter::Antialiasing); + chartView->setRubberBand( QChartView::HorizontalRubberBand ); + chartView->setContentsMargins(0,0,0,0); + + QHBoxLayout *baseScreensContainer = new QHBoxLayout(this); + baseScreensContainer->setMargin(0); + baseScreensContainer->addWidget(chartView); + ui->chartContainer->setLayout(baseScreensContainer); + ui->chartContainer->setContentsMargins(0,0,0,0); + setCssProperty(ui->chartContainer, "container-chart"); +} + +void DashboardWidget::changeChartColors(){ + QColor gridLineColorX; + QColor linePenColorY; + QColor backgroundColor; + QColor gridY; + if(isLightTheme()){ + gridLineColorX = QColor(255,255,255); + linePenColorY = gridLineColorX; + backgroundColor = linePenColorY; + axisY->setGridLineColor(QColor("#1a000000")); + }else{ + gridY = QColor("#40ffffff"); + axisY->setGridLineColor(gridY); + gridLineColorX = QColor(15,11,22); + linePenColorY = gridLineColorX; + backgroundColor = linePenColorY; + } + + axisX->setGridLineColor(gridLineColorX); + axisY->setLinePenColor(linePenColorY); + chart->setBackgroundBrush(QBrush(backgroundColor)); + if (set0) set0->setBorderColor(gridLineColorX); + if (set1) set1->setBorderColor(gridLineColorX); +} + +// pair PIV, zPIV +QMap> DashboardWidget::getAmountBy() { + if (chartShow != ALL) { + bool filterByMonth = false; + if (monthFilter != 0 && chartShow == MONTH) { + filterByMonth = true; + } + if (yearFilter != 0) { + if (filterByMonth) { + QDate monthFirst = QDate(yearFilter, monthFilter, 1); + stakesFilter->setDateRange( + QDateTime(monthFirst), + QDateTime(QDate(yearFilter, monthFilter, monthFirst.daysInMonth())) + ); + } else { + stakesFilter->setDateRange( + QDateTime(QDate(yearFilter, 1, 1)), + QDateTime(QDate(yearFilter, 12, 31)) + ); + } + } else if (filterByMonth) { + QDate currentDate = QDate::currentDate(); + QDate monthFirst = QDate(currentDate.year(), monthFilter, 1); + stakesFilter->setDateRange( + QDateTime(monthFirst), + QDateTime(QDate(currentDate.year(), monthFilter, monthFirst.daysInMonth())) + ); + ui->comboBoxYears->setCurrentText(QString::number(currentDate.year())); + } else { + stakesFilter->clearDateRange(); + } + } else { + stakesFilter->clearDateRange(); + } + int size = stakesFilter->rowCount(); + QMap> amountBy; + // Get all of the stakes + for (int i = 0; i < size; ++i) { + QModelIndex modelIndex = stakesFilter->index(i, TransactionTableModel::ToAddress); + qint64 amount = llabs(modelIndex.data(TransactionTableModel::AmountRole).toLongLong()); + QDate date = modelIndex.data(TransactionTableModel::DateRole).toDateTime().date(); + bool isPiv = modelIndex.data(TransactionTableModel::TypeRole).toInt() != TransactionRecord::StakeZPIV; + + int time = 0; + switch (chartShow) { + case YEAR: { + time = date.month(); + break; + } + case ALL: { + time = date.year(); + break; + } + case MONTH: { + time = date.day(); + break; + } + default: + inform(tr("Error loading chart, invalid show option")); + return amountBy; + } + if (amountBy.contains(time)) { + if (isPiv) { + amountBy[time].first += amount; + } else + amountBy[time].second += amount; + } else { + if (isPiv) { + amountBy[time] = std::make_pair(amount, 0); + } else { + amountBy[time] = std::make_pair(0, amount); + hasZpivStakes = true; + } + } + } + return amountBy; +} + +ChartData DashboardWidget::loadChartData(bool withMonthNames) { + ChartData chartData; + chartData.amountsByCache = getAmountBy(); // pair PIV, zPIV + std::pair range = getChartRange(chartData.amountsByCache); + bool isOrderedByMonth = chartShow == MONTH; + int daysInMonth = QDate(yearFilter, monthFilter, 1).daysInMonth(); + + for (int j = range.first; j < range.second; j++) { + int num = (isOrderedByMonth && j > daysInMonth) ? (j % daysInMonth) : j; + qreal piv = 0; + qreal zpiv = 0; + if (chartData.amountsByCache.contains(num)) { + std::pair pair = chartData.amountsByCache[num]; + piv = (pair.first != 0) ? pair.first / 100000000 : 0; + zpiv = (pair.second != 0) ? pair.second / 100000000 : 0; + chartData.totalPiv += pair.first; + chartData.totalZpiv += pair.second; + } + + chartData.xLabels << ((withMonthNames) ? monthsNames[num - 1] : QString::number(num)); + + chartData.valuesPiv.append(piv); + chartData.valueszPiv.append(zpiv); + + int max = std::max(piv, zpiv); + if (max > chartData.maxValue) { + chartData.maxValue = max; + } + } + return chartData; +} + +void DashboardWidget::onChartYearChanged(const QString& yearStr) { + if (isChartInitialized) { + int newYear = yearStr.toInt(); + if (newYear != yearFilter) { + yearFilter = newYear; + refreshChart(); + } + } +} + +void DashboardWidget::onChartMonthChanged(const QString& monthStr) { + if (isChartInitialized) { + int newMonth = ui->comboBoxMonths->currentData().toInt(); + if (newMonth != monthFilter) { + monthFilter = newMonth; + refreshChart(); +#ifndef Q_OS_MAC + // quick hack to re paint the chart view. + chart->removeSeries(series); + chart->addSeries(series); +#endif + } + } +} + +bool DashboardWidget::refreshChart(){ + isChartMin = width() < 1300; + isChartInitialized = false; + showHideEmptyChart(true, true); + return execute(REQUEST_LOAD_TASK); +} + +void DashboardWidget::onChartRefreshed() { + if (chart) { + if(series){ + series->clear(); + series->detachAxis(axisX); + series->detachAxis(axisY); + } + axisX->clear(); + } + // init sets + set0 = new QBarSet("PIV"); + set1 = new QBarSet("zPIV"); + set0->setColor(QColor(92,75,125)); + set1->setColor(QColor(176,136,255)); + + if(!series) { + series = new QBarSeries(); + chart->addSeries(series); + } + series->attachAxis(axisX); + series->attachAxis(axisY); + + set0->append(chartData.valuesPiv); + set1->append(chartData.valueszPiv); + + // Total + nDisplayUnit = walletModel->getOptionsModel()->getDisplayUnit(); + if (chartData.totalPiv > 0 || chartData.totalZpiv > 0) { + setCssProperty(ui->labelAmountPiv, "text-stake-piv"); + setCssProperty(ui->labelAmountZpiv, "text-stake-zpiv"); + } else { + setCssProperty(ui->labelAmountPiv, "text-stake-piv-disable"); + setCssProperty(ui->labelAmountZpiv, "text-stake-zpiv-disable"); + } + forceUpdateStyle({ui->labelAmountPiv, ui->labelAmountZpiv}); + ui->labelAmountPiv->setText(GUIUtil::formatBalance(chartData.totalPiv, nDisplayUnit)); + ui->labelAmountZpiv->setText(GUIUtil::formatBalance(chartData.totalZpiv, nDisplayUnit, true)); + + series->append(set0); + if(hasZpivStakes) + series->append(set1); + + // bar width + if (chartShow == YEAR) + series->setBarWidth(0.8); + else { + series->setBarWidth(0.3); + } + axisX->append(chartData.xLabels); + axisY->setRange(0, chartData.maxValue); + + // Controllers + switch (chartShow) { + case ALL: { + ui->container_chart_dropboxes->setVisible(false); + break; + } + case YEAR: { + ui->container_chart_dropboxes->setVisible(true); + ui->containerBoxMonths->setVisible(false); + break; + } + case MONTH: { + ui->container_chart_dropboxes->setVisible(true); + ui->containerBoxMonths->setVisible(true); + break; + } + default: break; + } + + // Refresh years filter, first address created is the start + int yearStart = QDateTime::fromTime_t(static_cast(walletModel->getCreationTime())).date().year(); + int currentYear = QDateTime::currentDateTime().date().year(); + + QString selection; + if (ui->comboBoxYears->count() > 0) { + selection = ui->comboBoxYears->currentText(); + isChartInitialized = false; + } + ui->comboBoxYears->clear(); + if (yearStart == currentYear) { + ui->comboBoxYears->addItem(QString::number(currentYear)); + } else { + for (int i = yearStart; i < (currentYear + 1); ++i)ui->comboBoxYears->addItem(QString::number(i)); + } + + if (!selection.isEmpty()) { + ui->comboBoxYears->setCurrentText(selection); + isChartInitialized = true; + } else { + ui->comboBoxYears->setCurrentText(QString::number(currentYear)); + } + + // back to normal + isChartInitialized = true; + showHideEmptyChart(false, false, true); +} + +std::pair DashboardWidget::getChartRange(QMap> amountsBy) { + switch (chartShow) { + case YEAR: + return std::make_pair(1, 13); + case ALL: { + QList keys = amountsBy.uniqueKeys(); + qSort(keys); + return std::make_pair(keys.first(), keys.last() + 1); + } + case MONTH: + return std::make_pair(dayStart, dayStart + 9); + default: + inform(tr("Error loading chart, invalid show option")); + return std::make_pair(0, 0); + } +} + +void DashboardWidget::updateAxisX(const QStringList* args) { + axisX->clear(); + QStringList months; + std::pair range = getChartRange(chartData.amountsByCache); + if (args) { + months = *args; + } else { + for (int i = range.first; i < range.second; i++) months << QString::number(i); + } + axisX->append(months); +} + +void DashboardWidget::onChartArrowClicked() { + dayStart--; + if (dayStart == 0) { + dayStart = QDate(yearFilter, monthFilter, 1).daysInMonth(); + } + refreshChart(); +} + +void DashboardWidget::windowResizeEvent(QResizeEvent *event){ + if (hasStakes() > 0 && axisX) { + if (width() > 1300) { + if (isChartMin) { + isChartMin = false; + switch (chartShow) { + case YEAR: { + updateAxisX(&monthsNames); + break; + } + case ALL: break; + case MONTH: { + updateAxisX(); + break; + } + default: + inform(tr("Error loading chart, invalid show option")); + return; + } + chartView->repaint(); + } + } else { + if (!isChartMin) { + updateAxisX(); + isChartMin = true; + } + } + } +} + +bool DashboardWidget::hasStakes() { + return stakesFilter->rowCount() > 0; +} + +#endif + +void DashboardWidget::run(int type) { +#ifdef USE_QTCHARTS + if (type == REQUEST_LOAD_TASK) { + bool withMonthNames = !isChartMin && (chartShow == YEAR); + chartData = loadChartData(withMonthNames); + QMetaObject::invokeMethod(this, "onChartRefreshed", Qt::QueuedConnection); + } +#endif +} +void DashboardWidget::onError(int type, QString error) { + inform(tr("Error loading chart: %1").arg(error)); +} + +void DashboardWidget::processNewTransaction(const QModelIndex& parent, int start, int /*end*/) { + // Prevent notifications-spam when initial block download is in progress + if (!walletModel || !clientModel || clientModel->inInitialBlockDownload()) + return; + + if (!txModel || txModel->processingQueuedTransactions()) + return; + + QString date = txModel->index(start, TransactionTableModel::Date, parent).data().toString(); + qint64 amount = txModel->index(start, TransactionTableModel::Amount, parent).data(Qt::EditRole).toULongLong(); + QString type = txModel->index(start, TransactionTableModel::Type, parent).data().toString(); + QString address = txModel->index(start, TransactionTableModel::ToAddress, parent).data().toString(); + + emit incomingTransaction(date, walletModel->getOptionsModel()->getDisplayUnit(), amount, type, address); +} + +DashboardWidget::~DashboardWidget(){ +#ifdef USE_QTCHARTS + delete chart; + quitWorker(true); +#endif + delete ui; +} diff --git a/src/qt/pivx/dashboardwidget.h b/src/qt/pivx/dashboardwidget.h new file mode 100644 index 000000000000..b35ec895d4f8 --- /dev/null +++ b/src/qt/pivx/dashboardwidget.h @@ -0,0 +1,186 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DASHBOARDWIDGET_H +#define DASHBOARDWIDGET_H + +#include "qt/pivx/pwidget.h" +#include "qt/pivx/furabstractlistitemdelegate.h" +#include "qt/pivx/furlistrow.h" +#include "transactiontablemodel.h" +#include "qt/pivx/txviewholder.h" +#include "transactionfilterproxy.h" + +#include +#include +#include +#include + +#if defined(HAVE_CONFIG_H) +#include "config/pivx-config.h" /* for USE_QTCHARTS */ +#endif + +#ifdef USE_QTCHARTS + +#include +#include +#include +#include +#include +#include + +QT_CHARTS_USE_NAMESPACE + +using namespace QtCharts; + +#endif + +class PIVXGUI; +class WalletModel; + +namespace Ui { +class DashboardWidget; +} + +class SortEdit : public QLineEdit{ + Q_OBJECT +public: + explicit SortEdit(QWidget* parent = nullptr) : QLineEdit(parent){} + + inline void mousePressEvent(QMouseEvent *) override{ + emit Mouse_Pressed(); + } + + ~SortEdit() override{} + +signals: + void Mouse_Pressed(); + +}; + +enum SortTx { + DATE_ASC = 0, + DATE_DESC = 1, + AMOUNT_ASC = 2, + AMOUNT_DESC = 3 +}; + +enum ChartShowType { + ALL, + YEAR, + MONTH, + DAY +}; + +class ChartData { +public: + ChartData() {} + + QMap> amountsByCache; + qreal maxValue = 0; + qint64 totalPiv = 0; + qint64 totalZpiv = 0; + QList valuesPiv; + QList valueszPiv; + QStringList xLabels; +}; + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +class DashboardWidget : public PWidget +{ + Q_OBJECT + +public: + explicit DashboardWidget(PIVXGUI* _window); + ~DashboardWidget(); + + void loadWalletModel() override; + void loadChart(); + + void run(int type) override; + void onError(int type, QString error) override; + +public slots: + void walletSynced(bool isSync); + /** + * Show incoming transaction notification for new transactions. + * The new items are those between start and end inclusive, under the given parent item. + */ + void processNewTransaction(const QModelIndex& parent, int start, int /*end*/); +signals: + /** Notify that a new transaction appeared */ + void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address); +private slots: + void handleTransactionClicked(const QModelIndex &index); + void changeTheme(bool isLightTheme, QString &theme) override; + void onSortChanged(const QString&); + void onSortTypeChanged(const QString& value); + void updateDisplayUnit(); + void showList(); + void onTxArrived(const QString& hash); + +#ifdef USE_QTCHARTS + void windowResizeEvent(QResizeEvent *event); + void changeChartColors(); + void onChartYearChanged(const QString&); + void onChartMonthChanged(const QString&); + void onChartArrowClicked(); +#endif + +private: + Ui::DashboardWidget *ui; + FurAbstractListItemDelegate* txViewDelegate; + TransactionFilterProxy* filter; + TxViewHolder* txHolder; + TransactionTableModel* txModel; + int nDisplayUnit = -1; + bool isSync = false; + +#ifdef USE_QTCHARTS + + int64_t lastRefreshTime = 0; + + // Chart + TransactionFilterProxy* stakesFilter = nullptr; + bool isChartInitialized = false; + QChartView *chartView = nullptr; + QBarSeries *series = nullptr; + QBarSet *set0 = nullptr; + QBarSet *set1 = nullptr; + + QBarCategoryAxis *axisX = nullptr; + QValueAxis *axisY = nullptr; + + QChart *chart = nullptr; + bool isChartMin = false; + ChartShowType chartShow = YEAR; + int yearFilter = 0; + int monthFilter = 0; + int dayStart = 1; + bool hasZpivStakes = false; + + ChartData chartData; + + void initChart(); + void showHideEmptyChart(bool show, bool loading, bool forceView = false); + bool refreshChart(); + void tryChartRefresh(); + QMap> getAmountBy(); + ChartData loadChartData(bool withMonthNames); + void updateAxisX(const QStringList *arg = nullptr); + void setChartShow(ChartShowType type); + std::pair getChartRange(QMap> amountsBy); + bool hasStakes(); + +private slots: + void onChartRefreshed(); + +#endif + +}; + +#endif // DASHBOARDWIDGET_H diff --git a/src/qt/pivx/defaultdialog.cpp b/src/qt/pivx/defaultdialog.cpp new file mode 100644 index 000000000000..a5109d6e719e --- /dev/null +++ b/src/qt/pivx/defaultdialog.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/defaultdialog.h" +#include "qt/pivx/forms/ui_defaultdialog.h" +#include "guiutil.h" +DefaultDialog::DefaultDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::DefaultDialog) +{ + ui->setupUi(this); + + // Stylesheet + this->setStyleSheet(parent ? parent->styleSheet() : GUIUtil::loadStyleSheet()); + + // Container + ui->frame->setProperty("cssClass", "container-dialog"); + + // Text + ui->labelTitle->setText("Dialog Title"); + ui->labelTitle->setProperty("cssClass", "text-title-dialog"); + + + ui->labelMessage->setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."); + ui->labelMessage->setProperty("cssClass", "text-main-grey"); + + // Buttons + ui->btnEsc->setText(""); + ui->btnEsc->setProperty("cssClass", "ic-close"); + + ui->btnCancel->setProperty("cssClass", "btn-dialog-cancel"); + ui->btnSave->setText("OK"); + ui->btnSave->setProperty("cssClass", "btn-primary"); + + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnSave, &QPushButton::clicked, [this](){this->isOk = true; accept();}); +} + +void DefaultDialog::setText(QString title, QString message, QString okBtnText, QString cancelBtnText){ + if(!okBtnText.isNull()) ui->btnSave->setText(okBtnText); + if(!cancelBtnText.isNull()){ + ui->btnCancel->setVisible(true); + ui->btnCancel->setText(cancelBtnText); + }else{ + ui->btnCancel->setVisible(false); + } + if(!message.isNull()) ui->labelMessage->setText(message); + if(!title.isNull()) ui->labelTitle->setText(title); +} + +DefaultDialog::~DefaultDialog() +{ + delete ui; +} diff --git a/src/qt/pivx/defaultdialog.h b/src/qt/pivx/defaultdialog.h new file mode 100644 index 000000000000..e7dad870ec39 --- /dev/null +++ b/src/qt/pivx/defaultdialog.h @@ -0,0 +1,29 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DEFAULTDIALOG_H +#define DEFAULTDIALOG_H + +#include + +namespace Ui { +class DefaultDialog; +} + +class DefaultDialog : public QDialog +{ + Q_OBJECT + +public: + explicit DefaultDialog(QWidget *parent = nullptr); + ~DefaultDialog(); + + void setText(QString title = "", QString message = "", QString okBtnText = "", QString cancelBtnText = ""); + + bool isOk = false; +private: + Ui::DefaultDialog *ui; +}; + +#endif // DEFAULTDIALOG_H diff --git a/src/qt/pivx/denomgenerationdialog.cpp b/src/qt/pivx/denomgenerationdialog.cpp new file mode 100644 index 000000000000..587004abe7d1 --- /dev/null +++ b/src/qt/pivx/denomgenerationdialog.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/denomgenerationdialog.h" +#include "qt/pivx/forms/ui_denomgenerationdialog.h" +#include "QGraphicsDropShadowEffect" + +DenomGenerationDialog::DenomGenerationDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::DenomGenerationDialog) +{ + ui->setupUi(this); + + + // Stylesheet + this->setStyleSheet(parent->styleSheet()); + + // Container + + ui->frame->setProperty("cssClass", "container-dialog"); + + // Text + + ui->labelTitle->setText("Denom Generation"); + ui->labelTitle->setProperty("cssClass", "text-title-dialog"); + + + ui->labelMessage->setText("This will unlock your wallet fully, so that anyone with access to it can spend until the wallet is closed or locked again."); + ui->labelMessage->setProperty("cssClass", "text-main-grey"); + + + /* Check Denom */ + + ui->checkBox5000->setText("5000"); + + ui->checkBox1000->setText("1000"); + + ui->checkBox500->setText("500"); + + ui->checkBox100->setText("100"); + + ui->checkBox50->setText("50"); + + ui->checkBox10->setText("10"); + + ui->checkBox5->setText("5"); + + ui->checkBox1->setText("1"); + + ui->checkBoxAll->setText("Select all"); + + + + // Buttons + + ui->btnEsc->setText(""); + ui->btnEsc->setProperty("cssClass", "ic-close"); + + ui->btnCancel->setProperty("cssClass", "btn-dialog-cancel"); + ui->btnSave->setText("SAVE"); + ui->btnSave->setProperty("cssClass", "btn-primary"); + + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close())); +} + +DenomGenerationDialog::~DenomGenerationDialog() +{ + delete ui; +} diff --git a/src/qt/pivx/denomgenerationdialog.h b/src/qt/pivx/denomgenerationdialog.h new file mode 100644 index 000000000000..768508a9c9d0 --- /dev/null +++ b/src/qt/pivx/denomgenerationdialog.h @@ -0,0 +1,26 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef DENOMGENERATIONDIALOG_H +#define DENOMGENERATIONDIALOG_H + +#include + +namespace Ui { +class DenomGenerationDialog; +} + +class DenomGenerationDialog : public QDialog +{ + Q_OBJECT + +public: + explicit DenomGenerationDialog(QWidget *parent = nullptr); + ~DenomGenerationDialog(); + +private: + Ui::DenomGenerationDialog *ui; +}; + +#endif // DENOMGENERATIONDIALOG_H diff --git a/src/qt/pivx/expandablebutton.cpp b/src/qt/pivx/expandablebutton.cpp new file mode 100644 index 000000000000..a1ffbc14e361 --- /dev/null +++ b/src/qt/pivx/expandablebutton.cpp @@ -0,0 +1,105 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/expandablebutton.h" +#include "qt/pivx/forms/ui_expandablebutton.h" +#include "qt/pivx/qtutils.h" +#include +#include +#include +#include + +ExpandableButton::ExpandableButton(QWidget *parent) : + QWidget(parent), + ui(new Ui::ExpandableButton), + isAnimating(false) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + ui->pushButton->setCheckable(true); + this->layout()->setSizeConstraint(QLayout::SetFixedSize); + + connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(mousePressEvent())); +} + +void ExpandableButton::setButtonClassStyle(const char *name, const QVariant &value, bool forceUpdate){ + ui->pushButton->setProperty(name, value); + if(forceUpdate){ + updateStyle(ui->pushButton); + } +} + +void ExpandableButton::setIcon(QString path){ + ui->pushButton->setIcon(QIcon(path)); +} + +void ExpandableButton::setButtonText(const QString _text){ + this->text = _text; + if(this->isExpanded){ + ui->pushButton->setText(_text); + } +} + +void ExpandableButton::setText2(QString text2) +{ + this->text = text2; + ui->pushButton->setText(text2); +} + +ExpandableButton::~ExpandableButton() +{ + delete ui; +} + +bool ExpandableButton::isChecked(){ + return ui->pushButton->isChecked(); +} + +void ExpandableButton::setChecked(bool check){ + ui->pushButton->setChecked(check); +} + +void ExpandableButton::setSmall() +{ + ui->pushButton->setText(""); + this->setMaximumWidth(36); + this->isExpanded = false; + update(); +} + +void ExpandableButton::setExpanded(){ + this->setMaximumWidth(100); + ui->pushButton->setText(text); + this->isExpanded = true; +} + +void ExpandableButton::enterEvent(QEvent *) { + if(!this->isAnimating){ + setExpanded(); + emit Mouse_Hover(); + } + update(); +} + +void ExpandableButton::leaveEvent(QEvent *) { + if(!keepExpanded){ + this->setSmall(); + } + emit Mouse_HoverLeave(); +} + +void ExpandableButton::mousePressEvent(){ + emit Mouse_Pressed(); +} + +void ExpandableButton::mousePressEvent(QMouseEvent *ev) +{ + emit Mouse_Pressed(); +} + +void ExpandableButton::on_pushButton_clicked(bool checked) +{ + // TODO: Add callback event +} diff --git a/src/qt/pivx/expandablebutton.h b/src/qt/pivx/expandablebutton.h new file mode 100644 index 000000000000..9743c5698e86 --- /dev/null +++ b/src/qt/pivx/expandablebutton.h @@ -0,0 +1,73 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef EXPANDABLEBUTTON2_H +#define EXPANDABLEBUTTON2_H + +#include +#include +#include +#include + +#include +#include + +namespace Ui { +class ExpandableButton; +} + +class ExpandableButton : public QWidget +{ + Q_OBJECT + +public: + explicit ExpandableButton(QWidget *parent = nullptr); + ~ExpandableButton(); + + void setButtonClassStyle(const char *name, const QVariant &value, bool forceUpdate = false); + void setButtonText(const QString _text); + void setIcon(QString path); + + bool isChecked(); + void setChecked(bool check); + void setKeepExpanded(bool _keepExpended){ + this->keepExpanded = _keepExpended; + } + void setSmall(); + void setExpanded(); +signals: + void Mouse_Pressed(); + void Mouse_Hover(); + void Mouse_HoverLeave(); + +public slots: + void setText2(QString text2); + + QString getText(){ + return this->text; + } + +protected: + virtual void enterEvent(QEvent *); + virtual void leaveEvent(QEvent *); + + //virtual void mouseMoveEvent(QMouseEvent *ev); + virtual void mousePressEvent(QMouseEvent *ev); + +private slots: + + void on_pushButton_clicked(bool checked); + + void mousePressEvent(); +private: + Ui::ExpandableButton *ui; + QString text; + std::atomic isAnimating; + QPropertyAnimation *animation = nullptr; + bool isExpanded = false; + + bool keepExpanded = false; +}; + +#endif // EXPANDABLEBUTTON2_H diff --git a/src/qt/pivx/forms/addnewaddressdialog.ui b/src/qt/pivx/forms/addnewaddressdialog.ui new file mode 100644 index 000000000000..790d30bcd717 --- /dev/null +++ b/src/qt/pivx/forms/addnewaddressdialog.ui @@ -0,0 +1,200 @@ + + + AddNewAddressDialog + + + + 0 + 0 + 500 + 530 + + + + Dialog + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 20 + + + 20 + + + + + My Address + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 260 + 260 + + + + + 260 + 260 + + + + + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + + D7VFR83SQbiezrW72hjcWJtcfip5krte2Z + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PushButton + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 20 + + + 20 + + + + + + 0 + 50 + + + + CANCEL + + + + + + + + 0 + 50 + + + + OK + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/addnewcontactdialog.ui b/src/qt/pivx/forms/addnewcontactdialog.ui new file mode 100644 index 000000000000..75f7c4e0f146 --- /dev/null +++ b/src/qt/pivx/forms/addnewcontactdialog.ui @@ -0,0 +1,270 @@ + + + AddNewContactDialog + + + + 0 + 0 + 600 + 350 + + + + Dialog + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 20 + + + 20 + + + 20 + + + 20 + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + TextLabel + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PushButton + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + 0 + + + 40 + + + 40 + + + + + TextLabel + + + Qt::AlignCenter + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + 10 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + CANCEL + + + + + + + + 200 + 50 + + + + OK + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/addresseswidget.ui b/src/qt/pivx/forms/addresseswidget.ui new file mode 100644 index 000000000000..76dfcaf1727f --- /dev/null +++ b/src/qt/pivx/forms/addresseswidget.ui @@ -0,0 +1,427 @@ + + + AddressesWidget + + + + 0 + 0 + 629 + 406 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 0 + + + 20 + + + 10 + + + + + 5 + + + + + Send + + + + + + + TextLabel + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + true + + + + + + + + 0 + 100 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 30 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 100 + 100 + + + + + 100 + 100 + + + + + + + + 100 + 100 + + + + + + + + + + + No active Master Node yet + + + Qt::AlignCenter + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + + + + 0 + 50 + + + + + + + + + 0 + + + 0 + + + 10 + + + 0 + + + 20 + + + + + 10 + + + + + Contact name + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 20 + + + + + + + + 10 + + + + + Enter address + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 160 + 50 + + + + OK + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + OptionButton + QWidget +
qt/pivx/optionbutton.h
+ 1 +
+
+ + +
diff --git a/src/qt/pivx/forms/addresslabelrow.ui b/src/qt/pivx/forms/addresslabelrow.ui new file mode 100644 index 000000000000..10120a8a5712 --- /dev/null +++ b/src/qt/pivx/forms/addresslabelrow.ui @@ -0,0 +1,140 @@ + + + AddressLabelRow + + + + 0 + 0 + 660 + 60 + + + + + 0 + 60 + + + + Form + + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Bob Allen + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + DN6i46dytMPVhV1JMGZFuQBh7BZZ6nNLox + + + + + + + border:none; background-color:transparent; + + + + + + + ://ic-menu-hover://ic-menu-hover + + + + 24 + 24 + + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + + + diff --git a/src/qt/pivx/forms/coincontrolpivwidget.ui b/src/qt/pivx/forms/coincontrolpivwidget.ui new file mode 100644 index 000000000000..a46f1da91b40 --- /dev/null +++ b/src/qt/pivx/forms/coincontrolpivwidget.ui @@ -0,0 +1,530 @@ + + + CoinControlPivWidget + + + + 0 + 0 + 918 + 552 + + + + Dialog + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 30 + + + 20 + + + 30 + + + 20 + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + Transaction Details + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PushButton + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + + + + PIV: + + + + + + + TextLabel + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + + Quantity: + + + + + + + TextLabel + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + + Fee: + + + + + + + TextLabel + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 15 + + + + + + + + + + Amount + + + Qt::AlignCenter + + + + + + + Label + + + Qt::AlignCenter + + + + + + + Address + + + Qt::AlignCenter + + + + + + + Type + + + Qt::AlignCenter + + + + + + + Date + + + Qt::AlignCenter + + + + + + + Confirmations + + + Qt::AlignCenter + + + + + + + + + + 1 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 10 + 30 + + + + + + + + + + CheckBox + + + + + + + + + 20 + + + + + + + + Bytes: + + + + + + + TextLabel + + + + + + + + + + + + + Dust: + + + + + + + TextLabel + + + + + + + + + + + + + Change: + + + + + + + TextLabel + + + + + + + + + + + + + After Fee: + + + + + + + TextLabel + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + CANCEL + + + + + + + + 200 + 50 + + + + OK + + + + + + + + + + + + + CoinControlTreeWidget + QTreeWidget +
coincontroltreewidget.h
+
+
+ + +
diff --git a/src/qt/pivx/forms/contactdropdownrow.ui b/src/qt/pivx/forms/contactdropdownrow.ui new file mode 100644 index 000000000000..4f6f93581824 --- /dev/null +++ b/src/qt/pivx/forms/contactdropdownrow.ui @@ -0,0 +1,118 @@ + + + ContactDropdownRow + + + + 0 + 0 + 660 + 60 + + + + + 0 + 60 + + + + Form + + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 12 + + + 12 + + + + + + + + Bob Allen + + + + + + + + + + DN6i46dytMPVhV1JMGZFuQBh7BZZ6nNLox + + + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + diff --git a/src/qt/pivx/forms/dashboardwidget.ui b/src/qt/pivx/forms/dashboardwidget.ui new file mode 100644 index 000000000000..fa19f64c0011 --- /dev/null +++ b/src/qt/pivx/forms/dashboardwidget.ui @@ -0,0 +1,1302 @@ + + + DashboardWidget + + + + 0 + 0 + 800 + 595 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 20 + + + 15 + + + 20 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 5 + + + 5 + + + + + Transactions + + + + + + + You can see here the history of your account + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 100 + 0 + + + + + + + + + 150 + 0 + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 9 + + + 20 + + + 9 + + + 20 + + + 0 + + + + + border:none; + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + border:none; + + + + + + + 24 + 24 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 12 + 20 + + + + + + + + + + + Warning + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + + + + + + true + + + QAbstractItemView::SelectItems + + + QAbstractItemView::ScrollPerItem + + + + + + + + 0 + 100 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 20 + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 30 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 100 + 100 + + + + + 100 + 100 + + + + + + + + 100 + 100 + + + + + + + + + + + No transactions + + + Qt::AlignCenter + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 280 + 50 + + + + PushButton + + + + + + + + + + + + + + 200 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 0 + + + + + 5 + + + + + + 0 + 30 + + + + Staking Rewards + + + + + + + TextLabel + + + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 20 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + 0 + + + + + TextLabel + + + Qt::AlignCenter + + + + + + + TextLabel + + + Qt::AlignCenter + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 16 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 190 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Staking statistics + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 14 + 14 + + + + + 14 + 14 + + + + + + + + + + + PIV + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + + 14 + 14 + + + + + 14 + 14 + + + + + + + + + + + zPIV + + + + + + + + + + 0 + 150 + + + + #chartContainer{padding:0px; margin:0px;} + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 25 + 0 + + + + + 25 + 16777215 + + + + #widget{ + padding:0px; + margin:0px; +} + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 127 + + + + + + + + + 20 + 20 + + + + + 20 + 20 + + + + + + + + + + + + + + + + + + 0 + 0 + + + + padding:0px; +margin:0px; + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + + + + + + 28 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 80 + + + + + 16777215 + 80 + + + + Sort by + + + + 5 + + + 0 + + + 0 + + + + + + 50 + 35 + + + + + 16777215 + 16777215 + + + + Days + + + true + + + true + + + + + + + + 50 + 35 + + + + + 16777215 + 16777215 + + + + Months + + + true + + + true + + + + + + + + 0 + 0 + + + + + 50 + 35 + + + + + 16777215 + 16777215 + + + + Years + + + true + + + true + + + true + + + + + + + + + + + 55 + 80 + + + + + 16777215 + 80 + + + + Filter by + + + + 5 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 55 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 55 + 0 + + + + + + + + + + + + 0 + 0 + + + + + 50 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 40 + 0 + + + + + + + + + + + + + + + + + + + + + 0 + 100 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 25 + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 30 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 100 + 100 + + + + + 100 + 100 + + + + + + + + 100 + 100 + + + + + + + + + + + LabelText + + + Qt::AlignCenter + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + #labelMessageEmpty { + padding-left:30px; + padding-right:30px; +} + + + TextLabel + + + Qt::AlignCenter + + + true + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/defaultdialog.ui b/src/qt/pivx/forms/defaultdialog.ui new file mode 100644 index 000000000000..9d3ebd5a9c20 --- /dev/null +++ b/src/qt/pivx/forms/defaultdialog.ui @@ -0,0 +1,259 @@ + + + DefaultDialog + + + + 0 + 0 + 500 + 350 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 30 + + + 20 + + + 30 + + + 20 + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + Transaction Details + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + Text Label + + + Qt::AlignCenter + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 10 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 170 + 50 + + + + + 170 + 16777215 + + + + CANCEL + + + + + + + + 170 + 50 + + + + + 170 + 16777215 + + + + SAVE + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/denomgenerationdialog.ui b/src/qt/pivx/forms/denomgenerationdialog.ui new file mode 100644 index 000000000000..10406a42f4ed --- /dev/null +++ b/src/qt/pivx/forms/denomgenerationdialog.ui @@ -0,0 +1,341 @@ + + + DenomGenerationDialog + + + + 0 + 0 + 500 + 450 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 30 + + + 20 + + + 30 + + + 20 + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + Transaction Details + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PushButton + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + This will unlock your wallet fully, so that anyone with access to it can spend until the wallet is closed or locked again. + + + Qt::AlignCenter + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 40 + + + + + 5000 + + + + + + + 100 + + + + + + + 10 + + + + + + + 1000 + + + + + + + 50 + + + + + + + 500 + + + + + + + 5 + + + + + + + 1 + + + + + + + Select All + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 50 + + + + CANCEL + + + + + + + + 0 + 50 + + + + SAVE + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/expandablebutton.ui b/src/qt/pivx/forms/expandablebutton.ui new file mode 100644 index 000000000000..57ea773763b3 --- /dev/null +++ b/src/qt/pivx/forms/expandablebutton.ui @@ -0,0 +1,79 @@ + + + ExpandableButton + + + + 0 + 0 + 48 + 42 + + + + + 0 + 0 + + + + + 36 + 0 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 36 + 36 + + + + + 36 + 36 + + + + padding-right:5px;padding-left:5px; + + + + + + + 32 + 32 + + + + true + + + + + + + + diff --git a/src/qt/pivx/forms/loadingdialog.ui b/src/qt/pivx/forms/loadingdialog.ui new file mode 100644 index 000000000000..6f893a41c1bb --- /dev/null +++ b/src/qt/pivx/forms/loadingdialog.ui @@ -0,0 +1,173 @@ + + + LoadingDialog + + + + 0 + 0 + 800 + 636 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 10 + + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 600 + 600 + + + + + 600 + 600 + + + + TextLabel + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Loading + + + Qt::AlignCenter + + + + + + + + 20 + 0 + + + + . + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/lockunlock.ui b/src/qt/pivx/forms/lockunlock.ui new file mode 100644 index 000000000000..b2db2f7f0637 --- /dev/null +++ b/src/qt/pivx/forms/lockunlock.ui @@ -0,0 +1,203 @@ + + + LockUnlock + + + + 0 + 0 + 528 + 141 + + + + Form + + + margin:0px; padding:0px; border:none; + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 2 + + + + + + + + + + + 36 + 36 + + + + + 16777215 + 36 + + + + + + + true + + + true + + + true + + + + + + + + + + + + 36 + 36 + + + + + 16777215 + 36 + + + + + + + true + + + true + + + + + + + + + + + + 36 + 36 + + + + + 16777215 + 36 + + + + + + + true + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 2 + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/masternodeswidget.ui b/src/qt/pivx/forms/masternodeswidget.ui new file mode 100644 index 000000000000..222ba745c458 --- /dev/null +++ b/src/qt/pivx/forms/masternodeswidget.ui @@ -0,0 +1,352 @@ + + + MasterNodesWidget + + + + 0 + 0 + 629 + 406 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + + + 0 + + + 20 + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + + + + + + + + 0 + 100 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 30 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 100 + 100 + + + + + 100 + 100 + + + + + + + + 100 + 100 + + + + + + + + + + + No active Master Node yet + + + Qt::AlignCenter + + + + + + + + + + + + + 20 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 280 + 50 + + + + + 280 + 50 + + + + PushButton + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + + + + 0 + 50 + + + + + + + + + 0 + 50 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + OptionButton + QWidget +
qt/pivx/optionbutton.h
+ 1 +
+
+ + +
diff --git a/src/qt/pivx/forms/masternodewizarddialog.ui b/src/qt/pivx/forms/masternodewizarddialog.ui new file mode 100644 index 000000000000..6fbefacfa21a --- /dev/null +++ b/src/qt/pivx/forms/masternodewizarddialog.ui @@ -0,0 +1,1075 @@ + + + MasterNodeWizardDialog + + + + 0 + 0 + 715 + 602 + + + + Dialog + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 20 + + + 20 + + + + + 0 + + + 20 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 20 + 20 + + + + + 20 + 20 + + + + + + + + + + + + + + 0 + 24 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 100 + 20 + + + + + + + + + 22 + 22 + + + + + 22 + 22 + + + + 0 + + + + + 22 + 22 + + + + + 22 + 22 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 22 + 22 + + + + + 22 + 22 + + + + 1 + + + true + + + true + + + true + + + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + + + + + + + + + + + + 22 + 22 + + + + + 22 + 22 + + + + 0 + + + + + 22 + 22 + + + + + 22 + 22 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 22 + 22 + + + + + 22 + 22 + + + + 2 + + + true + + + false + + + true + + + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + + + + + + + + + + + + 22 + 22 + + + + + 22 + 22 + + + + 0 + + + + + 22 + 22 + + + + + 22 + 22 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 22 + 22 + + + + + 22 + 22 + + + + 3 + + + true + + + false + + + true + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 100 + 20 + + + + + + + + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 70 + 20 + + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Intro + + + true + + + true + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Name + + + true + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 80 + 0 + + + + + 80 + 16777215 + + + + Address + + + true + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 70 + 20 + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 30 + + + + + + + + + 0 + 350 + + + + + 16777215 + 350 + + + + + + 6 + + + 80 + + + 12 + + + 80 + + + 12 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Create New Master Node Controller + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + <html><head/><body><p>To create a PIVX Masternode you must dedicate 10.000 PIV (the unit of PIVX) to the network (however, these coins are still yours and will never leave your possession). </p><p></p><p>You can deactivate the node and unlock the coins at any time.</p></body></html> + + + Qt::AlignHCenter|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 75 + true + + + + Make sure you have this amount of coins. + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 6 + + + 140 + + + 12 + + + 140 + + + 12 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Set Master Node’s Name + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + <html><head/><body><p>A transaction of 10,000 PIV will be made</p><p>to a new empty address in your wallet.</p><p>The Address is labeled under the master node's name.</p></body></html> + + + Qt::AlignHCenter|Qt::AlignTop + + + true + + + + + + + + + 6 + + + 140 + + + 12 + + + 140 + + + 12 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Set Master Node’s IP and port + + + + + + + Address of the node that must always be online running the actual master node. + + + Qt::AlignCenter + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Enter IP address + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 14 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + Enter Port + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 14 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 50 + + + + + 180 + 16777215 + + + + CANCEL + + + + + + + + 0 + 50 + + + + + 180 + 16777215 + + + + OK + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/mninfodialog.ui b/src/qt/pivx/forms/mninfodialog.ui new file mode 100644 index 000000000000..db41482c5f70 --- /dev/null +++ b/src/qt/pivx/forms/mninfodialog.ui @@ -0,0 +1,616 @@ + + + MnInfoDialog + + + + 0 + 0 + 574 + 700 + + + + + 574 + 530 + + + + Form + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + + + 0 + + + 20 + + + 10 + + + 20 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + Master Node Information + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + border:none; + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + + + #scrollArea { +background:transparent; +} + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustIgnored + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 570 + 596 + + + + false + + + #scrollAreaWidgetContents { +background:transparent; +} + + + + 0 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 16 + + + 0 + + + 16 + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + Public Key: + + + + + + + 492526e7fa3c810b35016...40a5df85ee227ab00b1156994 + + + + + + + + 34 + 34 + + + + + 34 + 34 + + + + + + + + 24 + 24 + + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + 0 + + + 12 + + + + + + 16777215 + 16777215 + + + + Address: + + + + + + + 127.0.0.2:43223 + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + Collaterall tx id: + + + + + + + 492526e7fa3c810b35016...40a5df85ee227ab00b1156994 + + + + + + + + 34 + 34 + + + + + 34 + 34 + + + + + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + 12 + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Output index: + + + + + + + 1 Inputs + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + Status: + + + + + + + MISSING + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + + + padding-top:1px; + + + 0 + + + Export data to run the Master Node on a remote server + + + true + + + 0 + + + + + + + + 34 + 34 + + + + + 34 + 34 + + + + + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/mnrow.ui b/src/qt/pivx/forms/mnrow.ui new file mode 100644 index 000000000000..4f2cd4381193 --- /dev/null +++ b/src/qt/pivx/forms/mnrow.ui @@ -0,0 +1,166 @@ + + + MNRow + + + + 0 + 0 + 475 + 65 + + + + Form + + + + + + + 0 + + + 20 + + + 0 + + + 20 + + + 0 + + + + + border:none; + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + + + border:none;padding:0px; + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + user_masternode + + + + + + + Address: 88.26.164.88:51474 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Jan. 19, 2019 + + + + + + + border:none; background-color:transparent; padding:0px; + + + + + + + :/ic-menu-hover:/ic-menu-hover + + + + 24 + 24 + + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + diff --git a/src/qt/pivx/forms/myaddressrow.ui b/src/qt/pivx/forms/myaddressrow.ui new file mode 100644 index 000000000000..d285bc09b6b9 --- /dev/null +++ b/src/qt/pivx/forms/myaddressrow.ui @@ -0,0 +1,74 @@ + + + MyAddressRow + + + + 0 + 0 + 400 + 60 + + + + Form + + + + 0 + + + 20 + + + 10 + + + 20 + + + 20 + + + + + + + Savings + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Jan. 19, 2019 + + + + + + + + + DN6i46dytMPVhV1JMGZFuQBh7BZZ6nNLox + + + + + + + + diff --git a/src/qt/pivx/forms/navmenuwidget.ui b/src/qt/pivx/forms/navmenuwidget.ui new file mode 100644 index 000000000000..04c06ef80640 --- /dev/null +++ b/src/qt/pivx/forms/navmenuwidget.ui @@ -0,0 +1,276 @@ + + + NavMenuWidget + + + + 0 + 0 + 102 + 706 + + + + Form + + + padding:0px; +border:none; +margin:0px; + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 10 + + + + + + 0 + 120 + + + + + + + + 64 + 64 + + + + + + + + + 100 + 80 + + + + + + + + 32 + 32 + + + + true + + + true + + + true + + + + + + + + 100 + 80 + + + + + + + + 32 + 32 + + + + true + + + true + + + + + + + + 100 + 80 + + + + + + + true + + + true + + + + + + + + 100 + 80 + + + + + + + + 32 + 32 + + + + true + + + true + + + + + + + + 100 + 80 + + + + + + + + 32 + 32 + + + + true + + + true + + + + + + + + 100 + 80 + + + + + + + + 32 + 32 + + + + true + + + true + + + + + + + + 100 + 80 + + + + + + + + 32 + 32 + + + + true + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + V 1.0.0 + + + Qt::AlignBottom|Qt::AlignHCenter + + + + + + + + + + + diff --git a/src/qt/pivx/forms/optionbutton.ui b/src/qt/pivx/forms/optionbutton.ui new file mode 100644 index 000000000000..95b2bbfba9bc --- /dev/null +++ b/src/qt/pivx/forms/optionbutton.ui @@ -0,0 +1,181 @@ + + + OptionButton + + + + 0 + 0 + 563 + 80 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 5 + + + + + 0 + + + + + + 20 + 0 + + + + + 20 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 10 + 10 + + + + + 10 + 10 + + + + + + + + + + + + + + TextLabel + + + + + + + + + TextLabel + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + 24 + 24 + + + + true + + + false + + + + + + + + + + + diff --git a/src/qt/pivx/forms/privacywidget.ui b/src/qt/pivx/forms/privacywidget.ui new file mode 100644 index 000000000000..0a9f1d1c259f --- /dev/null +++ b/src/qt/pivx/forms/privacywidget.ui @@ -0,0 +1,792 @@ + + + PrivacyWidget + + + + 0 + 0 + 629 + 549 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 0 + + + 20 + + + 20 + + + + + 0 + + + + + 5 + + + + + Title + + + + + + + + 16777215 + 16777215 + + + + TextLabel + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 120 + 30 + + + + + 120 + 30 + + + + PushButton + + + true + + + true + + + + + + + + 120 + 30 + + + + + 120 + 30 + + + + PushButton + + + true + + + true + + + true + + + + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 0 + + + + + 5 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + 0 + + + + + + 0 + 50 + + + + 8 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 180 + 50 + + + + PushButton + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 0 + + + 20 + + + + + TextLabel + + + + + + + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + true + + + Qt::NoFocus + + + + + + + + 0 + 100 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 30 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 100 + 100 + + + + + 100 + 100 + + + + + + + + 100 + 100 + + + + + + + + + + + No active Master Node yet + + + Qt::AlignCenter + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + + + + + 0 + 50 + + + + + + + + + 0 + 50 + + + + + + + + + 0 + 50 + + + + + + + + + 0 + 50 + + + + + + + + 0 + + + + + + 12 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + TextLabel + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + TextLabel + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + TextLabel + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + TextLabel + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + TextLabel + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + TextLabel + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + TextLabel + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + TextLabel + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + OptionButton + QWidget +
qt/pivx/optionbutton.h
+ 1 +
+
+ + +
diff --git a/src/qt/pivx/forms/receivedialog.ui b/src/qt/pivx/forms/receivedialog.ui new file mode 100644 index 000000000000..cb84cbade0d2 --- /dev/null +++ b/src/qt/pivx/forms/receivedialog.ui @@ -0,0 +1,285 @@ + + + ReceiveDialog + + + + 0 + 0 + 600 + 550 + + + + Dialog + + + background:white; + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 30 + + + 20 + + + 30 + + + 20 + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + Transaction Details + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PushButton + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 260 + 260 + + + + + 260 + 260 + + + + + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + D7VFR83SQbiezrW72hjcWJtcfip5krte2Z + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + 20 + + + 20 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 50 + + + + CANCEL + + + + + + + + 0 + 50 + + + + OK + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/receivewidget.ui b/src/qt/pivx/forms/receivewidget.ui new file mode 100644 index 000000000000..1d5a88974147 --- /dev/null +++ b/src/qt/pivx/forms/receivewidget.ui @@ -0,0 +1,398 @@ + + + ReceiveWidget + + + + 0 + 0 + 629 + 629 + + + + + 0 + 0 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + + + 0 + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 50 + + + + + + + + + 510 + 16777215 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 260 + 260 + + + + + 260 + 260 + + + + + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + 0 + 0 + + + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 141 + 20 + + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + 0 + 0 + + + + + 300 + 0 + + + + No address + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + Add Label + + + + + + + Generate Address + + + + + + + Copy + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + + + 6 + + + 19 + + + 19 + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + + + + OptionButton + QWidget +
qt/pivx/optionbutton.h
+ 1 +
+
+ + +
diff --git a/src/qt/pivx/forms/requestdialog.ui b/src/qt/pivx/forms/requestdialog.ui new file mode 100644 index 000000000000..6d42cfd7d2b4 --- /dev/null +++ b/src/qt/pivx/forms/requestdialog.ui @@ -0,0 +1,686 @@ + + + RequestDialog + + + + 0 + 0 + 602 + 607 + + + + Dialog + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 30 + + + 20 + + + 30 + + + 0 + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + New Request Payment + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + + + + + + + 540 + 0 + + + + + 540 + 16777215 + + + + 0 + + + + + 540 + 0 + + + + + 540 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + 400 + 50 + + + + Lorem ipsum dolor sit amet, consectur cling elit, sed do + + + Qt::AlignCenter + + + true + + + + + + + + 9 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 350 + 16 + + + + + 16777215 + 16 + + + + Amount + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + 100 + 50 + + + + + 16777215 + 50 + + + + + 0 + + + 0 + + + 0 + + + 10 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + 9 + + + + + + 0 + 16 + + + + + 16777215 + 16 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + 9 + + + + + + 0 + 16 + + + + + 16777215 + 16 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 50 + + + + + + + + + 260 + 260 + + + + + 260 + 260 + + + + + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + D7VFR83SQbiezrW72hjcWJtcfip5krte2Z + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 20 + + + + + + + + 20 + + + 20 + + + 20 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 180 + 50 + + + + COPY ADDRESS + + + + + + + + 180 + 50 + + + + COPY URL + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 20 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 180 + 50 + + + + CANCEL + + + + + + + + 180 + 50 + + + + REQUEST + + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/send.ui b/src/qt/pivx/forms/send.ui new file mode 100644 index 000000000000..8e4a05cf509c --- /dev/null +++ b/src/qt/pivx/forms/send.ui @@ -0,0 +1,788 @@ + + + send + + + + 0 + 0 + 893 + 700 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 0 + + + 20 + + + 20 + + + + + 5 + + + + + Send + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + TextLabel + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 120 + 30 + + + + + 120 + 30 + + + + PushButton + + + true + + + true + + + + + + + + 120 + 30 + + + + + 120 + 30 + + + + PushButton + + + true + + + true + + + true + + + + + + + + + + TextLabel + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 0 + + + 10 + + + 0 + + + 20 + + + 0 + + + + + margin-left:8px; + + + TextLabel + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 1 + + + + + + + + TextLabel + + + + + + + + + + 0 + 350 + + + + #scrollArea { + background:transparent; + margin-top:10px; +} + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustIgnored + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 591 + 16 + + + + + 0 + 0 + + + + false + + + #scrollAreaWidgetContents { + background:transparent; + } + + + + 0 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 6 + + + 20 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + PushButton + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 20 + 20 + + + + + + + + Qt::RightToLeft + + + PushButton + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + PushButton + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 16 + + + + + + + + 20 + + + + + 0 + + + 8 + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + + 6 + + + 12 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + + 0 + + + 20 + + + 10 + + + 20 + + + 10 + + + + + 0 + + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 1 + 0 + + + + + 1 + 16777215 + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 0 + + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + PushButton + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + + + + 0 + 50 + + + + + + + + + 0 + 50 + + + + + + + + + 0 + 50 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + PushButton + + + + + + + + + + + + + + + OptionButton + QWidget +
qt/pivx/optionbutton.h
+ 1 +
+
+ + +
diff --git a/src/qt/pivx/forms/sendchangeaddressdialog.ui b/src/qt/pivx/forms/sendchangeaddressdialog.ui new file mode 100644 index 000000000000..f7b15338f112 --- /dev/null +++ b/src/qt/pivx/forms/sendchangeaddressdialog.ui @@ -0,0 +1,269 @@ + + + SendChangeAddressDialog + + + + 0 + 0 + 500 + 400 + + + + Dialog + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 30 + + + 20 + + + 30 + + + 20 + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + Transaction Details + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PushButton + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 50 + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim. + + + Qt::AlignCenter + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 0 + + + 20 + + + 20 + + + + + + 0 + 50 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 6 + + + 30 + + + 30 + + + + + + 180 + 50 + + + + CANCEL + + + + + + + + 180 + 50 + + + + OK + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/sendconfirmdialog.ui b/src/qt/pivx/forms/sendconfirmdialog.ui new file mode 100644 index 000000000000..94ed8dd95718 --- /dev/null +++ b/src/qt/pivx/forms/sendconfirmdialog.ui @@ -0,0 +1,919 @@ + + + TxDetailDialog + + + + 0 + 0 + 574 + 680 + + + + + 574 + 455 + + + + Form + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + + + 0 + + + 20 + + + 10 + + + 20 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + Transaction Details + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + + + #scrollArea { +background:transparent; +} + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustIgnored + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 556 + 650 + + + + false + + + #scrollAreaWidgetContents { +background:transparent; +} + + + + 0 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 16 + + + 0 + + + 16 + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + ID: + + + + + + + 492526e7fa3c810b35016...40a5df85ee227ab00b1156994 + + + + + + + + 34 + 34 + + + + + 34 + 34 + + + + + + + + 24 + 24 + + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + 0 + + + 12 + + + + + + 16777215 + 16777215 + + + + Sending to: + + + + + + + D7VFR83SQbiezrW72hjcWJtcfip5krte2Z + + + + + + + + 34 + 20 + + + + + 38 + 20 + + + + + + + + + + + + + + + + + + 0 + 50 + + + + #outputsScrollArea { +background:transparent; +} + + + true + + + + + 0 + 0 + 522 + 48 + + + + #container_outputs_base { +background:transparent; +} + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + Total amount + + + + + + + 2 PIV + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + 12 + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Coin inputs: + + + + + + + 1 Inputs + + + + + + + + 34 + 20 + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 90 + + + + + QLayout::SetMaximumSize + + + 0 + + + + + Previous Transaction + + + + + + + Output Index + + + Qt::AlignCenter + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + Fee: + + + + + + + 0.0001 PIV + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + Change address: + + + + + + + D7VFR83SQbie…BhjcWJtcfip5krte2Z + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + Confirmations: + + + + + + + 12 + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + Size: + + + + + + + 2 kB + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + Date: + + + + + + + May 25, 2017 + + + + + + + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + + + + + + 0 + + + + + + 16777215 + 16777215 + + + + Status: + + + + + + + Spendable + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 10 + + + + + + + + + + + + + + + + + + + 10 + + + 20 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + CANCEL + + + + + + + + 200 + 50 + + + + OK + + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/sendcustomfeedialog.ui b/src/qt/pivx/forms/sendcustomfeedialog.ui new file mode 100644 index 000000000000..e70bb8893391 --- /dev/null +++ b/src/qt/pivx/forms/sendcustomfeedialog.ui @@ -0,0 +1,371 @@ + + + SendCustomFeeDialog + + + + 0 + 0 + 600 + 550 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 30 + + + 20 + + + 30 + + + 20 + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + Transaction Details + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Customize the transaction fee at your to your liking, depending on the fee value your transaction will be included or not in the blockchain. + + + Qt::AlignCenter + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + + + 12 + + + 12 + + + + + 5 + + + + + Recomended + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + 0.00 KB + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 5 + + + + + Custom + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + + + Per kilobyte + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 180 + 50 + + + + CANCEL + + + + + + + + 180 + 50 + + + + OK + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/sendmultirow.ui b/src/qt/pivx/forms/sendmultirow.ui new file mode 100644 index 000000000000..8a3336fdfa38 --- /dev/null +++ b/src/qt/pivx/forms/sendmultirow.ui @@ -0,0 +1,314 @@ + + + SendMultiRow + + + + 0 + 0 + 493 + 180 + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 20 + + + 5 + + + + + + 0 + 0 + + + + + 0 + 60 + + + + + 16777215 + 85 + + + + + 0 + + + 8 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + 0 + 0 + + + + + 0 + 50 + + + + + 16777215 + 55 + + + + + 0 + + + 12 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + 6 + + + + + + 0 + 0 + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + 16 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + 14 + + + 0 + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + + + + + + + + + + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + + 6 + + + 20 + + + 0 + + + 0 + + + 10 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + margin-bottom:2px; +margin-left:0.05px; +padding:0px; + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/snackbar.ui b/src/qt/pivx/forms/snackbar.ui new file mode 100644 index 000000000000..dcd1976b029f --- /dev/null +++ b/src/qt/pivx/forms/snackbar.ui @@ -0,0 +1,116 @@ + + + SnackBar + + + + 0 + 0 + 400 + 60 + + + + + 0 + 60 + + + + + 16777215 + 60 + + + + Form + + + + 0 + + + 100 + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + + + 20 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + padding-left:45px; +font-size: 15px; +color:white; + + + Contact Stored + + + Qt::AlignCenter + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + true + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/splash.ui b/src/qt/pivx/forms/splash.ui new file mode 100644 index 000000000000..08faed8cf64c --- /dev/null +++ b/src/qt/pivx/forms/splash.ui @@ -0,0 +1,215 @@ + + + Splash + + + + 0 + 0 + 1200 + 700 + + + + + 0 + 700 + + + + + 16777215 + 700 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 750 + 520 + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 300 + 100 + + + + + 300 + 100 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 0 + 30 + + + + + 16 + + + + color:white; + + + Loading… + + + Qt::AlignHCenter|Qt::AlignTop + + + + + + + + 0 + 8 + + + + + 16777215 + 8 + + + + + 0 + + + 0 + + + 4 + + + 0 + + + 0 + + + + + 24 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 8 + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/tooltipmenu.ui b/src/qt/pivx/forms/tooltipmenu.ui new file mode 100644 index 000000000000..7f22e6be9cad --- /dev/null +++ b/src/qt/pivx/forms/tooltipmenu.ui @@ -0,0 +1,153 @@ + + + TooltipMenu + + + + 0 + 0 + 90 + 110 + + + + + 90 + 110 + + + + + 16777215 + 140 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 10 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + Qt::NoFocus + + + Copy + + + + + + + + 0 + 0 + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + Qt::NoFocus + + + Edit + + + + + + + + 0 + 0 + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + Qt::NoFocus + + + Delete + + + + + + + + + + + diff --git a/src/qt/pivx/forms/topbar.ui b/src/qt/pivx/forms/topbar.ui new file mode 100644 index 000000000000..657089f053bf --- /dev/null +++ b/src/qt/pivx/forms/topbar.ui @@ -0,0 +1,701 @@ + + + TopBar + + + + 0 + 0 + 734 + 200 + + + + + 0 + 200 + + + + + 16777215 + 200 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 65 + + + + + 0 + + + 14 + + + 0 + + + 14 + + + 0 + + + + + + 0 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 36 + + + + padding:0px;margin:0px; + + + 480.0685 PIV + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 1 + 30 + + + + + 1 + 30 + + + + background-color:white; +padding:0px; +border:none; + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 36 + + + + 1,000 zPIV + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 12 + + + 0 + + + + + + 0 + 36 + + + + + 16777215 + 36 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 36 + 36 + + + + + 16777215 + 36 + + + + + + + + + + + + 36 + 36 + + + + + + + + + 36 + 36 + + + + + + + + + 36 + 36 + + + + + + + + + 0 + 0 + + + + + 36 + 0 + + + + + + + + + 36 + 36 + + + + + 16777215 + 36 + + + + + + + + + 36 + 36 + + + + + + + + + + + + + + 0 + 135 + + + + + 10 + + + 0 + + + 10 + + + 10 + + + + + 9 + + + + + 0 + + + 0 + + + 30 + + + + + + + Available + + + + + + + 480.0685 PIV + + + + + + + + + 0 + + + + + + + Pending + + + + + + + 6.943 PIV + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + Immature + + + + + + + 10 PIV + + + + + + + + + + + + + + 1 + 100 + + + + + 1 + 16777215 + + + + background-color:white; +padding:0px; +border:none; + + + + + + + + + + 0 + + + 30 + + + + + + + Available + + + + + + + 1,000 zPIV + + + + + + + + + 0 + + + + + + + Pending + + + + + + + 60 zPIV + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + + + Immature + + + + + + + 10 zPIV + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 90 + 110 + + + + + 90 + 110 + + + + + 0 + + + 5 + + + 10 + + + 5 + + + 0 + + + + + + 70 + 70 + + + + + 16777215 + 70 + + + + + + + + 70 + 70 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 36 + 36 + + + + + 36 + 36 + + + + + + + + + + + + + + + + + + + + + ExpandableButton + QWidget +
qt/pivx/expandablebutton.h
+ 1 +
+
+ + +
diff --git a/src/qt/pivx/forms/txrow.ui b/src/qt/pivx/forms/txrow.ui new file mode 100644 index 000000000000..f0fce8b17f9d --- /dev/null +++ b/src/qt/pivx/forms/txrow.ui @@ -0,0 +1,177 @@ + + + TxRow + + + + 0 + 0 + 601 + 70 + + + + + 0 + 40 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 9 + + + 20 + + + 9 + + + 20 + + + 0 + + + + + border:none; + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + border:none; + + + + + + + 24 + 24 + + + + + + + + 3 + + + 12 + + + + + + + + Received from Bob + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + + + 18/05/18 + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + + + + + +0.000585 PIV + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + background-color:#bababa; + + + + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + + + + + + + diff --git a/src/qt/pivx/forms/walletpassworddialog.ui b/src/qt/pivx/forms/walletpassworddialog.ui new file mode 100644 index 000000000000..780c730dff7f --- /dev/null +++ b/src/qt/pivx/forms/walletpassworddialog.ui @@ -0,0 +1,409 @@ + + + WalletPasswordDialog + + + + 0 + 0 + 550 + 450 + + + + Dialog + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 30 + + + 20 + + + 30 + + + 20 + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + TextLabel + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + PushButton + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 50 + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim. + + + Qt::AlignCenter + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 5 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + 5 + + + 1 + + + 1 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 15 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 180 + 50 + + + + CANCEL + + + + + + + + 180 + 50 + + + + OK + + + + + + + + + + + + + diff --git a/src/qt/pivx/forms/welcomecontentwidget.ui b/src/qt/pivx/forms/welcomecontentwidget.ui new file mode 100644 index 000000000000..b1d1b2585221 --- /dev/null +++ b/src/qt/pivx/forms/welcomecontentwidget.ui @@ -0,0 +1,1158 @@ + + + WelcomeContentWidget + + + + 0 + 0 + 1200 + 750 + + + + Dialog + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 880 + 520 + + + + + 880 + 520 + + + + + 0 + + + 30 + + + 30 + + + + + + 0 + + + 1 + + + 1 + + + 1 + + + 1 + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 14 + + + + + + + + 0 + + + 20 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 20 + 20 + + + + + 20 + 20 + + + + + + + + + + + + + + 0 + 24 + + + + + 16777215 + 24 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 140 + 20 + + + + + + + + + 22 + 22 + + + + + 22 + 22 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 22 + 22 + + + + + 22 + 22 + + + + 1 + + + true + + + true + + + true + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + + + + + + + + + + + + 22 + 22 + + + + + 22 + 22 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 22 + 22 + + + + + 22 + 22 + + + + 2 + + + true + + + false + + + true + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + + + + + + + + + + + + 22 + 22 + + + + + 22 + 22 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 22 + 22 + + + + + 22 + 22 + + + + 3 + + + true + + + false + + + true + + + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + + + + + + + + + + + + 22 + 22 + + + + + 22 + 22 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 22 + 22 + + + + + 22 + 22 + + + + 4 + + + true + + + false + + + true + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 140 + 20 + + + + + + + + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 96 + 20 + + + + + + + + + 110 + 0 + + + + + 100 + 16777215 + + + + Language + + + true + + + true + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 110 + 0 + + + + + 100 + 16777215 + + + + Welcome + + + true + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 110 + 0 + + + + + 100 + 16777215 + + + + Privacy + + + true + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 110 + 0 + + + + + 100 + 16777215 + + + + Masternodes + + + true + + + false + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 96 + 20 + + + + + + + + + + + + + + + + 40 + + + 40 + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 60 + + + + + + + + + + 6 + + + 200 + + + 12 + + + 200 + + + 12 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 60 + + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Select your language + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + 40 + + + 40 + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 60 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 16777215 + 60 + + + + padding:1px; + + + Welcome to +PIVX Core Wallet + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + PIVX is the world’s most advanced privacy-enabled Proof of Stake blockchain technology, all developed by a team of highly experienced developers and cryptographers. + + + Qt::AlignHCenter|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + 6 + + + 140 + + + 12 + + + 140 + + + 12 + + + + + Qt::Vertical + + + + 20 + 60 + + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + How PIVX respects your privacy? + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + <html><head/><body><p>As our manifesto says: Privacy is a non-negotiable basic human right; it grants users the freedom the share their data whenever and with whomever they want - PIVX believes in self sovereignty</p></body></html> + + + Qt::AlignHCenter|Qt::AlignTop + + + true + + + + + + + + + 6 + + + 140 + + + 12 + + + 140 + + + 12 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 60 + + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + What is a Masternode? + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + The masternode network is PIVX's second layer network on top of the blockchain that enables our DAO to provide decentralized governance, treasury, and SwiftX transactions. + + + Qt::AlignCenter + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/furabstractlistitemdelegate.cpp b/src/qt/pivx/furabstractlistitemdelegate.cpp new file mode 100644 index 000000000000..6cc1598cbca5 --- /dev/null +++ b/src/qt/pivx/furabstractlistitemdelegate.cpp @@ -0,0 +1,43 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/furabstractlistitemdelegate.h" +#include "qt/pivx/moc_furabstractlistitemdelegate.cpp" + +FurAbstractListItemDelegate::FurAbstractListItemDelegate(int _rowHeight, FurListRow<> *_row, QObject *parent) : + QAbstractItemDelegate(parent), rowHeight(_rowHeight), row(_row){} + +void FurAbstractListItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index ) const +{ + painter->save(); + + // Status + bool isStateSelected = option.state & QStyle::State_Selected; + bool isStateHovered = option.state & QStyle::State_MouseOver; + + QRect selectedRect = option.rect; + selectedRect.setLeft(0); + painter->fillRect(selectedRect, this->row->rectColor(isStateHovered, isStateSelected)); + + painter->translate(option.rect.topLeft()); + QWidget *row = this->row->createHolder(index.row()); + row->setStyleSheet(qobject_cast(parent())->styleSheet()); + this->row->init(row, index, isStateHovered, isStateSelected); + row->setAttribute(Qt::WA_DontShowOnScreen, true); + row->setGeometry(option.rect); + row->resize(option.rect.width(),option.rect.height()); + row->render(painter, QPoint(), QRegion(), QWidget::DrawChildren ); + + painter->restore(); +} + +FurListRow<>* FurAbstractListItemDelegate::getRowFactory(){ + return this->row; +} + +QSize FurAbstractListItemDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex&) const +{ + return QSize(rowHeight, rowHeight); +} diff --git a/src/qt/pivx/furabstractlistitemdelegate.h b/src/qt/pivx/furabstractlistitemdelegate.h new file mode 100644 index 000000000000..2b078805105f --- /dev/null +++ b/src/qt/pivx/furabstractlistitemdelegate.h @@ -0,0 +1,40 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef FURABSTRACTLISTITEMDELEGATE_H +#define FURABSTRACTLISTITEMDELEGATE_H + +#include "qt/pivx/furlistrow.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +class FurAbstractListItemDelegate : public QAbstractItemDelegate +{ + Q_OBJECT +public: + FurAbstractListItemDelegate(int _rowHeight, FurListRow<>* _row, QObject *parent=nullptr); + + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + void paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index ) const; + + FurListRow<> *getRowFactory(); +private: + int rowHeight = 0; + FurListRow<>* row = nullptr; + +}; + +#endif // FURABSTRACTLISTITEMDELEGATE_H diff --git a/src/qt/pivx/furlistrow.h b/src/qt/pivx/furlistrow.h new file mode 100644 index 000000000000..c288ed2f2a37 --- /dev/null +++ b/src/qt/pivx/furlistrow.h @@ -0,0 +1,31 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef FURLISTROW_H +#define FURLISTROW_H + +#include +#include + +template +class FurListRow{ + +public: + FurListRow(){} + virtual inline ~FurListRow(){} + + virtual inline T createHolder(int){ + return nullptr; + } + + virtual inline void init(T, const QModelIndex&, bool isHovered, bool isSelected) const{ + + } + + virtual inline QColor rectColor(bool isHovered, bool isSelected){ + return QColor(); + } +}; + +#endif // FURLISTROW_H diff --git a/src/qt/pivx/loadingdialog.cpp b/src/qt/pivx/loadingdialog.cpp new file mode 100644 index 000000000000..53d9c7973720 --- /dev/null +++ b/src/qt/pivx/loadingdialog.cpp @@ -0,0 +1,88 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/loadingdialog.h" +#include "qt/pivx/forms/ui_loadingdialog.h" +#include + +void Worker::process(){ + try { + if (runnable) + runnable->run(type); + emit finished(); + } catch (std::exception& e) { + std::cout << e.what() << std::endl; + emit error(QString::fromStdString(e.what())); + } +}; + +LoadingDialog::LoadingDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::LoadingDialog) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + ui->frame->setProperty("cssClass", "container-loading"); + + QMovie *movie = new QMovie("://ani-loading-dark"); + ui->labelMovie->setText(""); + ui->labelMovie->setMovie(movie); + movie->start(); + + ui->labelMessage->setText(tr("Loading")); + ui->labelMessage->setProperty("cssClass", "text-loading"); + ui->labelDots->setProperty("cssClass", "text-loading"); +} + +void LoadingDialog::execute(Runnable *runnable, int type){ + loadingTimer = new QTimer(this); + connect(loadingTimer, SIGNAL(timeout()), this, SLOT(loadingTextChange())); + loadingTimer->start(250); + + QThread* thread = new QThread; + Worker* worker = new Worker(runnable, type); + worker->moveToThread(thread); + connect(worker, SIGNAL (error(QString)), this, SLOT (errorString(QString))); + connect(thread, SIGNAL (started()), worker, SLOT (process())); + connect(worker, SIGNAL (finished()), thread, SLOT (quit())); + connect(worker, SIGNAL (finished()), worker, SLOT (deleteLater())); + connect(thread, SIGNAL (finished()), thread, SLOT (deleteLater())); + connect(worker, SIGNAL (finished()), this, SLOT (finished())); + thread->start(); +} + +void LoadingDialog::loadingTextChange(){ + if (loading == 4) { + loading = 0; + } else { + loading++; + } + switch (loading) { + case 1: + ui->labelDots->setText(""); + break; + case 2: + ui->labelDots->setText("."); + break; + case 3: + ui->labelDots->setText(".."); + break; + case 4: + ui->labelDots->setText("..."); + break; + } +} + +void LoadingDialog::finished(){ + loadingTimer->stop(); + accept(); + deleteLater(); +} + +LoadingDialog::~LoadingDialog() +{ + delete ui; +} diff --git a/src/qt/pivx/loadingdialog.h b/src/qt/pivx/loadingdialog.h new file mode 100644 index 000000000000..262d0b52cce0 --- /dev/null +++ b/src/qt/pivx/loadingdialog.h @@ -0,0 +1,55 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef LOADINGDIALOG_H +#define LOADINGDIALOG_H + +#include +#include +#include +#include +#include "qt/pivx/prunnable.h" + +namespace Ui { +class LoadingDialog; +} + +class Worker : public QObject { + Q_OBJECT +public: + Worker(Runnable* runnable, int type):runnable(runnable), type(type){} + ~Worker(){} +public slots: + void process(); +signals: + void finished(); + void error(QString err); + +private: + Runnable* runnable; + int type; +}; + +class LoadingDialog : public QDialog +{ + Q_OBJECT + +public: + explicit LoadingDialog(QWidget *parent = nullptr); + ~LoadingDialog(); + + + void execute(Runnable *runnable, int type); + +public slots: + void finished(); + void loadingTextChange(); + +private: + Ui::LoadingDialog *ui; + QTimer *loadingTimer = nullptr; + int loading = 0; +}; + +#endif // LOADINGDIALOG_H diff --git a/src/qt/pivx/lockunlock.cpp b/src/qt/pivx/lockunlock.cpp new file mode 100644 index 000000000000..f6048342b766 --- /dev/null +++ b/src/qt/pivx/lockunlock.cpp @@ -0,0 +1,92 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/lockunlock.h" +#include "qt/pivx/forms/ui_lockunlock.h" + +LockUnlock::LockUnlock(QWidget *parent) : + QWidget(parent), + ui(new Ui::LockUnlock) +{ + ui->setupUi(this); + + // Load css. + this->setStyleSheet(parent->styleSheet()); + + ui->container->setProperty("cssClass", "top-sub-menu"); + + ui->pushButtonUnlocked->setProperty("cssClass", "btn-check-lock-sub-menu-unlocked"); + ui->pushButtonUnlocked->setStyleSheet("padding-left: 34px;"); + ui->pushButtonLocked->setProperty("cssClass", "btn-check-lock-sub-menu-locked"); + ui->pushButtonLocked->setStyleSheet("padding-left: 34px;"); + ui->pushButtonStaking->setProperty("cssClass", "btn-check-lock-sub-menu-staking"); + ui->pushButtonStaking->setStyleSheet("padding-left: 34px;"); + + ui->pushButtonUnlocked->setText(tr("Unlock Wallet")); + ui->pushButtonLocked->setText(tr("Lock Wallet")); + ui->pushButtonStaking->setText(tr("Staking Only")); + + // Connect + connect(ui->pushButtonUnlocked, SIGNAL(clicked()), this, SLOT(onUnlockClicked())); + connect(ui->pushButtonLocked, SIGNAL(clicked()), this, SLOT(onLockClicked())); + connect(ui->pushButtonStaking, SIGNAL(clicked()), this, SLOT(onStakingClicked())); +} + +LockUnlock::~LockUnlock() +{ + delete ui; +} + +void LockUnlock::updateStatus(WalletModel::EncryptionStatus status){ + switch (status){ + case WalletModel::EncryptionStatus::Unlocked: + ui->pushButtonUnlocked->setChecked(true); + ui->pushButtonLocked->setChecked(false); + ui->pushButtonStaking->setChecked(false); + break; + case WalletModel::EncryptionStatus::UnlockedForAnonymizationOnly: + ui->pushButtonUnlocked->setChecked(false); + ui->pushButtonLocked->setChecked(false); + ui->pushButtonStaking->setChecked(true); + break; + case WalletModel::EncryptionStatus::Locked: + ui->pushButtonUnlocked->setChecked(false); + ui->pushButtonLocked->setChecked(true); + ui->pushButtonStaking->setChecked(false); + break; + default: + break; + } +} + +void LockUnlock::onLockClicked(){ + lock = 0; + emit lockClicked(StateClicked::LOCK); +} + +void LockUnlock::onUnlockClicked(){ + lock = 1; + emit lockClicked(StateClicked::UNLOCK); +} + +void LockUnlock::onStakingClicked(){ + lock = 2; + emit lockClicked(StateClicked::UNLOCK_FOR_STAKING); +} + +void LockUnlock::enterEvent(QEvent *) +{ + isOnHover = true; + emit Mouse_Entered(); +} + +void LockUnlock::leaveEvent(QEvent *) +{ + isOnHover = false; + emit Mouse_Leave(); +} + +bool LockUnlock::isHovered(){ + return isOnHover; +} diff --git a/src/qt/pivx/lockunlock.h b/src/qt/pivx/lockunlock.h new file mode 100644 index 000000000000..6495294693ae --- /dev/null +++ b/src/qt/pivx/lockunlock.h @@ -0,0 +1,49 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef LOCKUNLOCK_H +#define LOCKUNLOCK_H + +#include +#include "walletmodel.h" + +namespace Ui { +class LockUnlock; +} + +enum StateClicked{ + LOCK,UNLOCK,UNLOCK_FOR_STAKING +}; + + +class LockUnlock : public QWidget +{ + Q_OBJECT + +public: + explicit LockUnlock(QWidget *parent = nullptr); + ~LockUnlock(); + void updateStatus(WalletModel::EncryptionStatus status); + int lock = 0; + bool isHovered(); +signals: + void Mouse_Entered(); + void Mouse_Leave(); + + void lockClicked(const StateClicked& state); +protected: + virtual void enterEvent(QEvent *); + virtual void leaveEvent(QEvent *); + +public slots: + void onLockClicked(); + void onUnlockClicked(); + void onStakingClicked(); + +private: + Ui::LockUnlock *ui; + bool isOnHover = false; +}; + +#endif // LOCKUNLOCK_H diff --git a/src/qt/pivx/masternodeswidget.cpp b/src/qt/pivx/masternodeswidget.cpp new file mode 100644 index 000000000000..cb400e1da255 --- /dev/null +++ b/src/qt/pivx/masternodeswidget.cpp @@ -0,0 +1,376 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/masternodeswidget.h" +#include "qt/pivx/forms/ui_masternodeswidget.h" +#include "qt/pivx/qtutils.h" +#include "qt/pivx/mnrow.h" +#include "qt/pivx/mninfodialog.h" + +#include "qt/pivx/masternodewizarddialog.h" + +#include "activemasternode.h" +#include "clientmodel.h" +#include "guiutil.h" +#include "init.h" +#include "masternode-sync.h" +#include "masternodeconfig.h" +#include "masternodeman.h" +#include "sync.h" +#include "wallet/wallet.h" +#include "walletmodel.h" +#include "askpassphrasedialog.h" +#include "util.h" +#include "qt/pivx/optionbutton.h" +#include +#include +#include + +#define DECORATION_SIZE 65 +#define NUM_ITEMS 3 + +class MNHolder : public FurListRow +{ +public: + MNHolder(); + + explicit MNHolder(bool _isLightTheme) : FurListRow(), isLightTheme(_isLightTheme){} + + MNRow* createHolder(int pos) override{ + return new MNRow(); + } + + void init(QWidget* holder,const QModelIndex &index, bool isHovered, bool isSelected) const override{ + MNRow* row = static_cast(holder); + QString label = index.data(Qt::DisplayRole).toString(); + QString address = index.sibling(index.row(), MNModel::ADDRESS).data(Qt::DisplayRole).toString(); + QString status = index.sibling(index.row(), MNModel::STATUS).data(Qt::DisplayRole).toString(); + bool wasCollateralAccepted = index.sibling(index.row(), MNModel::WAS_COLLATERAL_ACCEPTED).data(Qt::DisplayRole).toBool(); + row->updateView("Address: " + address, label, status, wasCollateralAccepted); + } + + QColor rectColor(bool isHovered, bool isSelected) override{ + return getRowColor(isLightTheme, isHovered, isSelected); + } + + ~MNHolder() override{} + + bool isLightTheme; +}; + +#include "qt/pivx/moc_masternodeswidget.cpp" + +MasterNodesWidget::MasterNodesWidget(PIVXGUI *parent) : + PWidget(parent), + ui(new Ui::MasterNodesWidget) +{ + ui->setupUi(this); + + delegate = new FurAbstractListItemDelegate( + DECORATION_SIZE, + new MNHolder(isLightTheme()), + this + ); + mnModel = new MNModel(this); + + this->setStyleSheet(parent->styleSheet()); + + /* Containers */ + setCssProperty(ui->left, "container"); + ui->left->setContentsMargins(0,20,0,20); + setCssProperty(ui->right, "container-right"); + ui->right->setContentsMargins(20,20,20,20); + + /* Light Font */ + QFont fontLight; + fontLight.setWeight(QFont::Light); + + /* Title */ + ui->labelTitle->setText(tr("Masternodes")); + setCssTitleScreen(ui->labelTitle); + ui->labelTitle->setFont(fontLight); + + ui->labelSubtitle1->setText(tr("Full nodes that incentivize node operators to perform the core consensus functions\nand vote on the treasury system receiving a periodic reward.")); + setCssSubtitleScreen(ui->labelSubtitle1); + + /* Buttons */ + ui->pushButtonSave->setText(tr("Create Masternode Controller")); + setCssBtnPrimary(ui->pushButtonSave); + + /* Options */ + ui->btnAbout->setTitleClassAndText("btn-title-grey", "What is a Masternode?"); + ui->btnAbout->setSubTitleClassAndText("text-subtitle", "FAQ explaining what Masternodes are"); + ui->btnAboutController->setTitleClassAndText("btn-title-grey", "What is a Controller?"); + ui->btnAboutController->setSubTitleClassAndText("text-subtitle", "FAQ explaining what is a Masternode Controller"); + + setCssProperty(ui->listMn, "container"); + ui->listMn->setItemDelegate(delegate); + ui->listMn->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE)); + ui->listMn->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2)); + ui->listMn->setAttribute(Qt::WA_MacShowFocusRect, false); + ui->listMn->setSelectionBehavior(QAbstractItemView::SelectRows); + + ui->emptyContainer->setVisible(false); + setCssProperty(ui->pushImgEmpty, "img-empty-master"); + ui->labelEmpty->setText(tr("No active Masternode yet")); + setCssProperty(ui->labelEmpty, "text-empty"); + + connect(ui->pushButtonSave, SIGNAL(clicked()), this, SLOT(onCreateMNClicked())); + connect(ui->listMn, SIGNAL(clicked(QModelIndex)), this, SLOT(onMNClicked(QModelIndex))); + connect(ui->btnAbout, &OptionButton::clicked, [this](){window->openFAQ(9);}); + connect(ui->btnAboutController, &OptionButton::clicked, [this](){window->openFAQ(10);}); +} + +void MasterNodesWidget::showEvent(QShowEvent *event){ + if (mnModel) mnModel->updateMNList(); + if(!timer) { + timer = new QTimer(this); + connect(timer, &QTimer::timeout, [this]() {mnModel->updateMNList();}); + } + timer->start(30000); +} + +void MasterNodesWidget::hideEvent(QHideEvent *event){ + if(timer) timer->stop(); +} + +void MasterNodesWidget::loadWalletModel(){ + if(walletModel) { + ui->listMn->setModel(mnModel); + ui->listMn->setModelColumn(AddressTableModel::Label); + updateListState(); + } +} + +void MasterNodesWidget::updateListState() { + if (mnModel->rowCount() > 0) { + ui->listMn->setVisible(true); + ui->emptyContainer->setVisible(false); + } else { + ui->listMn->setVisible(false); + ui->emptyContainer->setVisible(true); + } +} + +void MasterNodesWidget::onMNClicked(const QModelIndex &index){ + ui->listMn->setCurrentIndex(index); + QRect rect = ui->listMn->visualRect(index); + QPoint pos = rect.topRight(); + pos.setX(pos.x() - (DECORATION_SIZE * 2)); + pos.setY(pos.y() + (DECORATION_SIZE * 1.5)); + if(!this->menu){ + this->menu = new TooltipMenu(window, this); + this->menu->setEditBtnText(tr("Start")); + this->menu->setDeleteBtnText(tr("Delete")); + this->menu->setCopyBtnText(tr("Info")); + connect(this->menu, &TooltipMenu::message, this, &AddressesWidget::message); + connect(this->menu, SIGNAL(onEditClicked()), this, SLOT(onEditMNClicked())); + connect(this->menu, SIGNAL(onDeleteClicked()), this, SLOT(onDeleteMNClicked())); + connect(this->menu, SIGNAL(onCopyClicked()), this, SLOT(onInfoMNClicked())); + this->menu->adjustSize(); + }else { + this->menu->hide(); + } + this->index = index; + menu->move(pos); + menu->show(); + + // Back to regular status + ui->listMn->scrollTo(index); + ui->listMn->clearSelection(); + ui->listMn->setFocus(); +} + +void MasterNodesWidget::onEditMNClicked(){ + if(walletModel) { + if (index.sibling(index.row(), MNModel::WAS_COLLATERAL_ACCEPTED).data(Qt::DisplayRole).toBool()) { + // Start MN + QString strAlias = this->index.data(Qt::DisplayRole).toString(); + if (ask(tr("Start Master Node"), tr("Are you sure you want to start masternode %1?\n").arg(strAlias))) { + if (!verifyWalletUnlocked()) return; + startAlias(strAlias); + } + }else { + inform(tr("Cannot start masternode, the collateral transaction has not been accepted by the network.\nPlease wait few more minutes.")); + } + } +} + +void MasterNodesWidget::startAlias(QString strAlias){ + QString strStatusHtml; + strStatusHtml += "Alias: " + strAlias + " "; + + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { + if (mne.getAlias() == strAlias.toStdString()) { + std::string strError; + CMasternodeBroadcast mnb; + if (CMasternodeBroadcast::Create(mne.getIp(), mne.getPrivKey(), mne.getTxHash(), mne.getOutputIndex(), strError, mnb)) { + strStatusHtml += "successfully started."; + mnodeman.UpdateMasternodeList(mnb); + mnb.Relay(); + mnModel->updateMNList(); + } else { + strStatusHtml += "failed to start.\nError: " + QString::fromStdString(strError); + } + break; + } + } + inform(strStatusHtml); +} + +void MasterNodesWidget::onInfoMNClicked(){ + if(!verifyWalletUnlocked()) return; + showHideOp(true); + MnInfoDialog* dialog = new MnInfoDialog(window); + QString label = index.data(Qt::DisplayRole).toString(); + QString address = index.sibling(index.row(), MNModel::ADDRESS).data(Qt::DisplayRole).toString(); + QString status = index.sibling(index.row(), MNModel::STATUS).data(Qt::DisplayRole).toString(); + QString txId = index.sibling(index.row(), MNModel::COLLATERAL_ID).data(Qt::DisplayRole).toString(); + QString outIndex = index.sibling(index.row(), MNModel::COLLATERAL_OUT_INDEX).data(Qt::DisplayRole).toString(); + QString pubKey = index.sibling(index.row(), MNModel::PUB_KEY).data(Qt::DisplayRole).toString(); + dialog->setData(pubKey, label, address, txId, outIndex, status); + dialog->adjustSize(); + showDialog(dialog, 3, 17); + if (dialog->exportMN){ + if (ask(tr("Remote Masternode Data"), + tr("You are just about to export the required data to run a Masternode\non a remote server to your clipboard.\n\n\n" + "You will only have to paste the data in the pivx.conf file\nof your remote server and start it, " + "then start the Masternode using\nthis controller wallet (select the Masternode in the list and press \"start\").\n" + ))) { + // export data + QString exportedMN = "masternode=1\n" + "externalip=" + address.split(":")[0] + "\n" + + "masternodeaddr=" + address + + "\n" + + "masternodeprivkey=" + index.sibling(index.row(), MNModel::PRIV_KEY).data(Qt::DisplayRole).toString() + "\n"; + GUIUtil::setClipboard(exportedMN); + inform(tr("Masternode exported!, check your clipboard")); + } + } + + dialog->deleteLater(); +} + +void MasterNodesWidget::onDeleteMNClicked(){ + QString qAliasString = index.data(Qt::DisplayRole).toString(); + std::string aliasToRemove = qAliasString.toStdString(); + + if (!ask(tr("Delete Master Node"), tr("You are just about to delete Master Node:\n%1\n\nAre you sure?").arg(qAliasString))) + return; + + std::string strConfFile = "masternode.conf"; + std::string strDataDir = GetDataDir().string(); + if (strConfFile != boost::filesystem::basename(strConfFile) + boost::filesystem::extension(strConfFile)){ + throw std::runtime_error(strprintf(_("masternode.conf %s resides outside data directory %s"), strConfFile, strDataDir)); + } + + boost::filesystem::path pathBootstrap = GetDataDir() / strConfFile; + if (boost::filesystem::exists(pathBootstrap)) { + boost::filesystem::path pathMasternodeConfigFile = GetMasternodeConfigFile(); + boost::filesystem::ifstream streamConfig(pathMasternodeConfigFile); + + if (!streamConfig.good()) { + inform(tr("Invalid masternode.conf file")); + return; + } + + int lineNumToRemove = -1; + int linenumber = 1; + std::string lineCopy = ""; + for (std::string line; std::getline(streamConfig, line); linenumber++) { + if (line.empty()) continue; + + std::istringstream iss(line); + std::string comment, alias, ip, privKey, txHash, outputIndex; + + if (iss >> comment) { + if (comment.at(0) == '#') continue; + iss.str(line); + iss.clear(); + } + + if (!(iss >> alias >> ip >> privKey >> txHash >> outputIndex)) { + iss.str(line); + iss.clear(); + if (!(iss >> alias >> ip >> privKey >> txHash >> outputIndex)) { + streamConfig.close(); + inform(tr("Error parsing masternode.conf file")); + return; + } + } + + if (aliasToRemove == alias) { + lineNumToRemove = linenumber; + } else + lineCopy += line + "\n"; + + } + + if (lineCopy.size() == 0) { + lineCopy = "# Masternode config file\n" + "# Format: alias IP:port masternodeprivkey collateral_output_txid collateral_output_index\n" + "# Example: mn1 127.0.0.2:51472 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0\n"; + } + + streamConfig.close(); + + if (lineNumToRemove != -1) { + boost::filesystem::path pathConfigFile("masternode_temp.conf"); + if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir() / pathConfigFile; + FILE* configFile = fopen(pathConfigFile.string().c_str(), "w"); + fwrite(lineCopy.c_str(), std::strlen(lineCopy.c_str()), 1, configFile); + fclose(configFile); + + boost::filesystem::path pathOldConfFile("old_masternode.conf"); + if (!pathOldConfFile.is_complete()) pathOldConfFile = GetDataDir() / pathOldConfFile; + if (boost::filesystem::exists(pathOldConfFile)) { + boost::filesystem::remove(pathOldConfFile); + } + rename(pathMasternodeConfigFile, pathOldConfFile); + + boost::filesystem::path pathNewConfFile("masternode.conf"); + if (!pathNewConfFile.is_complete()) pathNewConfFile = GetDataDir() / pathNewConfFile; + rename(pathConfigFile, pathNewConfFile); + + // Remove alias + masternodeConfig.remove(aliasToRemove); + // Update list + mnModel->removeMn(index); + updateListState(); + } + } else{ + inform(tr("masternode.conf file doesn't exists")); + } +} + +void MasterNodesWidget::onCreateMNClicked(){ + if(verifyWalletUnlocked()) { + if(walletModel->getBalance() <= (COIN * 10000)){ + inform(tr("No enough balance to create a master node, 10,000 PIV required.")); + return; + } + showHideOp(true); + MasterNodeWizardDialog *dialog = new MasterNodeWizardDialog(walletModel, window); + if(openDialogWithOpaqueBackgroundY(dialog, window, 5, 7)) { + if (dialog->isOk) { + // Update list + mnModel->addMn(dialog->mnEntry); + updateListState(); + // add mn + inform(dialog->returnStr); + } else { + warn(tr("Error creating master node"), dialog->returnStr); + } + } + dialog->deleteLater(); + } +} + +void MasterNodesWidget::changeTheme(bool isLightTheme, QString& theme){ + static_cast(this->delegate->getRowFactory())->isLightTheme = isLightTheme; +} + +MasterNodesWidget::~MasterNodesWidget() +{ + delete ui; +} diff --git a/src/qt/pivx/masternodeswidget.h b/src/qt/pivx/masternodeswidget.h new file mode 100644 index 000000000000..eaa133189be0 --- /dev/null +++ b/src/qt/pivx/masternodeswidget.h @@ -0,0 +1,58 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MASTERNODESWIDGET_H +#define MASTERNODESWIDGET_H + +#include +#include "qt/pivx/pwidget.h" +#include "qt/pivx/furabstractlistitemdelegate.h" +#include "qt/pivx/mnmodel.h" +#include "qt/pivx/tooltipmenu.h" +#include + +class PIVXGUI; + +namespace Ui { +class MasterNodesWidget; +} + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +class MasterNodesWidget : public PWidget +{ + Q_OBJECT + +public: + + explicit MasterNodesWidget(PIVXGUI *parent = nullptr); + ~MasterNodesWidget(); + + void loadWalletModel() override; + void showEvent(QShowEvent *event) override; + void hideEvent(QHideEvent *event) override; + +private slots: + void onCreateMNClicked(); + void changeTheme(bool isLightTheme, QString &theme) override; + void onMNClicked(const QModelIndex &index); + void onEditMNClicked(); + void onDeleteMNClicked(); + void onInfoMNClicked(); + void updateListState(); + +private: + Ui::MasterNodesWidget *ui; + FurAbstractListItemDelegate *delegate; + MNModel *mnModel = nullptr; + TooltipMenu* menu = nullptr; + QModelIndex index; + QTimer *timer = nullptr; + + void startAlias(QString strAlias); +}; + +#endif // MASTERNODESWIDGET_H diff --git a/src/qt/pivx/masternodewizarddialog.cpp b/src/qt/pivx/masternodewizarddialog.cpp new file mode 100644 index 000000000000..d04295be7656 --- /dev/null +++ b/src/qt/pivx/masternodewizarddialog.cpp @@ -0,0 +1,428 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/masternodewizarddialog.h" +#include "qt/pivx/forms/ui_masternodewizarddialog.h" +#include "qt/pivx/qtutils.h" +#include "optionsmodel.h" +#include "activemasternode.h" +#include +#include +#include + +MasterNodeWizardDialog::MasterNodeWizardDialog(WalletModel *model, QWidget *parent) : + QDialog(parent), + ui(new Ui::MasterNodeWizardDialog), + icConfirm1(new QPushButton()), + icConfirm3(new QPushButton()), + icConfirm4(new QPushButton()), + walletModel(model) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + setCssProperty(ui->frame, "container-dialog"); + ui->frame->setContentsMargins(10,10,10,10); + + setCssProperty({ui->labelLine1, ui->labelLine3}, "line-purple"); + setCssProperty({ui->groupBoxName, ui->groupContainer}, "container-border"); + setCssProperty({ui->pushNumber1, ui->pushNumber3, ui->pushNumber4}, "btn-number-check"); + setCssProperty({ui->pushName1, ui->pushName3, ui->pushName4}, "btn-name-check"); + + ui->pushNumber1->setEnabled(false); + ui->pushNumber3->setEnabled(false); + ui->pushNumber4->setEnabled(false); + ui->pushName1->setEnabled(false); + ui->pushName3->setEnabled(false); + ui->pushName4->setEnabled(false); + + // Frame 1 + setCssProperty(ui->labelTitle1, "text-title-dialog"); + setCssProperty(ui->labelMessage1a, "text-main-grey"); + setCssProperty(ui->labelMessage1b, "text-main-purple"); + + // Frame 3 + setCssProperty(ui->labelTitle3, "text-title-dialog"); + setCssProperty(ui->labelMessage3, "text-main-grey"); + + ui->lineEditName->setPlaceholderText(tr("e.g user_masternode")); + initCssEditLine(ui->lineEditName); + ui->lineEditName->setValidator(new QRegExpValidator(QRegExp("^[A-Za-z0-9]+"), ui->lineEditName)); + + // Frame 4 + setCssProperty(ui->labelTitle4, "text-title-dialog"); + setCssProperty({ui->labelSubtitleIp, ui->labelSubtitlePort}, "text-title"); + setCssSubtitleScreen(ui->labelSubtitleAddressIp); + + ui->lineEditIpAddress->setPlaceholderText("e.g 18.255.255.255"); + ui->lineEditPort->setPlaceholderText("e.g 51472"); + initCssEditLine(ui->lineEditIpAddress); + initCssEditLine(ui->lineEditPort); + ui->stackedWidget->setCurrentIndex(pos); + ui->lineEditPort->setValidator(new QIntValidator(0, 9999999, ui->lineEditPort)); + if(walletModel->isTestnet()){ + ui->lineEditPort->setEnabled(false); + ui->lineEditPort->setText("51474"); + } else { + ui->lineEditPort->setText("51472"); + } + + // Confirm icons + ui->stackedIcon1->addWidget(icConfirm1); + ui->stackedIcon3->addWidget(icConfirm3); + ui->stackedIcon4->addWidget(icConfirm4); + initBtn({icConfirm1, icConfirm3, icConfirm4}); + setCssProperty({icConfirm1, icConfirm3, icConfirm4}, "ic-step-confirm"); + + // Connect btns + setCssBtnPrimary(ui->btnNext); + ui->btnNext->setText(tr("NEXT")); + setCssProperty(ui->btnBack , "btn-dialog-cancel"); + ui->btnBack->setVisible(false); + ui->btnBack->setText(tr("BACK")); + setCssProperty(ui->pushButtonSkip, "ic-close"); + + connect(ui->pushButtonSkip, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnNext, SIGNAL(clicked()), this, SLOT(onNextClicked())); + connect(ui->btnBack, SIGNAL(clicked()), this, SLOT(onBackClicked())); +} + +void MasterNodeWizardDialog::onNextClicked(){ + switch(pos){ + case 0:{ + ui->stackedWidget->setCurrentIndex(1); + ui->pushName4->setChecked(false); + ui->pushName3->setChecked(true); + ui->pushName1->setChecked(true); + icConfirm1->setVisible(true); + ui->pushNumber3->setChecked(true); + + ui->btnBack->setVisible(true); + break; + } + case 1:{ + + // No empty names accepted. + if (ui->lineEditName->text().isEmpty()) { + setCssEditLine(ui->lineEditName, false, true); + return; + } + setCssEditLine(ui->lineEditName, true, true); + + ui->stackedWidget->setCurrentIndex(2); + ui->pushName4->setChecked(false); + ui->pushName3->setChecked(true); + ui->pushName1->setChecked(true); + icConfirm3->setVisible(true); + ui->pushNumber4->setChecked(true); + ui->btnBack->setVisible(true); + break; + } + case 2:{ + + // No empty address accepted + if (ui->lineEditIpAddress->text().isEmpty()) { + return; + } + + icConfirm4->setVisible(true); + ui->btnBack->setVisible(true); + ui->btnBack->setVisible(true); + isOk = createMN(); + accept(); + } + } + pos++; +} + +bool MasterNodeWizardDialog::createMN(){ + if (walletModel) { + /** + * + 1) generate the mn key. + 2) create the mn address. + 3) send a tx with 10k to that address. + 4) get thereate output. + 5) use those values on the masternode.conf + */ + + // First create the mn key + CKey secret; + secret.MakeNewKey(false); + CBitcoinSecret mnKey = CBitcoinSecret(secret); + std::string mnKeyString = mnKey.ToString(); + + // second create mn address + QString addressLabel = ui->lineEditName->text(); + if (addressLabel.isEmpty()) { + returnStr = tr("address label cannot be empty"); + return false; + } + std::string alias = addressLabel.toStdString(); + + QString addressStr = ui->lineEditIpAddress->text(); + QString portStr = ui->lineEditPort->text(); + if (addressStr.isEmpty() || portStr.isEmpty()) { + returnStr = tr("IP or port cannot be empty"); + return false; + } + // TODO: Validate IP address.. + int portInt = portStr.toInt(); + if (portInt <= 0 && portInt > 999999){ + returnStr = tr("Invalid port number"); + return false; + } + // ip + port + std::string ipAddress = addressStr.toStdString(); + std::string port = portStr.toStdString(); + + // New receive address + CBitcoinAddress address = walletModel->getNewAddress(alias); + + // const QString& addr, const QString& label, const CAmount& amount, const QString& message + SendCoinsRecipient sendCoinsRecipient(QString::fromStdString(address.ToString()), "", CAmount(10000) * COIN, ""); + + // Send the 10 tx to one of your address + QList recipients; + recipients.append(sendCoinsRecipient); + WalletModelTransaction currentTransaction(recipients); + WalletModel::SendCoinsReturn prepareStatus; + + prepareStatus = walletModel->prepareTransaction(currentTransaction); + + // process prepareStatus and on error generate message shown to user + processSendCoinsReturn(prepareStatus, + BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), + currentTransaction.getTransactionFee()), + true + ); + + if (prepareStatus.status != WalletModel::OK) { + returnStr = tr("Prepare master node failed.."); + return false; + } + + WalletModel::SendCoinsReturn sendStatus = walletModel->sendCoins(currentTransaction); + // process sendStatus and on error generate message shown to user + processSendCoinsReturn(sendStatus); + + if (sendStatus.status == WalletModel::OK) { + // now change the conf + std::string strConfFile = "masternode.conf"; + std::string strDataDir = GetDataDir().string(); + if (strConfFile != boost::filesystem::basename(strConfFile) + boost::filesystem::extension(strConfFile)){ + throw std::runtime_error(strprintf(_("masternode.conf %s resides outside data directory %s"), strConfFile, strDataDir)); + } + + boost::filesystem::path pathBootstrap = GetDataDir() / strConfFile; + if (boost::filesystem::exists(pathBootstrap)) { + boost::filesystem::path pathMasternodeConfigFile = GetMasternodeConfigFile(); + boost::filesystem::ifstream streamConfig(pathMasternodeConfigFile); + + if (!streamConfig.good()) { + returnStr = tr("Invalid masternode.conf file"); + return false; + } + + int linenumber = 1; + std::string lineCopy = ""; + for (std::string line; std::getline(streamConfig, line); linenumber++) { + if (line.empty()) continue; + + std::istringstream iss(line); + std::string comment, alias, ip, privKey, txHash, outputIndex; + + if (iss >> comment) { + if (comment.at(0) == '#') continue; + iss.str(line); + iss.clear(); + } + + if (!(iss >> alias >> ip >> privKey >> txHash >> outputIndex)) { + iss.str(line); + iss.clear(); + if (!(iss >> alias >> ip >> privKey >> txHash >> outputIndex)) { + streamConfig.close(); + returnStr = tr("Error parsing masternode.conf file"); + return false; + } + } + lineCopy += line + "\n"; + } + + if (lineCopy.size() == 0) { + lineCopy = "# Masternode config file\n" + "# Format: alias IP:port masternodeprivkey collateral_output_txid collateral_output_index\n" + "# Example: mn1 127.0.0.2:51472 93HaYBVUCYjEMeeH1Y4sBGLALQZE1Yc1K64xiqgX37tGBDQL8Xg 2bcd3c84c84f87eaa86e4e56834c92927a07f9e18718810b92e0d0324456a67c 0" + "#"; + } + lineCopy += "\n"; + + streamConfig.close(); + + CWalletTx* walletTx = currentTransaction.getTransaction(); + std::string txID = walletTx->GetHash().GetHex(); + int indexOut = -1; + for (int i=0; i < (int)walletTx->vout.size(); i++){ + CTxOut& out = walletTx->vout[i]; + if (out.nValue == 10000 * COIN){ + indexOut = i; + } + } + if (indexOut == -1) { + returnStr = tr("Invalid collaterall output index"); + return false; + } + std::string indexOutStr = std::to_string(indexOut); + + boost::filesystem::path pathConfigFile("masternode_temp.conf"); + if (!pathConfigFile.is_complete()) pathConfigFile = GetDataDir() / pathConfigFile; + FILE* configFile = fopen(pathConfigFile.string().c_str(), "w"); + lineCopy += alias+" "+ipAddress+":"+port+" "+mnKeyString+" "+txID+" "+indexOutStr+"\n"; + fwrite(lineCopy.c_str(), std::strlen(lineCopy.c_str()), 1, configFile); + fclose(configFile); + + boost::filesystem::path pathOldConfFile("old_masternode.conf"); + if (!pathOldConfFile.is_complete()) pathOldConfFile = GetDataDir() / pathOldConfFile; + if (boost::filesystem::exists(pathOldConfFile)) { + boost::filesystem::remove(pathOldConfFile); + } + rename(pathMasternodeConfigFile, pathOldConfFile); + + boost::filesystem::path pathNewConfFile("masternode.conf"); + if (!pathNewConfFile.is_complete()) pathNewConfFile = GetDataDir() / pathNewConfFile; + rename(pathConfigFile, pathNewConfFile); + + mnEntry = masternodeConfig.add(alias, ipAddress+":"+port, mnKeyString, txID, indexOutStr); + + returnStr = tr("Master node created!"); + return true; + } else{ + returnStr = tr("masternode.conf file doesn't exists"); + } + } + } + return false; +} + +void MasterNodeWizardDialog::onBackClicked(){ + if (pos == 0) return; + pos--; + switch(pos){ + case 0:{ + ui->stackedWidget->setCurrentIndex(0); + ui->pushNumber1->setChecked(true); + ui->pushNumber4->setChecked(false); + ui->pushNumber3->setChecked(false); + ui->pushName4->setChecked(false); + ui->pushName3->setChecked(false); + ui->pushName1->setChecked(true); + icConfirm1->setVisible(false); + ui->btnBack->setVisible(false); + break; + } + case 1:{ + ui->stackedWidget->setCurrentIndex(1); + ui->pushNumber4->setChecked(false); + ui->pushNumber3->setChecked(true); + ui->pushName4->setChecked(false); + ui->pushName3->setChecked(true); + icConfirm3->setVisible(false); + + break; + } + } +} + +void MasterNodeWizardDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn& sendCoinsReturn, const QString& msgArg, bool fPrepare) +{ + bool fAskForUnlock = false; + + QPair msgParams; + // Default to a warning message, override if error message is needed + msgParams.second = CClientUIInterface::MSG_WARNING; + + // This comment is specific to SendCoinsDialog usage of WalletModel::SendCoinsReturn. + // WalletModel::TransactionCommitFailed is used only in WalletModel::sendCoins() + // all others are used only in WalletModel::prepareTransaction() + switch (sendCoinsReturn.status) { + case WalletModel::InvalidAddress: + msgParams.first = tr("The recipient address is not valid, please recheck."); + break; + case WalletModel::InvalidAmount: + msgParams.first = tr("The amount to pay must be larger than 0."); + break; + case WalletModel::AmountExceedsBalance: + msgParams.first = tr("The amount exceeds your balance."); + break; + case WalletModel::AmountWithFeeExceedsBalance: + msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg); + break; + case WalletModel::DuplicateAddress: + msgParams.first = tr("Duplicate address found, can only send to each address once per send operation."); + break; + case WalletModel::TransactionCreationFailed: + msgParams.first = tr("Transaction creation failed!"); + msgParams.second = CClientUIInterface::MSG_ERROR; + break; + case WalletModel::TransactionCommitFailed: + msgParams.first = tr("The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); + msgParams.second = CClientUIInterface::MSG_ERROR; + break; + case WalletModel::AnonymizeOnlyUnlocked: + // Unlock is only need when the coins are send + if(!fPrepare) + fAskForUnlock = true; + else + msgParams.first = tr("Error: The wallet was unlocked only to anonymize coins."); + break; + + case WalletModel::InsaneFee: + msgParams.first = tr("A fee %1 times higher than %2 per kB is considered an insanely high fee.").arg(10000).arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), ::minRelayTxFee.GetFeePerK())); + break; + // included to prevent a compiler warning. + case WalletModel::OK: + default: + return; + } + + // Unlock wallet if it wasn't fully unlocked already + if(fAskForUnlock) { + walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full, false); + if(walletModel->getEncryptionStatus () != WalletModel::Unlocked) { + msgParams.first = tr("Error: The wallet was unlocked only to anonymize coins. Unlock canceled."); + } + else { + // Wallet unlocked + return; + } + } + + inform(msgParams.first); +} + +void MasterNodeWizardDialog::inform(QString text){ + if (!snackBar) + snackBar = new SnackBar(nullptr, this); + snackBar->setText(text); + snackBar->resize(this->width(), snackBar->height()); + openDialog(snackBar, this); +} + +QSize BUTTON_SIZE = QSize(22, 22); +void MasterNodeWizardDialog::initBtn(std::initializer_list args){ + for (QPushButton* btn : args) { + btn->setMinimumSize(BUTTON_SIZE); + btn->setMaximumSize(BUTTON_SIZE); + btn->move(0, 0); + btn->show(); + btn->raise(); + btn->setVisible(false); + } +} + +MasterNodeWizardDialog::~MasterNodeWizardDialog(){ + if(snackBar) delete snackBar; + delete ui; +} diff --git a/src/qt/pivx/masternodewizarddialog.h b/src/qt/pivx/masternodewizarddialog.h new file mode 100644 index 000000000000..523fc95b4c41 --- /dev/null +++ b/src/qt/pivx/masternodewizarddialog.h @@ -0,0 +1,53 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MASTERNODEWIZARDDIALOG_H +#define MASTERNODEWIZARDDIALOG_H + +#include +#include "walletmodel.h" +#include "qt/pivx/snackbar.h" +#include "masternodeconfig.h" + +class WalletModel; + +namespace Ui { +class MasterNodeWizardDialog; +class QPushButton; +} + +class MasterNodeWizardDialog : public QDialog +{ + Q_OBJECT + +public: + explicit MasterNodeWizardDialog(WalletModel *walletMode, QWidget *parent = nullptr); + ~MasterNodeWizardDialog(); + + QString returnStr = ""; + bool isOk = false; + CMasternodeConfig::CMasternodeEntry* mnEntry = nullptr; + +private slots: + void onNextClicked(); + void onBackClicked(); +private: + Ui::MasterNodeWizardDialog *ui; + QPushButton* icConfirm1; + QPushButton* icConfirm3; + QPushButton* icConfirm4; + SnackBar *snackBar = nullptr; + int pos = 0; + + WalletModel *walletModel = nullptr; + bool createMN(); + // Process WalletModel::SendCoinsReturn and generate a pair consisting + // of a message and message flags for use in emit message(). + // Additional parameter msgArg can be used via .arg(msgArg). + void processSendCoinsReturn(const WalletModel::SendCoinsReturn& sendCoinsReturn, const QString& msgArg = QString(), bool fPrepare = false); + void inform(QString text); + void initBtn(std::initializer_list args); +}; + +#endif // MASTERNODEWIZARDDIALOG_H diff --git a/src/qt/pivx/mninfodialog.cpp b/src/qt/pivx/mninfodialog.cpp new file mode 100644 index 000000000000..bc25c03a159b --- /dev/null +++ b/src/qt/pivx/mninfodialog.cpp @@ -0,0 +1,67 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/mninfodialog.h" +#include "qt/pivx/forms/ui_mninfodialog.h" +#include "walletmodel.h" +#include "wallet/wallet.h" +#include "guiutil.h" +#include "qt/pivx/qtutils.h" +#include + +MnInfoDialog::MnInfoDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::MnInfoDialog) +{ + ui->setupUi(this); + this->setStyleSheet(parent->styleSheet()); + setCssProperty(ui->frame, "container-dialog"); + ui->labelTitle->setText(tr("Master Node Information")); + setCssProperty(ui->labelTitle, "text-title-dialog"); + setCssTextBodyDialog({ui->labelAmount, ui->labelSend, ui->labelInputs, ui->labelFee, ui->labelId}); + setCssProperty({ui->labelDivider1, ui->labelDivider4, ui->labelDivider6, ui->labelDivider7, ui->labelDivider8, ui->labelDivider9}, "container-divider"); + setCssTextBodyDialog({ui->textAmount, ui->textAddress, ui->textInputs, ui->textStatus, ui->textId, ui->textExport}); + setCssProperty({ui->pushCopy, ui->pushCopyId, ui->pushExport}, "ic-copy-big"); + setCssProperty(ui->btnEsc, "ic-close"); + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(closeDialog())); + connect(ui->pushCopy, &QPushButton::clicked, [this](){ copyInform(txId, "Master Node public key copied"); }); + connect(ui->pushCopyId, &QPushButton::clicked, [this](){ copyInform(pubKey, "Collateral tx id copied"); }); + connect(ui->pushExport, &QPushButton::clicked, [this](){ exportMN = true; accept(); }); +} + +void MnInfoDialog::setData(QString pubKey, QString name, QString address, QString txId, QString outputIndex, QString status){ + this->pubKey = pubKey; + this->txId = txId; + QString shortPubKey = pubKey; + QString shortTxId = txId; + if(shortPubKey.length() > 20) { + shortPubKey = shortPubKey.left(13) + "..." + shortPubKey.right(13); + } + if(shortTxId.length() > 20) { + shortTxId = shortTxId.left(12) + "..." + shortTxId.right(12); + } + ui->textId->setText(shortPubKey); + ui->textAddress->setText(address); + ui->textAmount->setText(shortTxId); + ui->textInputs->setText(outputIndex); + ui->textStatus->setText(status); +} + +void MnInfoDialog::copyInform(QString& copyStr, QString message){ + GUIUtil::setClipboard(copyStr); + if(!snackBar) snackBar = new SnackBar(nullptr, this); + snackBar->setText(tr(message.toStdString().c_str())); + snackBar->resize(this->width(), snackBar->height()); + openDialog(snackBar, this); +} + +void MnInfoDialog::closeDialog(){ + if(snackBar && snackBar->isVisible()) snackBar->hide(); + close(); +} + +MnInfoDialog::~MnInfoDialog(){ + if(snackBar) delete snackBar; + delete ui; +} diff --git a/src/qt/pivx/mninfodialog.h b/src/qt/pivx/mninfodialog.h new file mode 100644 index 000000000000..b5850ae17ca9 --- /dev/null +++ b/src/qt/pivx/mninfodialog.h @@ -0,0 +1,43 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MNINFODIALOG_H +#define MNINFODIALOG_H + +#include +#include "qt/pivx/snackbar.h" + +class WalletModel; + +namespace Ui { +class MnInfoDialog; +} + +class MnInfoDialog : public QDialog +{ + Q_OBJECT + +public: + explicit MnInfoDialog(QWidget *parent = nullptr); + ~MnInfoDialog(); + + bool exportMN = false; + + void setData(QString privKey, QString name, QString address, QString txId, QString outputIndex, QString status); + +public slots: + void closeDialog(); + +private: + Ui::MnInfoDialog *ui; + SnackBar *snackBar = nullptr; + int nDisplayUnit = 0; + WalletModel *model = nullptr; + QString txId; + QString pubKey; + + void copyInform(QString& copyStr, QString message); +}; + +#endif // MNINFODIALOG_H diff --git a/src/qt/pivx/mnmodel.cpp b/src/qt/pivx/mnmodel.cpp new file mode 100644 index 000000000000..dbe68f24f6a6 --- /dev/null +++ b/src/qt/pivx/mnmodel.cpp @@ -0,0 +1,152 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/mnmodel.h" +#include "masternode-sync.h" +#include "masternodeman.h" +#include "activemasternode.h" +#include "sync.h" +#include "uint256.h" +#include "wallet/wallet.h" + +MNModel::MNModel(QObject *parent) : QAbstractTableModel(parent){ + updateMNList(); +} + +void MNModel::updateMNList(){ + int end = nodes.size(); + nodes.clear(); + collateralTxAccepted.clear(); + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { + int nIndex; + if(!mne.castOutputIndex(nIndex)) + continue; + + uint256 txHash(mne.getTxHash()); + CTxIn txIn(txHash, uint32_t(nIndex)); + CMasternode* pmn = mnodeman.Find(txIn); + if (!pmn){ + pmn = new CMasternode(); + pmn->vin = txIn; + pmn->activeState = CMasternode::MASTERNODE_MISSING; + } + nodes.insert(QString::fromStdString(mne.getAlias()), std::make_pair(QString::fromStdString(mne.getIp()), pmn)); + if(pwalletMain) { + bool txAccepted = false; + { + LOCK2(cs_main, pwalletMain->cs_wallet); + const CWalletTx *walletTx = pwalletMain->GetWalletTx(txHash); + if (walletTx->GetDepthInMainChain() > 0) { + txAccepted = true; + } + } + collateralTxAccepted.insert(mne.getTxHash(), txAccepted); + } + } + emit dataChanged(index(0, 0, QModelIndex()), index(end, 5, QModelIndex()) ); +} + +int MNModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + return nodes.size(); +} + +int MNModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + return 6; +} + + +QVariant MNModel::data(const QModelIndex &index, int role) const +{ + if(!index.isValid()) + return QVariant(); + + // rec could be null, always verify it. + CMasternode* rec = static_cast(index.internalPointer()); + bool isAvailable = rec; + int row = index.row(); + if (role == Qt::DisplayRole || role == Qt::EditRole) { + switch (index.column()) { + case ALIAS: + return nodes.uniqueKeys().value(row); + case ADDRESS: + return nodes.values().value(row).first; + case PUB_KEY: + return (isAvailable) ? QString::fromStdString(nodes.values().value(row).second->pubKeyMasternode.GetHash().GetHex()) : "Not available"; + case COLLATERAL_ID: + return (isAvailable) ? QString::fromStdString(rec->vin.prevout.hash.GetHex()) : "Not available"; + case COLLATERAL_OUT_INDEX: + return (isAvailable) ? QString::number(rec->vin.prevout.n) : "Not available"; + case STATUS: { + std::pair pair = nodes.values().value(row); + return (pair.second) ? QString::fromStdString(pair.second->Status()) : "MISSING"; + } + case PRIV_KEY: { + for (CMasternodeConfig::CMasternodeEntry mne : masternodeConfig.getEntries()) { + if (mne.getTxHash().compare(rec->vin.prevout.hash.GetHex()) == 0){ + return QString::fromStdString(mne.getPrivKey()); + } + } + return "Not available"; + } + case WAS_COLLATERAL_ACCEPTED:{ + if (!isAvailable) return false; + std::string txHash = rec->vin.prevout.hash.GetHex(); + if(!collateralTxAccepted.value(txHash)){ + bool txAccepted = false; + { + LOCK2(cs_main, pwalletMain->cs_wallet); + const CWalletTx *walletTx = pwalletMain->GetWalletTx(rec->vin.prevout.hash); + txAccepted = walletTx->GetDepthInMainChain() > 0; + } + return txAccepted; + } + return true; + } + } + } + return QVariant(); +} + +QModelIndex MNModel::index(int row, int column, const QModelIndex& parent) const +{ + Q_UNUSED(parent); + std::pair pair = nodes.values().value(row); + CMasternode* data = pair.second; + if (data) { + return createIndex(row, column, data); + } else if (!pair.first.isEmpty()){ + return createIndex(row, column, nullptr); + } else { + return QModelIndex(); + } +} + + +bool MNModel::removeMn(const QModelIndex& modelIndex) { + QString alias = modelIndex.data(Qt::DisplayRole).toString(); + int idx = modelIndex.row(); + beginRemoveRows(QModelIndex(), idx, idx); + nodes.take(alias); + endRemoveRows(); + emit dataChanged(index(idx, 0, QModelIndex()), index(idx, 5, QModelIndex()) ); + return true; +} + +bool MNModel::addMn(CMasternodeConfig::CMasternodeEntry* mne){ + beginInsertRows(QModelIndex(), nodes.size(), nodes.size()); + int nIndex; + if(!mne->castOutputIndex(nIndex)) + return false; + + CMasternode* pmn = mnodeman.Find(CTxIn(uint256S(mne->getTxHash()), uint32_t(nIndex))); + nodes.insert(QString::fromStdString(mne->getAlias()), std::make_pair(QString::fromStdString(mne->getIp()), pmn)); + endInsertRows(); + return true; +} \ No newline at end of file diff --git a/src/qt/pivx/mnmodel.h b/src/qt/pivx/mnmodel.h new file mode 100644 index 000000000000..d37a80930ce7 --- /dev/null +++ b/src/qt/pivx/mnmodel.h @@ -0,0 +1,48 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MNMODEL_H +#define MNMODEL_H + +#include +#include "masternode.h" +#include "masternodeconfig.h" + +class MNModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit MNModel(QObject *parent = nullptr); + ~MNModel() override{} + + enum ColumnIndex { + ALIAS = 0, /**< User specified MN alias */ + ADDRESS = 1, /**< Node address */ + PROTO_VERSION = 2, /**< Node protocol version */ + STATUS = 3, /**< Node status */ + ACTIVE_TIMESTAMP = 4, /**< */ + PUB_KEY = 5, + COLLATERAL_ID = 6, + COLLATERAL_OUT_INDEX = 7, + PRIV_KEY = 8, + WAS_COLLATERAL_ACCEPTED = 9 + }; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, const QModelIndex& parent) const override; + bool removeMn(const QModelIndex& index); + bool addMn(CMasternodeConfig::CMasternodeEntry* entry); + void updateMNList(); + + +private: + // alias mn node ---> pair + QMap> nodes; + QMap collateralTxAccepted; +}; + +#endif // MNMODEL_H diff --git a/src/qt/pivx/mnrow.cpp b/src/qt/pivx/mnrow.cpp new file mode 100644 index 000000000000..361270096c45 --- /dev/null +++ b/src/qt/pivx/mnrow.cpp @@ -0,0 +1,33 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/mnrow.h" +#include "qt/pivx/forms/ui_mnrow.h" +#include "qt/pivx/qtutils.h" + +MNRow::MNRow(QWidget *parent) : + QWidget(parent), + ui(new Ui::MNRow) +{ + ui->setupUi(this); + setCssProperty(ui->labelAddress, "text-list-body2"); + setCssProperty(ui->labelName, "text-list-title1"); + setCssProperty(ui->labelDate, "text-list-caption-medium"); + ui->lblDivisory->setStyleSheet("background-color:#bababa;"); +} + +void MNRow::updateView(QString address, QString label, QString status, bool wasCollateralAccepted){ + ui->labelName->setText(label); + ui->labelAddress->setText(address); + ui->labelDate->setText("Status: " + status); + if (!wasCollateralAccepted){ + ui->labelDate->setText("Status: Collateral tx not found"); + } else { + ui->labelDate->setText("Status: " + status); + } +} + +MNRow::~MNRow(){ + delete ui; +} diff --git a/src/qt/pivx/mnrow.h b/src/qt/pivx/mnrow.h new file mode 100644 index 000000000000..965554d41738 --- /dev/null +++ b/src/qt/pivx/mnrow.h @@ -0,0 +1,30 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MYADDRESSROW_H +#define MYADDRESSROW_H + +#include + +namespace Ui { +class MNRow; +} + +class MNRow : public QWidget +{ + Q_OBJECT + +public: + explicit MNRow(QWidget *parent = nullptr); + ~MNRow(); + + void updateView(QString address, QString label, QString status, bool wasCollateralAccepted); + +signals: + void onMenuClicked(); +private: + Ui::MNRow *ui; +}; + +#endif // MYADDRESSROW_H diff --git a/src/qt/pivx/myaddressrow.cpp b/src/qt/pivx/myaddressrow.cpp new file mode 100644 index 000000000000..0a22592724d7 --- /dev/null +++ b/src/qt/pivx/myaddressrow.cpp @@ -0,0 +1,32 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/myaddressrow.h" +#include "qt/pivx/forms/ui_myaddressrow.h" + +MyAddressRow::MyAddressRow(QWidget *parent) : + QWidget(parent), + ui(new Ui::MyAddressRow) +{ + ui->setupUi(this); + ui->labelName->setProperty("cssClass", "text-list-title1"); + ui->labelAddress->setProperty("cssClass", "text-list-body2"); + ui->labelDate->setProperty("cssClass", "text-list-caption"); + +} + +void MyAddressRow::updateView(QString address, QString label, QString date){ + ui->labelName->setText(label); + ui->labelAddress->setText(address); + if (date.isEmpty()){ + ui->labelDate->setVisible(false); + } else { + ui->labelDate->setVisible(true); + ui->labelDate->setText(date); + } +} + +MyAddressRow::~MyAddressRow(){ + delete ui; +} diff --git a/src/qt/pivx/myaddressrow.h b/src/qt/pivx/myaddressrow.h new file mode 100644 index 000000000000..90bd078b14fe --- /dev/null +++ b/src/qt/pivx/myaddressrow.h @@ -0,0 +1,28 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MYADDRESSROW_H +#define MYADDRESSROW_H + +#include + +namespace Ui { +class MyAddressRow; +} + +class MyAddressRow : public QWidget +{ + Q_OBJECT + +public: + explicit MyAddressRow(QWidget *parent = nullptr); + ~MyAddressRow(); + + void updateView(QString address, QString label, QString date); + +private: + Ui::MyAddressRow *ui; +}; + +#endif // MYADDRESSROW_H diff --git a/src/qt/pivx/navmenuwidget.cpp b/src/qt/pivx/navmenuwidget.cpp new file mode 100644 index 000000000000..5686506e9e3d --- /dev/null +++ b/src/qt/pivx/navmenuwidget.cpp @@ -0,0 +1,147 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/navmenuwidget.h" +#include "qt/pivx/forms/ui_navmenuwidget.h" +#include "qt/pivx/pivxgui.h" +#include "qt/pivx/qtutils.h" +#include "clientversion.h" + +NavMenuWidget::NavMenuWidget(PIVXGUI *mainWindow, QWidget *parent) : + QWidget(parent), + ui(new Ui::NavMenuWidget), + window(mainWindow) +{ + ui->setupUi(this); + this->setFixedWidth(100); + setCssProperty(ui->navContainer_2, "container-nav"); + setCssProperty(ui->imgLogo, "img-nav-logo"); + + // App version + ui->labelVersion->setText(QString(tr("v%1")).arg(QString::fromStdString(FormatVersionFriendly()))); + ui->labelVersion->setProperty("cssClass", "text-title-white"); + + // Buttons + ui->btnDashboard->setProperty("name", "dash"); + ui->btnDashboard->setText("HOME\n"); + ui->btnDashboard->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + + ui->btnSend->setProperty("name", "send"); + ui->btnSend->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + ui->btnSend->setText("SEND\n"); + + ui->btnAddress->setProperty("name", "address"); + ui->btnAddress->setText("CONTACTS\n"); + ui->btnAddress->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + + ui->btnPrivacy->setProperty("name", "privacy"); + ui->btnPrivacy->setText("PRIVACY\n"); + ui->btnPrivacy->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + + ui->btnMaster->setProperty("name", "master"); + ui->btnMaster->setText("MASTER\r\nNODES"); + ui->btnMaster->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + + ui->btnSettings->setProperty("name", "settings"); + ui->btnSettings->setText("SETTINGS\n"); + ui->btnSettings->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + + ui->btnReceive->setProperty("name", "receive"); + ui->btnReceive->setText("RECEIVE\n"); + ui->btnReceive->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); + + btns = {ui->btnDashboard, ui->btnSend, ui->btnReceive, ui->btnAddress, ui->btnPrivacy, ui->btnMaster, ui->btnSettings}; + onNavSelected(ui->btnDashboard, true); + + connectActions(); +} + +/** + * Actions + */ +void NavMenuWidget::connectActions() { + connect(ui->btnDashboard,SIGNAL(clicked()),this, SLOT(onDashboardClicked())); + connect(ui->btnSend,SIGNAL(clicked()),this, SLOT(onSendClicked())); + connect(ui->btnAddress,SIGNAL(clicked()),this, SLOT(onAddressClicked())); + connect(ui->btnPrivacy,SIGNAL(clicked()),this, SLOT(onPrivacyClicked())); + connect(ui->btnMaster,SIGNAL(clicked()),this, SLOT(onMasterNodesClicked())); + connect(ui->btnSettings,SIGNAL(clicked()),this, SLOT(onSettingsClicked())); + connect(ui->btnReceive,SIGNAL(clicked()),this, SLOT(onReceiveClicked())); + + ui->btnDashboard->setShortcut(QKeySequence(SHORT_KEY + Qt::Key_1)); + ui->btnSend->setShortcut(QKeySequence(SHORT_KEY + Qt::Key_2)); + ui->btnReceive->setShortcut(QKeySequence(SHORT_KEY + Qt::Key_3)); + ui->btnAddress->setShortcut(QKeySequence(SHORT_KEY + Qt::Key_4)); + ui->btnPrivacy->setShortcut(QKeySequence(SHORT_KEY + Qt::Key_5)); + ui->btnMaster->setShortcut(QKeySequence(SHORT_KEY + Qt::Key_6)); + ui->btnSettings->setShortcut(QKeySequence(SHORT_KEY + Qt::Key_7)); +} + +void NavMenuWidget::onSendClicked(){ + window->goToSend(); + onNavSelected(ui->btnSend); +} + +void NavMenuWidget::onDashboardClicked(){ + window->goToDashboard(); + onNavSelected(ui->btnDashboard); +} + +void NavMenuWidget::onAddressClicked(){ + window->goToAddresses(); + onNavSelected(ui->btnAddress); +} + + +void NavMenuWidget::onPrivacyClicked(){ + window->goToPrivacy(); + onNavSelected(ui->btnPrivacy); +} + +void NavMenuWidget::onMasterNodesClicked(){ + window->goToMasterNodes(); + onNavSelected(ui->btnMaster); +} + +void NavMenuWidget::onSettingsClicked(){ + window->goToSettings(); + onNavSelected(ui->btnSettings); +} + +void NavMenuWidget::onReceiveClicked(){ + window->goToReceive(); + onNavSelected(ui->btnReceive); +} + +void NavMenuWidget::onNavSelected(QWidget* active, bool startup) { + QString start = "btn-nav-"; + foreach (QWidget* w, btns) { + QString clazz = start + w->property("name").toString(); + if (w == active) { + clazz += "-active"; + } + setCssProperty(w, clazz); + } + if (!startup) updateButtonStyles(); +} + +void NavMenuWidget::selectSettings(){ + onSettingsClicked(); +} + +void NavMenuWidget::updateButtonStyles(){ + forceUpdateStyle({ + ui->btnDashboard, + ui->btnSend, + ui->btnAddress, + ui->btnPrivacy, + ui->btnMaster, + ui->btnSettings, + ui->btnReceive + }); +} + +NavMenuWidget::~NavMenuWidget(){ + delete ui; +} diff --git a/src/qt/pivx/navmenuwidget.h b/src/qt/pivx/navmenuwidget.h new file mode 100644 index 000000000000..5a61ae33ac29 --- /dev/null +++ b/src/qt/pivx/navmenuwidget.h @@ -0,0 +1,45 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef NAVMENUWIDGET_H +#define NAVMENUWIDGET_H + +#include + +class PIVXGUI; + +namespace Ui { +class NavMenuWidget; +} + +class NavMenuWidget : public QWidget +{ + Q_OBJECT + +public: + explicit NavMenuWidget(PIVXGUI* mainWindow, QWidget *parent = nullptr); + ~NavMenuWidget(); + +public slots: + void selectSettings(); + +private slots: + void onSendClicked(); + void onDashboardClicked(); + void onPrivacyClicked(); + void onAddressClicked(); + void onMasterNodesClicked(); + void onSettingsClicked(); + void onReceiveClicked(); + void updateButtonStyles(); +private: + Ui::NavMenuWidget *ui; + PIVXGUI* window; + QList btns; + + void connectActions(); + void onNavSelected(QWidget* active, bool startup = false); +}; + +#endif // NAVMENUWIDGET_H diff --git a/src/qt/pivx/optionbutton.cpp b/src/qt/pivx/optionbutton.cpp new file mode 100644 index 000000000000..9fa124b3cea3 --- /dev/null +++ b/src/qt/pivx/optionbutton.cpp @@ -0,0 +1,71 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/optionbutton.h" +#include "qt/pivx/forms/ui_optionbutton.h" +#include "qt/pivx/qtutils.h" +#include + +OptionButton::OptionButton(QWidget *parent) : + QWidget(parent), + ui(new Ui::OptionButton) +{ + ui->setupUi(this); + setCssProperty(ui->labelArrow3, "ic-arrow"); + setCssProperty(ui->layoutOptions2, "container-options"); + ui->layoutOptions2->setContentsMargins(0,10,10,10); + setCssProperty(ui->labelCircle, "btn-options-indicator"); + connect(ui->labelArrow3, &QPushButton::clicked, [this](){setChecked(!ui->labelArrow3->isChecked());}); + setActive(false); +} + +OptionButton::~OptionButton(){ + delete ui; +} + +void OptionButton::setTitleClassAndText(QString className, QString text){ + ui->labelTitleChange->setText(text); + setCssProperty(ui->labelTitleChange, className); +} + +void OptionButton::setTitleText(QString text){ + ui->labelTitleChange->setText(text); +} + +void OptionButton::setSubTitleClassAndText(QString className, QString text){ + ui->labelSubtitleChange->setText(text); + setCssProperty(ui->labelSubtitleChange, className); +} + +void OptionButton::setRightIconClass(QString className, bool forceUpdate){ + setCssProperty(ui->labelArrow3, className); + if(forceUpdate) updateStyle(ui->labelArrow3); +} + +void OptionButton::setRightIcon(QPixmap icon){ + //ui->labelArrow3->setPixmap(icon); +} + +void OptionButton::setActive(bool isActive){ + if (isActive) { + ui->layoutCircle->setVisible(true); + setCssProperty(ui->labelTitleChange, "btn-title-purple"); + updateStyle(ui->labelTitleChange); + } else { + ui->layoutCircle->setVisible(false); + setCssProperty(ui->labelTitleChange, "btn-title-grey"); + updateStyle(ui->labelTitleChange); + } +} + +void OptionButton::setChecked(bool checked){ + ui->labelArrow3->setChecked(checked); + emit clicked(); +} + +void OptionButton::mousePressEvent(QMouseEvent *qevent){ + if (qevent->button() == Qt::LeftButton){ + setChecked(!ui->labelArrow3->isChecked()); + } +} diff --git a/src/qt/pivx/optionbutton.h b/src/qt/pivx/optionbutton.h new file mode 100644 index 000000000000..c177d8ca7daf --- /dev/null +++ b/src/qt/pivx/optionbutton.h @@ -0,0 +1,39 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef OPTIONBUTTON_H +#define OPTIONBUTTON_H + +#include + +namespace Ui { +class OptionButton; +} + +class OptionButton : public QWidget +{ + Q_OBJECT + +public: + explicit OptionButton(QWidget *parent = nullptr); + ~OptionButton(); + + void setSubTitleClassAndText(QString className, QString text); + void setTitleClassAndText(QString className, QString text); + void setTitleText(QString text); + void setRightIconClass(QString className, bool forceUpdate = false); + void setRightIcon(QPixmap icon); + void setActive(bool); + void setChecked(bool checked); +signals: + void clicked(); + +protected: + virtual void mousePressEvent(QMouseEvent *qevent); + +private: + Ui::OptionButton *ui; +}; + +#endif // OPTIONBUTTON_H diff --git a/src/qt/pivx/pivxgui.cpp b/src/qt/pivx/pivxgui.cpp new file mode 100644 index 000000000000..dda325e9b1b8 --- /dev/null +++ b/src/qt/pivx/pivxgui.cpp @@ -0,0 +1,648 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/pivxgui.h" + +#ifdef Q_OS_MAC +#include "macdockiconhandler.h" +#endif + +#include +#include "clientmodel.h" +#include "optionsmodel.h" +#include "networkstyle.h" +#include "notificator.h" +#include "guiinterface.h" +#include "qt/pivx/qtutils.h" +#include "qt/pivx/defaultdialog.h" +#include "qt/pivx/settings/settingsfaqwidget.h" + +#include +#include +#include +#include +#include +#include + +#include "util.h" + + +const QString PIVXGUI::DEFAULT_WALLET = "~Default"; + +PIVXGUI::PIVXGUI(const NetworkStyle* networkStyle, QWidget* parent) : + QMainWindow(parent), + clientModel(0){ + + /* Open CSS when configured */ + this->setStyleSheet(GUIUtil::loadStyleSheet()); + this->setMinimumSize(1200, 740); + GUIUtil::restoreWindowGeometry("nWindow", QSize(1200, 740), this); + + QString windowTitle = tr("PIVX Core") + " - "; +#ifdef ENABLE_WALLET + /* if compiled with wallet support, -disablewallet can still disable the wallet */ + enableWallet = !GetBoolArg("-disablewallet", false); +#else + enableWallet = false; +#endif // ENABLE_WALLET + + if (enableWallet) { + windowTitle += tr("Wallet"); + } else { + windowTitle += tr("Node"); + } + + setWindowTitle(windowTitle); + +#ifndef Q_OS_MAC + QApplication::setWindowIcon(networkStyle->getAppIcon()); + setWindowIcon(networkStyle->getAppIcon()); +#else + MacDockIconHandler::instance()->setIcon(networkStyle->getAppIcon()); +#endif + + + + +#ifdef ENABLE_WALLET + // Create wallet frame + if(enableWallet){ + + QFrame* centralWidget = new QFrame(this); + this->setMinimumWidth(1200); + this->setMinimumHeight(740); + QHBoxLayout* centralWidgetLayouot = new QHBoxLayout(); + centralWidget->setLayout(centralWidgetLayouot); + centralWidgetLayouot->setContentsMargins(0,0,0,0); + centralWidgetLayouot->setSpacing(0); + + centralWidget->setProperty("cssClass", "container"); + centralWidget->setStyleSheet("padding:0px; border:none; margin:0px;"); + + // First the nav + navMenu = new NavMenuWidget(this); + centralWidgetLayouot->addWidget(navMenu); + + this->setCentralWidget(centralWidget); + this->setContentsMargins(0,0,0,0); + + QFrame *container = new QFrame(centralWidget); + container->setContentsMargins(0,0,0,0); + centralWidgetLayouot->addWidget(container); + + // Then topbar + the stackedWidget + QVBoxLayout *baseScreensContainer = new QVBoxLayout(this); + baseScreensContainer->setMargin(0); + baseScreensContainer->setSpacing(0); + baseScreensContainer->setContentsMargins(0,0,0,0); + container->setLayout(baseScreensContainer); + + // Insert the topbar + topBar = new TopBar(this); + topBar->setContentsMargins(0,0,0,0); + baseScreensContainer->addWidget(topBar); + + // Now stacked widget + stackedContainer = new QStackedWidget(this); + QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + stackedContainer->setSizePolicy(sizePolicy); + stackedContainer->setContentsMargins(0,0,0,0); + baseScreensContainer->addWidget(stackedContainer); + + // Init + dashboard = new DashboardWidget(this); + sendWidget = new SendWidget(this); + receiveWidget = new ReceiveWidget(this); + addressesWidget = new AddressesWidget(this); + privacyWidget = new PrivacyWidget(this); + masterNodesWidget = new MasterNodesWidget(this); + settingsWidget = new SettingsWidget(this); + + // Add to parent + stackedContainer->addWidget(dashboard); + stackedContainer->addWidget(sendWidget); + stackedContainer->addWidget(receiveWidget); + stackedContainer->addWidget(addressesWidget); + stackedContainer->addWidget(privacyWidget); + stackedContainer->addWidget(masterNodesWidget); + stackedContainer->addWidget(settingsWidget); + stackedContainer->setCurrentWidget(dashboard); + + } else +#endif + { + // When compiled without wallet or -disablewallet is provided, + // the central widget is the rpc console. + rpcConsole = new RPCConsole(enableWallet ? this : 0); + setCentralWidget(rpcConsole); + } + + // Create actions for the toolbar, menu bar and tray/dock icon + createActions(networkStyle); + + // Create system tray icon and notification + createTrayIcon(networkStyle); + + // Connect events + connectActions(); + + // TODO: Add event filter?? + // // Install event filter to be able to catch status tip events (QEvent::StatusTip) + // this->installEventFilter(this); + + // Subscribe to notifications from core + subscribeToCoreSignals(); + +} + +void PIVXGUI::createActions(const NetworkStyle* networkStyle){ + toggleHideAction = new QAction(networkStyle->getAppIcon(), tr("&Show / Hide"), this); + toggleHideAction->setStatusTip(tr("Show or hide the main Window")); + + quitAction = new QAction(QIcon(":/icons/quit"), tr("E&xit"), this); + quitAction->setStatusTip(tr("Quit application")); + quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q)); + quitAction->setMenuRole(QAction::QuitRole); + + connect(toggleHideAction, SIGNAL(triggered()), this, SLOT(toggleHidden())); + connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit())); +} + +/** + * Here add every event connection + */ +void PIVXGUI::connectActions() { + QShortcut *consoleShort = new QShortcut(this); + consoleShort->setKey(QKeySequence(SHORT_KEY + Qt::Key_C)); + connect(consoleShort, &QShortcut::activated, [this](){ + navMenu->selectSettings(); + settingsWidget->showDebugConsole(); + goToSettings(); + }); + connect(topBar, &TopBar::showHide, this, &PIVXGUI::showHide); + connect(topBar, &TopBar::themeChanged, this, &PIVXGUI::changeTheme); + connect(settingsWidget, &SettingsWidget::showHide, this, &PIVXGUI::showHide); + connect(sendWidget, &SendWidget::showHide, this, &PIVXGUI::showHide); + connect(receiveWidget, &ReceiveWidget::showHide, this, &PIVXGUI::showHide); + connect(addressesWidget, &AddressesWidget::showHide, this, &PIVXGUI::showHide); + connect(privacyWidget, &PrivacyWidget::showHide, this, &PIVXGUI::showHide); + connect(masterNodesWidget, &MasterNodesWidget::showHide, this, &PIVXGUI::showHide); + connect(masterNodesWidget, &MasterNodesWidget::execDialog, this, &PIVXGUI::execDialog); + connect(settingsWidget, &SettingsWidget::execDialog, this, &PIVXGUI::execDialog); +} + + +void PIVXGUI::createTrayIcon(const NetworkStyle* networkStyle) { +#ifndef Q_OS_MAC + trayIcon = new QSystemTrayIcon(this); + QString toolTip = tr("PIVX Core client") + " " + networkStyle->getTitleAddText(); + trayIcon->setToolTip(toolTip); + trayIcon->setIcon(networkStyle->getAppIcon()); + trayIcon->hide(); +#endif + notificator = new Notificator(QApplication::applicationName(), trayIcon, this); +} + +// +PIVXGUI::~PIVXGUI() { + // Unsubscribe from notifications from core + unsubscribeFromCoreSignals(); + + GUIUtil::saveWindowGeometry("nWindow", this); + if (trayIcon) // Hide tray icon, as deleting will let it linger until quit (on Ubuntu) + trayIcon->hide(); +#ifdef Q_OS_MAC + MacDockIconHandler::cleanup(); +#endif +} + + +/** Get restart command-line parameters and request restart */ +void PIVXGUI::handleRestart(QStringList args){ + if (!ShutdownRequested()) + emit requestedRestart(args); +} + + +void PIVXGUI::setClientModel(ClientModel* clientModel) { + this->clientModel = clientModel; + if(this->clientModel) { + + // Create system tray menu (or setup the dock menu) that late to prevent users from calling actions, + // while the client has not yet fully loaded + createTrayIconMenu(); + + topBar->setClientModel(clientModel); + dashboard->setClientModel(clientModel); + sendWidget->setClientModel(clientModel); + settingsWidget->setClientModel(clientModel); + + // Receive and report messages from client model + connect(clientModel, SIGNAL(message(QString, QString, unsigned int)), this, SLOT(message(QString, QString, unsigned int))); + connect(topBar, SIGNAL(walletSynced(bool)), dashboard, SLOT(walletSynced(bool))); + + // Get restart command-line parameters and handle restart + connect(settingsWidget, &SettingsWidget::handleRestart, [this](QStringList arg){handleRestart(arg);}); + + if (rpcConsole) { + rpcConsole->setClientModel(clientModel); + } + + if (trayIcon) { + trayIcon->show(); + } + } else { + // Disable possibility to show main window via action + toggleHideAction->setEnabled(false); + if (trayIconMenu) { + // Disable context menu on tray icon + trayIconMenu->clear(); + } + } +} + +void PIVXGUI::createTrayIconMenu() { +#ifndef Q_OS_MAC + // return if trayIcon is unset (only on non-Mac OSes) + if (!trayIcon) + return; + + trayIconMenu = new QMenu(this); + trayIcon->setContextMenu(trayIconMenu); + + connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), + this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); +#else + // Note: On Mac, the dock icon is used to provide the tray's functionality. + MacDockIconHandler* dockIconHandler = MacDockIconHandler::instance(); + dockIconHandler->setMainWindow((QMainWindow*)this); + trayIconMenu = dockIconHandler->dockMenu(); +#endif + + // Configuration of the tray icon (or dock icon) icon menu + trayIconMenu->addAction(toggleHideAction); + trayIconMenu->addSeparator(); + +#ifndef Q_OS_MAC // This is built-in on Mac + trayIconMenu->addSeparator(); + trayIconMenu->addAction(quitAction); +#endif +} + +#ifndef Q_OS_MAC +void PIVXGUI::trayIconActivated(QSystemTrayIcon::ActivationReason reason) +{ + if (reason == QSystemTrayIcon::Trigger) { + // Click on system tray icon triggers show/hide of the main window + toggleHidden(); + } +} +#endif + +void PIVXGUI::changeEvent(QEvent* e) +{ + QMainWindow::changeEvent(e); +#ifndef Q_OS_MAC // Ignored on Mac + if (e->type() == QEvent::WindowStateChange) { + if (clientModel && clientModel->getOptionsModel() && clientModel->getOptionsModel()->getMinimizeToTray()) { + QWindowStateChangeEvent* wsevt = static_cast(e); + if (!(wsevt->oldState() & Qt::WindowMinimized) && isMinimized()) { + QTimer::singleShot(0, this, SLOT(hide())); + e->ignore(); + } + } + } +#endif +} + +void PIVXGUI::closeEvent(QCloseEvent* event) +{ +#ifndef Q_OS_MAC // Ignored on Mac + if (clientModel && clientModel->getOptionsModel()) { + if (!clientModel->getOptionsModel()->getMinimizeOnClose()) { + QApplication::quit(); + } + } +#endif + QMainWindow::closeEvent(event); +} + + +void PIVXGUI::messageInfo(const QString& text){ + if(!this->snackBar) this->snackBar = new SnackBar(this, this); + this->snackBar->setText(text); + this->snackBar->resize(this->width(), snackBar->height()); + openDialog(this->snackBar, this); +} + + +void PIVXGUI::message(const QString& title, const QString& message, unsigned int style, bool* ret) { + QString strTitle = tr("PIVX Core"); // default title + // Default to information icon + int nNotifyIcon = Notificator::Information; + + QString msgType; + + // Prefer supplied title over style based title + if (!title.isEmpty()) { + msgType = title; + } else { + switch (style) { + case CClientUIInterface::MSG_ERROR: + msgType = tr("Error"); + break; + case CClientUIInterface::MSG_WARNING: + msgType = tr("Warning"); + break; + case CClientUIInterface::MSG_INFORMATION: + msgType = tr("Information"); + break; + default: + msgType = tr("System Message"); + break; + } + } + + // Check for error/warning icon + if (style & CClientUIInterface::ICON_ERROR) { + nNotifyIcon = Notificator::Critical; + } else if (style & CClientUIInterface::ICON_WARNING) { + nNotifyIcon = Notificator::Warning; + } + + // Display message + if (style & CClientUIInterface::MODAL) { + // Check for buttons, use OK as default, if none was supplied + int r = 0; + showNormalIfMinimized(); + if(style & CClientUIInterface::BTN_MASK){ + r = openStandardDialog( + (title.isEmpty() ? strTitle : title), message, "OK", "CANCEL" + ); + }else{ + r = openStandardDialog((title.isEmpty() ? strTitle : title), message, "OK"); + } + if (ret != NULL) + *ret = r; + } else if(style & CClientUIInterface::MSG_INFORMATION_SNACK){ + messageInfo(message); + }else { + // Append title to "PIVX - " + if (!msgType.isEmpty()) + strTitle += " - " + msgType; + notificator->notify((Notificator::Class) nNotifyIcon, strTitle, message); + } +} + +bool PIVXGUI::openStandardDialog(QString title, QString body, QString okBtn, QString cancelBtn){ + DefaultDialog *dialog; + if (isVisible()) { + showHide(true); + dialog = new DefaultDialog(this); + dialog->setText(title, body, okBtn, cancelBtn); + dialog->adjustSize(); + openDialogWithOpaqueBackground(dialog, this); + } else { + dialog = new DefaultDialog(); + dialog->setText(title, body, okBtn); + dialog->setWindowTitle(tr("PIVX Core")); + dialog->adjustSize(); + dialog->raise(); + dialog->exec(); + } + bool ret = dialog->isOk; + dialog->deleteLater(); + return ret; +} + + +void PIVXGUI::showNormalIfMinimized(bool fToggleHidden) { + if (!clientModel) + return; + // activateWindow() (sometimes) helps with keyboard focus on Windows + if (isHidden()) { + show(); + activateWindow(); + } else if (isMinimized()) { + showNormal(); + activateWindow(); + } else if (GUIUtil::isObscured(this)) { + raise(); + activateWindow(); + } else if (fToggleHidden) + hide(); +} + +void PIVXGUI::toggleHidden() { + showNormalIfMinimized(true); +} + +void PIVXGUI::detectShutdown() { + if (ShutdownRequested()) { + if (rpcConsole) + rpcConsole->hide(); + qApp->quit(); + } +} + +void PIVXGUI::goToDashboard(){ + if(stackedContainer->currentWidget() != dashboard){ + stackedContainer->setCurrentWidget(dashboard); + topBar->showBottom(); + } +} + +void PIVXGUI::goToSend(){ + showTop(sendWidget); +} + +void PIVXGUI::goToAddresses(){ + showTop(addressesWidget); +} + +void PIVXGUI::goToPrivacy(){ + showTop(privacyWidget); +} + +void PIVXGUI::goToMasterNodes(){ + showTop(masterNodesWidget); +} + +void PIVXGUI::goToSettings(){ + showTop(settingsWidget); +} + +void PIVXGUI::goToReceive(){ + showTop(receiveWidget); +} + +void PIVXGUI::showTop(QWidget* view){ + if(stackedContainer->currentWidget() != view){ + stackedContainer->setCurrentWidget(view); + topBar->showTop(); + } +} + +void PIVXGUI::changeTheme(bool isLightTheme){ + + QString css = GUIUtil::loadStyleSheet(); + this->setStyleSheet(css); + + // Notify + emit themeChanged(isLightTheme, css); + + // Update style + updateStyle(this); +} + +void PIVXGUI::resizeEvent(QResizeEvent* event){ + // Parent.. + QMainWindow::resizeEvent(event); + // background + showHide(opEnabled); + // Notify + emit windowResizeEvent(event); +} + +bool PIVXGUI::execDialog(QDialog *dialog, int xDiv, int yDiv){ + return openDialogWithOpaqueBackgroundY(dialog, this); +} + +void PIVXGUI::showHide(bool show){ + if(!op) op = new QLabel(this); + if(!show){ + op->setVisible(false); + opEnabled = false; + }else{ + QColor bg("#000000"); + bg.setAlpha(200); + if(!isLightTheme()){ + bg = QColor("#00000000"); + bg.setAlpha(150); + } + + QPalette palette; + palette.setColor(QPalette::Window, bg); + op->setAutoFillBackground(true); + op->setPalette(palette); + op->setWindowFlags(Qt::CustomizeWindowHint); + op->move(0,0); + op->show(); + op->activateWindow(); + op->resize(width(), height()); + op->setVisible(true); + opEnabled = true; + } +} + +int PIVXGUI::getNavWidth(){ + return this->navMenu->width(); +} + +void PIVXGUI::openFAQ(int section){ + showHide(true); + SettingsFaqWidget* dialog = new SettingsFaqWidget(this); + if (section > 0) dialog->setSection(section); + openDialogWithOpaqueBackgroundFullScreen(dialog, this); + dialog->deleteLater(); +} + + +#ifdef ENABLE_WALLET +bool PIVXGUI::addWallet(const QString& name, WalletModel* walletModel) +{ + // Single wallet supported for now.. + if(!stackedContainer || !clientModel || !walletModel) + return false; + + // todo: show out of sync warning.. + // todo: complete this next method + //connect(walletView, SIGNAL(showNormalIfMinimized()), gui, SLOT(showNormalIfMinimized())); + + // set the model for every view + dashboard->setWalletModel(walletModel); + topBar->setWalletModel(walletModel); + receiveWidget->setWalletModel(walletModel); + sendWidget->setWalletModel(walletModel); + addressesWidget->setWalletModel(walletModel); + privacyWidget->setWalletModel(walletModel); + masterNodesWidget->setWalletModel(walletModel); + settingsWidget->setWalletModel(walletModel); + + // Connect actions.. + connect(privacyWidget, &PrivacyWidget::message, this, &PIVXGUI::message); + connect(masterNodesWidget, &MasterNodesWidget::message, this, &PIVXGUI::message); + connect(topBar, &TopBar::message, this, &PIVXGUI::message); + connect(sendWidget, &SendWidget::message,this, &PIVXGUI::message); + connect(receiveWidget, &ReceiveWidget::message,this, &PIVXGUI::message); + connect(addressesWidget, &AddressesWidget::message,this, &PIVXGUI::message); + connect(settingsWidget, &SettingsWidget::message, this, &PIVXGUI::message); + + // Pass through transaction notifications + connect(dashboard, SIGNAL(incomingTransaction(QString, int, CAmount, QString, QString)), this, SLOT(incomingTransaction(QString, int, CAmount, QString, QString))); + + return true; +} + +bool PIVXGUI::setCurrentWallet(const QString& name) { + // Single wallet supported. + return true; +} + +void PIVXGUI::removeAllWallets() { + // Single wallet supported. +} + +void PIVXGUI::incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address) { + // Only send notifications when not disabled + if(!bdisableSystemnotifications){ + // On new transaction, make an info balloon + message((amount) < 0 ? (pwalletMain->fMultiSendNotify == true ? tr("Sent MultiSend transaction") : tr("Sent transaction")) : tr("Incoming transaction"), + tr("Date: %1\n" + "Amount: %2\n" + "Type: %3\n" + "Address: %4\n") + .arg(date) + .arg(BitcoinUnits::formatWithUnit(unit, amount, true)) + .arg(type) + .arg(address), + CClientUIInterface::MSG_INFORMATION); + + pwalletMain->fMultiSendNotify = false; + } +} + +#endif // ENABLE_WALLET + + +static bool ThreadSafeMessageBox(PIVXGUI* gui, const std::string& message, const std::string& caption, unsigned int style) +{ + bool modal = (style & CClientUIInterface::MODAL); + // The SECURE flag has no effect in the Qt GUI. + // bool secure = (style & CClientUIInterface::SECURE); + style &= ~CClientUIInterface::SECURE; + bool ret = false; + std::cout << "thread safe box: " << message << std::endl; + // In case of modal message, use blocking connection to wait for user to click a button + QMetaObject::invokeMethod(gui, "message", + modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(caption)), + Q_ARG(QString, QString::fromStdString(message)), + Q_ARG(unsigned int, style), + Q_ARG(bool*, &ret)); + return ret; +} + + +void PIVXGUI::subscribeToCoreSignals() +{ + // Connect signals to client + uiInterface.ThreadSafeMessageBox.connect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3)); +} + +void PIVXGUI::unsubscribeFromCoreSignals() +{ + // Disconnect signals from client + uiInterface.ThreadSafeMessageBox.disconnect(boost::bind(ThreadSafeMessageBox, this, _1, _2, _3)); +} diff --git a/src/qt/pivx/pivxgui.h b/src/qt/pivx/pivxgui.h new file mode 100644 index 000000000000..59289edf642a --- /dev/null +++ b/src/qt/pivx/pivxgui.h @@ -0,0 +1,186 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef PIVX_CORE_NEW_GUI_PIVXGUI_H +#define PIVX_CORE_NEW_GUI_PIVXGUI_H + +#if defined(HAVE_CONFIG_H) +#include "config/pivx-config.h" +#endif + +#include +#include +#include +#include + +#include "qt/pivx/navmenuwidget.h" +#include "qt/pivx/topbar.h" +#include "qt/pivx/dashboardwidget.h" +#include "qt/pivx/send.h" +#include "qt/pivx/receivewidget.h" +#include "qt/pivx/addresseswidget.h" +#include "qt/pivx/privacywidget.h" +#include "qt/pivx/masternodeswidget.h" +#include "qt/pivx/snackbar.h" +#include "qt/pivx/settings/settingswidget.h" +#include "qt/rpcconsole.h" + + +class ClientModel; +class NetworkStyle; +class Notificator; +class WalletModel; + + +/** + PIVX GUI main class. This class represents the main window of the PIVX UI. It communicates with both the client and + wallet models to give the user an up-to-date view of the current core state. +*/ +class PIVXGUI : public QMainWindow +{ + Q_OBJECT + +public: + static const QString DEFAULT_WALLET; + + explicit PIVXGUI(const NetworkStyle* networkStyle, QWidget* parent = 0); + ~PIVXGUI(); + + /** Set the client model. + The client model represents the part of the core that communicates with the P2P network, and is wallet-agnostic. + */ + void setClientModel(ClientModel* clientModel); + + + void resizeEvent(QResizeEvent *event) override; + void showHide(bool show); + int getNavWidth(); +signals: + void themeChanged(bool isLightTheme, QString& theme); + void windowResizeEvent(QResizeEvent* event); +public slots: + void changeTheme(bool isLightTheme); + void goToDashboard(); + void goToSend(); + void goToReceive(); + void goToAddresses(); + void goToPrivacy(); + void goToMasterNodes(); + void goToSettings(); + + void connectActions(); + + /** Get restart command-line parameters and request restart */ + void handleRestart(QStringList args); + + /** Notify the user of an event from the core network or transaction handling code. + @param[in] title the message box / notification title + @param[in] message the displayed text + @param[in] style modality and style definitions (icon and used buttons - buttons only for message boxes) + @see CClientUIInterface::MessageBoxFlags + @param[in] ret pointer to a bool that will be modified to whether Ok was clicked (modal only) + */ + void message(const QString& title, const QString& message, unsigned int style, bool* ret = nullptr); + void messageInfo(const QString& message); + bool execDialog(QDialog *dialog, int xDiv = 3, int yDiv = 5); + /** Open FAQ dialog **/ + void openFAQ(int section = 0); + + /** Show incoming transaction notification for new transactions. */ + void incomingTransaction(const QString& date, int unit, const CAmount& amount, const QString& type, const QString& address); +#ifdef ENABLE_WALLET + /** Set the wallet model. + The wallet model represents a bitcoin wallet, and offers access to the list of transactions, address book and sending + functionality. + */ + bool addWallet(const QString& name, WalletModel* walletModel); + bool setCurrentWallet(const QString& name); + void removeAllWallets(); +#endif // ENABLE_WALLET + +protected: + + void changeEvent(QEvent* e) override; + void closeEvent(QCloseEvent* event) override; + + /* + void dragEnterEvent(QDragEnterEvent* event); + void dropEvent(QDropEvent* event); + bool eventFilter(QObject* object, QEvent* event); + */ + +private: + bool enableWallet; + ClientModel* clientModel = nullptr; + + // Actions + QAction* quitAction = nullptr; + QAction* toggleHideAction = nullptr; + + + // Frame + NavMenuWidget *navMenu = nullptr; + TopBar *topBar = nullptr; + QStackedWidget *stackedContainer = nullptr; + + DashboardWidget *dashboard = nullptr; + SendWidget *sendWidget = nullptr; + ReceiveWidget *receiveWidget = nullptr; + AddressesWidget *addressesWidget = nullptr; + PrivacyWidget *privacyWidget = nullptr; + MasterNodesWidget *masterNodesWidget = nullptr; + SettingsWidget* settingsWidget = nullptr; + + SnackBar *snackBar = nullptr; + + RPCConsole* rpcConsole = nullptr; + + // + QSystemTrayIcon* trayIcon = nullptr; + QMenu* trayIconMenu = nullptr; + Notificator* notificator = nullptr; + + QLabel *op = nullptr; + bool opEnabled = false; + + /** Create the main UI actions. */ + void createActions(const NetworkStyle* networkStyle); + /** Create system tray icon and notification */ + void createTrayIcon(const NetworkStyle* networkStyle); + /** Create system tray menu (or setup the dock menu) */ + void createTrayIconMenu(); + + void showTop(QWidget *view); + bool openStandardDialog(QString title = "", QString body = "", QString okBtn = "OK", QString cancelBtn = "CANCEL"); + + /** Connect core signals to GUI client */ + void subscribeToCoreSignals(); + /** Disconnect core signals from GUI client */ + void unsubscribeFromCoreSignals(); + +private slots: + /** Show window if hidden, unminimize when minimized, rise when obscured or show if hidden and fToggleHidden is true */ + void showNormalIfMinimized(bool fToggleHidden = false); + + /** Simply calls showNormalIfMinimized(true) for use in SLOT() macro */ + void toggleHidden(); + + /** called by a timer to check if fRequestShutdown has been set **/ + void detectShutdown(); + +#ifndef Q_OS_MAC + /** Handle tray icon clicked */ + void trayIconActivated(QSystemTrayIcon::ActivationReason reason); +#endif + +signals: + /** Signal raised when a URI was entered or dragged to the GUI */ + void receivedURI(const QString& uri); + /** Restart handling */ + void requestedRestart(QStringList args); + +}; + + +#endif //PIVX_CORE_NEW_GUI_PIVXGUI_H diff --git a/src/qt/pivx/privacywidget.cpp b/src/qt/pivx/privacywidget.cpp new file mode 100644 index 000000000000..1d9e8e3a22e1 --- /dev/null +++ b/src/qt/pivx/privacywidget.cpp @@ -0,0 +1,441 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/privacywidget.h" +#include "qt/pivx/forms/ui_privacywidget.h" +#include "qt/pivx/qtutils.h" +#include "guiutil.h" +#include "qt/pivx/denomgenerationdialog.h" +#include "qt/pivx/txviewholder.h" +#include "walletmodel.h" +#include "optionsmodel.h" +#include "coincontroldialog.h" +#include "coincontrol.h" +#include "zpiv/accumulators.h" + +#define DECORATION_SIZE 65 +#define NUM_ITEMS 3 + +PrivacyWidget::PrivacyWidget(PIVXGUI* parent) : + PWidget(parent), + ui(new Ui::PrivacyWidget) +{ + ui->setupUi(this); + this->setStyleSheet(parent->styleSheet()); + + /* Containers */ + setCssProperty(ui->left, "container"); + ui->left->setContentsMargins(0,20,0,0); + setCssProperty(ui->right, "container-right"); + ui->right->setContentsMargins(20,10,20,20); + + /* Light Font */ + QFont fontLight; + fontLight.setWeight(QFont::Light); + + /* Title */ + ui->labelTitle->setText(tr("Privacy")); + setCssTitleScreen(ui->labelTitle); + ui->labelTitle->setFont(fontLight); + + /* Button Group */ + ui->pushLeft->setText(tr("Convert")); + setCssProperty(ui->pushLeft, "btn-check-left"); + ui->pushRight->setText(tr("Mint")); + setCssProperty(ui->pushRight, "btn-check-right"); + + /* Subtitle */ + ui->labelSubtitle1->setText(tr("Minting zPIV anonymizes your PIV by removing any\ntransaction history, making transactions untraceable ")); + setCssSubtitleScreen(ui->labelSubtitle1); + + ui->labelSubtitle2->setText(tr("Mint new zPIV or convert back to PIV")); + setCssSubtitleScreen(ui->labelSubtitle2); + ui->labelSubtitle2->setContentsMargins(0,2,0,0); + setCssProperty(ui->labelSubtitleAmount, "text-title"); + + ui->lineEditAmount->setPlaceholderText("0.00 PIV "); + ui->lineEditAmount->setValidator(new QRegExpValidator(QRegExp("[0-9]+"))); + initCssEditLine(ui->lineEditAmount); + + /* Denom */ + ui->labelTitleDenom1->setText("Denom. with value 1:"); + setCssProperty(ui->labelTitleDenom1, "text-subtitle"); + ui->labelValueDenom1->setText("0x1 = 0 zPIV"); + setCssProperty(ui->labelValueDenom1, "text-body2"); + + ui->labelTitleDenom5->setText("Denom. with value 5:"); + setCssProperty(ui->labelTitleDenom5, "text-subtitle"); + ui->labelValueDenom5->setText("0x5 = 0 zPIV"); + setCssProperty(ui->labelValueDenom5, "text-body2"); + + ui->labelTitleDenom10->setText("Denom. with value 10:"); + setCssProperty(ui->labelTitleDenom10, "text-subtitle"); + ui->labelValueDenom10->setText("0x10 = 0 zPIV"); + setCssProperty(ui->labelValueDenom10, "text-body2"); + + ui->labelTitleDenom50->setText("Denom. with value 50:"); + setCssProperty(ui->labelTitleDenom50, "text-subtitle"); + ui->labelValueDenom50->setText("0x50 = 0 zPIV"); + setCssProperty(ui->labelValueDenom50, "text-body2"); + + ui->labelTitleDenom100->setText("Denom. with value 100:"); + setCssProperty(ui->labelTitleDenom100, "text-subtitle"); + ui->labelValueDenom100->setText("0x100 = 0 zPIV"); + setCssProperty(ui->labelValueDenom100, "text-body2"); + + ui->labelTitleDenom500->setText("Denom. with value 500:"); + setCssProperty(ui->labelTitleDenom500, "text-subtitle"); + ui->labelValueDenom500->setText("0x500 = 0 zPIV"); + setCssProperty(ui->labelValueDenom500, "text-body2"); + + ui->labelTitleDenom1000->setText("Denom. with value 1000:"); + setCssProperty(ui->labelTitleDenom1000, "text-subtitle"); + ui->labelValueDenom1000->setText("0x1000 = 0 zPIV"); + setCssProperty(ui->labelValueDenom1000, "text-body2"); + + ui->labelTitleDenom5000->setText("Denom. with value 5000:"); + setCssProperty(ui->labelTitleDenom5000, "text-subtitle"); + ui->labelValueDenom5000->setText("0x5000 = 0 zPIV"); + setCssProperty(ui->labelValueDenom5000, "text-body2"); + + ui->layoutDenom->setVisible(false); + + // List + ui->labelListHistory->setText(tr("Last Zerocoin Movements")); + setCssProperty(ui->labelListHistory, "text-title"); + + //ui->emptyContainer->setVisible(false); + setCssProperty(ui->pushImgEmpty, "img-empty-privacy"); + ui->labelEmpty->setText(tr("No transactions yet")); + setCssProperty(ui->labelEmpty, "text-empty"); + + // Buttons + setCssBtnPrimary(ui->pushButtonSave); + + // Only Convert to PIV enabled. + ui->containerViewPrivacyChecks->setVisible(false); + onMintSelected(false); + + ui->btnTotalzPIV->setTitleClassAndText("btn-title-grey", "Total 0 zPIV"); + ui->btnTotalzPIV->setSubTitleClassAndText("text-subtitle", "Show denominations of zPIV owned."); + ui->btnTotalzPIV->setRightIconClass("ic-arrow"); + + ui->btnCoinControl->setTitleClassAndText("btn-title-grey", "Coin Control"); + ui->btnCoinControl->setSubTitleClassAndText("text-subtitle", "Select PIV outputs to mint into zPIV."); + + ui->btnDenomGeneration->setTitleClassAndText("btn-title-grey", "Denom Generation"); + ui->btnDenomGeneration->setSubTitleClassAndText("text-subtitle", "Select the denomination of the coins."); + ui->btnDenomGeneration->setVisible(false); + + ui->btnRescanMints->setTitleClassAndText("btn-title-grey", "Rescan Mints"); + ui->btnRescanMints->setSubTitleClassAndText("text-subtitle", "Find mints in the blockchain."); + + ui->btnResetZerocoin->setTitleClassAndText("btn-title-grey", "Reset Zerocoin"); + ui->btnResetZerocoin->setSubTitleClassAndText("text-subtitle", "Reset zerocoin database."); + + connect(ui->btnTotalzPIV, SIGNAL(clicked()), this, SLOT(onTotalZpivClicked())); + connect(ui->btnCoinControl, SIGNAL(clicked()), this, SLOT(onCoinControlClicked())); + connect(ui->btnDenomGeneration, SIGNAL(clicked()), this, SLOT(onDenomClicked())); + connect(ui->btnRescanMints, SIGNAL(clicked()), this, SLOT(onRescanMintsClicked())); + connect(ui->btnResetZerocoin, SIGNAL(clicked()), this, SLOT(onResetZeroClicked())); + + ui->pushRight->setChecked(true); + connect(ui->pushLeft, &QPushButton::clicked, [this](){onMintSelected(false);}); + connect(ui->pushRight, &QPushButton::clicked, [this](){onMintSelected(true);}); + + // List + setCssProperty(ui->listView, "container"); + txHolder = new TxViewHolder(isLightTheme()); + delegate = new FurAbstractListItemDelegate( + DECORATION_SIZE, + txHolder, + this + ); + + ui->listView->setItemDelegate(delegate); + ui->listView->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE)); + ui->listView->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2)); + ui->listView->setAttribute(Qt::WA_MacShowFocusRect, false); + ui->listView->setSelectionBehavior(QAbstractItemView::SelectRows); +} + +void PrivacyWidget::loadWalletModel(){ + if(walletModel) { + txModel = walletModel->getTransactionTableModel(); + // Set up transaction list + filter = new TransactionFilterProxy(); + filter->setSourceModel(txModel); + filter->sort(TransactionTableModel::Date, Qt::DescendingOrder); + filter->setShowZcTxes(true); + txHolder->setDisplayUnit(walletModel->getOptionsModel()->getDisplayUnit()); + txHolder->setFilter(filter); + ui->listView->setModel(filter); + + updateDisplayUnit(); + updateDenomsSupply(); + + if (!txModel->hasZcTxes()) { + ui->emptyContainer->setVisible(true); + ui->listView->setVisible(false); + }else{ + showList(); + } + + connect(ui->pushButtonSave, SIGNAL(clicked()), this, SLOT(onSendClicked())); + } + +} + +void PrivacyWidget::onMintSelected(bool isMint){ + QString btnText; + if(isMint){ + btnText = tr("Mint zPIV"); + ui->btnCoinControl->setVisible(true); + ui->labelSubtitleAmount->setText(tr("Enter amount of PIV to mint into zPIV")); + }else{ + btnText = tr("Convert back to PIV"); + ui->btnCoinControl->setVisible(false); + ui->labelSubtitleAmount->setText(tr("Enter amount of zPIV to convert back into PIV")); + } + ui->pushButtonSave->setText(btnText); +} + +void PrivacyWidget::updateDisplayUnit() { + if (walletModel && walletModel->getOptionsModel()) { + nDisplayUnit = walletModel->getOptionsModel()->getDisplayUnit(); + + txHolder->setDisplayUnit(nDisplayUnit); + ui->listView->update(); + } +} + +void PrivacyWidget::showList(){ + ui->emptyContainer->setVisible(false); + ui->listView->setVisible(true); +} + +void PrivacyWidget::onTotalZpivClicked(){ + bool isVisible = ui->layoutDenom->isVisible(); + if(!isVisible){ + ui->layoutDenom->setVisible(true); + ui->btnTotalzPIV->setRightIconClass("btn-dropdown", true); + }else{ + ui->layoutDenom->setVisible(false); + ui->btnTotalzPIV->setRightIconClass("ic-arrow", true); + } +} + +void PrivacyWidget::onSendClicked(){ + if (!walletModel || !walletModel->getOptionsModel()) + return; + + if(GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { + warn(tr("Zerocoin"), tr("zPIV is currently undergoing maintenance")); + return; + } + + // Only convert enabled. + bool isConvert = true;// ui->pushLeft->isChecked(); + + if(!GUIUtil::requestUnlock(walletModel, AskPassphraseDialog::Context::Mint_zPIV, true)){ + inform(tr("You need to unlock the wallet to be able to %1 zPIV").arg(isConvert ? tr("convert") : tr("mint"))); + return; + } + + bool isValid = true; + CAmount value = GUIUtil::parseValue( + ui->lineEditAmount->text(), + walletModel->getOptionsModel()->getDisplayUnit(), + &isValid + ); + + if (!isValid || value <= 0) { + setCssEditLine(ui->lineEditAmount, false, true); + inform(tr("Invalid value")); + return; + } + + setCssEditLine(ui->lineEditAmount, true, true); + if(isConvert){ + spend(value); + }else{ + mint(value); + } +} + +void PrivacyWidget::mint(CAmount value){ + std::string strError; + if(!walletModel->mintCoins(value, CoinControlDialog::coinControl, strError)){ + inform(tr(strError.data())); + }else{ + // Mint succeed + inform(tr("zPIV minted successfully")); + // clear + ui->lineEditAmount->clear(); + } +} + +void PrivacyWidget::spend(CAmount value){ + CZerocoinSpendReceipt receipt; + std::vector selectedMints; + bool mintChange = false; + bool minimizeChange = false; + + if(!walletModel->convertBackZpiv( + value, + selectedMints, + mintChange, + minimizeChange, + receipt, + walletModel->getNewAddress() + )){ + inform(receipt.GetStatusMessage().data()); + }else{ + // Spend succeed + inform(tr("zPIV converted back to PIV")); + // clear + ui->lineEditAmount->clear(); + } +} + + +void PrivacyWidget::onCoinControlClicked(){ + if(ui->pushRight->isChecked()) { + if (walletModel->getBalance() > 0) { + if (!coinControlDialog) { + coinControlDialog = new CoinControlDialog(); + coinControlDialog->setModel(walletModel); + } + coinControlDialog->exec(); + ui->btnCoinControl->setActive(CoinControlDialog::coinControl->HasSelected()); + } else { + inform(tr("You don't have any PIV to select.")); + } + } +} + +void PrivacyWidget::onDenomClicked(){ + showHideOp(true); + DenomGenerationDialog* dialog = new DenomGenerationDialog(window); + openDialogWithOpaqueBackgroundY(dialog, window, 4.5, 5); +} + +void PrivacyWidget::onRescanMintsClicked(){ + if (ask(tr("Rescan Mints"), + tr("Your zerocoin mints are going to be scanned from the blockchain from scratch")) + ){ + std::string strResetMintResult = walletModel->resetMintZerocoin(); + inform(QString::fromStdString(strResetMintResult)); + } +} + +void PrivacyWidget::onResetZeroClicked(){ + if (ask(tr("Reset Spent Zerocoins"), + tr("Your zerocoin spends are going to be scanned from the blockchain from scratch")) + ){ + std::string strResetMintResult = walletModel->resetSpentZerocoin(); + inform(QString::fromStdString(strResetMintResult)); + } +} + +void PrivacyWidget::updateDenomsSupply(){ + std::map mapDenomBalances; + std::map mapUnconfirmed; + std::map mapImmature; + for (const auto& denom : libzerocoin::zerocoinDenomList){ + mapDenomBalances.insert(std::make_pair(denom, 0)); + mapUnconfirmed.insert(std::make_pair(denom, 0)); + mapImmature.insert(std::make_pair(denom, 0)); + } + + std::set vMints; + walletModel->listZerocoinMints(vMints, true, false, true, true); + + std::map mapMaturityHeights = GetMintMaturityHeight(); + for (auto& meta : vMints){ + // All denominations + mapDenomBalances.at(meta.denom)++; + + if (!meta.nHeight || chainActive.Height() - meta.nHeight <= Params().Zerocoin_MintRequiredConfirmations()) { + // All unconfirmed denominations + mapUnconfirmed.at(meta.denom)++; + } else { + if (meta.denom == libzerocoin::CoinDenomination::ZQ_ERROR) { + mapImmature.at(meta.denom)++; + } else if (meta.nHeight >= mapMaturityHeights.at(meta.denom)) { + mapImmature.at(meta.denom)++; + } + } + } + + int64_t nCoins = 0; + int64_t nSumPerCoin = 0; + int64_t nUnconfirmed = 0; + int64_t nImmature = 0; + QString strDenomStats, strUnconfirmed = ""; + + for (const auto& denom : libzerocoin::zerocoinDenomList) { + nCoins = libzerocoin::ZerocoinDenominationToInt(denom); + nSumPerCoin = nCoins * mapDenomBalances.at(denom); + nUnconfirmed = mapUnconfirmed.at(denom); + nImmature = mapImmature.at(denom); + + strUnconfirmed = ""; + if (nUnconfirmed) { + strUnconfirmed += QString::number(nUnconfirmed) + QString(" unconf. "); + } + if(nImmature) { + strUnconfirmed += QString::number(nImmature) + QString(" immature "); + } + if(nImmature || nUnconfirmed) { + strUnconfirmed = QString("( ") + strUnconfirmed + QString(") "); + } + + strDenomStats = strUnconfirmed + QString::number(mapDenomBalances.at(denom)) + " x " + + QString::number(nCoins) + " = " + + QString::number(nSumPerCoin) + " zPIV "; + + switch (nCoins) { + case libzerocoin::CoinDenomination::ZQ_ONE: + ui->labelValueDenom1->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_FIVE: + ui->labelValueDenom5->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_TEN: + ui->labelValueDenom10->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_FIFTY: + ui->labelValueDenom50->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_ONE_HUNDRED: + ui->labelValueDenom100->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_FIVE_HUNDRED: + ui->labelValueDenom500->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_ONE_THOUSAND: + ui->labelValueDenom1000->setText(strDenomStats); + break; + case libzerocoin::CoinDenomination::ZQ_FIVE_THOUSAND: + ui->labelValueDenom5000->setText(strDenomStats); + break; + default: + // Error Case: don't update display + break; + } + } + + CAmount matureZerocoinBalance = walletModel->getZerocoinBalance() - walletModel->getUnconfirmedZerocoinBalance() - walletModel->getImmatureZerocoinBalance(); + ui->btnTotalzPIV->setTitleText(tr("Total %1").arg(GUIUtil::formatBalance(matureZerocoinBalance, nDisplayUnit, true))); +} + +void PrivacyWidget::changeTheme(bool isLightTheme, QString& theme){ + static_cast(this->delegate->getRowFactory())->isLightTheme = isLightTheme; + ui->listView->update(); +} + +PrivacyWidget::~PrivacyWidget(){ + delete ui; +} diff --git a/src/qt/pivx/privacywidget.h b/src/qt/pivx/privacywidget.h new file mode 100644 index 000000000000..b0cf3a9f1991 --- /dev/null +++ b/src/qt/pivx/privacywidget.h @@ -0,0 +1,64 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef PRIVACYWIDGET_H +#define PRIVACYWIDGET_H + +#include "qt/pivx/pwidget.h" +#include "qt/pivx/furabstractlistitemdelegate.h" +#include "qt/pivx/txviewholder.h" +#include "transactiontablemodel.h" +#include "transactionfilterproxy.h" +#include "coincontroldialog.h" + +#include +#include + +class PIVXGUI; +class WalletModel; + +namespace Ui { +class PrivacyWidget; +} + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +class PrivacyWidget : public PWidget +{ + Q_OBJECT + +public: + explicit PrivacyWidget(PIVXGUI* parent); + ~PrivacyWidget(); + + void loadWalletModel() override; +private slots: + void changeTheme(bool isLightTheme, QString &theme) override; + void onCoinControlClicked(); + void onDenomClicked(); + void onRescanMintsClicked(); + void onResetZeroClicked(); + void onTotalZpivClicked(); + void updateDisplayUnit(); + void showList(); + void onSendClicked(); + void onMintSelected(bool isMint); + +private: + Ui::PrivacyWidget *ui; + FurAbstractListItemDelegate *delegate = nullptr; + TransactionTableModel* txModel = nullptr; + TxViewHolder *txHolder = nullptr; + TransactionFilterProxy* filter = nullptr; + CoinControlDialog *coinControlDialog = nullptr; + + int nDisplayUnit; + void mint(CAmount value); + void spend(CAmount value); + void updateDenomsSupply(); +}; + +#endif // PRIVACYWIDGET_H diff --git a/src/qt/pivx/prunnable.h b/src/qt/pivx/prunnable.h new file mode 100644 index 000000000000..9c5e525b934f --- /dev/null +++ b/src/qt/pivx/prunnable.h @@ -0,0 +1,14 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef PIVX_CORE_NEW_GUI_PRUNNABLE_H +#define PIVX_CORE_NEW_GUI_PRUNNABLE_H + +class Runnable { +public: + virtual void run(int type) = 0; + virtual void onError(int type, QString error) = 0; +}; + +#endif //PIVX_CORE_NEW_GUI_PRUNNABLE_H diff --git a/src/qt/pivx/pwidget.cpp b/src/qt/pivx/pwidget.cpp new file mode 100644 index 000000000000..10373a2e24fe --- /dev/null +++ b/src/qt/pivx/pwidget.cpp @@ -0,0 +1,120 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/pwidget.h" +#include "qt/pivx/qtutils.h" +#include "qt/pivx/moc_pwidget.cpp" +#include "qt/pivx/loadingdialog.h" + +PWidget::PWidget(PIVXGUI* _window, QWidget *parent) : QWidget((parent) ? parent : _window), window(_window){init();} +PWidget::PWidget(PWidget* parent) : QWidget(parent), window(parent->getWindow()){init();} + +void PWidget::init() { + if(window) + connect(window, SIGNAL(themeChanged(bool, QString&)), this, SLOT(onChangeTheme(bool, QString&))); +} + +void PWidget::setClientModel(ClientModel* model){ + this->clientModel = model; + loadClientModel(); +} + +void PWidget::setWalletModel(WalletModel* model){ + this->walletModel = model; + loadWalletModel(); +} + +void PWidget::onChangeTheme(bool isLightTheme, QString& theme){ + this->setStyleSheet(theme); + changeTheme(isLightTheme, theme); + updateStyle(this); +} + +void PWidget::showHideOp(bool show){ + emit showHide(show); +} + +void PWidget::inform(const QString& message){ + emitMessage("", message, CClientUIInterface::MSG_INFORMATION_SNACK); +} + +void PWidget::warn(const QString& title, const QString& message){ + emitMessage(title, message, CClientUIInterface::MSG_ERROR); +} + +bool PWidget::ask(const QString& title, const QString& message){ + bool ret = false; + emitMessage(title, message, CClientUIInterface::MSG_INFORMATION | CClientUIInterface::BTN_MASK | CClientUIInterface::MODAL, &ret); + return ret; +} + +void PWidget::showDialog(QDialog *dlg, int xDiv, int yDiv){ + emit execDialog(dlg, xDiv, yDiv); +} + +void PWidget::emitMessage(const QString& title, const QString& body, unsigned int style, bool* ret){ + emit message(title, body, style, ret); +} + +bool PWidget::execute(int type){ + // if the thread it's already running don't start a new task + if (!quitWorker(false)) + return false; + + thread = new QThread; + Worker* worker = new Worker(this, type); + worker->moveToThread(thread); + connect(worker, SIGNAL (error(QString&)), this, SLOT (errorString(QString))); + connect(thread, SIGNAL (started()), worker, SLOT (process())); + connect(worker, SIGNAL (finished()), thread, SLOT (quit())); + connect(worker, SIGNAL (finished()), worker, SLOT (deleteLater())); + connect(thread, SIGNAL (finished()), thread, SLOT (deleteLater())); + connect(thread, &QThread::destroyed, [this](){ this->thread = nullptr; }); + thread->start(); + return true; +} + +bool PWidget::verifyWalletUnlocked(){ + if (!walletModel->isWalletUnlocked()) { + inform(tr("Wallet locked, you need to unlock it to perform this action")); + return false; + } + return true; +} + +bool PWidget::quitWorker(bool forceTermination) { + if (thread) { + // don't run it if it's already running + if (!thread->isFinished() && !forceTermination) + return false; + thread->quit(); + delete thread; + thread = nullptr; + } + return true; +} + +//////////////////////////////////////////////////////////////// +//////////////////Override methods////////////////////////////// +//////////////////////////////////////////////////////////////// + + +void PWidget::loadClientModel(){ + // override +} + +void PWidget::loadWalletModel(){ + // override +} + +void PWidget::changeTheme(bool isLightTheme, QString& theme){ + // override +} + +void PWidget::run(int type) { + // override +} +void PWidget::onError(int type, QString error) { + // override +} \ No newline at end of file diff --git a/src/qt/pivx/pwidget.h b/src/qt/pivx/pwidget.h new file mode 100644 index 000000000000..abf17bda64e4 --- /dev/null +++ b/src/qt/pivx/pwidget.h @@ -0,0 +1,71 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef PWIDGET_H +#define PWIDGET_H + +#include +#include +#include +#include +#include "qt/pivx/prunnable.h" + +class PIVXGUI; +class ClientModel; +class WalletModel; + +namespace Ui { +class PWidget; +} + +class PWidget : public QWidget, public Runnable +{ + Q_OBJECT +public: + explicit PWidget(PIVXGUI* _window = nullptr, QWidget *parent = nullptr); + explicit PWidget(PWidget *parent = nullptr); + + void setClientModel(ClientModel* model); + void setWalletModel(WalletModel* model); + + PIVXGUI* getWindow() { return this->window; } + + void run(int type) override; + void onError(int type, QString error) override; + +signals: + void message(const QString& title, const QString& body, unsigned int style, bool* ret = nullptr); + void showHide(bool show); + bool execDialog(QDialog *dialog, int xDiv = 3, int yDiv = 5); + +protected slots: + virtual void changeTheme(bool isLightTheme, QString &theme); + void onChangeTheme(bool isLightTheme, QString &theme); + +protected: + PIVXGUI* window = nullptr; + ClientModel* clientModel = nullptr; + WalletModel* walletModel = nullptr; + + virtual void loadClientModel(); + virtual void loadWalletModel(); + + void showHideOp(bool show); + bool execute(int type); + void inform(const QString& message); + void warn(const QString& title, const QString& message); + bool ask(const QString& title, const QString& message); + void showDialog(QDialog *dialog, int xDiv = 3, int yDiv = 5); + void emitMessage(const QString& title, const QString& message, unsigned int style, bool* ret = nullptr); + + bool verifyWalletUnlocked(); + bool quitWorker(bool forceTermination); + +private: + QThread* thread = nullptr; + + void init(); +}; + +#endif // PWIDGET_H diff --git a/src/qt/pivx/qtutils.cpp b/src/qt/pivx/qtutils.cpp new file mode 100644 index 000000000000..accd641fa349 --- /dev/null +++ b/src/qt/pivx/qtutils.cpp @@ -0,0 +1,252 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/qtutils.h" + +#include "qt/pivx/snackbar.h" +#include "qrencode.h" +#include "guiconstants.h" + +#include +#include +#include +#include + +// Open dialog at the bottom +bool openDialog(QDialog *widget, QWidget *gui){ + widget->setWindowFlags(Qt::CustomizeWindowHint); + widget->setAttribute(Qt::WA_TranslucentBackground, true); + QPropertyAnimation* animation = new QPropertyAnimation(widget, "pos"); + animation->setDuration(300); + animation->setStartValue(QPoint(0, gui->height())); + animation->setEndValue(QPoint(0, gui->height() - widget->height())); + animation->setEasingCurve(QEasingCurve::OutQuad); + animation->start(QAbstractAnimation::DeleteWhenStopped); + widget->activateWindow(); + widget->raise(); + return widget->exec(); +} + +void closeDialog(QDialog *widget, PIVXGUI *gui){ + widget->setWindowFlags(Qt::CustomizeWindowHint); + widget->setAttribute(Qt::WA_TranslucentBackground, true); + QPropertyAnimation* animation = new QPropertyAnimation(widget, "pos"); + animation->setDuration(300); + animation->setStartValue(widget->pos()); + animation->setEndValue(QPoint(0, gui->height() + 100)); + animation->setEasingCurve(QEasingCurve::OutQuad); + animation->start(QAbstractAnimation::DeleteWhenStopped); +} + +void openDialogFullScreen(QWidget *parent, QWidget * dialog){ + dialog->setWindowFlags(Qt::CustomizeWindowHint); + dialog->move(0, 0); + dialog->show(); + dialog->activateWindow(); + dialog->resize(parent->width(),parent->height()); +} + +bool openDialogWithOpaqueBackgroundY(QDialog *widget, PIVXGUI *gui, double posX, int posY){ + widget->setWindowFlags(Qt::CustomizeWindowHint); + widget->setAttribute(Qt::WA_TranslucentBackground, true); + QPropertyAnimation* animation = new QPropertyAnimation(widget, "pos"); + animation->setDuration(300); + int xPos = gui->width() / posX ; + animation->setStartValue(QPoint(xPos, gui->height())); + animation->setEndValue(QPoint(xPos, gui->height() / posY));//- (gui->height()) / posY )); + animation->setEasingCurve(QEasingCurve::OutQuad); + animation->start(QAbstractAnimation::DeleteWhenStopped); + widget->activateWindow(); + bool res = widget->exec(); + gui->showHide(false); + return res; +} + +bool openDialogWithOpaqueBackground(QDialog *widget, PIVXGUI *gui, double posX){ + return openDialogWithOpaqueBackgroundY(widget, gui, posX, 5); +} + +bool openDialogWithOpaqueBackgroundFullScreen(QDialog *widget, PIVXGUI *gui){ + widget->setWindowFlags(Qt::CustomizeWindowHint); + widget->setAttribute(Qt::WA_TranslucentBackground, true); + + widget->activateWindow(); + widget->resize(gui->width(),gui->height()); + + QPropertyAnimation* animation = new QPropertyAnimation(widget, "pos"); + animation->setDuration(300); + int xPos = 0; + animation->setStartValue(QPoint(xPos, gui->height())); + animation->setEndValue(QPoint(xPos, 0)); + animation->setEasingCurve(QEasingCurve::OutQuad); + animation->start(QAbstractAnimation::DeleteWhenStopped); + widget->activateWindow(); + bool res = widget->exec(); + gui->showHide(false); + return res; +} + +QPixmap encodeToQr(QString str, QString &errorStr, QColor qrColor){ + if (!str.isEmpty()) { + // limit URI length + if (str.length() > MAX_URI_LENGTH) { + errorStr = "Resulting URI too long, try to reduce the text for label / message."; + return QPixmap(); + } else { + QRcode* code = QRcode_encodeString(str.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1); + if (!code) { + errorStr = "Error encoding URI into QR Code."; + return QPixmap(); + } + QImage myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32); + myImage.fill(0xffffff); + unsigned char* p = code->data; + for (int y = 0; y < code->width; y++) { + for (int x = 0; x < code->width; x++) { + myImage.setPixel(x + 4, y + 4, ((*p & 1) ? qrColor.rgb() : 0xffffff)); + p++; + } + } + QRcode_free(code); + return QPixmap::fromImage(myImage); + } + } + return QPixmap(); +} + +void setupSettings(QSettings *settings){ + if(!settings->contains("lightTheme")){ + settings->setValue("lightTheme", true); + } +} + +QSettings *settings = nullptr; + +QSettings* getSettings(){ + if(!settings){ + settings = new QSettings(); + // Setup initial values if them are not there + setupSettings(settings); + } + + return settings; +} + +bool isLightTheme(){ + return getSettings()->value("lightTheme", true).toBool(); +} + +void setTheme(bool isLight){ + QSettings* settings = getSettings(); + settings->setValue("theme", isLight ? "default" : "default-dark"); + settings->setValue("lightTheme", isLight); +} + + +// Style + +void updateStyle(QWidget* widget){ + widget->style()->unpolish(widget); + widget->style()->polish(widget); + widget->update(); +} + + +QColor getRowColor(bool isLightTheme, bool isHovered, bool isSelected){ + if(isLightTheme){ + if (isSelected) { + return QColor("#25b088ff"); + }else if(isHovered){ + return QColor("#25bababa"); + } else{ + return QColor("#ffffff"); + } + }else{ + if (isSelected) { + return QColor("#25b088ff"); + }else if(isHovered){ + return QColor("#25bababa"); + } else{ + return QColor("#0f0b16"); + } + } +} + +void initComboBox(QComboBox* combo, QLineEdit* lineEdit){ + setCssProperty(combo, "btn-combo"); + combo->setEditable(true); + if (lineEdit) { + lineEdit->setReadOnly(true); + lineEdit->setAlignment(Qt::AlignRight); + combo->setLineEdit(lineEdit); + } + combo->setStyleSheet("selection-background-color:transparent; selection-color:transparent;"); + combo->setView(new QListView()); +} + +void initCssEditLine(QLineEdit *edit, bool isDialog){ + if (isDialog) setCssEditLineDialog(edit, true, false); + else setCssEditLine(edit, true, false); + setShadow(edit); + edit->setAttribute(Qt::WA_MacShowFocusRect, 0); +} + +void setCssEditLine(QLineEdit *edit, bool isValid, bool forceUpdate){ + setCssProperty(edit, isValid ? "edit-primary" : "edit-primary-error", forceUpdate); +} + +void setCssEditLineDialog(QLineEdit *edit, bool isValid, bool forceUpdate){ + setCssProperty(edit, isValid ? "edit-primary-dialog" : "edit-primary-dialog-error", forceUpdate); +} + +void setShadow(QWidget *edit){ + QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect(); + shadowEffect->setColor(QColor(0, 0, 0, 22)); + shadowEffect->setXOffset(0); + shadowEffect->setYOffset(3); + shadowEffect->setBlurRadius(6); + edit->setGraphicsEffect(shadowEffect); +} + +void setCssBtnPrimary(QPushButton *btn, bool forceUpdate){ + setCssProperty(btn, "btn-primary", forceUpdate); +} + +void setCssBtnSecondary(QPushButton *btn, bool forceUpdate){ + setCssProperty(btn, "btn-secundary", forceUpdate); +} + +void setCssTextBodyDialog(std::initializer_list args){ + foreach (QWidget* w, args) { setCssTextBodyDialog(w); } +} + +void setCssTextBodyDialog(QWidget* widget) { + setCssProperty(widget, "text-body1-dialog", false); +} + +void setCssTitleScreen(QLabel* label) { + setCssProperty(label, "text-title-screen", false); +} + +void setCssSubtitleScreen(QWidget* wid) { + setCssProperty(wid, "text-subtitle", false); +} + +void setCssProperty(std::initializer_list args, QString value){ + foreach (QWidget* w, args) { setCssProperty(w, value); } +} + +void setCssProperty(QWidget *wid, QString value, bool forceUpdate){ + wid->setProperty("cssClass", value); + forceUpdateStyle(wid, forceUpdate); +} + +void forceUpdateStyle(QWidget *widget, bool forceUpdate){ + if(forceUpdate) + updateStyle(widget); +} + +void forceUpdateStyle(std::initializer_list args){ + foreach (QWidget* w, args) { forceUpdateStyle(w, true); } +} \ No newline at end of file diff --git a/src/qt/pivx/qtutils.h b/src/qt/pivx/qtutils.h new file mode 100644 index 000000000000..626f60cba556 --- /dev/null +++ b/src/qt/pivx/qtutils.h @@ -0,0 +1,68 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef QTUTILS_H +#define QTUTILS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qt/pivx/pivxgui.h" + +static Qt::Modifier SHORT_KEY +#ifdef Q_OS_MAC + = Qt::CTRL; +#else + = Qt::ALT; +#endif + +bool openDialog(QDialog *widget, QWidget *gui); +void closeDialog(QDialog *widget, PIVXGUI *gui); +void openDialogFullScreen(QWidget *parent, QWidget * dialog); +bool openDialogWithOpaqueBackgroundY(QDialog *widget, PIVXGUI *gui, double posX = 3, int posY = 5); +bool openDialogWithOpaqueBackground(QDialog *widget, PIVXGUI *gui, double posX = 3); +bool openDialogWithOpaqueBackgroundFullScreen(QDialog *widget, PIVXGUI *gui); + +// +QPixmap encodeToQr(QString str, QString &errorStr, QColor qrColor = Qt::black); + +// Helpers +void updateStyle(QWidget* widget); +QColor getRowColor(bool isLightTheme, bool isHovered, bool isSelected); + +// Settings +QSettings* getSettings(); +void setupSettings(QSettings *settings); + +bool isLightTheme(); +void setTheme(bool isLight); + +void initComboBox(QComboBox* combo, QLineEdit* lineEdit = nullptr); + +void initCssEditLine(QLineEdit *edit, bool isDialog = false); +void setCssEditLine(QLineEdit *edit, bool isValid, bool forceUpdate = false); +void setCssEditLineDialog(QLineEdit *edit, bool isValid, bool forceUpdate = false); +void setShadow(QWidget *edit); + +void setCssBtnPrimary(QPushButton *btn, bool forceUpdate = false); +void setCssBtnSecondary(QPushButton *btn, bool forceUpdate = false); +void setCssTitleScreen(QLabel* label); +void setCssSubtitleScreen(QWidget* wid); +void setCssTextBodyDialog(std::initializer_list args); +void setCssTextBodyDialog(QWidget* widget); +void setCssProperty(std::initializer_list args, QString value); +void setCssProperty(QWidget *wid, QString value, bool forceUpdate = false); +void forceUpdateStyle(QWidget *widget, bool forceUpdate); +void forceUpdateStyle(std::initializer_list args); + +#endif // QTUTILS_H diff --git a/src/qt/pivx/receivedialog.cpp b/src/qt/pivx/receivedialog.cpp new file mode 100644 index 000000000000..228f8e35b2f4 --- /dev/null +++ b/src/qt/pivx/receivedialog.cpp @@ -0,0 +1,81 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/receivedialog.h" +#include "qt/pivx/forms/ui_receivedialog.h" +#include "qt/pivx/qtutils.h" +#include "walletmodel.h" +#include + +ReceiveDialog::ReceiveDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::ReceiveDialog) +{ + ui->setupUi(this); + // Stylesheet + this->setStyleSheet(parent->styleSheet()); + + ui->frameContainer->setProperty("cssClass", "container-dialog"); + ui->frameContainer->setContentsMargins(10,10,10,10); + + + // Title + + ui->labelTitle->setText("My Address"); + ui->labelTitle->setProperty("cssClass", "text-title-dialog"); + + // Address + + ui->labelAddress->setText("D7VFR83SQbiezrW72hjcWJtcfip5krte2Z"); + ui->labelAddress->setProperty("cssClass", "label-address-box"); + + // QR image + + QPixmap pixmap(":/res/img/img-qr-test-big.png"); + ui->labelQrImg->setPixmap(pixmap.scaled( + ui->labelQrImg->width(), + ui->labelQrImg->height(), + Qt::KeepAspectRatio) + ); + + + // Buttons + ui->btnEsc->setText(""); + ui->btnEsc->setProperty("cssClass", "ic-close"); + + ui->btnCancel->setProperty("cssClass", "btn-dialog-cancel"); + ui->btnSave->setText("COPY"); + ui->btnSave->setProperty("cssClass", "btn-primary"); + ui->btnCancel->setVisible(false); + + + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnSave, SIGNAL(clicked()), this, SLOT(onCopy())); +} + +void ReceiveDialog::updateQr(QString address){ + if(!info) info = new SendCoinsRecipient(); + info->address = address; + QString uri = GUIUtil::formatBitcoinURI(*info); + ui->labelQrImg->setText(""); + ui->labelAddress->setText(address); + QString error; + QPixmap pixmap = encodeToQr(uri, error); + if(!pixmap.isNull()){ + qrImage = &pixmap; + ui->labelQrImg->setPixmap(qrImage->scaled(ui->labelQrImg->width(), ui->labelQrImg->height())); + }else{ + ui->labelQrImg->setText(!error.isEmpty() ? error : "Error encoding address"); + } +} + +void ReceiveDialog::onCopy(){ + GUIUtil::setClipboard(info->address); + accept(); +} + +ReceiveDialog::~ReceiveDialog() +{ + delete ui; +} diff --git a/src/qt/pivx/receivedialog.h b/src/qt/pivx/receivedialog.h new file mode 100644 index 000000000000..a9e54c642523 --- /dev/null +++ b/src/qt/pivx/receivedialog.h @@ -0,0 +1,35 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef RECEIVEDIALOG_H +#define RECEIVEDIALOG_H + +#include +#include + +class SendCoinsRecipient; + +namespace Ui { +class ReceiveDialog; +} + +class ReceiveDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ReceiveDialog(QWidget *parent = nullptr); + ~ReceiveDialog(); + + void updateQr(QString address); + +private slots: + void onCopy(); +private: + Ui::ReceiveDialog *ui; + QPixmap *qrImage; + SendCoinsRecipient *info = nullptr; +}; + +#endif // RECEIVEDIALOG_H diff --git a/src/qt/pivx/receivewidget.cpp b/src/qt/pivx/receivewidget.cpp new file mode 100644 index 000000000000..81d1e0d71bc4 --- /dev/null +++ b/src/qt/pivx/receivewidget.cpp @@ -0,0 +1,283 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/receivewidget.h" +#include "qt/pivx/forms/ui_receivewidget.h" +#include "qt/pivx/requestdialog.h" +#include "qt/pivx/addnewcontactdialog.h" +#include "qt/pivx/qtutils.h" +#include "qt/pivx/myaddressrow.h" +#include "qt/pivx/furlistrow.h" +#include "walletmodel.h" +#include "guiutil.h" + +#include +#include +#include + +#define DECORATION_SIZE 70 +#define NUM_ITEMS 3 + +class AddressHolder : public FurListRow +{ +public: + AddressHolder(); + + explicit AddressHolder(bool _isLightTheme) : FurListRow(), isLightTheme(_isLightTheme){} + + MyAddressRow* createHolder(int pos) override{ + return new MyAddressRow(); + } + + void init(QWidget* holder,const QModelIndex &index, bool isHovered, bool isSelected) const override{ + MyAddressRow *row = static_cast(holder); + QString address = index.data(Qt::DisplayRole).toString(); + QString label = index.sibling(index.row(), AddressTableModel::Label).data(Qt::DisplayRole).toString(); + uint time = index.sibling(index.row(), AddressTableModel::Date).data(Qt::DisplayRole).toUInt(); + QString date = (time == 0) ? "" : GUIUtil::dateTimeStr(QDateTime::fromTime_t(time)); + row->updateView(address, label, date); + } + + QColor rectColor(bool isHovered, bool isSelected) override{ + return getRowColor(isLightTheme, isHovered, isSelected); + } + + ~AddressHolder() override{} + + bool isLightTheme; +}; + +#include "qt/pivx/moc_receivewidget.cpp" + +ReceiveWidget::ReceiveWidget(PIVXGUI* parent) : + PWidget(parent), + ui(new Ui::ReceiveWidget) +{ + ui->setupUi(this); + this->setStyleSheet(parent->styleSheet()); + + delegate = new FurAbstractListItemDelegate( + DECORATION_SIZE, + new AddressHolder(isLightTheme()), + this + ); + + // Containers + setCssProperty(ui->left, "container"); + ui->left->setContentsMargins(20,20,20,20); + setCssProperty(ui->right, "container-right"); + ui->right->setContentsMargins(0,9,0,0); + + // Title + ui->labelTitle->setText(tr("Receive")); + ui->labelSubtitle1->setText(tr("Scan the QR code or copy the address to receive PIV.")); + setCssTitleScreen(ui->labelTitle); + setCssSubtitleScreen(ui->labelSubtitle1); + + // Address + ui->labelAddress->setText(tr("No address ")); + setCssProperty(ui->labelAddress, "label-address-box"); + + ui->labelDate->setText("Dec. 19, 2018"); + setCssSubtitleScreen(ui->labelDate); + ui->labelLabel->setText(""); + setCssSubtitleScreen(ui->labelLabel); + + // Options + ui->btnMyAddresses->setTitleClassAndText("btn-title-grey", "My Addresses"); + ui->btnMyAddresses->setSubTitleClassAndText("text-subtitle", "List your own addresses."); + ui->btnMyAddresses->layout()->setMargin(0); + ui->btnMyAddresses->setRightIconClass("ic-arrow"); + + ui->btnRequest->setTitleClassAndText("btn-title-grey", "Create Request"); + ui->btnRequest->setSubTitleClassAndText("text-subtitle", "Request payment with a fixed amount."); + ui->btnRequest->layout()->setMargin(0); + + ui->pushButtonLabel->setText(tr("Add Label")); + ui->pushButtonLabel->setLayoutDirection(Qt::RightToLeft); + setCssProperty(ui->pushButtonLabel, "btn-secundary-label"); + + ui->pushButtonNewAddress->setText(tr("Generate Address")); + ui->pushButtonNewAddress->setLayoutDirection(Qt::RightToLeft); + setCssProperty(ui->pushButtonNewAddress, "btn-secundary-new-address"); + + ui->pushButtonCopy->setText(tr("Copy")); + ui->pushButtonCopy->setLayoutDirection(Qt::RightToLeft); + setCssProperty(ui->pushButtonCopy, "btn-secundary-copy"); + + // List Addresses + setCssProperty(ui->listViewAddress, "container"); + ui->listViewAddress->setItemDelegate(delegate); + ui->listViewAddress->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE)); + ui->listViewAddress->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2)); + ui->listViewAddress->setAttribute(Qt::WA_MacShowFocusRect, false); + ui->listViewAddress->setSelectionBehavior(QAbstractItemView::SelectRows); + + spacer = new QSpacerItem(40, 20, QSizePolicy::Maximum, QSizePolicy::Expanding); + ui->btnMyAddresses->setChecked(true); + ui->container_right->addItem(spacer); + ui->listViewAddress->setVisible(false); + + // Connect + connect(ui->pushButtonLabel, SIGNAL(clicked()), this, SLOT(onLabelClicked())); + connect(ui->pushButtonCopy, SIGNAL(clicked()), this, SLOT(onCopyClicked())); + connect(ui->pushButtonNewAddress, SIGNAL(clicked()), this, SLOT(onNewAddressClicked())); + connect(ui->listViewAddress, SIGNAL(clicked(QModelIndex)), this, SLOT(handleAddressClicked(QModelIndex))); + connect(ui->btnRequest, SIGNAL(clicked()), this, SLOT(onRequestClicked())); + connect(ui->btnMyAddresses, SIGNAL(clicked()), this, SLOT(onMyAddressesClicked())); +} + +void ReceiveWidget::loadWalletModel(){ + if(walletModel) { + this->addressTableModel = walletModel->getAddressTableModel(); + this->filter = new AddressFilterProxyModel(AddressTableModel::Receive, this); + this->filter->setSourceModel(addressTableModel); + ui->listViewAddress->setModel(this->filter); + ui->listViewAddress->setModelColumn(AddressTableModel::Address); + + if(!info) info = new SendCoinsRecipient(); + refreshView(); + + // data change + connect(this->addressTableModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, SLOT(refreshView())); + } +} + +void ReceiveWidget::refreshView(QString refreshAddress){ + try { + QString latestAddress = (refreshAddress.isEmpty()) ? this->addressTableModel->getLastUnusedAddress() : refreshAddress; + if (latestAddress.isEmpty()) // new default address + latestAddress = QString::fromStdString(walletModel->getNewAddress("Default").ToString()); + ui->labelAddress->setText(latestAddress); + int64_t time = walletModel->getKeyCreationTime(CBitcoinAddress(latestAddress.toStdString())); + ui->labelDate->setText(GUIUtil::dateTimeStr(QDateTime::fromTime_t(static_cast(time)))); + updateQr(latestAddress); + updateLabel(); + } catch (const std::runtime_error& error){ + ui->labelQrImg->setText(tr("No available address, try unlocking the wallet")); + inform(tr("Error generating address")); + } +} + +void ReceiveWidget::updateLabel(){ + if(!info->address.isEmpty()) { + // Check if address label exists + QString label = addressTableModel->labelForAddress(info->address); + if (!label.isEmpty()) { + ui->labelLabel->setVisible(true); + ui->labelLabel->setText(label); + ui->pushButtonLabel->setText(tr("Change Label")); + }else{ + ui->labelLabel->setVisible(false); + } + } +} + +void ReceiveWidget::updateQr(QString address){ + info->address = address; + QString uri = GUIUtil::formatBitcoinURI(*info); + ui->labelQrImg->setText(""); + + QString error; + QColor qrColor("#382d4d"); + QPixmap pixmap = encodeToQr(uri, error, qrColor); + if(!pixmap.isNull()){ + qrImage = &pixmap; + ui->labelQrImg->setPixmap(qrImage->scaled(ui->labelQrImg->width(), ui->labelQrImg->height())); + }else{ + ui->labelQrImg->setText(!error.isEmpty() ? error : "Error encoding address"); + } +} + +void ReceiveWidget::handleAddressClicked(const QModelIndex &index){ + QModelIndex rIndex = filter->mapToSource(index); + refreshView(rIndex.data(Qt::DisplayRole).toString()); +} + +void ReceiveWidget::onLabelClicked(){ + if(walletModel && !isShowingDialog) { + isShowingDialog = true; + showHideOp(true); + AddNewContactDialog *dialog = new AddNewContactDialog(window); + dialog->setTexts(tr("Edit Address Label")); + dialog->setData(info->address, addressTableModel->labelForAddress(info->address)); + if (openDialogWithOpaqueBackgroundY(dialog, window, 3.5, 6)) { + QString label = dialog->getLabel(); + const CBitcoinAddress address = CBitcoinAddress(info->address.toUtf8().constData()); + if (!label.isEmpty() && walletModel->updateAddressBookLabels( + address.Get(), + label.toUtf8().constData(), + "receive" + ) + ) { + // update label status (icon color) + updateLabel(); + inform(tr("Address label saved")); + } else { + inform(tr("Error storing address label")); + } + } + isShowingDialog = false; + } +} + +void ReceiveWidget::onNewAddressClicked(){ + try { + if (!verifyWalletUnlocked()) return; + CBitcoinAddress address = walletModel->getNewAddress(""); + updateQr(QString::fromStdString(address.ToString())); + ui->labelAddress->setText(!info->address.isEmpty() ? info->address : tr("No address")); + updateLabel(); + inform(tr("New address created")); + } catch (const std::runtime_error& error){ + // Error generating address + inform("Error generating address"); + } +} + +void ReceiveWidget::onCopyClicked(){ + GUIUtil::setClipboard(info->address); + inform(tr("Address copied")); +} + + +void ReceiveWidget::onRequestClicked(){ + if(walletModel && !isShowingDialog) { + if (!verifyWalletUnlocked()) return; + isShowingDialog = true; + showHideOp(true); + RequestDialog *dialog = new RequestDialog(window); + dialog->setWalletModel(walletModel); + openDialogWithOpaqueBackgroundY(dialog, window, 3.5, 12); + if (dialog->res == 1){ + inform(tr("URI copied to clipboard")); + } else if (dialog->res == 2){ + inform(tr("Address copied to clipboard")); + } + dialog->deleteLater(); + isShowingDialog = false; + } +} + +void ReceiveWidget::onMyAddressesClicked(){ + bool isVisible = ui->listViewAddress->isVisible(); + if(!isVisible){ + ui->btnMyAddresses->setRightIconClass("btn-dropdown", true); + ui->listViewAddress->setVisible(true); + ui->container_right->removeItem(spacer); + ui->listViewAddress->update(); + }else{ + ui->btnMyAddresses->setRightIconClass("ic-arrow", true); + ui->container_right->addItem(spacer); + ui->listViewAddress->setVisible(false); + } +} + +void ReceiveWidget::changeTheme(bool isLightTheme, QString& theme){ + static_cast(this->delegate->getRowFactory())->isLightTheme = isLightTheme; +} + +ReceiveWidget::~ReceiveWidget(){ + delete ui; +} diff --git a/src/qt/pivx/receivewidget.h b/src/qt/pivx/receivewidget.h new file mode 100644 index 000000000000..92c1871cbd4f --- /dev/null +++ b/src/qt/pivx/receivewidget.h @@ -0,0 +1,70 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef RECEIVEWIDGET_H +#define RECEIVEWIDGET_H + +#include "qt/pivx/pwidget.h" +#include "addresstablemodel.h" +#include "qt/pivx/furabstractlistitemdelegate.h" +#include "qt/pivx/addressfilterproxymodel.h" + +#include +#include +#include + +class PIVXGUI; +class SendCoinsRecipient; + +namespace Ui { +class ReceiveWidget; +} + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +class ReceiveWidget : public PWidget +{ + Q_OBJECT + +public: + explicit ReceiveWidget(PIVXGUI* parent); + ~ReceiveWidget(); + + void loadWalletModel() override; + +public slots: + void onRequestClicked(); + void onMyAddressesClicked(); + void onNewAddressClicked(); + +private slots: + void changeTheme(bool isLightTheme, QString &theme) override ; + void onLabelClicked(); + void onCopyClicked(); + void refreshView(QString refreshAddress = QString()); + void handleAddressClicked(const QModelIndex &index); +private: + Ui::ReceiveWidget *ui; + + FurAbstractListItemDelegate *delegate; + AddressTableModel* addressTableModel = nullptr; + AddressFilterProxyModel *filter = nullptr; + + QSpacerItem *spacer = nullptr; + + // Cached last address + SendCoinsRecipient *info = nullptr; + // Cached qr + QPixmap *qrImage = nullptr; + + void updateQr(QString address); + void updateLabel(); + + bool isShowingDialog = false; + +}; + +#endif // RECEIVEWIDGET_H diff --git a/src/qt/pivx/requestdialog.cpp b/src/qt/pivx/requestdialog.cpp new file mode 100644 index 000000000000..2c8dedd3c032 --- /dev/null +++ b/src/qt/pivx/requestdialog.cpp @@ -0,0 +1,148 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/requestdialog.h" +#include "qt/pivx/forms/ui_requestdialog.h" +#include +#include + +#include "qt/pivx/qtutils.h" +#include "guiutil.h" +#include "amount.h" +#include "optionsmodel.h" + +RequestDialog::RequestDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::RequestDialog) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + setCssProperty(ui->frame, "container-dialog"); + + // Text + ui->labelTitle->setText(tr("New Request Payment")); + setCssProperty(ui->labelTitle, "text-title-dialog"); + + ui->labelMessage->setText(tr("Instead of share a PIVX address, you can create a Payment Request message which bundles up more information than is contained in just a PIVX address.")); + setCssProperty(ui->labelMessage, "text-main-grey"); + + // Combo Coins + setCssProperty(ui->comboBoxCoin, "btn-combo-coins"); + setCssProperty(ui->comboContainer, "container-purple"); + + ui->comboBoxCoin->addItem("PIV", 0); + ui->comboBoxCoin->addItem("zPIV", 1); + ui->comboBoxCoin->setView(new QListView()); + + // Label + ui->labelSubtitleLabel->setText(tr("Label")); + setCssProperty(ui->labelSubtitleLabel, "text-title2-dialog"); + ui->lineEditLabel->setPlaceholderText(tr("Enter a label to be saved within the address")); + setCssEditLineDialog(ui->lineEditLabel, true); + + // Amount + ui->labelSubtitleAmount->setText(tr("Amount")); + setCssProperty(ui->labelSubtitleAmount, "text-title2-dialog"); + ui->lineEditAmount->setPlaceholderText("0.00 PIV"); + setCssEditLineDialog(ui->lineEditAmount, true); + + QDoubleValidator *doubleValidator = new QDoubleValidator(0, 9999999, 7, this); + doubleValidator->setNotation(QDoubleValidator::StandardNotation); + ui->lineEditAmount->setValidator(doubleValidator); + + // Description + ui->labelSubtitleDescription->setText(tr("Description (optional)")); + setCssProperty(ui->labelSubtitleDescription, "text-title2-dialog"); + + ui->lineEditDescription->setPlaceholderText(tr("Add description ")); + setCssEditLineDialog(ui->lineEditDescription, true); + + // Stack + ui->stack->setCurrentIndex(pos); + // Request QR Page + // Address + ui->labelAddress->setText(tr("Error")); + setCssProperty(ui->labelAddress, "text-main-grey-big"); + + // Buttons + setCssProperty(ui->btnEsc, "ic-close"); + setCssProperty(ui->btnCancel, "btn-dialog-cancel"); + ui->btnSave->setText(tr("GENERATE")); + setCssBtnPrimary(ui->btnSave); + setCssBtnPrimary(ui->btnCopyAddress); + setCssBtnPrimary(ui->btnCopyUrl); + + connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnSave, SIGNAL(clicked()), this, SLOT(onNextClicked())); + // TODO: Change copy address for save image (the method is already implemented in other class called exportQr or something like that) + connect(ui->btnCopyAddress, SIGNAL(clicked()), this, SLOT(onCopyClicked())); + connect(ui->btnCopyUrl, SIGNAL(clicked()), this, SLOT(onCopyUriClicked())); +} + +void RequestDialog::setWalletModel(WalletModel *model){ + this->walletModel = model; +} + + +void RequestDialog::onNextClicked(){ + if(walletModel) { + info = new SendCoinsRecipient(); + info->label = ui->lineEditLabel->text(); + info->message = ui->lineEditDescription->text(); + info->address = QString::fromStdString(walletModel->getNewAddress((info->label.isEmpty() ? "" : info->label.toStdString())).ToString()); + int displayUnit = walletModel->getOptionsModel()->getDisplayUnit(); + bool isValueValid = true; + CAmount value = GUIUtil::parseValue( + ui->lineEditAmount->text(), + displayUnit, + &isValueValid + ); + info->amount = value; + + if(value <= 0 || !isValueValid){ + return; + } + ui->labelTitle->setText("Request for " + BitcoinUnits::format(displayUnit, value, false, BitcoinUnits::separatorAlways) + " PIV"); + updateQr(info->address); + ui->labelAddress->setText(info->address); + ui->buttonsStack->setVisible(false); + pos = 1; + ui->stack->setCurrentIndex(pos); + } +} + +void RequestDialog::onCopyClicked(){ + if(info) { + GUIUtil::setClipboard(info->address); + res = 2; + accept(); + } +} + +void RequestDialog::onCopyUriClicked(){ + if(info) { + GUIUtil::setClipboard(GUIUtil::formatBitcoinURI(*info)); + res = 1; + accept(); + } +} + +void RequestDialog::updateQr(QString str){ + QString uri = GUIUtil::formatBitcoinURI(*info); + ui->labelQrImg->setText(""); + QString error; + QPixmap pixmap = encodeToQr(uri, error); + if(!pixmap.isNull()){ + qrImage = &pixmap; + ui->labelQrImg->setPixmap(qrImage->scaled(ui->labelQrImg->width(), ui->labelQrImg->height())); + }else{ + ui->labelQrImg->setText(!error.isEmpty() ? error : "Error encoding address"); + } +} + +RequestDialog::~RequestDialog(){ + delete ui; +} diff --git a/src/qt/pivx/requestdialog.h b/src/qt/pivx/requestdialog.h new file mode 100644 index 000000000000..e3dfa4becce0 --- /dev/null +++ b/src/qt/pivx/requestdialog.h @@ -0,0 +1,47 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef REQUESTDIALOG_H +#define REQUESTDIALOG_H + +#include +#include +#include "walletmodel.h" + +class WalletModel; +class PIVXGUI; + +namespace Ui { +class RequestDialog; +} + +class RequestDialog : public QDialog +{ + Q_OBJECT + +public: + explicit RequestDialog(QWidget *parent = nullptr); + ~RequestDialog(); + + void setWalletModel(WalletModel *model); + int res = -1; + +private slots: + void onNextClicked(); + void onCopyClicked(); + void onCopyUriClicked(); + +private: + Ui::RequestDialog *ui; + int pos = 0; + WalletModel *walletModel; + // Cached last address + SendCoinsRecipient *info = nullptr; + + QPixmap *qrImage = nullptr; + + void updateQr(QString str); +}; + +#endif // REQUESTDIALOG_H diff --git a/src/qt/pivx/res/css/style_dark.css b/src/qt/pivx/res/css/style_dark.css new file mode 100644 index 000000000000..dc4502a0c683 --- /dev/null +++ b/src/qt/pivx/res/css/style_dark.css @@ -0,0 +1,3112 @@ +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH CONTAINER +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container"] { + background-color:#0f0b16; +} + +*[cssClass="container-border"] { + background-color:#0f0b16; + border: 1px solid #0f0b16; +} + +*[cssClass="container-border-light"] { + background-color:#0f0b16; + border: 1px solid #33FFFFFF; + border-radius:2px; +} + +*[cssClass="container_right"] { + background-color:#0f0b16; + border-left: 1px solid #33FFFFFF; +} + +*[cssClass="container-right"] { + background-color:#0f0b16; + border-left: 1px solid #33FFFFFF; +} + +*[cssClass="container-square"] { + background-color:#0f0b16; + border: 1px solid #33FFFFFF; +} + +*[cssClass="container-options"] { + background-color:#0f0b16; + border-bottom: 1px solid #bababa; +} + +*[cssClass="container-divider"] { + background-color:#B3FFFFFF; +} + +*[cssClass="container-purple"] { + background-color:#5c4b7d; + border: 0; +} + +*[cssClass="container-border-purple"] { + background-color:#0f0b16; + border: 1px solid #5c4b7d; + border-radius:2px; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH NAVIGATION +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-nav"] { + background-color: qlineargradient(y1:0, y2: 1, stop: 0 #0f0b16, stop: 1 #4f3c74); +} + +QPushButton[cssClass="img-nav-logo"] { + qproperty-icon: url("://img-nav-logo"); + qproperty-iconSize: 49px 60px; +} + +*[cssClass="btn-nav-receive"] { + qproperty-icon: url("://ic-nav-receive") off, + url("://ic-nav-receive-active") on; + qproperty-iconSize: 24px 40px; + background-color:transparent; + padding-top: 25px; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-receive"]:checked { + background-color: #0f0b16; + padding-top: 25px; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-receive"]:checked:hover { + background-color: #0f0b16; + color: #B088FF; +} + +*[cssClass="btn-nav-receive"]:hover { + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-receive-active"] { + qproperty-icon:url("://ic-nav-receive-active") ; + qproperty-iconSize: 24px 40px; + background-color: #0f0b16; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-settings"] { + qproperty-icon: url("://ic-nav-settings") off, + url("://ic-nav-settings-active") on; + qproperty-iconSize: 24px 40px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-settings"]:checked { + background-color: #0f0b16; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-settings"]:checked:hover { + background-color: #0f0b16; + color: #B088FF; +} + +*[cssClass="btn-nav-settings"]:hover { + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-settings-active"] { + qproperty-icon:url("://ic-nav-settings-active") ; + qproperty-iconSize: 24px 40px; + background-color: #0f0b16; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-dash"] { + qproperty-icon: url("://ic-nav-dashboard") off, + url("://ic-nav-dashboard-active") on ; + qproperty-iconSize: 24px 40px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-dash"]:checked { + background-color: #0f0b16; + padding-top: 25px; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-dash"]:checked:hover { + background-color: #0f0b16; + color: #B088FF; +} + + +*[cssClass="btn-nav-dash"]:hover { + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-dash-active"] { + qproperty-icon:url("://ic-nav-dashboard-active"); + qproperty-iconSize: 24px 40px; + background-color: #0f0b16; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-send"] { + qproperty-icon: url("://ic-nav-send") off, + url("://ic-nav-send") on ; + qproperty-iconSize: 24px 40px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-send"]:checked { + background-color: #0f0b16; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-send"]:checked:hover { + background-color: #0f0b16; + color: #B088FF; +} + +*[cssClass="btn-nav-send"]:hover { + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-send-active"] { + qproperty-icon:url("://ic-nav-send-active") ; + qproperty-iconSize: 24px 40px; + background-color: #0f0b16; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-address"] { + qproperty-icon: url("://ic-nav-address") off, + url("://ic-nav-address-active") on ; + qproperty-iconSize: 24px 40px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-address"]:checked { + background-color: #0f0b16; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-address"]:checked:hover { + background-color: #0f0b16; + color: #B088FF; +} + +*[cssClass="btn-nav-address"]:hover { + background-color: #1A000000; + color: #938da5; +} + + +*[cssClass="btn-nav-address-active"] { + qproperty-icon:url("://ic-nav-address-active") ; + qproperty-iconSize: 24px 40px; + background-color: #0f0b16; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-privacy"] { + qproperty-icon: url("://ic-nav-privacy") off, + url("//ic-nav-privacy-active") on ; + qproperty-iconSize: 24px 40px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-privacy"]:checked { + background-color: #0f0b16; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-privacy"]:checked:hover { + background-color: #0f0b16; + color: #B088FF; +} + +*[cssClass="btn-nav-privacy"]:hover { + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-privacy-active"] { + qproperty-icon:url("://ic-nav-privacy-active") ; + qproperty-iconSize: 24px 40px; + background-color: #0f0b16; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-master"] { + qproperty-icon: url("://ic-nav-master") off, + url("://ic-nav-master-active") on; + qproperty-iconSize: 24px 30px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-master"]:checked { + qproperty-icon: url("://ic-nav-master-active"); + background-color: #0f0b16; + padding-top: 32px; + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-master"]:checked:hover { + background-color: #0f0b16; + color: #B088FF; +} + +*[cssClass="btn-nav-master"]:hover { + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-master-active"] { + qproperty-icon:url("://ic-nav-master-active"); + qproperty-iconSize: 24px 30px; + background-color: #0f0b16; + font-size:14px; + color: #B088FF; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH TOP BAR +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-top"] { + border-image: url("://bg-dashboard-banner") 0 0 0 0 stretch stretch; + background-color:#000000; +} + +*[cssClass="text-title-topbar"] { + color:#a3a3a4; + font-size:16px; + font-weight: ligther; +} + +*[cssClass="amount-topbar"] { + color:#FFFFFF; + font-size:35px; +} + +*[cssClass="amount-small-topbar"] { + color:#FFFFFF; + font-size:22px; +} + +*[cssClass="container-qr"] { + border-radius: 2px; + background-color: #bb241a3c; +} + +QPushButton[cssClass="btn-qr"] { + qproperty-icon: url("://ic-arrow-drop-down-white"); + qproperty-iconSize: 24px 24px; + background-color:transparent; +} + +*[cssClass="sync-status"] { + background-color:#505c4b7d; + color:#FFFFFF; + border-bottom:2px solid #b088ff; + padding-right:10px; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-faq"] { + qproperty-icon: url("://ic-check-faq"); + qproperty-iconSize: 24px 24px; + background-color:#505c4b7d; + color:#FFFFFF; + padding-right:6px; + padding-left:6px; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-faq-inactive"] { + qproperty-icon: url("://ic-check-faq") ; + qproperty-iconSize: 24px 24px; + background-color:#505c4b7d; + color:#FFFFFF; + padding-right:6px; + padding-left:6px; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-faq"]:checked { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-sync"] { + qproperty-icon: url("://ic-check-sync"); + qproperty-iconSize: 24px 24px; + background-color:#505c4b7d; + color:#FFFFFF; + padding-right:6px; + padding-left:6px; + border-bottom:2px solid #505c4b7d; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-sync-inactive"] { + qproperty-icon: url("://ic-check-sync-off") ; + qproperty-iconSize: 24px 24px; + background-color:#505c4b7d; + color:#FFFFFF; + padding-right:6px; + padding-left:6px; + border-bottom:2px solid #505c4b7d; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-sync"]:checked { + background-color:#505c4b7d; + border-bottom:2px solid #505c4b7d; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-mint"] { + qproperty-icon: url("://ic-check-mint") ; + qproperty-iconSize: 24px 24px; + background-color:#405c4b7d; + color:#FFFFFF; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-mint-inactive"] { + qproperty-icon: url("://ic-check-mint-off") ; + qproperty-iconSize: 24px 24px; + background-color:#405c4b7d; + color:#B3FFFFFF; + border-bottom:2px solid #5C4B7D; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-mint"]:checked { + background-color:#505c4b7d; + color:#ffffff; + border-bottom:2px solid #b088ff; +} + + +QPushButton[cssClass="btn-check-stack"] { + qproperty-icon: url("://ic-check-staking"); + qproperty-iconSize: 24px 24px; + color:#ffffff; + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-stack-inactive"] { + qproperty-icon: url("://ic-check-staking-off"); + qproperty-iconSize: 24px 24px; + color:#B3FFFFFF; + background-color:#405c4b7d; + border-bottom:2px solid #5C4B7D; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-stack"]:checked { + background-color:#505c4b7d; + color:#ffffff; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-connect"] { + qproperty-icon: url("://ic-check-connect") ; + qproperty-iconSize: 24px 24px; + color:#ffffff; + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-connect-inactive"] { + qproperty-icon: url("://ic-check-connect-off"); + qproperty-iconSize: 24px 24px; + color:#B3FFFFFF; + background-color:#405c4b7d; + border-bottom:2px solid #5C4B7D; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-connect"]:checked { + background-color:#505c4b7d; + color:#ffffff; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-status-lock"] { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + qproperty-icon: url("://ic-wallet-status-locked") off, + url("://ic-wallet-status-locked") on ; + qproperty-iconSize: 24px 24px; + color:#ffffff; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-status-unlock"] { + background-color:#405c4b7d; + border-bottom:2px solid #5C4B7D; + qproperty-icon: url("://ic-wallet-status-unlocked") off, + url("://ic-wallet-status-unlocked") on ; + qproperty-iconSize: 24px 24px; + color:#B3FFFFFF; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-status-staking"] { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + qproperty-icon: url("://ic-wallet-status-staking") off, + url("://ic-wallet-status-staking") on ; + qproperty-iconSize: 24px 24px; + color:#ffffff; + border-radius:2px; +} + + + +QPushButton[cssClass="btn-check-text"] { + color:#7f7c87; + background-color:#372A4C; + font-size:18px; + border-bottom:2px solid #5C4B7D; +} + +QPushButton[cssClass="btn-check-text"]:checked { + color:#FFFFFF; + background-color:#5c4b7d; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-text-theme"] { + color:#FFFFFF; + background-color:#405c4b7d; + font-size:18px; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-text-theme"]:checked { + color:#FFFFFF; + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-theme"] { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + qproperty-icon: url("://ic-check-theme-dark") off, + url("://ic-check-theme-light") on ; + qproperty-iconSize: 24px 24px; + color:white; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-theme-dark"] { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + qproperty-icon: url("://ic-check-theme-dark") off, + url("://ic-check-theme-dark") on ; + qproperty-iconSize: 24px 24px; + color:white; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-theme-light"] { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + qproperty-icon: url("://ic-check-theme-light") off, + url("://ic-check-theme-light") on ; + qproperty-iconSize: 24px 24px; + color:white; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-theme"]:checked { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-peers"] { + qproperty-icon: url("://ic-check-peers") ; + qproperty-iconSize: 24px 24px; + color:#FFFFFF; + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-peers"]:checked { + background-color:#505c4b7d; + color:#FFFFFF; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-peers-inactive"] { + qproperty-icon: url("://ic-check-peers-off"); + qproperty-iconSize: 24px 24px; + color:#B3FFFFFF; + background-color:#405c4b7d; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + + + +QPushButton[cssClass="btn-check-lock-sub-menu-unlocked"] { + background-image: url("://ic-submenu-unlock"); + background-position:left center; + background-repeat:no-repeat; + background-color: transparent; + text-align: left; + padding-left: 30px; + color:#B3FFFFFF; + border-bottom:0px; + border-radius:0px; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-unlocked"]:checked { + background-color:#50b088ff; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-unlocked"]:hover { + color:#FFFFFF; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-locked"] { + background-image: url("://ic-submenu-lock"); + background-position:left center; + background-repeat:no-repeat; + background-color: transparent; + text-align: left; + padding-left: 30px; + color:#B3FFFFFF; + border-bottom:0px; + border-radius:0px; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-locked"]:checked { + background-color:#50b088ff; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-locked"]:hover { + color:#FFFFFF; +} + + +QPushButton[cssClass="btn-check-lock-sub-menu-staking"] { + background-image: url("://ic-submenu-staking"); + background-position:left center; + background-repeat:no-repeat; + background-color: transparent; + text-align: left; + padding-left: 30px; + color:#B3FFFFFF; + border-bottom:0px; + border-radius:0px; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-staking"]:checked { + background-color:#50b088ff; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-staking"]:hover { + color:#FFFFFF; +} + + +*[cssClass="top-sub-menu"] { + background-color:#4C425F; +} + + +*[cssClass="top-sub-menu-text"] { + color:#B3FFFFFF; +} + +QProgressBar[cssClass="progress-sync"] { + border: 0; + background-color: transparent; +} + +QProgressBar[cssClass="progress-sync"]::chunk:horizontal { + background: qlineargradient(x1: 0, + y1: 0.5, + x2: 1, + y2: 0.5, + stop: 0 #b088ff, + stop: 1 #b088ff, + stop: 2 #b088ff,); +} + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH LISTS ELEMENTS +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="text-list-title-purple"] { + color:#b088ff; + font-size:20px; +} + +*[cssClass="text-list-title1"] { + color:#b088ff; + font-size:16px; +} + +*[cssClass="text-list-contact-title1"] { + color:#5c4b7d; + font-size:16px; +} + +*[cssClass="text-list-title1"] { + color:#5c4b7d; + font-size:16px; +} + +*[cssClass="text-list-body1-purple"] { + color:#b088ff; + font-size:14px; +} + +*[cssClass="text-list-body1"] { + color:#E6FFFFFF; + font-size:16px; +} + +*[cssClass="text-list-body-unconfirmed"] { + color:#B6B6B6; + font-size:16px; +} + +*[cssClass="text-list-body2"] { + color:#ffffff; + font-size:15.5px; +} + +*[cssClass="text-list-contact-body1"] { + color:#ffffff; + font-size:16px; +} + + +*[cssClass="text-list-body1-grey"] { + color:#E6FFFFFF; + font-size:16px; +} + +*[cssClass="text-list-body2-grey"] { + color:#E6FFFFFF; + font-size:14px; +} + +*[cssClass="text-list-caption"] { + color:#B3FFFFFF; + font-size:12px; +} + +*[cssClass="text-list-caption-medium"] { + color:#B3FFFFFF; + font-size:14px; +} + +*[cssClass="text-list-caption-unconfirmed"] { + color:#B6B6B6; +} + +*[cssClass="text-list-caption-grey"] { + color:#FFFFFF; + font-size:12px; +} + + +*[cssClass="text-list-amount-receive"] { + color:#008d36; + font-size:16px; +} + + +*[cssClass="text-list-amount-send"] { + color:#f84444; + font-size:16px; +} + +*[cssClass="text-list-amount-unconfirmed"] { + color:#B6B6B6; + font-size:16px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH TEXT +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="text-title-screen"] { + color:#b088ff; + font-size:22px; +} + +*[cssClass="text-title-dialog"] { + color:#5c4b7d; + font-size:22px; +} + +*[cssClass="text-title"] { + color:#b088ff; + font-size:16px; +} + +*[cssClass="text-title-white"] { + color:#FFFFFF; + font-size:16px; +} + +*[cssClass="text-content-white"] { + color:#FFFFFF; + font-size:16px; +} + +*[cssClass="btn-title-grey"] { + color:#FFFFFF; + font-size:22px; +} + +*[cssClass="btn-title-purple"] { + color:#5c4b7d; + font-size:22px; +} + +*[cssClass="btn-subtitle-grey"] { + color:#FFFFFF; + font-size:17px; +} + +*[cssClass="text-subtitle"] { + color:#B3FFFFFF; + font-size:14px; +} + +*[cssClass="text-body2-grey"] { + color:#707070; + font-size:14px; +} + + +*[cssClass="text-body1"] { + color:#FFFFFF; + font-size:17px; +} + +*[cssClass="text-body2"] { + color:#FFFFFF; + font-size:14px; +} + +*[cssClass="text-main-light"] { + color:#B3FFFFFF; + font-size:17px; +} + +*[cssClass="text-main-grey"] { + color:#FFFFFF; + font-size:17px; +} + + +*[cssClass="text-main-settings"] { + color:#FFFFFF; + font-size:18px; +} + +*[cssClass="text-main-purple"] { + color:#b088ff; + font-size:17px; +} + +*[cssClass="text-title-purple"] { + color:#5c4b7d; + font-size:22px; +} + +*[cssClass="text-main-grey-big"] { + color:#FFFFFF; + font-size:24px; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH BUTTONS +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +#groupBox { + background-color:transparent; + border-radius:0; +} + +*[cssClass="group-box"] { + background-color:transparent; + border-radius:0; +} + +QGroupBox::title { + color:#b088ff; + font-size:16px; + padding-bottom:9px; +} + +QPushButton[cssClass="btn-watch-password"] { + background: url("://ic-watch-password-white"); + background-repeat:no-repeat; + background-position:center; + background-color: transparent; + border:0; +} + + +QPushButton[cssClass="btn-menu"] { + qproperty-icon: url("://ic-menu-hover") off, + url("://ic-menu-hover") on ; + qproperty-iconSize: 24px 24px; +} + +QPushButton[cssClass="btn-dropdown"] { + qproperty-icon: url("://ic-arrow-drop-down-white") off, + url("://ic-arrow-drop-down-white") on ; + qproperty-iconSize: 24px 24px; +} + +QPushButton[cssClass="btn-dropdown"]:checked { + qproperty-icon: url("://ic-arrow-drop-up") off, + url("://ic-arrow-drop-up") on ; + qproperty-iconSize: 24px 24px; +} + +QPushButton[cssClass="btn-switch"] { + background-image: url("://ic-switch-off"); + background-position:right center; + background-repeat:no-repeat; + background-color:#0f0b16; + font-size:18px; + text-align:left; + color: #bababa; +} + +QPushButton[cssClass="btn-switch"]:checked { + background-image: url("://ic-switch-liliac-on"); + background-position:right center; + background-repeat:no-repeat; + background-color:#0f0b16; + text-align:left; + font-size:18px; + color: #b088ff; +} + +QPushButton[cssClass="btn-check"] { + border: 1px solid #5c4b7d; + background-color:#0f0b16; + padding:4px; + font-size:18px; + color: #707070; + border-radius: 2px; +} + +QPushButton[cssClass="btn-check"]:hover { + border: 1px solid #5c4b7d; + background-color:#0f0b16; + font-size:18px; + padding:4px; + color: #707070; + border-radius: 2px; +} + +QPushButton[cssClass="btn-check"]:pressed { + border: 1px solid #5c4b7d; + background-color:#0f0b16; + font-size:18px; + padding:4px; + color: #707070; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-check-right"] { + border: 1px solid #5c4b7d; + background-color:#0f0b16; + font-size:18px; + color: #707070; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + + +QPushButton[cssClass="btn-check-right"]:hover { + border: 1px solid #b088ff; + background-color:#0f0b16; + font-size:18px; + color: #707070; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + +QPushButton[cssClass="btn-check-right"]:pressed { + border: 1px solid #5c4b7d; + background-color:#4Db088ff; + font-size:18px; + color: #707070; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + + +QPushButton[cssClass="btn-check-right"]:checked { + border: 1px solid #5c4b7d; + background-color:#5c4b7d; + font-size:18px; + color: #FFFFFF; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + +QPushButton[cssClass="btn-check-right"]:checked:hover { + border: 1px solid #886fb7; + background-color:#886fb7; + font-size:18px; + padding:4px; + color: #FFFFFF; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + +QPushButton[cssClass="btn-check-right"]:checked:pressed { + border: 1px solid #20192e; + background-color:#20192e; + font-size:18px; + padding:4px; + color: #b088ff; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + + +QPushButton[cssClass="btn-check-left"] { + border: 1px solid #5c4b7d; + background-color:#0f0b16; + font-size:18px; + color: #707070; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + + +QPushButton[cssClass="btn-check-left"]:hover { + border: 1px solid #b088ff; + background-color:#0f0b16; + font-size:18px; + color: #707070; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + +QPushButton[cssClass="btn-check-left"]:pressed { + border: 1px solid #5c4b7d; + background-color:#4Db088ff; + font-size:18px; + color: #707070; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + + +QPushButton[cssClass="btn-check-left"]:checked { + border: 1px solid #5c4b7d; + background-color:#5c4b7d; + font-size:18px; + color: #FFFFFF; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + +QPushButton[cssClass="btn-check-left"]:checked:hover { + border: 1px solid #886fb7; + background-color:#886fb7; + font-size:18px; + padding:4px; + color: #FFFFFF; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + +QPushButton[cssClass="btn-check-left"]:checked:pressed { + border: 1px solid #1c122e; + background-color:#1c122e; + font-size:18px; + padding:4px; + color: #b088ff; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + + +QPushButton[cssClass="btn-check"]:checked { + border: 1px solid #5c4b7d; + background-color:#5c4b7d; + padding:4px; + font-size:18px; + color: #FFFFFF; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-check"]:checked:hover { + border: 1px solid #5c4b7d; + background-color:#5c4b7d; + font-size:18px; + padding:4px; + color: #FFFFFF; + border-radius: 2px; +} + +QPushButton[cssClass="btn-check"]:checked:pressed { + border: 1px solid #44375f; + background-color:#5c4b7d; + font-size:18px; + padding:4px 10px; + color: #FFFFFF; + border-radius: 2px; +} + +QPushButton[cssClass="btn-check"]:unchecked { + border: 1px solid #5c4b7d; + background-color:#0f0b16; + font-size:18px; + padding:4px; + color: #707070; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-primary"] { + border: 1px solid #5c4b7d; + background-color:#5c4b7d; + font-size:18px; + padding:4px 10px; + color: #FFFFFF; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-primary"]:hover { + border: 1px solid #44375f; + background-color:#44375f; + font-size:18px; + padding:4px 10px; + color: #FFFFFF; + border-radius: 2px; +} + +QPushButton[cssClass="btn-primary"]:pressed { + border: 1px solid #1c122e; + background-color:#1c122e; + font-size:18px; + padding:4px 10px; + color: #b088ff; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-secundary"] { + border: 1px solid #5c4b7d; + background-color:#0f0b16; + font-size:18px; + padding:4px 10px; + color: #b088ff; + border-radius: 2px; +} + +QPushButton[cssClass="btn-secundary"]:hover { + border: 1px solid #b088ff; + background-color:#0f0b16; + font-size:18px; + padding:4px 10px; + color: #b088ff; + border-radius: 2px; +} + +QPushButton[cssClass="btn-secundary"]:pressed { + border: 1px solid #b088ff; + background-color:#4Db088ff; + font-size:18px; + padding:4px 10px; + color: #b088ff; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-edit-primary"] { + border: 1px solid #bababa; + background-color:#0f0b16; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #FFFFFF; + text-align:left; +} + +QPushButton[cssClass="btn-edit-primary-folder"] { + border: 1px solid #bababa; + background-image: url("://ic-folder"); + background-position:right center; + background-repeat:no-repeat; + background-color:#0f0b16; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #FFFFFF; + text-align:left; +} + +*[cssClass="edit-primary-book"] { + border: 1px solid #bababa; + background-image: url("://ic-address-book-white"); + background-position:right center; + background-repeat:no-repeat; + background-color:#0f0b16; + font-size:16px; + border-radius: 2px; + padding:8px; + padding-right: 34px; + color: #FFFFFF; + text-align:left; +} + + +QLineEdit[cssClass="edit-primary-book"]:focus { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-book"]:focus:hover { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-book"]:hover { + border: 1px solid #FFFFFF; +} + +*[cssClass="edit-primary-book-error"] { + border: 1px solid #f84444; + background-image: url("://ic-address_book_grey"); + background-position:right center; + background-repeat:no-repeat; + background-color:#0f0b16; + font-size:16px; + border-radius: 2px; + padding:8px; + padding-right: 34px; + color: #FFFFFF; + text-align:left; +} + +*[cssClass="edit-primary-multi-book"] { + border: 1px solid #bababa; + background-image: url("://ic-address-send-white"); + background-position:right center; + background-repeat:no-repeat; + background-color:#0f0b16; + font-size:18px; + border-radius: 2px; + padding:8px; + padding-right: 12px; + padding-left:12px; + color: #FFFFFF; + text-align:left; +} + +QLineEdit[cssClass="edit-primary-multi-book"]:focus { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-multi-book"]:focus:hover { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-multi-book"]:hover { + border: 1px solid #FFFFFF; +} + +*[cssClass="edit-primary-multi-book-error"] { + border: 1px solid #f84444; + background-image: url("://ic-address-send-white"); + background-position:right center; + background-repeat:no-repeat; + background-color:#0f0b16; + font-size:17px; + border-radius: 2px; + padding:8px; + padding-right: 12px; + padding-left:12px; + color: #FFFFFF; + text-align:left; +} + + +*[cssClass="edit-primary-book-send"] { + border: 1px solid #bababa; + background-image: url("://ic-address-send-white"); + background-position:right center; + background-repeat:no-repeat; + background-color:#0f0b16; + font-size:18px; + border-radius: 2px; + padding:8px; + padding-right: 12px; + padding-left: 12px; + color: #FFFFFF; + text-align:left; +} + +QLineEdit[cssClass="edit-primary-book-send"]:focus { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-book-send"]:focus:hover { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-book-send"]:hover { + border: 1px solid #FFFFFF; +} + +*[cssClass="edit-primary-book-send-error"] { + border: 1px solid #f84444; + background-image: url("://ic-address-send-white"); + background-position:right center; + background-repeat:no-repeat; + background-color:#0f0b16; + font-size:18px; + border-radius: 2px; + padding:8px; + padding-right: 60px; + color: #FFFFFF; + text-align:left; +} + + +QPushButton[cssClass="btn-secundary-clear"] { + qproperty-icon: url("://ic-clear-liliac") off, + url("://ic-clear-liliac") on ; + qproperty-iconSize: 30px 22px; + border: 1px solid #5c4b7d; + background-color:#0f0b16; + font-size:18px; + padding-top:4px; + padding-left:0px; + padding-bottom:4px; + padding-right:6px; + color: #b088ff; + border-radius: 2px; +} + +QPushButton[cssClass="btn-secundary-clear"]:hover { + border: 1px solid #b088ff; + background-color:#0f0b16; +} + +QPushButton[cssClass="btn-secundary-clear"]:pressed { + border: 1px solid #b088ff; + background-color:#4Db088ff; +} + +QPushButton[cssClass="btn-secundary-new-address"] { + qproperty-icon: url("://ic-update-liliac") off, + url("://ic-update-liliac") on ; + qproperty-iconSize: 30px 30px; + border: 1px solid #5c4b7d; + background-color:#0f0b16; + font-size:18px; + padding-top:4px; + padding-left:6px; + padding-bottom:4px; + padding-right:6px; + color: #b088ff; + border-radius: 2px; +} + +QPushButton[cssClass="btn-secundary-new-address"]:hover { + border: 1px solid #b088ff; + background-color:#0f0b16; +} + +QPushButton[cssClass="btn-secundary-new-address"]:pressed { + border: 1px solid #b088ff; + background-color:#4Db088ff; +} + +QPushButton[cssClass="btn-secundary-label"] { + qproperty-icon: url("://ic-label-liliac") off, + url("://ic-label-liliac") on ; + qproperty-iconSize: 30px 30px; + border: 1px solid #5c4b7d; + background-color:#0f0b16; + font-size:18px; + padding-top:4px; + padding-left:6px; + padding-bottom:4px; + padding-right:6px; + color: #b088ff; + border-radius: 2px; +} + +QPushButton[cssClass="btn-secundary-label"]:hover { + border: 1px solid #b088ff; + background-color:#0f0b16; +} + +QPushButton[cssClass="btn-secundary-label"]:pressed { + border: 1px solid #b088ff; + background-color:#4Db088ff; +} + +QPushButton[cssClass="btn-secundary-copy"] { + qproperty-icon: url("://ic-copy-liliac") off, + url("://ic-copy-liliac") on ; + qproperty-iconSize: 30px 30px; + border: 1px solid #5c4b7d; + background-color:#0f0b16; + font-size:18px; + padding-top:4px; + padding-left:6px; + padding-bottom:4px; + padding-right:6px; + color: #b088ff; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-secundary-copy"]:hover { + border: 1px solid #b088ff; + background-color:#0f0b16; +} + +QPushButton[cssClass="btn-secundary-copy"]:pressed { + border: 1px solid #b088ff; + background-color:#4Db088ff; +} + + +QPushButton[cssClass="btn-secundary-add"] { + background-image: url("://ic-add-liliac"); + background-position:right center; + background-repeat:no-repeat; + border: 1px solid #5c4b7d; + background-color:#0f0b16; + font-size:18px; + padding-top:4px; + padding-left:6px; + padding-bottom:4px; + padding-right:30px; + color: #b088ff; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-secundary-add"]:hover { + border: 1px solid #b088ff; + background-color:#0f0b16; +} + +QPushButton[cssClass="btn-secundary-add"]:pressed { + border: 1px solid #b088ff; + background-color:#4Db088ff; +} + + +QPushButton[cssClass="btn-text-primary"] { + border: 0; + background-color:#0f0b16; + font-size:18px; + padding-top:4px; + padding-left:4px; + padding-bottom:4px; + padding-right:4px; + color: #b088ff; +} + +QPushButton[cssClass="btn-text-primary"]:hover { + color: #5c4b7d; +} + +QPushButton[cssClass="btn-text-primary"]:pressed { + color: #b088ff; +} + + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH LINE EDIT +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="edit-primary"] { + border: 1px solid #bababa; + background-color:#0f0b16; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #FFFFFF; +} + +*[cssClass="edit-primary"]:focus { + border: 1px solid #b088ff; +} + +*[cssClass="edit-primary"]:focus:hover { + border: 1px solid #b088ff; +} + +*[cssClass="edit-primary"]:hover { + border: 1px solid #FFFFFF; +} + +*[cssClass="edit-primary-disabled"] { + border: 1px solid #33ffffff; + background-color:#0f0b16; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #FFFFFF; +} + + +*[cssClass="edit-primary-error"] { + border: 1px solid #f84444; + background-color:#0f0b16; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #FFFFFF; +} + +QPushButton[cssClass="btn-expand"] { + background-image: url("://ic-expand"); + background-position:center; + background-repeat:no-repeat; + background-color:#0f0b16; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SPLASH +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-splash"] { + background-color:transparent; + border-image: url("://bg-splash-png") 0 0 0 0 stretch stretch; + border-radius: 4px; +} + +*[cssClass="img-splash-logo"] { + qproperty-icon: url("://img-logo-pivx"); + qproperty-iconSize: 300px 100px; + border:0; + background-color:transparent; +} + +*[cssClass="bg-progress"] { + border-top:2px solid #b088ff ; + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + background-color:transparent; +} + +QProgressBar[cssClass="progress-splash"]::chunk:horizontal { + background: qlineargradient(x1: 0, + y1: 0.5, + x2: 1, + y2: 0.5, + stop: 0 #80211a2f, + stop: 1 #80b088ff, + stop: 2 #80211a2f,); + margin-right: 2px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH DASHBOARD +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + + +*[cssClass="text-warning"] { + color:#f84444; + font-size:16px; +} + +*[cssClass="ic-warning"] { + qproperty-icon: url("://ic-transaction-warning") off, + url("://ic-transaction-warning") on ; + qproperty-iconSize: 24px 24px; +} + + +*[cssClass="text-amount-grey"] { + color:#FFFFFF; + font-size:20px; +} + +*[cssClass="text-stake-piv"] { + color:#5c4b7d; + font-size:16px; + padding:10px; + border-bottom: 5px solid #5c4b7d; +} + +*[cssClass="text-stake-piv-disable"] { + color:#69656F; + font-size:16px; + padding:10px; + border-bottom: 5px solid #69656F; +} + +*[cssClass="text-stake-zpiv"] { + color:#b088ff; + font-size:16px; + padding:10px; + border-bottom: 5px solid #b088ff; +} + +*[cssClass="text-stake-zpiv-disable"] { + color:#423E4A; + font-size:16px; + padding:10px; + border-bottom: 5px solid #423E4A; +} + +*[cssClass="legend-chart"] { + color:#FFFFFF; + font-size:16px; +} + +*[cssClass="text-chart-zpiv"] { + color:#b088ff; + font-size:16px; + padding-left:4px; +} + +*[cssClass="text-chart-piv"] { + color:#5c4b7d; + font-size:16px; + padding-left:4px; +} + +*[cssClass="square-chart-zpiv"] { + background-color:#b088ff; + border:none; +} + +*[cssClass="square-chart-piv"] { + background-color:#5c4b7d; + border:none; +} + +*[cssClass="text-amount-grey-big"] { + color:#FFFFFF; + font-size:26px; +} + + +*[cssClass="container-chart"] { + background-color:#0f0b16; +} + +QPushButton[cssClass="btn-chart-arrow"] { + qproperty-icon: url("://ic-arrow-left-white") ; + qproperty-iconSize: 12px 12px; + background-color: transparent; + border:0px; + border-radius:2px; +} + +QPushButton[cssClass="btn-chart-arrow"]:hover { + background-color: #5c4b7d; +} + +QPushButton[cssClass="btn-chart-arrow"]:pressed { + background-color:#20192e; +} + +QComboBox[cssClass="btn-combo-secundary"] { + background-color:#0f0b16; + padding:6px 12px 6px 6px; + font-size:16px; + border:1px solid #bababa; + color: #707070; + text-align: right; + border-radius:2px; +} + +QComboBox[cssClass="btn-combo-secundary"]::down-arrow { + image: url("://ic-arrow-drop-down-purple"); + width: 24px; + height: 24px; +} + +QComboBox[cssClass="btn-combo-chart"] { + background-color:#0f0b16; + padding:6px 12px 6px 6px; + font-size:16px; + border:1px solid #bababa; + color: #707070; + text-align: right; + border-radius:2px; +} + +QComboBox[cssClass="btn-combo-chart"]::down-arrow { + image: url("://ic-arrow-drop-down"); + width: 24px; + height: 24px; +} + + +QComboBox[cssClass="btn-combo-chart-selected"] { + background-color:#B35c4b7d; + padding:6px 12px 6px 6px; + font-size:16px; + border:1px solid #B35c4b7d; + color: #FFFFFF; + text-align: right; + border-radius:2px; +} + +QComboBox[cssClass="btn-combo-chart-selected"]::down-arrow { + image: url("://ic-arrow-drop-down-white"); + width: 24px; + padding-right: 10px; + height: 24px; +} + +QComboBox[cssClass="btn-combo-chart-selected"]:on { + padding-top: 10px; + padding-left: 10px; + background-color: #B35c4b7d; +} + +QComboBox::drop-down { + border-width: 0px; +} + +QComboBox::down-arrow { + image: url(noimg); border-width: 0px; +} + +QPushButton[cssClass="btn-check-time"] { + background-color:#0f0b16; + font-size:14px; + color: #707070; + padding:4px; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-time"]:checked { + background-color:#5c4b7d; + border-radius:2px; + font-size:14px; + padding:4px; + color: #FFFFFF; +} + +QPushButton[cssClass="btn-check-time"]:hover { + background-color:#B35c4b7d; + border-radius:2px; + font-size:14px; + padding:4px; + color: #FFFFFF; +} + +QPushButton[cssClass="btn-check-time"]:pressed { + background-color:#20192e; + border-radius:2px; + font-size:14px; + padding:4px; + color: #b088ff; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH CHECKBOX +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +QCheckBox { + spacing: 5px; + font-size:18px; + color:#FFFFFF; +} + +QCheckBox:checked { + spacing: 5px; + font-size:18px; + color:#b088ff; +} + +QCheckBox::indicator { + width: 24px; + height: 24px; +} + +QCheckBox::indicator:unchecked { + image: url("://ic-check-box"); +} + +QCheckBox::indicator:checked { + image: url("://ic-check-liliac-on"); +} + + +QCheckBox[cssClass="btn-watch-password"] { + spacing: 5px; + font-size:18px; + color:transparent; +} + + +QCheckBox[cssClass="btn-watch-password"]::indicator:unchecked { + image: url("://ic-watch-password-white"); +} + +QCheckBox[cssClass="btn-watch-password"]::indicator:checked { + image: url("://ic-watch-password-white"); +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH REQUEST DIALOG +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +QComboBox[cssClass="btn-combo-coins"] { + background-color:#5c4b7d; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #5c4b7d; + color: #FFFFFF; +} + +QComboBox[cssClass="btn-combo-coins"]::down-arrow { + image: url("://ic-arrow-drop-white-down"); + padding-right: 10px; + height: 16px; + width: 16px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH RECEIVE +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="label-address-box"] { + color:#FFFFFF; + background-color: #26b088ff; + font-size:22px; + padding:10px 10px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SPIN BOX +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +QSpinBox[cssClass="btn-spin-box"] { + background-color:#0f0b16; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #bababa; + color: #707070; + selection-background-color: #5c4b7d; + selection-color: #FFFFFF; +} + + +QSpinBox[cssClass="btn-spin-box"]::up-button { + image: url("://ic-arrow-drop-up-purple"); + subcontrol-position: top right; width: 20px; height: 20px; + border: 0px; + padding:0px; + margin:0px 5px 0px 0px; +} + +QSpinBox[cssClass="btn-spin-box"]::down-button { + image: url("://ic-arrow-drop-down-purple"); + subcontrol-position: bottom right; width: 20px; height: 20px; + border: 0px; + padding:0px; + margin:0px 5px 0px 0px; +} + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH COMBO BOX +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + + +QComboBox[cssClass="btn-combo"] { + background-color:#0f0b16; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #0f0b16; + color: #707070; + text-align: right; +} + +QComboBox[cssClass="btn-combo"]::down-arrow { + image: url("://ic-arrow-drop-down"); + width: 24px; + height: 24px; +} + +QComboBox[cssClass="btn-combo-edit"] { + background-color:#0f0b16; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #0f0b16; + color: #ffffff; + text-align: right; +} + +QComboBox[cssClass="btn-combo-edit"]::down-arrow { + image: url("://ic-arrow-drop-down-white"); + width: 24px; + height: 24px; +} + + +QComboBox[cssClass="btn-combo-options"] { + background-color:#0f0b16; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #0f0b16; + color: #707070; + text-align: right; +} + +QComboBox[cssClass="btn-combo-options"]::down-arrow { + image: url("://ic-arrow-drop-down"); + width: 24px; + height: 24px; +} + + +QComboBox { + background-color:transparent; + padding-right:20px; + font-size:16px; + color: #707070; + border-radius:0px; + border: 0px; +} + +QComboBox QFrame { border: 0px solid transparent; border-radius:0px;} + +QComboBox:on { /* shift the text when the popup opens */ + padding-top: 10px; + padding-left: 10px; + background-color: transparent; +} + +QComboBox::drop-down { + subcontrol-origin: padding; + subcontrol-position: center right; + width: 15px; + right:3px; + border-top-right-radius: 0px; /* same radius as the QComboBox */ + border-bottom-right-radius: 0px; + border-radius:0px; + background:none; +} + +QComboBox::down-arrow { + image: url("://ic-arrow-drop-down"); + width: 24px; + height: 24px; +} + +QComboBox::down-arrow:on { /* shift the arrow when popup is open */ + top: 1px; + left: 1px; +} + +QComboBox:item { + color: #707070; + font-size:18px; +} + +QComboBox QAbstractItemView { + margin:0px; + min-width: 150px; + border-radius:0px; + font-size:16px; + outline: 0px; +} + +QComboBox::selected:item { border: none; outline: 0px; } + +QComboBox QAbstractItemView::item { + margin:0px; + background-color: #FFFFFF; + padding:10px 20px; + font-size:16px; + color: #707070; + border-radius:0px; + outline: 0px; +} +QComboBox QAbstractItemView::item:selected { + background-color: #d8d5e0; + padding:10px 20px; + font-size:16px; + margin:0px; + color: #5c4b7d; + border-radius:0px; + outline: 0px; +} + +QComboBox QAbstractItemView QPushButton{ + border:0px; + outline: 0px; +} + +QComboBox QAbstractItemView::item:selected QPushButton:hover{ + border:0px; + outline: 0px; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH RADIO BUTTON +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ +QRadioButton:checked { + color: #b088ff; + font-size:20px; +} + +QRadioButton:unchecked { + color: #bababa; + font-size:20px; +} + +QRadioButton { + color: #bababa; + font-size:20px; + spacing:20px; +} + +QRadioButton::indicator { + width: 26px; + height: 26px; +} + +QRadioButton::indicator:checked { + background: url("://ic-radio-liliac-on"); + background-repeat:no-repeat; + background-position:center; +} + +QRadioButton::indicator:unchecked { + background: url("://btn-radio-off"); + background-repeat:no-repeat; + background-position:center; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SCROLL BAR +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +QScrollBar:vertical { + border: 0px solid #bababa; + background:#0f0b16; + width:4px; + margin: 0px 0px 0px 0px; +} + + +QScrollBar::handle:vertical { + background: #5c4b7d; + min-height: 0px; +} + +QScrollBar::add-line:vertical { + background: #0f0b16; + height: 0px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} +QScrollBar::sub-line:vertical { + background: #0f0b16; + height: 0 px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + height: 0px; +} + + +QScrollBar::right-arrow:horizontal, QScrollBar::left-arrow:horizontal +{ + border: none; + background: none; + color: none; +} + +QScrollBar::top-arrow:horizontal, QScrollBar::bottom-arrow:horizontal +{ + border: none; + background: none; + color: none; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH DIALOG MASTER NODE +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="line-purple"] { + background-color:#5c4b7d; +} + + +QPushButton[cssClass="btn-number-check"] { + border: 1px solid #5c4b7d; + background-color:transparent; + font-size:14px; + border-radius:11px; + color: #807b8a; +} + +QPushButton[cssClass="btn-number-check"]:checked { + border: 1px solid #b088ff; + background-color:#b088ff; + font-size:14px; + border-radius:11px; + color: #5c4b7d; +} + +QPushButton[cssClass="btn-name-check"] { + background-color: transparent; + border:none; + font-size:20px; + color: #807b8a; +} + +QPushButton[cssClass="btn-name-check"]:checked { + background-color:transparent; + border:none; + font-size:20px; + color: #b088ff; +} + + +QPushButton[cssClass="ic-step-confirm"] { + background-image: url("://ic-check-white"); + background-position:center; + background-repeat:no-repeat; + border: 1px solid #6C529D; + border-radius:11px; + background-color:#6C529D; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SEND +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-coin-type"] { + background-color:#0f0b16; + border: 1px solid #bababa; + border-radius: 2px; +} + + +*[cssClass="coin-icon-piv"] { + qproperty-icon: url("://ic-coin-piv") off, + url("://ic-coin-piv") on ; + qproperty-iconSize: 24px 24px; + background-color: #FFFFFF; + border: 2px solid #0f0b16; + border-radius: 12px; +} + +*[cssClass="coin-icon-zpiv"] { + qproperty-icon: url("://ic-coin-zpiv") off, + url("://ic-coin-zpiv") on ; + qproperty-iconSize: 24px 24px; + background-position:center; + background-repeat:no-repeat; + background-color: #FFFFFF; + border: 2px solid #0f0b16; + border-radius: 12px; +} + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH Dialog +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-dialog"] { + background-color:#0f0b16; + border-radius: 2px; + border:1px solid #b088ff; +} + + +*[cssClass="text-title-dialog"] { + color:#b088ff; + font-size:22px; +} + +*[cssClass="text-title2-dialog"] { + color:#b088ff; + font-size:16px; +} + +*[cssClass="text-title1-dialog"] { + color:#b088ff; + font-size:22px; +} + + +*[cssClass="text-body1-dialog"] { + color:#B3FFFFFF; + font-size:18px; +} + +*[cssClass="text-body2-dialog"] { + color:#B3FFFFFF; + font-size:15px; +} + +*[cssClass="text-body3-dialog"] { + color:#B3FFFFFF; + font-size:17px; +} + +QDialogButtonBox QPushButton { + border: 1px solid #5c4b7d; + background-color:#5c4b7d; + font-size:18px; + padding:4px 10px; + color: #FFFFFF; + +} + +QPushButton[cssClass="btn-dialog-cancel"] { + border: 0; + background-color:transparent; + font-size:18px; + padding:4px 10px; + color: #bababa; + border-radius: 2px; +} + + +QLineEdit[cssClass="edit-primary-dialog"] { + border: 1px solid #bababa; + background-color:#0f0b16; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #FFFFFF; +} + +QLineEdit[cssClass="edit-primary-dialog"]:focus { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-dialog"]:focus:hover { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-dialog"]:hover { + border: 1px solid #FFFFFF; +} + +QLineEdit[cssClass="edit-primary-dialog-error"] { + border: 1px solid #f84444; + background-color:#0f0b16; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #FFFFFF; +} + +QLabel[cssClass="label-subtitle-dialog"] { + background-color:#0f0b16; + font-size:16px; + color: #B088FF; + padding-top: 10px; + padding-bottom: 10px; +} + +QComboBox[cssClass="btn-combo-dialog"] { + background-color:#0f0b16; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #0f0b16; + color: #B088FF; + text-align: right; +} + +QComboBox[cssClass="btn-combo-dialog"]::down-arrow { + image: url("://ic-arrow-drop-down-white"); + width: 24px; + height: 24px; + padding-top: 1px; +} + + +QComboBox[cssClass="btn-combo-edit-dialog"] { + background-color:#0f0b16; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #bababa; + color: #B088FF; + text-align: right; +} + +QComboBox[cssClass="btn-combo-edit-dialog"]::down-arrow { + image: url("://ic-arrow-drop-down-white"); + width: 24px; + height: 24px; + padding-right: 12px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SETTINGS +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +QPushButton[cssClass="btn-settings-check"] { + background-image: url("://ic-arrow-drop-down-white"); + background-position:right center; + background-repeat:no-repeat; + background-color: #0f0b16; + border:none; + border-bottom:1px solid #bababa; + font-size:20px; + color: #707070; + text-align:left; +} + +QPushButton[cssClass="btn-settings-check"]:checked { + background-image: url("://ic-arrow-drop-up-white"); + background-position:right center; + background-repeat:no-repeat; + background-color:#0f0b16; + border:none; + border-bottom:1px solid #0f0b16; + font-size:20px; + color: #707070; + text-align:left; +} + +QPushButton[cssClass="btn-settings-options"] { + background-color: rgba(92, 75, 125, 0.2); + border:none; + font-size:20px; + color: rgba(255, 255, 255, 0.7); + padding:0 20px; + text-align:left; +} + +QPushButton[cssClass="btn-settings-options"]:checked { + background-color:#5c4b7d; + border:none; + font-size:20px; + color: #FFFFFF; + padding:0 20px; + text-align:left; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH Icons +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + + +*[cssClass="ic-close-white"] { + qproperty-icon: url("://ic-close-white") off, + url("://ic-close-white") on ; + qproperty-iconSize: 24px 24px; + +} + +*[cssClass="ic-arrow"] { + qproperty-icon: url("://ic-arrow-right-white") off, + url("://ic-arrow-right-white") on ; + qproperty-iconSize: 24px 24px; +} + +*[cssClass="ic-arrow-down"] { + qproperty-icon: url("://ic-arrow-drop-down-white") off, + url("://ic-arrow-drop-down-white") on ; + qproperty-iconSize: 24px 24px; + background-color: transparent; + border:none; +} + + + +*[cssClass="ic-copy"] { + qproperty-icon: url("://ic-copy-liliac") off, + url("://ic-copy-liliac") on ; + qproperty-iconSize: 24px 24px; + background-color: transparent; + border:none; +} + +*[cssClass="ic-copy-big"] { + qproperty-icon: url("://ic-copy-big-white") off, + url("://ic-copy-big-white") on ; + qproperty-iconSize: 24px 24px; + background-color: transparent; + border:none; +} + +*[cssClass="ic-close"] { + qproperty-icon: url("://ic-close-white"); + qproperty-iconSize: 24px 24px; + background-color: transparent; + border:none; +} + +*[cssClass="layout-arrow"] { + background: url("://ic-arrow-right-white"); + background-repeat:no-repeat; + background-position:right center; +} + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH FAQ +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="text-title-faq"] { + color:#b088ff; + font-size:26px; +} + + +*[cssClass="container-faq-buttons"] { + background:transparent; + border:1px solid #b088ff; + border-radius: 5px; +} + +*[cssClass="text-subtitle-faq"] { + color:#FFFFFF; + font-size:22px; +} + +*[cssClass="text-content-faq"] { + color:#FFFFFF; + font-size:18px; +} + +*[cssClass="container-number-faq"] { + color:#FFFFFF; + background-color: #5c4b7d; + font-size:14px; + border-radius: 2px; +} + + + +QPushButton[cssClass="btn-faq-exit"] { + background: url("://ic-exit"); + background-repeat:no-repeat; + background-position:right center; + background-color:transparent; + border:none; + padding:0 30px 0 0; + font-size:18px; + color: #CCFFFFFF; + text-align:left; +} + +QPushButton[cssClass="btn-faq-web"] { + background-color:transparent; + border:none; + font-size:16px; + color: #b088ff; + text-align:left; +} + + + +QPushButton[cssClass="btn-faq-options"] { + background-color:transparent; + border:none; + font-size:18px; + color: #FFFFFF; + padding:0 20px; + text-align:left; +} + +QPushButton[cssClass="btn-faq-options"]:checked { + background-color: rgba(176 ,136 ,255, 0.2); + border:none; + font-size:18px; + color: #FFFFFF; + padding:0 20px; + text-align:left; +} + + +#scrollAreaFaq QScrollBar:vertical { + border: 0px solid #bababa; + background:#0f0b16; + width:4px; + margin: 0px 0px 0px 0px; +} + + +#scrollAreaFaq QScrollBar::handle:vertical { + background: #5c4b7d; + min-height: 0px; +} + +#scrollAreaFaq QScrollBar::add-line:vertical { + background: #0f0b16; + height: 0px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +#scrollAreaFaq QScrollBar::sub-line:vertical { + background: #0f0b16; + height: 0 px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +#scrollAreaFaq QScrollBar::add-page:vertical, #scrollAreaFaq QScrollBar::sub-page:vertical { + height: 0px; +} + + +#scrollAreaFaq QScrollBar::right-arrow:horizontal, #scrollAreaFaq QScrollBar::left-arrow:horizontal +{ + border: none; + background: none; + color: none; +} + +#scrollAreaFa QScrollBar::top-arrow:horizontal, #scrollAreaFa QScrollBar::bottom-arrow:horizontal +{ + border: none; + background: none; + color: none; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH WELCOME +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +QPushButton[cssClass="btn-close-white"] { + background: url("://ic-close-white"); + background-repeat:no-repeat; + background-position:center; + background-color:transparent; +} + +QPushButton[cssClass="ic-step-confirm-welcome"] { + background-image: url("://ic-check-white"); + background-position:center; + background-repeat:no-repeat; + border: 1px solid #6C529D; + border-radius:11px; + background-color:#6C529D; +} + +*[cssClass="text-title-welcome"] { + color:#FFFFFF; + font-size:26px; +} + +*[cssClass="text-main-white"] { + color:#FFFFFF; + font-size:20px; +} + + +*[cssClass="container-welcome"] { + border-image: url("://bg-welcome") 0 0 0 0 stretch stretch; + background-color:#000000; +} + +*[cssClass="container-welcome-box"] { + background-color:transparent; + border: 1px solid transparent; +} + + +*[cssClass="line-welcome"] { + background-color: #807b8a; +} + +*[cssClass="container-welcome-stack"] { + background-image: url("://bg-welcome-container-png"); + background-position:center; + background-repeat:no-repeat; + background-color: transparent; + border: 1px solid #b088ff; + border-radius: 4px; +} + +*[cssClass="container-welcome-step1"] { + background-image: url("://img-welcome-step1"); + background-position:left bottom; + background-repeat:no-repeat; + background-color: transparent; +} + +*[cssClass="container-welcome-step2"] { + background-image: url("://img-welcome-step2"); + background-position:left bottom; + background-repeat:no-repeat; + background-color: transparent; +} + +*[cssClass="container-welcome-step3"] { + background-image: url("://img-welcome-step3"); + background-position:left bottom; + background-repeat:no-repeat; + background-color: transparent; +} + +*[cssClass="container-welcome-step4"] { + background-image: url("://img-welcome-step4"); + background-position:left bottom; + background-repeat:no-repeat; + background-color: transparent; +} + +QComboBox[cssClass="btn-combo-welcome"] { + background-color:#171022; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #b088ff; + color: #FFFFFF; +} + + +QComboBox[cssClass="btn-combo-welcome"]::down-arrow { + image: url("://ic-arrow-purple-down"); + width: 42px; + height: 42px; +} + +QPushButton[cssClass="btn-welcome-back"] { + background: url("://ic-arrow-white-left"); + background-repeat:no-repeat; + background-position:center; + border: 0px; + background-color:#5c4b7d; + color: #5c4b7d; +} + +QPushButton[cssClass="btn-welcome-next"] { + background: url("://ic-arrow-white-right"); + background-repeat:no-repeat; + background-position:center; + border: 0; + background-color: #5c4b7d; + color: #5c4b7d; +} + + +QPushButton[cssClass="btn-welcome-number-check"] { + border: 1px solid #5c4b7d; + background-color:transparent; + font-size:14px; + border-radius:11px; + color: #807b8a; +} + +QPushButton[cssClass="btn-welcome-number-check"]:checked { + border: 1px solid #b088ff; + background-color:#b088ff; + font-size:14px; + border-radius:11px; + color: #5c4b7d; +} + +QPushButton[cssClass="btn-welcome-name-check"] { + background-color: transparent; + border:none; + font-size:20px; + color: #807b8a; +} + +QPushButton[cssClass="btn-welcome-name-check"]:checked { + background-color:transparent; + border:none; + font-size:20px; + color: #b088ff; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH Tooltip +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +QToolTip { color: white; background-color: #b088ff; border: none;padding:10px; border-radius:2px;} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH ROW LIST +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-list-menu"]{ + background-color:white; + border-radius:2px; + padding:15px; + border: 1px solid #bababa; +} + +*[cssClass="btn-list-menu"]{ + border: 0; + background-color:#FFFFFF; + font-size:16px; + color: #707070; +} + +*[cssClass="btn-list-menu"]:hover{ + color: #5c4b7d; +} + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH EMPTY LIST +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="text-empty"]{ + color: #B3FFFFFF; + font-size: 18px; +} + + +*[cssClass="img-empty-master"] { + qproperty-icon: url("://img-empty-dark-masternode"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +*[cssClass="img-empty-transactions"] { + qproperty-icon: url("://img-empty-dark-transactions"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +*[cssClass="img-empty-peers"] { + qproperty-icon: url("://img-empty-dark-peers"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +*[cssClass="img-empty-contacts"] { + qproperty-icon: url("://img-empty-dark-contacts"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + + +*[cssClass="img-empty-error"] { + qproperty-icon: url("://img-empty-dark-error"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +*[cssClass="img-empty-multisend"] { + qproperty-icon: url("://img-empty-dark-multisend"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +*[cssClass="img-empty-staking-on"] { + qproperty-icon: url("://img-empty-dark-staking-on"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + + +*[cssClass="img-empty-staking-off"] { + qproperty-icon: url("://img-empty-dark-staking-off"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + + +*[cssClass="img-empty-privacy"] { + qproperty-icon: url("://img-empty-dark-privacy"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH TREE WIDGET +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +#treeWidget { + border:1px solid #5c4b7d; + background-color:#0f0b16;; + background-position:center; + background-repeat:no-repeat; + selection-background-color:#33b088ff; + selection-color: white; + font-size:14px; + border-radius:0px; + color: #FFFFFF; +} + +#treeWidget::indicator:first:checked{ + image: url("://ic-check-box-dark-active"); +} +#treeWidget::indicator:middle:checked{ + image: url("://ic-check-box-dark-active"); +} + +#treeWidget::indicator { + width: 24px; + height: 24px; +} + +#treeWidget::indicator:indeterminate { + image: url("://ic-check-box-liliac-indeterminate"); +} + +#treeWidget::indicator:unchecked { + image: url("://ic-check-box"); +} + +#treeWidget::indicator:checked { + image: url("://ic-check-box-dark-active"); +} + +#treeWidget::item { + border:none; + border-bottom: 1px solid #40ffffff; + border-radius:0px; + color: #ffffff; + padding-top: 6px; + padding-bottom: 6px; + background-color:#0f0b16; +} + +#treeWidget::branch:closed:has-children:!has-siblings { + border-image: none; + background-color:#0f0b16; + image: url("://ic-arrow-drop-up"); + border-bottom: 1px solid #40ffffff; +} + +#treeWidget::branch:closed:has-children:has-siblings { + border-image: none; + background-color:#0f0b16; + image: url("://ic-arrow-drop-up"); + border-bottom: 1px solid #40ffffff; +} + + +#treeWidget::branch:open:has-children:!has-siblings, +#treeWidget::branch:open:has-children:has-siblings { + border-image: none; + image: url("://ic-arrow-drop-down"); + border-bottom: 1px solid #40ffffff; +} + +#treeWidget::item:hover { + border:none; + border-bottom: 1px solid #40ffffff; + border-radius:0px; + color: #ffffff; + background-color:#26bababa; +} + +#treeWidget::item:selected { + border:none; + border-bottom: 1px solid #40ffffff; + border-radius:0px; + color: #ffffff; + background-color:#33b088ff; +} + + +#treeWidget::item:hover:selected { + border:none; + border-bottom: 1px solid #40ffffff; + border-radius:0px; + color: #ffffff; + background-color:#33b088ff; +} + + +#treeWidget::branch { + background-color: #0f0b16; + selection-background-color:#33b088ff; +} + +#treeWidget::branch:selected { + background-color:#33b088ff; +} + +#treeWidget::branch:!selected { + background-color:#33b088ff; +} + +#treeWidget::branch:hover { + background-color:#260f0b16; +} + +#treeWidget::branch:!has-children { + background-color: #0f0b16; +} + +QHeaderView::section { + background-color: #5c4b7d; + color: #FFFFFF; + padding-top: 6px; + padding-bottom: 6px; + font-size:14px; + border:0px solid #5c4b7d; +} + + +*[cssClass="table-tree"] { + border:0; + background-color:#0f0b16; + background-position:center; + background-repeat:no-repeat; + font-size:14px; + border-radius:0px; + color: #ffffff; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SEND MULTI +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +QPushButton[cssClass="ic-multi-number"] { + border:0; + background-color:transparent; + background-image: url("://bg-multi-number-dark"); + background-position:center; + background-repeat:no-repeat; + font-size:12px; + border-radius:12px; + color: #B088FF; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH OPTION BUTTON +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +*[cssClass="btn-options-indicator"]{ + border:0px ; + background:#5c4b7d; + border-radius: 5px; +} + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SNACK BAR +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +*[cssClass="container-snackbar"]{ + background-color:#382d4d; + border-top:2px solid #b088ff; +} + +*[cssClass="text-snackbar"]{ + color:#FFFFFF; + font-size:20px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH LOADING +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + */ + +*[cssClass="container-loading"]{ + background-color:#BF000000; +} + +*[cssClass="text-loading"]{ + color:#ffffff; + font-size:20px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH INTRO +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + */ + +*[cssClass="text-intro-white"] { + color:#FFFFFF; + font-size:16px; +} + + +QPushButton[cssClass="btn-dots-welcome"] { + border: 1px solid #b088ff; + background-color:#b088ff; + font-size:18px; + padding:8px; + color: #FFFFFF; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-dots-welcome"]:hover { + border: 1px solid #b088ff; + background-color:#44375f; + font-size:18px; + padding:8px; + color: #FFFFFF; + border-radius: 2px; +} + +QPushButton[cssClass="btn-dots-welcome"]:pressed { + border: 1px solid #b088ff; + background-color:#44375f; + font-size:18px; + padding:8px; + color: #b088ff; + border-radius: 2px; +} + +*[cssClass="edit-primary-welcome"] { + border:1px solid #b088ff; + border-right: 0px; + background-color:#171022; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #FFFFFF; +} + +*[cssClass="edit-primary-welcome"]:focus { + border: 1px solid #b088ff; + border-right: 0px; +} + +*[cssClass="edit-primary-welcome"]:focus:hover { + border: 1px solid #b088ff; + border-right: 0px; +} + +*[cssClass="edit-primary-welcome"]:hover { + border: 1px solid #b088ff; + border-right: 0px; +} + +*[cssClass="edit-primary-welcome-disabled"] { + border:1px solid #33ffffff; + border-right: 0px; + background-color:#171022; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #66FFFFFF; +} + +QRadioButton[cssClass="radio-welcome"]:checked { + color: #b088ff; + font-size:20px; +} + +QRadioButton[cssClass="radio-welcome"]:unchecked { + color: #bababa; + font-size:20px; +} + +QRadioButton[cssClass="radio-welcome"] { + color: #bababa; + font-size:20px; + spacing:20px; +} + +QRadioButton[cssClass="radio-welcome"]::indicator { + width: 26px; + height: 26px; +} + +QRadioButton[cssClass="radio-welcome"]::indicator:checked { + background: url("://ic-radio-liliac-on"); + background-repeat:no-repeat; + background-position:center; +} + +QRadioButton[cssClass="radio-welcome"]::indicator:unchecked { + background: url("://btn-radio-off"); + background-repeat:no-repeat; + background-position:center; +} diff --git a/src/qt/pivx/res/css/style_light.css b/src/qt/pivx/res/css/style_light.css new file mode 100644 index 000000000000..473843a8f85d --- /dev/null +++ b/src/qt/pivx/res/css/style_light.css @@ -0,0 +1,3105 @@ +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH CONTAINER +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container"] { + background-color:#FFFFFF; +} + +*[cssClass="container-border"] { + background-color:#FFFFFF; + border: 1px solid #FFFFFF; +} + +*[cssClass="container-border-light"] { + background-color:#FFFFFF; + border: 1px solid #bababa; + border-radius:2px; +} + +*[cssClass="container_right"] { + background-color:#FFFFFF; + border-left: 1px solid #bababa; +} + +*[cssClass="container-right"] { + background-color:#FFFFFF; + border-left: 1px solid #bababa; +} + +*[cssClass="container-square"] { + background-color:#FFFFFF; + border: 1px solid #bababa; +} + +*[cssClass="container-options"] { + background-color:#FFFFFF; + border-bottom: 1px solid #bababa; +} + +*[cssClass="container-divider"] { + background-color:#bababa; +} + +*[cssClass="container-purple"] { + background-color:#5c4b7d; + border: 0; +} + +*[cssClass="container-border-purple"] { + background-color:#FFFFFF; + border: 1px solid #5c4b7d; + border-radius:2px; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH NAVIGATION +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-nav"] { + background-color: qlineargradient(y1:0, y2: 1, stop: 0 #5c4b7d, stop: 1 #41365a); +} + +QPushButton[cssClass="img-nav-logo"] { + qproperty-icon: url("://img-nav-logo"); + qproperty-iconSize: 49px 60px; +} + +*[cssClass="btn-nav-receive"] { + qproperty-icon: url("://ic-nav-receive") off, + url("://ic-nav-receive-active") on; + qproperty-iconSize: 24px 40px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-receive"]:checked { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-receive"]:checked:hover { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + color: #B088FF; +} + +*[cssClass="btn-nav-receive"]:hover { + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-receive-active"] { + qproperty-icon:url("://ic-nav-receive-active") ; + qproperty-iconSize: 24px 40px; + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-settings"] { + qproperty-icon: url("://ic-nav-settings") off, + url("://ic-nav-settings-active") on; + qproperty-iconSize: 24px 40px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-settings"]:checked { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-settings"]:checked:hover { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + color: #B088FF; +} + +*[cssClass="btn-nav-settings"]:hover { + qproperty-icon: url("://ic-nav-settings-hover"); + qproperty-iconSize: 24px 40px; + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-settings-active"] { + qproperty-icon:url("://ic-nav-settings-active") ; + qproperty-iconSize: 24px 40px; + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-dash"] { + qproperty-icon: url("://ic-nav-dashboard") off, + url("://ic-nav-dashboard-active") on ; + qproperty-iconSize: 24px 40px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-dash"]:checked { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-dash"]:checked:hover { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + color: #B088FF; +} + + +*[cssClass="btn-nav-dash"]:hover { + qproperty-icon: url("://ic-nav-dashboard-hover"); + qproperty-iconSize: 24px 40px; + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-dash-active"] { + qproperty-icon:url("://ic-nav-dashboard-active"); + qproperty-iconSize: 24px 40px; + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-send"] { + qproperty-icon: url("://ic-nav-send") off, + url("://ic-nav-send") on ; + qproperty-iconSize: 24px 40px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-send"]:checked { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-send"]:checked:hover { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + color: #B088FF; +} + +*[cssClass="btn-nav-send"]:hover { + qproperty-icon: url("://ic-nav-send-hover"); + qproperty-iconSize: 24px 40px; + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-send-active"] { + qproperty-icon:url("://ic-nav-send-active") ; + qproperty-iconSize: 24px 40px; + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-address"] { + qproperty-icon: url("://ic-nav-address") off, + url("://ic-nav-address-active") on ; + qproperty-iconSize: 24px 40px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-address"]:checked { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-address"]:checked:hover { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + color: #B088FF; +} + +*[cssClass="btn-nav-address"]:hover { + qproperty-icon: url("://ic-nav-address-hover"); + qproperty-iconSize: 24px 40px; + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-address-active"] { + qproperty-icon:url("://ic-nav-address-active") ; + qproperty-iconSize: 24px 40px; + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-privacy"] { + qproperty-icon: url("://ic-nav-privacy") off, + url("//ic-nav-privacy-active") on ; + qproperty-iconSize: 24px 40px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-privacy"]:checked { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-privacy"]:checked:hover { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + color: #B088FF; +} + +*[cssClass="btn-nav-privacy"]:hover { + qproperty-icon: url("://ic-nav-privacy-hover"); + qproperty-iconSize: 24px 40px; + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-privacy-active"] { + qproperty-icon:url("://ic-nav-privacy-active") ; + qproperty-iconSize: 24px 40px; + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-master"] { + qproperty-icon: url("://ic-nav-master") off, + url("://ic-nav-master-active") on; + qproperty-iconSize: 24px 30px; + background-color:transparent; + font-size:14px; + color: #938da5; +} + +*[cssClass="btn-nav-master"]:checked { + qproperty-icon: url("://ic-nav-master-active"); + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +*[cssClass="btn-nav-master"]:checked:hover { + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + color: #B088FF; +} + +*[cssClass="btn-nav-master"]:hover { + qproperty-icon: url("://ic-nav-master-hover"); + qproperty-iconSize: 24px 30px; + background-color: #1A000000; + color: #938da5; +} + +*[cssClass="btn-nav-master-active"] { + qproperty-icon:url("://ic-nav-master-active"); + qproperty-iconSize: 24px 30px; + background-color: qlineargradient(x1:0, x2: 1, stop: 0 #3c2559, stop: 1 #1f162b); + font-size:14px; + color: #B088FF; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH TOP BAR +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-top"] { + border-image: url("://bg-dashboard-banner") 0 0 0 0 stretch stretch; + background-color:#000000; +} + +*[cssClass="text-title-topbar"] { + color:#a3a3a4; + font-size:16px; + font-weight: ligther; +} + +*[cssClass="amount-topbar"] { + color:#FFFFFF; + font-size:35px; +} + +*[cssClass="amount-small-topbar"] { + color:#FFFFFF; + font-size:22px; +} + +*[cssClass="container-qr"] { + border-radius: 2px; + background-color: #bb241a3c; +} + +QPushButton[cssClass="btn-qr"] { + qproperty-icon: url("://ic-arrow-drop-down-white"); + qproperty-iconSize: 24px 24px; + background-color:transparent; +} + +*[cssClass="sync-status"] { + background-color:#505c4b7d; + color:#FFFFFF; + border-bottom:2px solid #b088ff; + padding-right:10px; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-faq"] { + qproperty-icon: url("://ic-check-faq"); + qproperty-iconSize: 24px 24px; + background-color:#505c4b7d; + color:#FFFFFF; + padding-right:6px; + padding-left:6px; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-faq-inactive"] { + qproperty-icon: url("://ic-check-faq") ; + qproperty-iconSize: 24px 24px; + background-color:#505c4b7d; + color:#FFFFFF; + padding-right:6px; + padding-left:6px; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-faq"]:checked { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-sync"] { + qproperty-icon: url("://ic-check-sync"); + qproperty-iconSize: 24px 24px; + background-color:#505c4b7d; + color:#FFFFFF; + padding-right:6px; + padding-left:6px; + border-bottom:2px solid #505c4b7d; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-sync-inactive"] { + qproperty-icon: url("://ic-check-sync-off") ; + qproperty-iconSize: 24px 24px; + background-color:#505c4b7d; + color:#FFFFFF; + padding-right:6px; + padding-left:6px; + border-bottom:2px solid #505c4b7d; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-sync"]:checked { + background-color:#505c4b7d; + border-bottom:2px solid #505c4b7d; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-mint"] { + qproperty-icon: url("://ic-check-mint") ; + qproperty-iconSize: 24px 24px; + background-color:#405c4b7d; + color:#FFFFFF; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-mint-inactive"] { + qproperty-icon: url("://ic-check-mint-off") ; + qproperty-iconSize: 24px 24px; + background-color:#405c4b7d; + color:#B3FFFFFF; + border-bottom:2px solid #5C4B7D; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-mint"]:checked { + background-color:#505c4b7d; + color:#ffffff; + border-bottom:2px solid #b088ff; +} + + +QPushButton[cssClass="btn-check-stack"] { + qproperty-icon: url("://ic-check-staking"); + qproperty-iconSize: 24px 24px; + color:#ffffff; + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-stack-inactive"] { + qproperty-icon: url("://ic-check-staking-off"); + qproperty-iconSize: 24px 24px; + color:#B3FFFFFF; + background-color:#405c4b7d; + border-bottom:2px solid #5C4B7D; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-stack"]:checked { + background-color:#505c4b7d; + color:#ffffff; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-connect"] { + qproperty-icon: url("://ic-check-connect") ; + qproperty-iconSize: 24px 24px; + color:#ffffff; + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-connect-inactive"] { + qproperty-icon: url("://ic-check-connect-off"); + qproperty-iconSize: 24px 24px; + color:#B3FFFFFF; + background-color:#405c4b7d; + border-bottom:2px solid #5C4B7D; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-connect"]:checked { + background-color:#505c4b7d; + color:#ffffff; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-status-lock"] { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + qproperty-icon: url("://ic-wallet-status-locked") off, + url("://ic-wallet-status-locked") on ; + qproperty-iconSize: 24px 24px; + color:#ffffff; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-status-unlock"] { + background-color:#405c4b7d; + border-bottom:2px solid #5C4B7D; + qproperty-icon: url("://ic-wallet-status-unlocked") off, + url("://ic-wallet-status-unlocked") on ; + qproperty-iconSize: 24px 24px; + color:#B3FFFFFF; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-status-staking"] { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + qproperty-icon: url("://ic-wallet-status-staking") off, + url("://ic-wallet-status-staking") on ; + qproperty-iconSize: 24px 24px; + color:#ffffff; + border-radius:2px; +} + + + +QPushButton[cssClass="btn-check-text"] { + color:#7f7c87; + background-color:#372A4C; + font-size:18px; + border-bottom:2px solid #5C4B7D; +} + +QPushButton[cssClass="btn-check-text"]:checked { + color:#FFFFFF; + background-color:#5c4b7d; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-text-theme"] { + color:#FFFFFF; + background-color:#405c4b7d; + font-size:18px; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-text-theme"]:checked { + color:#FFFFFF; + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-theme"] { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + qproperty-icon: url("://ic-check-theme-dark") off, + url("://ic-check-theme-light") on ; + qproperty-iconSize: 24px 24px; + color:white; + border-radius:2px; +} + + +QPushButton[cssClass="btn-check-theme-dark"] { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + qproperty-icon: url("://ic-check-theme-dark") off, + url("://ic-check-theme-dark") on ; + qproperty-iconSize: 24px 24px; + color:white; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-theme-light"] { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + qproperty-icon: url("://ic-check-theme-light") off, + url("://ic-check-theme-light") on ; + qproperty-iconSize: 24px 24px; + color:white; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-theme"]:checked { + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-peers"] { + qproperty-icon: url("://ic-check-peers") ; + qproperty-iconSize: 24px 24px; + color:#FFFFFF; + background-color:#505c4b7d; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + +QPushButton[cssClass="btn-check-peers"]:checked { + background-color:#505c4b7d; + color:#FFFFFF; + border-bottom:2px solid #b088ff; +} + +QPushButton[cssClass="btn-check-peers-inactive"] { + qproperty-icon: url("://ic-check-peers-off"); + qproperty-iconSize: 24px 24px; + color:#B3FFFFFF; + background-color:#405c4b7d; + border-bottom:2px solid #b088ff; + border-radius:2px; +} + + + +QPushButton[cssClass="btn-check-lock-sub-menu-unlocked"] { + background-image: url("://ic-submenu-unlock"); + background-position:left center; + background-repeat:no-repeat; + background-color: transparent; + text-align: left; + padding-left: 30px; + color:#B3FFFFFF; + border-bottom:0px; + border-radius:0px; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-unlocked"]:checked { + background-color:#50b088ff; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-unlocked"]:hover { + color:#FFFFFF; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-locked"] { + background-image: url("://ic-submenu-lock"); + background-position:left center; + background-repeat:no-repeat; + background-color: transparent; + text-align: left; + padding-left: 30px; + color:#B3FFFFFF; + border-bottom:0px; + border-radius:0px; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-locked"]:checked { + background-color:#50b088ff; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-locked"]:hover { + color:#FFFFFF; +} + + +QPushButton[cssClass="btn-check-lock-sub-menu-staking"] { + background-image: url("://ic-submenu-staking"); + background-position:left center; + background-repeat:no-repeat; + background-color: transparent; + text-align: left; + padding-left: 30px; + color:#B3FFFFFF; + border-bottom:0px; + border-radius:0px; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-staking"]:checked { + background-color:#50b088ff; +} + +QPushButton[cssClass="btn-check-lock-sub-menu-staking"]:hover { + color:#FFFFFF; +} + + +*[cssClass="top-sub-menu"] { + background-color:#4C425F; +} + + +*[cssClass="top-sub-menu-text"] { + color:#B3FFFFFF; +} + +QProgressBar[cssClass="progress-sync"] { + border: 0; + background-color: transparent; +} + +QProgressBar[cssClass="progress-sync"]::chunk:horizontal { + background: qlineargradient(x1: 0, + y1: 0.5, + x2: 1, + y2: 0.5, + stop: 0 #b088ff, + stop: 1 #b088ff, + stop: 2 #b088ff,); +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH LISTS ELEMENTS +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="text-list-title-purple"] { + color:#5c4b7d; + font-size:20px; +} + +*[cssClass="text-list-contact-title1"] { + color:#5c4b7d; + font-size:16px; +} + +*[cssClass="text-list-title1"] { + color:#5c4b7d; + font-size:16px; +} + +*[cssClass="text-list-body1-purple"] { + color:#5c4b7d; + font-size:14px; +} + +*[cssClass="text-list-body1"] { + color:#707070; + font-size:16px; +} + +*[cssClass="text-list-body-unconfirmed"] { + color:#B6B6B6; + font-size:16px; +} + +*[cssClass="text-list-body2"] { + color:#707070; + font-size:15.5px; +} + +*[cssClass="text-list-contact-body1"] { + color:#707070; + font-size:16px; +} + + +*[cssClass="text-list-body1-grey"] { + color:#707070; + font-size:16px; +} + +*[cssClass="text-list-body2-grey"] { + color:#707070; + font-size:14px; +} + +*[cssClass="text-list-caption"] { + color:#bababa; + font-size:12px; +} + +*[cssClass="text-list-caption-medium"] { + color:#bababa; + font-size:14px; +} + +*[cssClass="text-list-caption-unconfirmed"] { + color:#B6B6B6; +} + +*[cssClass="text-list-caption-grey"] { + color:#707070; + font-size:12px; +} + + +*[cssClass="text-list-amount-receive"] { + color:#008d36; + font-size:16px; +} + + +*[cssClass="text-list-amount-send"] { + color:#f84444; + font-size:16px; +} + +*[cssClass="text-list-amount-unconfirmed"] { + color:#B6B6B6; + font-size:16px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH TEXT +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="text-title-screen"] { + color:#5c4b7d; + font-size:22px; +} + +*[cssClass="text-title-dialog"] { + color:#5c4b7d; + font-size:22px; +} + +*[cssClass="text-title"] { + color:#5c4b7d; + font-size:16px; +} + +*[cssClass="text-title-white"] { + color:#FFFFFF; + font-size:16px; +} + +*[cssClass="text-content-white"] { + color:#FFFFFF; + font-size:16px; +} + +*[cssClass="btn-title-grey"] { + color:#707070; + font-size:22px; +} + +*[cssClass="btn-title-purple"] { + color:#5c4b7d; + font-size:22px; +} + +*[cssClass="btn-subtitle-grey"] { + color:#707070; + font-size:17px; +} + +*[cssClass="text-subtitle"] { + color:#bababa; + font-size:14px; +} + +*[cssClass="text-body2-grey"] { + color:#707070; + font-size:14px; +} + + +*[cssClass="text-body1"] { + color:#707070; + font-size:17px; +} + +*[cssClass="text-body2"] { + color:#707070; + font-size:14px; +} + +*[cssClass="text-main-light"] { + color:#bababa; + font-size:17px; +} + +*[cssClass="text-main-grey"] { + color:#707070; + font-size:17px; +} + +*[cssClass="text-main-settings"] { + color:#707070; + font-size:18px; +} + +*[cssClass="text-main-purple"] { + color:#5c4b7d; + font-size:17px; +} + +*[cssClass="text-title-purple"] { + color:#5c4b7d; + font-size:22px; +} + +*[cssClass="text-main-grey-big"] { + color:#707070; + font-size:24px; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH BUTTONS +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +#groupBox { + background-color:transparent; + border-radius:0; +} + +*[cssClass="group-box"] { + background-color:transparent; + border-radius:0; +} + + +QGroupBox::title { + color:#5c4b7d; + font-size:16px; + padding-bottom:9px; +} + + +QPushButton[cssClass="btn-menu"] { + qproperty-icon: url("://ic-menu-hover") off, + url("://ic-menu-hover") on ; + qproperty-iconSize: 24px 24px; +} + +QPushButton[cssClass="btn-dropdown"] { + qproperty-icon: url("://ic-arrow-drop-down") off, + url("://ic-arrow-drop-down") on ; + qproperty-iconSize: 24px 24px; +} + +QPushButton[cssClass="btn-dropdown"]:checked { + qproperty-icon: url("://ic-arrow-drop-up") off, + url("://ic-arrow-drop-up") on ; + qproperty-iconSize: 24px 24px; +} + +QPushButton[cssClass="btn-switch"] { + background-image: url("://ic-switch-off"); + background-position:right center; + background-repeat:no-repeat; + background-color:#FFFFFF; + font-size:18px; + text-align:left; + color: #bababa; +} + +QPushButton[cssClass="btn-switch"]:checked { + background-image: url("://ic-switch-on"); + background-position:right center; + background-repeat:no-repeat; + background-color:#FFFFFF; + text-align:left; + font-size:18px; + color: #5c4b7d; +} + +QPushButton[cssClass="btn-check"] { + border: 1px solid #335c4b7d; + background-color:#FFFFFF; + padding:4px; + font-size:18px; + color: #707070; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-check"]:hover { + border: 1px solid #5c4b7d; + background-color:#FFFFFF; + font-size:18px; + padding:4px; + color: #5c4b7d; + border-radius: 2px; +} + +QPushButton[cssClass="btn-check"]:pressed { + border: 1px solid #5c4b7d; + background-color:#1A5c4b7d; + font-size:18px; + padding:4px; + color: #5c4b7d; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-check-right"] { + border: 1px solid #335c4b7d; + background-color:#FFFFFF; + font-size:18px; + color: #707070; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + + +QPushButton[cssClass="btn-check-right"]:hover { + border: 1px solid #5c4b7d; + background-color:#FFFFFF; + font-size:18px; + color: #707070; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + +QPushButton[cssClass="btn-check-right"]:pressed { + border: 1px solid #5c4b7d; + background-color:#1A5c4b7d; + font-size:18px; + color: #707070; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + + +QPushButton[cssClass="btn-check-right"]:checked { + border: 1px solid #5c4b7d; + background-color:#5c4b7d; + font-size:18px; + color: #FFFFFF; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + +QPushButton[cssClass="btn-check-right"]:checked:hover { + border: 1px solid #5c4b7d; + background-color:#33284d; + font-size:18px; + padding:4px; + color: #FFFFFF; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + +QPushButton[cssClass="btn-check-right"]:checked:pressed { + border: 1px solid #20192e; + background-color:#20192e; + font-size:18px; + padding:4px; + color: #b088ff; + border-top-right-radius:2px; + border-bottom-right-radius:2px; +} + + +QPushButton[cssClass="btn-check-left"] { + border: 1px solid #335c4b7d; + background-color:#FFFFFF; + font-size:18px; + color: #707070; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + + +QPushButton[cssClass="btn-check-left"]:hover { + border: 1px solid #5c4b7d; + background-color:#FFFFFF; + font-size:18px; + color: #707070; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + +QPushButton[cssClass="btn-check-left"]:pressed { + border: 1px solid #5c4b7d; + background-color:#1A5c4b7d; + font-size:18px; + color: #707070; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + + +QPushButton[cssClass="btn-check-left"]:checked { + border: 1px solid #5c4b7d; + background-color:#5c4b7d; + font-size:18px; + color: #FFFFFF; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + +QPushButton[cssClass="btn-check-left"]:checked:hover { + border: 1px solid #5c4b7d; + background-color:#33284d; + font-size:18px; + padding:4px; + color: #FFFFFF; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + +QPushButton[cssClass="btn-check-left"]:checked:pressed { + border: 1px solid #20192e; + background-color:#20192e; + font-size:18px; + padding:4px; + color: #b088ff; + border-top-left-radius:2px; + border-bottom-left-radius:2px; +} + + +QPushButton[cssClass="btn-check"]:checked { + border: 1px solid #335c4b7d; + background-color:#5c4b7d; + padding:4px; + font-size:18px; + color: #FFFFFF; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-check"]:checked:hover { + border: 1px solid #5c4b7d; + background-color:#44375f; + font-size:18px; + padding:4px; + color: #FFFFFF; + border-radius: 2px; +} + +QPushButton[cssClass="btn-check"]:checked:pressed { + border: 1px solid #44375f; + background-color:#44375f; + font-size:18px; + padding:4px 10px; + color: #b088ff; + border-radius: 2px; +} + +QPushButton[cssClass="btn-check"]:unchecked { + border: 1px solid #335c4b7d; + background-color:#ffffff; + padding:4px; + font-size:18px; + color: #707070; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-primary"] { + border: 1px solid #5c4b7d; + background-color:#5c4b7d; + font-size:18px; + padding:4px 10px; + color: #FFFFFF; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-primary"]:hover { + border: 1px solid #5c4b7d; + background-color:#44375f; + font-size:18px; + padding:4px 10px; + color: #FFFFFF; + border-radius: 2px; +} + +QPushButton[cssClass="btn-primary"]:pressed { + border: 1px solid #44375f; + background-color:#44375f; + font-size:18px; + padding:4px 10px; + color: #b088ff; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-secundary"] { + border: 1px solid #335c4b7d; + background-color:#FFFFFF; + font-size:18px; + padding:4px 10px; + color: #5c4b7d; + border-radius: 2px; +} + +QPushButton[cssClass="btn-secundary"]:hover { + border: 1px solid #5c4b7d; + background-color:#FFFFFF; + font-size:18px; + padding:4px 10px; + color: #5c4b7d; + border-radius: 2px; +} + +QPushButton[cssClass="btn-secundary"]:pressed { + border: 1px solid #5c4b7d; + background-color:#1A5c4b7d; + font-size:18px; + padding:4px 10px; + color: #5c4b7d; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-edit-primary"] { + border: 1px solid #bababa; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #707070; + text-align:left; +} + +QPushButton[cssClass="btn-edit-primary-folder"] { + border: 1px solid #bababa; + background-image: url("://ic-folder"); + background-position:right center; + background-repeat:no-repeat; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #707070; + text-align:left; +} + +*[cssClass="edit-primary-book"] { + border: 1px solid #bababa; + background-image: url("://ic-address_book_grey"); + background-position:right center; + background-repeat:no-repeat; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + padding-right: 34px; + color: #707070; + text-align:left; +} + +QLineEdit { + selection-background-color: #5c4b7d; + selection-color: white; +} + +QLineEdit[cssClass="edit-primary-book"]:focus { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-book"]:focus:hover { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-book"]:hover { + border: 1px solid #707070; +} + +*[cssClass="edit-primary-book-error"] { + border: 1px solid #f84444; + background-image: url("://ic-address_book_grey"); + background-position:right center; + background-repeat:no-repeat; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + padding-right: 34px; + color: #707070; + text-align:left; +} + +*[cssClass="edit-primary-multi-book"] { + border: 1px solid #bababa; + background-image: url("://ic-address-send"); + background-position:right center; + background-repeat:no-repeat; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + padding-right: 12px; + padding-left: 12px; + color: #707070; + text-align:left; +} + +QLineEdit[cssClass="edit-primary-multi-book"]:focus { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-multi-book"]:focus:hover { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-multi-book"]:hover { + border: 1px solid #707070; +} + +*[cssClass="edit-primary-multi-book-error"] { + border: 1px solid #f84444; + background-image: url("://ic-address-send"); + background-position:right center; + background-repeat:no-repeat; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + padding-right: 12px; + padding-left: 12px; + color: #707070; + text-align:left; +} + +*[cssClass="edit-primary-book-send"] { + border: 1px solid #bababa; + background-image: url("://ic-address-send"); + background-position:right center; + background-repeat:no-repeat; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + padding-right: 12px; + padding-left: 12px; + color: #707070; + text-align:left; +} + +QLineEdit[cssClass="edit-primary-book-send"]:focus { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-book-send"]:focus:hover { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-book-send"]:hover { + border: 1px solid #707070; +} + +*[cssClass="edit-primary-book-send-error"] { + border: 1px solid #f84444; + background-image: url("://ic-address-send"); + background-position:right center; + background-repeat:no-repeat; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + padding-right: 60px; + color: #707070; + text-align:left; +} + + +QPushButton[cssClass="btn-secundary-clear"] { + qproperty-icon: url("://ic-clear-purple") off, + url("://ic-clear-purple") on ; + qproperty-iconSize: 24px 24px; + border: 1px solid #335c4b7d; + background-color:#FFFFFF; + font-size:18px; + padding-top:4px; + padding-left:6px; + padding-bottom:4px; + padding-right:6px; + color: #5c4b7d; + border-radius: 2px; +} + +QPushButton[cssClass="btn-secundary-clear"]:hover { + border: 1px solid #5c4b7d; + background-color:#FFFFFF; +} + +QPushButton[cssClass="btn-secundary-clear"]:pressed { + border: 1px solid #5c4b7d; + background-color:#1A5c4b7d; +} + +QPushButton[cssClass="btn-secundary-new-address"] { + qproperty-icon: url("://ic-update") off, + url("://ic-update") on ; + qproperty-iconSize: 30px 30px; + border: 1px solid #335c4b7d; + background-color:#FFFFFF; + font-size:18px; + padding-top:4px; + padding-left:6px; + padding-bottom:4px; + padding-right:6px; + color: #5c4b7d; + border-radius: 2px; +} + +QPushButton[cssClass="btn-secundary-new-address"]:hover { + border: 1px solid #5c4b7d; + background-color:#FFFFFF; +} + +QPushButton[cssClass="btn-secundary-new-address"]:pressed { + border: 1px solid #5c4b7d; + background-color:#1A5c4b7d; +} + +QPushButton[cssClass="btn-secundary-label"] { + qproperty-icon: url("://ic-label") off, + url("://ic-label") on ; + qproperty-iconSize: 30px 30px; + border: 1px solid #335c4b7d; + background-color:#FFFFFF; + font-size:18px; + padding-top:4px; + padding-left:6px; + padding-bottom:4px; + padding-right:10px; + color: #5c4b7d; + border-radius: 2px; +} + +QPushButton[cssClass="btn-secundary-label"]:hover { + border: 1px solid #5c4b7d; + background-color:#FFFFFF; +} + +QPushButton[cssClass="btn-secundary-label"]:pressed { + border: 1px solid #5c4b7d; + background-color:#1A5c4b7d; +} + +QPushButton[cssClass="btn-secundary-copy"] { + qproperty-icon: url("://ic-copy") off, + url("://ic-copy") on ; + qproperty-iconSize: 30px 30px; + border: 1px solid #335c4b7d; + background-color:#FFFFFF; + font-size:18px; + padding-top:4px; + padding-left:6px; + padding-bottom:4px; + padding-right:6px; + color: #5c4b7d; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-secundary-copy"]:hover { + border: 1px solid #5c4b7d; + background-color:#FFFFFF; +} + +QPushButton[cssClass="btn-secundary-copy"]:pressed { + border: 1px solid #5c4b7d; + background-color:#1A5c4b7d; +} + + +QPushButton[cssClass="btn-secundary-add"] { + background-image: url("://ic-add-purple"); + background-position:right center; + background-repeat:no-repeat; + border: 1px solid #335c4b7d; + background-color:#FFFFFF; + font-size:18px; + padding-top:4px; + padding-left:6px; + padding-bottom:4px; + padding-right:30px; + color: #5c4b7d; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-secundary-add"]:hover { + border: 1px solid #5c4b7d; + background-color:#FFFFFF; +} + +QPushButton[cssClass="btn-secundary-add"]:pressed { + border: 1px solid #5c4b7d; + background-color:#1A5c4b7d; +} + + +QPushButton[cssClass="btn-text-primary"] { + border: 0; + background-color:#FFFFFF; + font-size:18px; + padding-top:4px; + padding-left:4px; + padding-bottom:4px; + padding-right:4px; + color: #5c4b7d; +} + + +QPushButton[cssClass="btn-text-primary"]:hover { + color: #44375f; +} + +QPushButton[cssClass="btn-text-primary"]:pressed { + color: #575756; +} + + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH LINE EDIT +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="edit-primary"] { + border: 1px solid #bababa; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #707070; +} + +*[cssClass="edit-primary"]:focus { + border: 1px solid #b088ff; +} + +*[cssClass="edit-primary"]:focus:hover { + border: 1px solid #b088ff; +} + +*[cssClass="edit-primary"]:hover { + border: 1px solid #707070; +} + +*[cssClass="edit-primary-disabled"] { + border: 1px solid #33ffffff; + background-color:#0f0b16; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #FFFFFF; +} + +*[cssClass="edit-primary-error"] { + border: 1px solid #f84444; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #707070; +} + +QPushButton[cssClass="btn-expand"] { + background-image: url("://ic-expand"); + background-position:center; + background-repeat:no-repeat; + background-color:#FFFFFF; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SPLASH +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-splash"] { + background-color:transparent; + border-image: url("://bg-splash-png") 0 0 0 0 stretch stretch; + border-radius: 4px; +} + +*[cssClass="img-splash-logo"] { + qproperty-icon: url("://img-logo-pivx"); + qproperty-iconSize: 300px 100px; + border:0; + background-color:transparent; +} + +*[cssClass="bg-progress"] { + border-top:2px solid #b088ff ; + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-right-radius: 4px; + border-bottom-left-radius: 4px; + background-color:transparent; +} + +QProgressBar[cssClass="progress-splash"]::chunk:horizontal { + background: qlineargradient(x1: 0, + y1: 0.5, + x2: 1, + y2: 0.5, + stop: 0 #80211a2f, + stop: 1 #80b088ff, + stop: 2 #80211a2f,); + margin-right: 2px; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH DASHBOARD +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + + +*[cssClass="text-warning"] { + color:#f84444; + font-size:16px; +} + +*[cssClass="ic-warning"] { + qproperty-icon: url("://ic-transaction-warning") off, + url("://ic-transaction-warning") on ; + qproperty-iconSize: 24px 24px; +} + + +*[cssClass="text-amount-grey"] { + color:#707070; + font-size:20px; +} + +*[cssClass="text-stake-piv"] { + color:#5c4b7d; + font-size:16px; + padding:10px; + border-bottom: 5px solid #5c4b7d; +} + +*[cssClass="text-stake-piv-disable"] { + color:#d7d5da; + font-size:16px; + padding:10px; + border-bottom: 5px solid #bbb8c0; +} + +*[cssClass="text-stake-zpiv"] { + color:#b088ff; + font-size:16px; + padding:10px; + border-bottom: 5px solid #b088ff; +} + +*[cssClass="text-stake-zpiv-disable"] { + color:#d7d5da; + font-size:16px; + padding:10px; + border-bottom: 5px solid #d7d5da; +} + +*[cssClass="legend-chart"] { + color:#707070; + font-size:16px; +} + +*[cssClass="text-chart-zpiv"] { + color:#b088ff; + font-size:16px; + padding-left:4px; +} + +*[cssClass="text-chart-piv"] { + color:#5c4b7d; + font-size:16px; + padding-left:4px; +} + +*[cssClass="square-chart-zpiv"] { + background-color:#b088ff; + border:none; +} + +*[cssClass="square-chart-piv"] { + background-color:#5c4b7d; + border:none; +} + +*[cssClass="text-amount-grey-big"] { + color:#707070; + font-size:26px; +} + + +*[cssClass="container-chart"] { + background-color:#e8e7ee; +} + +QPushButton[cssClass="btn-chart-arrow"] { + qproperty-icon: url("://ic-arrow-left") ; + qproperty-iconSize: 12px 12px; + background-color: transparent; + border:0px; + border-radius:2px; +} + +QPushButton[cssClass="btn-chart-arrow"]:hover { + background-color: #B35c4b7d; +} + +QPushButton[cssClass="btn-chart-arrow"]:pressed { + background-color:#20192e; +} + +QComboBox[cssClass="btn-combo-secundary"] { + background-color:#ffffff; + padding:6px 12px 6px 6px; + font-size:16px; + border:1px solid #5c4b7d; + color: #5c4b7d; + text-align: right; + border-radius: 2px; +} + +QComboBox[cssClass="btn-combo-secundary"]::down-arrow { + image: url("://ic-arrow-drop-down-purple"); + width: 24px; + height: 24px; +} + + +QComboBox[cssClass="btn-combo-chart"] { + background-color:#ffffff; + padding:6px 12px 6px 6px; + font-size:16px; + border:1px solid #ffffff; + color: #bababa; + text-align: right; + border-radius: 2px; +} + +QComboBox[cssClass="btn-combo-chart"]::down-arrow { + image: url("://ic-arrow-drop-down"); + width: 24px; + height: 24px; +} + + +QComboBox[cssClass="btn-combo-chart-selected"] { + background-color:#5c4b7d; + padding:6px 12px 6px 6px; + font-size:16px; + border:1px solid #5c4b7d; + color: #FFFFFF; + text-align: right; + border-radius: 2px; +} + +QComboBox[cssClass="btn-combo-chart-selected"]::down-arrow { + image: url("://ic-arrow-drop-down-white"); + width: 24px; + padding-right: 10px; + height: 24px; +} + +QComboBox[cssClass="btn-combo-chart-selected"]:on { + padding-top: 10px; + padding-left: 10px; + background-color: #5c4b7d; +} + +QComboBox::drop-down { + border-width: 0px; +} + +QComboBox::down-arrow { + image: url(noimg); border-width: 0px; +} + +QPushButton[cssClass="btn-check-time"] { + background-color:#FFFFFF; + font-size:14px; + color: #707070; + padding:4px; + border-radius: 2px; +} + +QPushButton[cssClass="btn-check-time"]:checked { + background-color:#5c4b7d; + border-radius:2px; + font-size:14px; + padding:4px; + color: #FFFFFF; +} + +QPushButton[cssClass="btn-check-time"]:hover { + background-color:#44375f; + border-radius:2px; + font-size:14px; + padding:4px; + color: #FFFFFF; +} + +QPushButton[cssClass="btn-check-time"]:pressed { + background-color:#20192e; + border-radius:2px; + font-size:14px; + padding:4px; + color: #b088ff; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH CHECKBOX +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +QCheckBox { + spacing: 5px; + font-size:18px; + color:#707070; +} + +QCheckBox:checked { + spacing: 5px; + font-size:18px; + color:#5c4b7d; +} + +QCheckBox::indicator { + width: 24px; + height: 24px; +} + +QCheckBox::indicator:unchecked { + image: url("://ic-check-box"); +} + +QCheckBox::indicator:checked { + image: url("://ic-check-active"); +} + + +QCheckBox[cssClass="btn-watch-password"] { + spacing: 5px; + font-size:18px; + color:transparent; +} + + +QCheckBox[cssClass="btn-watch-password"]::indicator:unchecked { + image: url("://ic-watch-password"); +} + +QCheckBox[cssClass="btn-watch-password"]::indicator:checked { + image: url("://ic-watch-password"); +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH REQUEST DIALOG +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +QComboBox[cssClass="btn-combo-coins"] { + background-color:#5c4b7d; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #5c4b7d; + color: #FFFFFF; +} + +QComboBox[cssClass="btn-combo-coins"]::down-arrow { + image: url("://ic-arrow-drop-white-down"); + padding-right: 10px; + height: 16px; + width: 16px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH RECEIVE +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="label-address-box"] { + color:#707070; + background-color: #f2f2f2; + font-size:22px; + padding:10px 10px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SPIN BOX +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +QSpinBox[cssClass="btn-spin-box"] { + background-color:#FFFFFF; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #bababa; + color: #5c4b7d; + selection-background-color: #5c4b7d; + selection-color: #FFFFFF; +} + + +QSpinBox[cssClass="btn-spin-box"]::up-button { + image: url("://ic-arrow-drop-up-purple"); + subcontrol-position: top right; width: 20px; height: 20px; + border: 0px; + padding:0px; + margin:0px 5px 0px 0px; +} + +QSpinBox[cssClass="btn-spin-box"]::down-button { + image: url("://ic-arrow-drop-down-purple"); + subcontrol-position: bottom right; width: 20px; height: 20px; + border: 0px; + padding:0px; + margin:0px 5px 0px 0px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH COMBO BOX +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + + +QComboBox[cssClass="btn-combo"] { + background-color:#ffffff; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #ffffff; + color: #707070; + text-align: right; +} + +QComboBox[cssClass="btn-combo"]::down-arrow { + image: url("://ic-arrow-drop-down"); + width: 24px; + height: 24px; +} + +QComboBox[cssClass="btn-combo-edit"] { + background-color:#ffffff; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #ffffff; + color: #5c4b7d; + text-align: right; +} + +QComboBox[cssClass="btn-combo-edit"]::down-arrow { + image: url("://ic-arrow-drop-down-purple"); + width: 24px; + height: 24px; +} + + +QComboBox[cssClass="btn-combo-options"] { + background-color:#ffffff; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #ffffff; + color: #5c4b7d; + text-align: right; +} + +QComboBox[cssClass="btn-combo-options"]::down-arrow { + image: url("://ic-arrow-drop-down"); + width: 24px; + height: 24px; +} + + +QComboBox { + background-color:transparent; + padding-right:20px; + font-size:16px; + color: #707070; + border-radius:0px; + border: 0px; +} + +QComboBox QFrame { border: 0px solid #bababa; border-radius:0px;} + +QComboBox:on { /* shift the text when the popup opens */ + padding-top: 10px; + padding-left: 10px; + background-color: transparent; +} + +QComboBox::drop-down { + subcontrol-origin: padding; + subcontrol-position: center right; + width: 15px; + right:3px; + border-top-right-radius: 0px; /* same radius as the QComboBox */ + border-bottom-right-radius: 0px; + border-radius:0px; + background:none; +} + +QComboBox::down-arrow { + image: url("://ic-arrow-drop-down"); + width: 24px; + height: 24px; +} + +QComboBox::down-arrow:on { /* shift the arrow when popup is open */ + top: 1px; + left: 1px; +} + +QComboBox:item { + color: #707070; + font-size:18px; + outline: 0px; +} + +QComboBox QAbstractItemView { + margin:0px; + min-width: 150px; + border-radius:0px; + font-size:16px; + outline: 0px; +} + +QComboBox::selected:item { border: none; outline: 0px; } + +QComboBox QAbstractItemView::item { + margin:0px; + background-color: #FFFFFF; + padding:10px 20px; + font-size:16px; + color: #707070; + border-radius:0px; + border:0px; + outline: 0px; +} +QComboBox QAbstractItemView::item:selected { + background-color: #d8d5e0; + padding:10px 20px; + font-size:16px; + margin:0px; + color: #5c4b7d; + border-radius:0px; + border:none; + outline: 0px; +} + +QComboBox QAbstractItemView QPushButton{ + border:0px; + outline: 0px; +} + +QComboBox QAbstractItemView::item:selected QPushButton:hover{ + border:0px; + outline: 0px; +} +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH RADIO BUTTON +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ +QRadioButton:checked { + color: #5c4b7d; + font-size:20px; +} + +QRadioButton:unchecked { + color: #bababa; + font-size:20px; +} + +QRadioButton { + color: #bababa; + font-size:20px; + spacing:10px; +} + +QRadioButton::indicator { + width: 26px; + height: 26px; +} + +QRadioButton::indicator:checked { + background: url("://btn-radio-active"); + background-repeat:no-repeat; + background-position:center; +} + +QRadioButton::indicator:unchecked { + background: url("://btn-radio-off"); + background-repeat:no-repeat; + background-position:center; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SCROLL BAR +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +QScrollBar:vertical { + border: 0px solid #bababa; + background:white; + width:4px; + margin: 0px 0px 0px 0px; +} + + +QScrollBar::handle:vertical { + background: #bababa; + min-height: 0px; +} + +QScrollBar::add-line:vertical { + background: #bababa; + height: 0px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} +QScrollBar::sub-line:vertical { + background: #bababa; + height: 0 px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + height: 0px; +} + + +QScrollBar::right-arrow:horizontal, QScrollBar::left-arrow:horizontal +{ + border: none; + background: none; + color: none; +} + +QScrollBar::top-arrow:horizontal, QScrollBar::bottom-arrow:horizontal +{ + border: none; + background: none; + color: none; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH DIALOG MASTER NODE +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="line-purple"] { + background-color:#5c4b7d; +} + +QPushButton[cssClass="btn-number-check"] { + border: 1px solid #5c4b7d; + background-color:#FFFFFF; + font-size:14px; + border-radius:11px; + color: #5c4b7d; +} + +QPushButton[cssClass="btn-number-check"]:checked { + border: 1px solid #5c4b7d; + background-color:#5c4b7d; + font-size:14px; + border-radius:11px; + color: #FFFFFF; +} + +QPushButton[cssClass="btn-name-check"] { + background-color: #FFFFFF; + border:none; + font-size:20px; + color: rgba(92, 75, 125, 0.5); +} + +QPushButton[cssClass="btn-name-check"]:checked { + background-color:#FFFFFF; + border:none; + font-size:20px; + color: #5c4b7d; +} + +QPushButton[cssClass="ic-step-confirm"] { + background-image: url("://ic-check-white"); + background-position:center; + background-repeat:no-repeat; + border-radius:11px; + border: 1px solid #bababa; + background-color:#bababa; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SEND +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-coin-type"] { + background-color:#FFFFFF; + border: 1px solid #bababa; + border-radius: 2px; +} + + +*[cssClass="coin-icon-piv"] { + qproperty-icon: url("://ic-coin-piv") off, + url("://ic-coin-piv") on ; + qproperty-iconSize: 24px 24px; + background-color: #FFFFFF; + border: 2px solid #FFFFFF; + border-radius: 12px; +} + +*[cssClass="coin-icon-zpiv"] { + qproperty-icon: url("://ic-coin-zpiv") off, + url("://ic-coin-zpiv") on ; + qproperty-iconSize: 24px 24px; + background-position:center; + background-repeat:no-repeat; + background-color: #FFFFFF; + border: 2px solid #FFFFFF; + border-radius: 12px; +} + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH Dialog +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-dialog"] { + background-color:#FFFFFF; + border-radius: 2px; +} + +*[cssClass="text-title2-dialog"] { + color:#5c4b7d; + font-size:16px; +} + +*[cssClass="text-title1-dialog"] { + color:#707070; + font-size:22px; +} + + +*[cssClass="text-body1-dialog"] { + color:#707070; + font-size:18px; +} + +*[cssClass="text-body2-dialog"] { + color:#707070; + font-size:15px; +} + +*[cssClass="text-body3-dialog"] { + color:#707070; + font-size:17px; +} + +QDialogButtonBox QPushButton { + border: 1px solid #5c4b7d; + background-color:#5c4b7d; + font-size:18px; + padding:4px 10px; + color: #FFFFFF; + +} + +QPushButton[cssClass="btn-dialog-cancel"] { + border: 0; + background-color:transparent; + font-size:18px; + padding:4px 10px; + color: #bababa; + border-radius: 2px; +} + + +QLineEdit[cssClass="edit-primary-dialog"] { + border: 1px solid #bababa; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #707070; +} + +QLineEdit[cssClass="edit-primary-dialog"]:focus { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-dialog"]:focus:hover { + border: 1px solid #b088ff; +} + +QLineEdit[cssClass="edit-primary-dialog"]:hover { + border: 1px solid #707070; +} + +QLineEdit[cssClass="edit-primary-dialog-error"] { + border: 1px solid #f84444; + background-color:#ffffff; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #707070; +} + + +QComboBox[cssClass="btn-combo-edit-dialog"] { + background-color:#ffffff; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #bababa; + color: #5c4b7d; + text-align: right; +} + +QComboBox[cssClass="btn-combo-edit-dialog"]::down-arrow { + image: url("://ic-arrow-drop-down"); + width: 24px; + height: 24px; + padding-right: 12px; +} + +QComboBox[cssClass="btn-combo-dialog"] { + background-color:#ffffff; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #ffffff; + color: #5c4b7d; + text-align: right; +} + +QComboBox[cssClass="btn-combo-dialog"]::down-arrow { + image: url("://ic-arrow-drop-down"); + width: 24px; + height: 24px; + padding-top: 1px; +} + +QLabel[cssClass="label-subtitle-dialog"] { + background-color:#ffffff; + font-size:16px; + color: #5c4b7d; + padding-top: 10px; + padding-bottom: 10px; +} + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SETTINGS +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +QPushButton[cssClass="btn-settings-check"] { + background-image: url("://ic-arrow-drop-down"); + background-position:right center; + background-repeat:no-repeat; + background-color: #FFFFFF; + border:none; + border-bottom:1px solid #bababa; + font-size:20px; + color: #707070; + text-align:left; +} + +QPushButton[cssClass="btn-settings-check"]:checked { + background-image: url("://ic-arrow-drop-up"); + background-position:right center; + background-repeat:no-repeat; + background-color:#FFFFFF; + border:none; + border-bottom:1px solid #FFFFFF; + font-size:20px; + color: #707070; + text-align:left; +} + +QPushButton[cssClass="btn-settings-options"] { + background-color: rgba(92, 75, 125, 0.1); + border:none; + font-size:20px; + color: #707070; + padding:0 20px; + text-align:left; +} + +QPushButton[cssClass="btn-settings-options"]:checked { + background-color:#877B9F; + border:none; + font-size:20px; + color: #FFFFFF; + padding:0 20px; + text-align:left; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH Icons +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + + +*[cssClass="ic-close-white"] { + qproperty-icon: url("://ic-close-white") off, + url("://ic-close-white") on ; + qproperty-iconSize: 24px 24px; + +} + +*[cssClass="ic-arrow"] { + qproperty-icon: url("://ic-arrow-right") off, + url("://ic-arrow-right") on ; + qproperty-iconSize: 24px 24px; +} + +QPushButton[cssClass="ic-arrow"]:checked{ + qproperty-icon: url("://ic-arrow-drop-down") off, + url("://ic-arrow-drop-down") on ; + qproperty-iconSize: 24px 24px; +} + +*[cssClass="ic-arrow-down"] { + qproperty-icon: url("://ic-arrow-drop-down") off, + url("://ic-arrow-drop-down") on ; + qproperty-iconSize: 24px 24px; + background-color: transparent; + border:none; +} + +*[cssClass="ic-copy"] { + qproperty-icon: url("://ic-copy") off, + url("://ic-copy") on ; + qproperty-iconSize: 24px 24px; + background-color: transparent; + border:none; +} + +*[cssClass="ic-copy-big"] { + qproperty-icon: url("://ic-copy-big") off, + url("://ic-copy-big") on ; + qproperty-iconSize: 24px 24px; + background-color: transparent; + border:none; +} + +*[cssClass="ic-close"] { + qproperty-icon: url("://ic-close") off, + url("://ic-close") on ; + qproperty-iconSize: 24px 24px; + background-color: transparent; + border:none; +} + +*[cssClass="layout-arrow"] { + background: url("://ic-arrow-right"); + background-repeat:no-repeat; + background-position:right center; +} + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH FAQ +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="text-title-faq"] { + color:#b088ff; + font-size:26px; +} + + +*[cssClass="container-faq-buttons"] { + background:transparent; + border:1px solid #b088ff; + border-radius: 5px; +} + +*[cssClass="text-subtitle-faq"] { + color:#FFFFFF; + font-size:22px; +} + +*[cssClass="text-content-faq"] { + color:#FFFFFF; + font-size:18px; +} + +*[cssClass="container-number-faq"] { + color:#FFFFFF; + background-color: #5c4b7d; + font-size:14px; + border-radius: 2px; +} + + + +QPushButton[cssClass="btn-faq-exit"] { + background: url("://ic-exit"); + background-repeat:no-repeat; + background-position:right center; + background-color:transparent; + border:none; + padding:0 30px 0 0; + font-size:18px; + color: #CCFFFFFF; + text-align:left; +} + +QPushButton[cssClass="btn-faq-web"] { + background-color:transparent; + border:none; + font-size:16px; + color: #b088ff; + text-align:left; +} + + + +QPushButton[cssClass="btn-faq-options"] { + background-color:transparent; + border:none; + font-size:18px; + color: #FFFFFF; + padding:0 20px; + text-align:left; +} + +QPushButton[cssClass="btn-faq-options"]:checked { + background-color: rgba(176 ,136 ,255, 0.2); + border:none; + font-size:18px; + color: #FFFFFF; + padding:0 20px; + text-align:left; +} + + +#scrollAreaFaq QScrollBar:vertical { + border: 0px solid #bababa; + background:#0f0b16; + width:4px; + margin: 0px 0px 0px 0px; +} + + +#scrollAreaFaq QScrollBar::handle:vertical { + background: #5c4b7d; + min-height: 0px; +} + +#scrollAreaFaq QScrollBar::add-line:vertical { + background: #0f0b16; + height: 0px; + subcontrol-position: bottom; + subcontrol-origin: margin; +} + +#scrollAreaFaq QScrollBar::sub-line:vertical { + background: #0f0b16; + height: 0 px; + subcontrol-position: top; + subcontrol-origin: margin; +} + +#scrollAreaFaq QScrollBar::add-page:vertical, #scrollAreaFaq QScrollBar::sub-page:vertical { + height: 0px; +} + + +#scrollAreaFaq QScrollBar::right-arrow:horizontal, #scrollAreaFaq QScrollBar::left-arrow:horizontal +{ + border: none; + background: none; + color: none; +} + +#scrollAreaFa QScrollBar::top-arrow:horizontal, #scrollAreaFa QScrollBar::bottom-arrow:horizontal +{ + border: none; + background: none; + color: none; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH WELCOME +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +QPushButton[cssClass="btn-close-white"] { + background: url("://ic-close-white"); + background-repeat:no-repeat; + background-position:center; + background-color:transparent; +} + +QPushButton[cssClass="ic-step-confirm-welcome"] { + background-image: url("://ic-check-white"); + background-position:center; + background-repeat:no-repeat; + border: 1px solid #6C529D; + border-radius:11px; + background-color:#6C529D; +} + +*[cssClass="text-title-welcome"] { + color:#FFFFFF; + font-size:26px; +} + +*[cssClass="text-main-white"] { + color:#FFFFFF; + font-size:20px; +} + + +*[cssClass="container-welcome"] { + border-image: url("://bg-welcome") 0 0 0 0 stretch stretch; + background-color:#000000; +} + +*[cssClass="container-welcome-box"] { + background-color:transparent; + border: 1px solid transparent; +} + + +*[cssClass="line-welcome"] { + background-color: #807b8a; +} + +*[cssClass="container-welcome-stack"] { + background-image: url("://bg-welcome-container-png"); + background-position:center; + background-repeat:no-repeat; + background-color: transparent; + border: 1px solid #b088ff; + border-radius: 4px; +} + +*[cssClass="container-welcome-step1"] { + background-image: url("://img-welcome-step1"); + background-position:left bottom; + background-repeat:no-repeat; + background-color: transparent; +} + +*[cssClass="container-welcome-step2"] { + background-image: url("://img-welcome-step2"); + background-position:left bottom; + background-repeat:no-repeat; + background-color: transparent; +} + +*[cssClass="container-welcome-step3"] { + background-image: url("://img-welcome-step3"); + background-position:left bottom; + background-repeat:no-repeat; + background-color: transparent; +} + +*[cssClass="container-welcome-step4"] { + background-image: url("://img-welcome-step4"); + background-position:left bottom; + background-repeat:no-repeat; + background-color: transparent; +} + +QComboBox[cssClass="btn-combo-welcome"] { + background-color:#171022; + padding:10px 20px 10px 10px; + font-size:16px; + border:1px solid #b088ff; + color: #FFFFFF; +} + +QComboBox[cssClass="btn-combo-welcome"]::down-arrow { + image: url("://ic-arrow-purple-down"); + width: 42px; + height: 42px; +} + +QPushButton[cssClass="btn-welcome-back"] { + background: url("://ic-arrow-white-left"); + background-repeat:no-repeat; + background-position:center; + border: 0px; + background-color:#5c4b7d; + color: #5c4b7d; +} + +QPushButton[cssClass="btn-welcome-next"] { + background: url("://ic-arrow-white-right"); + background-repeat:no-repeat; + background-position:center; + border: 0; + background-color:#5c4b7d; + color: #5c4b7d; +} + + +QPushButton[cssClass="btn-welcome-number-check"] { + border: 1px solid #5c4b7d; + background-color:transparent; + font-size:14px; + border-radius:11px; + color: #807b8a; +} + +QPushButton[cssClass="btn-welcome-number-check"]:checked { + border: 1px solid #b088ff; + background-color:#b088ff; + font-size:14px; + border-radius:11px; + color: #5c4b7d; +} + +QPushButton[cssClass="btn-welcome-name-check"] { + background-color: transparent; + border:none; + font-size:20px; + color: #807b8a; +} + +QPushButton[cssClass="btn-welcome-name-check"]:checked { + background-color:transparent; + border:none; + font-size:20px; + color: #b088ff; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH Tooltip +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +QToolTip { color: white; background-color: #b088ff; border: none;padding:10px; border-radius:2px;} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH ROW LIST +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="container-list-menu"]{ + background-color:white; + border-radius:2px; + padding:15px; + border: 1px solid #bababa; +} + +*[cssClass="btn-list-menu"]{ + border: 0; + background-color:#FFFFFF; + font-size:16px; + color: #707070; +} + +*[cssClass="btn-list-menu"]:hover{ + color: #5c4b7d; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH EMPTY LIST +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +*[cssClass="text-empty"]{ + color: #707070; + font-size: 18px; +} + + +*[cssClass="img-empty-master"] { + qproperty-icon: url("://img-empty-masternode"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +*[cssClass="img-empty-transactions"] { + qproperty-icon: url("://img-empty-transactions"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +*[cssClass="img-empty-peers"] { + qproperty-icon: url("://img-empty-peers"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +*[cssClass="img-empty-contacts"] { + qproperty-icon: url("://img-empty-contacts"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + + +*[cssClass="img-empty-error"] { + qproperty-icon: url("://img-empty-error"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +*[cssClass="img-empty-multisend"] { + qproperty-icon: url("://img-empty-multisend"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +*[cssClass="img-empty-staking-on"] { + qproperty-icon: url("://img-empty-staking-on"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + + +*[cssClass="img-empty-staking-off"] { + qproperty-icon: url("://img-empty-staking-off"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +*[cssClass="img-empty-privacy"] { + qproperty-icon: url("://img-empty-privacy"); + qproperty-iconSize: 100px 100px; + background-color: transparent; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH TREE WIDGET +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + +#treeWidget { + border:1px solid #5c4b7d; + background-color:#FFFFFF; + background-position:center; + background-repeat:no-repeat; + selection-background-color:#33b088ff; + selection-color: white; + font-size:14px; + border-radius:0px; + color: #707070; +} + +#treeWidget::indicator:first:checked{ + image: url("://ic-check-active"); +} +#treeWidget::indicator:middle:checked{ + image: url("://ic-check-active"); +} + +#treeWidget::indicator { + width: 24px; + height: 24px; +} + +#treeWidget::indicator:indeterminate { + image: url("://ic-check-box-indeterminate"); +} + +#treeWidget::indicator:unchecked { + image: url("://ic-check-box"); +} + +#treeWidget::indicator:checked { + image: url("://ic-check-active"); +} + +#treeWidget::item { + border:none; + border-bottom: 1px solid #bababa; + border-radius:0px; + color: #707070; + padding-top: 6px; + padding-bottom: 6px; + background-color:rgba(255,255,255,100); +} + +#treeWidget::branch:closed:has-children:!has-siblings { + border-image: none; + background-color:rgba(255,255,255,100); + image: url("://ic-arrow-drop-up"); + border-bottom: 1px solid #bababa; +} + +#treeWidget::branch:closed:has-children:has-siblings { + border-image: none; + background-color:rgba(255,255,255,100); + image: url("://ic-arrow-drop-up"); + border-bottom: 1px solid #bababa; +} + + +#treeWidget::branch:open:has-children:!has-siblings, +#treeWidget::branch:open:has-children:has-siblings { + border-image: none; + image: url("://ic-arrow-drop-down"); + border-bottom: 1px solid #bababa; +} + +#treeWidget::item:hover { + border:none; + border-bottom: 1px solid #bababa; + border-radius:0px; + color: #707070; + background-color:#26bababa; +} + +#treeWidget::item:selected { + border:none; + border-bottom: 1px solid #bababa; + border-radius:0px; + color: #707070; + background-color:#33b088ff; +} + + +#treeWidget::item:hover:selected { + border:none; + border-bottom: 1px solid #bababa; + border-radius:0px; + color: #707070; + background-color:#33b088ff; +} + + +#treeWidget::branch { + background-color: #FFFFFF; + selection-background-color:#33b088ff; +} + +#treeWidget::branch:selected { + background-color:#33b088ff; +} + +#treeWidget::branch:!selected { + background-color:#33b088ff; +} + +#treeWidget::branch:hover { + background-color:#26bababa; +} + +#treeWidget::branch:!has-children { + background-color: #FFFFFF; +} + +QHeaderView::section { + background-color: #5c4b7d; + color: #FFFFFF; + padding-top: 6px; + padding-bottom: 6px; + font-size:14px; + border:0px solid #5c4b7d; +} + + +*[cssClass="table-tree"] { + border:0; + background-color:#FFFFFF; + background-position:center; + background-repeat:no-repeat; + font-size:14px; + border-radius:0px; + color: #707070; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SEND MULTI +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +QPushButton[cssClass="ic-multi-number"] { + border:0; + background-color:transparent; + background-image: url("://bg-multi-number"); + background-position:center; + background-repeat:no-repeat; + font-size:12px; + border-radius:12px; + color: #5c4b7d; +} + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH OPTION BUTTON +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +*[cssClass="btn-options-indicator"]{ + border:0px ; + background:#5c4b7d; + border-radius: 5px; +} + + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH SNACK BAR +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ + + +*[cssClass="container-snackbar"]{ + background-color:#382d4d; + border-top:2px solid #b088ff; +} + +*[cssClass="text-snackbar"]{ + color:#FFFFFF; + font-size:20px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH LOADING +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + */ + +*[cssClass="container-loading"]{ + background-color:#BF000000; +} + +*[cssClass="text-loading"]{ + color:#ffffff; + font-size:20px; +} + + +/*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +HH INTRO +HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + */ + +*[cssClass="text-intro-white"] { + color:#FFFFFF; + font-size:16px; +} + +QPushButton[cssClass="btn-dots-welcome"] { + border: 1px solid #b088ff; + background-color:#b088ff; + font-size:18px; + padding:8px; + color: #FFFFFF; + border-radius: 2px; +} + + +QPushButton[cssClass="btn-dots-welcome"]:hover { + border: 1px solid #b088ff; + background-color:#44375f; + font-size:18px; + padding:8px; + color: #FFFFFF; + border-radius: 2px; +} + +QPushButton[cssClass="btn-dots-welcome"]:pressed { + border: 1px solid #b088ff; + background-color:#44375f; + font-size:18px; + padding:8px; + color: #b088ff; + border-radius: 2px; +} + +*[cssClass="edit-primary-welcome"] { + border:1px solid #b088ff; + border-right: 0px; + background-color:#171022; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #FFFFFF; +} + +*[cssClass="edit-primary-welcome"]:focus { + border: 1px solid #b088ff; + border-right: 0px; +} + +*[cssClass="edit-primary-welcome"]:focus:hover { + border: 1px solid #b088ff; + border-right: 0px; +} + +*[cssClass="edit-primary-welcome"]:hover { + border: 1px solid #b088ff; + border-right: 0px; +} + +*[cssClass="edit-primary-welcome-disabled"] { + border:1px solid #33ffffff; + border-right: 0px; + background-color:#171022; + font-size:18px; + border-radius: 2px; + padding:8px; + color: #66FFFFFF; +} + +QRadioButton[cssClass="radio-welcome"]:checked { + color: #b088ff; + font-size:20px; +} + +QRadioButton[cssClass="radio-welcome"]:unchecked { + color: #bababa; + font-size:20px; +} + +QRadioButton[cssClass="radio-welcome"] { + color: #bababa; + font-size:20px; + spacing:20px; +} + +QRadioButton[cssClass="radio-welcome"]::indicator { + width: 26px; + height: 26px; +} + +QRadioButton[cssClass="radio-welcome"]::indicator:checked { + background: url("://ic-radio-liliac-on"); + background-repeat:no-repeat; + background-position:center; +} + +QRadioButton[cssClass="radio-welcome"]::indicator:unchecked { + background: url("://btn-radio-off"); + background-repeat:no-repeat; + background-position:center; +} \ No newline at end of file diff --git a/src/qt/pivx/res/img/ani-loading-dark.gif b/src/qt/pivx/res/img/ani-loading-dark.gif new file mode 100644 index 000000000000..f8c0e075402f Binary files /dev/null and b/src/qt/pivx/res/img/ani-loading-dark.gif differ diff --git a/src/qt/pivx/res/img/ani-loading.gif b/src/qt/pivx/res/img/ani-loading.gif new file mode 100644 index 000000000000..f018944e9a6e Binary files /dev/null and b/src/qt/pivx/res/img/ani-loading.gif differ diff --git a/src/qt/pivx/res/img/bg-dashboard-banner.png b/src/qt/pivx/res/img/bg-dashboard-banner.png new file mode 100644 index 000000000000..e4073619ef9d Binary files /dev/null and b/src/qt/pivx/res/img/bg-dashboard-banner.png differ diff --git a/src/qt/pivx/res/img/bg-multi-number-dark.svg b/src/qt/pivx/res/img/bg-multi-number-dark.svg new file mode 100644 index 000000000000..24ba761d73ad --- /dev/null +++ b/src/qt/pivx/res/img/bg-multi-number-dark.svg @@ -0,0 +1,10 @@ + + + + Top BarTheme Copy + Created with Sketch. + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/bg-multi-number.svg b/src/qt/pivx/res/img/bg-multi-number.svg new file mode 100644 index 000000000000..d0d6d6aaba8e --- /dev/null +++ b/src/qt/pivx/res/img/bg-multi-number.svg @@ -0,0 +1,10 @@ + + + + Top BarTheme Copy + Created with Sketch. + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/bg-splash.png b/src/qt/pivx/res/img/bg-splash.png new file mode 100644 index 000000000000..c2712088428a Binary files /dev/null and b/src/qt/pivx/res/img/bg-splash.png differ diff --git a/src/qt/pivx/res/img/bg-splash.svg b/src/qt/pivx/res/img/bg-splash.svg new file mode 100644 index 000000000000..024df7d3b1c6 --- /dev/null +++ b/src/qt/pivx/res/img/bg-splash.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/bg-welcome-container.jpg b/src/qt/pivx/res/img/bg-welcome-container.jpg new file mode 100644 index 000000000000..74cc45f65e86 Binary files /dev/null and b/src/qt/pivx/res/img/bg-welcome-container.jpg differ diff --git a/src/qt/pivx/res/img/bg-welcome-container.png b/src/qt/pivx/res/img/bg-welcome-container.png new file mode 100644 index 000000000000..465dab021ca6 Binary files /dev/null and b/src/qt/pivx/res/img/bg-welcome-container.png differ diff --git a/src/qt/pivx/res/img/bg-welcome-container.svg b/src/qt/pivx/res/img/bg-welcome-container.svg new file mode 100644 index 000000000000..e1df088fb174 --- /dev/null +++ b/src/qt/pivx/res/img/bg-welcome-container.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/bg-welcome-container@2x.png b/src/qt/pivx/res/img/bg-welcome-container@2x.png new file mode 100644 index 000000000000..66d91506fb03 Binary files /dev/null and b/src/qt/pivx/res/img/bg-welcome-container@2x.png differ diff --git a/src/qt/pivx/res/img/bg-welcome-container@3x.png b/src/qt/pivx/res/img/bg-welcome-container@3x.png new file mode 100644 index 000000000000..74faed88bd88 Binary files /dev/null and b/src/qt/pivx/res/img/bg-welcome-container@3x.png differ diff --git a/src/qt/pivx/res/img/bg-welcome.jpg b/src/qt/pivx/res/img/bg-welcome.jpg new file mode 100644 index 000000000000..907fba87912c Binary files /dev/null and b/src/qt/pivx/res/img/bg-welcome.jpg differ diff --git a/src/qt/pivx/res/img/bg-welcome.png b/src/qt/pivx/res/img/bg-welcome.png new file mode 100644 index 000000000000..3a49b481473b Binary files /dev/null and b/src/qt/pivx/res/img/bg-welcome.png differ diff --git a/src/qt/pivx/res/img/bg-welcome.svg b/src/qt/pivx/res/img/bg-welcome.svg new file mode 100644 index 000000000000..4075110c66d2 --- /dev/null +++ b/src/qt/pivx/res/img/bg-welcome.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/bg-welcome@2x.jpg b/src/qt/pivx/res/img/bg-welcome@2x.jpg new file mode 100644 index 000000000000..935b0824ca43 Binary files /dev/null and b/src/qt/pivx/res/img/bg-welcome@2x.jpg differ diff --git a/src/qt/pivx/res/img/bg-welcome@3x.jpg b/src/qt/pivx/res/img/bg-welcome@3x.jpg new file mode 100644 index 000000000000..1e8143cd18bc Binary files /dev/null and b/src/qt/pivx/res/img/bg-welcome@3x.jpg differ diff --git a/src/qt/pivx/res/img/btn-radio-active.svg b/src/qt/pivx/res/img/btn-radio-active.svg new file mode 100755 index 000000000000..998091fdc256 --- /dev/null +++ b/src/qt/pivx/res/img/btn-radio-active.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/src/qt/pivx/res/img/btn-radio-off.svg b/src/qt/pivx/res/img/btn-radio-off.svg new file mode 100755 index 000000000000..cbfbf608b6ea --- /dev/null +++ b/src/qt/pivx/res/img/btn-radio-off.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/src/qt/pivx/res/img/dark/ic-transaction-mint-inactive.svg b/src/qt/pivx/res/img/dark/ic-transaction-mint-inactive.svg new file mode 100644 index 000000000000..3cb0d7c4045c --- /dev/null +++ b/src/qt/pivx/res/img/dark/ic-transaction-mint-inactive.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/dark/ic-transaction-mint.svg b/src/qt/pivx/res/img/dark/ic-transaction-mint.svg new file mode 100644 index 000000000000..3cb0d7c4045c --- /dev/null +++ b/src/qt/pivx/res/img/dark/ic-transaction-mint.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/dark/ic-transaction-received-inactive.svg b/src/qt/pivx/res/img/dark/ic-transaction-received-inactive.svg new file mode 100644 index 000000000000..081c5fa556bf --- /dev/null +++ b/src/qt/pivx/res/img/dark/ic-transaction-received-inactive.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/dark/ic-transaction-received.svg b/src/qt/pivx/res/img/dark/ic-transaction-received.svg new file mode 100644 index 000000000000..081c5fa556bf --- /dev/null +++ b/src/qt/pivx/res/img/dark/ic-transaction-received.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/dark/ic-transaction-sent-inactive.svg b/src/qt/pivx/res/img/dark/ic-transaction-sent-inactive.svg new file mode 100644 index 000000000000..e1de6967cce3 --- /dev/null +++ b/src/qt/pivx/res/img/dark/ic-transaction-sent-inactive.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/dark/ic-transaction-sent.svg b/src/qt/pivx/res/img/dark/ic-transaction-sent.svg new file mode 100644 index 000000000000..e1de6967cce3 --- /dev/null +++ b/src/qt/pivx/res/img/dark/ic-transaction-sent.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/dark/ic-transaction-staked-inactive.svg b/src/qt/pivx/res/img/dark/ic-transaction-staked-inactive.svg new file mode 100644 index 000000000000..7dcb5e2ecefe --- /dev/null +++ b/src/qt/pivx/res/img/dark/ic-transaction-staked-inactive.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/qt/pivx/res/img/dark/ic-transaction-staked.svg b/src/qt/pivx/res/img/dark/ic-transaction-staked.svg new file mode 100644 index 000000000000..7dcb5e2ecefe --- /dev/null +++ b/src/qt/pivx/res/img/dark/ic-transaction-staked.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/qt/pivx/res/img/dark/ic-transaction-warning.svg b/src/qt/pivx/res/img/dark/ic-transaction-warning.svg new file mode 100644 index 000000000000..472efe880973 --- /dev/null +++ b/src/qt/pivx/res/img/dark/ic-transaction-warning.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-add-label.svg b/src/qt/pivx/res/img/ic-add-label.svg new file mode 100755 index 000000000000..f7773ed691e8 --- /dev/null +++ b/src/qt/pivx/res/img/ic-add-label.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-add-liliac.svg b/src/qt/pivx/res/img/ic-add-liliac.svg new file mode 100644 index 000000000000..37a4f2be29db --- /dev/null +++ b/src/qt/pivx/res/img/ic-add-liliac.svg @@ -0,0 +1,12 @@ + + + + Add purple + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-add-purple.svg b/src/qt/pivx/res/img/ic-add-purple.svg new file mode 100644 index 000000000000..603e99e982d5 --- /dev/null +++ b/src/qt/pivx/res/img/ic-add-purple.svg @@ -0,0 +1,12 @@ + + + + Add purple + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-add.svg b/src/qt/pivx/res/img/ic-add.svg new file mode 100755 index 000000000000..d0ef6ce9019d --- /dev/null +++ b/src/qt/pivx/res/img/ic-add.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-address-book-grey.svg b/src/qt/pivx/res/img/ic-address-book-grey.svg new file mode 100644 index 000000000000..320a499478de --- /dev/null +++ b/src/qt/pivx/res/img/ic-address-book-grey.svg @@ -0,0 +1,12 @@ + + + + Address Book + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-address-book-white.svg b/src/qt/pivx/res/img/ic-address-book-white.svg new file mode 100644 index 000000000000..7fc9f7b2950a --- /dev/null +++ b/src/qt/pivx/res/img/ic-address-book-white.svg @@ -0,0 +1,12 @@ + + + + Address Book + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-address-book.svg b/src/qt/pivx/res/img/ic-address-book.svg new file mode 100755 index 000000000000..e0ce80f7844a --- /dev/null +++ b/src/qt/pivx/res/img/ic-address-book.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-address-send-white.svg b/src/qt/pivx/res/img/ic-address-send-white.svg new file mode 100644 index 000000000000..deb933bae74d --- /dev/null +++ b/src/qt/pivx/res/img/ic-address-send-white.svg @@ -0,0 +1,12 @@ + + + + Address Book Send + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-address-send.svg b/src/qt/pivx/res/img/ic-address-send.svg new file mode 100644 index 000000000000..d6e7178e868d --- /dev/null +++ b/src/qt/pivx/res/img/ic-address-send.svg @@ -0,0 +1,12 @@ + + + + Address Book Send + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-arrow-drop-down-purple.svg b/src/qt/pivx/res/img/ic-arrow-drop-down-purple.svg new file mode 100755 index 000000000000..004592ef6307 --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-drop-down-purple.svg @@ -0,0 +1,14 @@ + + + + ic-arrow-down + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-arrow-drop-down-white.svg b/src/qt/pivx/res/img/ic-arrow-drop-down-white.svg new file mode 100644 index 000000000000..bed6d4cc9db2 --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-drop-down-white.svg @@ -0,0 +1,14 @@ + + + + ic-arrow-down + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-arrow-drop-down.svg b/src/qt/pivx/res/img/ic-arrow-drop-down.svg new file mode 100755 index 000000000000..b0480e6f2f05 --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-drop-down.svg @@ -0,0 +1,14 @@ + + + + ic-arrow-down + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-arrow-drop-up-purple.svg b/src/qt/pivx/res/img/ic-arrow-drop-up-purple.svg new file mode 100755 index 000000000000..fab07a44135a --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-drop-up-purple.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-arrow-drop-up-white.svg b/src/qt/pivx/res/img/ic-arrow-drop-up-white.svg new file mode 100644 index 000000000000..66de33d164ef --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-drop-up-white.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-arrow-drop-up.svg b/src/qt/pivx/res/img/ic-arrow-drop-up.svg new file mode 100755 index 000000000000..2ae351972380 --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-drop-up.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-arrow-drop-white-down.svg b/src/qt/pivx/res/img/ic-arrow-drop-white-down.svg new file mode 100644 index 000000000000..79ec6324d7c7 --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-drop-white-down.svg @@ -0,0 +1,14 @@ + + + + ic-arrow-drop-down + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-arrow-left-white.svg b/src/qt/pivx/res/img/ic-arrow-left-white.svg new file mode 100644 index 000000000000..c7fa0e0c4c48 --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-left-white.svg @@ -0,0 +1,15 @@ + + + + Artboard + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-arrow-left.svg b/src/qt/pivx/res/img/ic-arrow-left.svg new file mode 100644 index 000000000000..46b89d7b6365 --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-left.svg @@ -0,0 +1,15 @@ + + + + Artboard + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-arrow-purple-down.svg b/src/qt/pivx/res/img/ic-arrow-purple-down.svg new file mode 100644 index 000000000000..1dd3bc638d55 --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-purple-down.svg @@ -0,0 +1,14 @@ + + + + ComboBox + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-arrow-right-white.svg b/src/qt/pivx/res/img/ic-arrow-right-white.svg new file mode 100644 index 000000000000..4479ee5d4c7c --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-right-white.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-arrow-right.svg b/src/qt/pivx/res/img/ic-arrow-right.svg new file mode 100644 index 000000000000..bad23c4ee87d --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-right.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-arrow-white-left.svg b/src/qt/pivx/res/img/ic-arrow-white-left.svg new file mode 100644 index 000000000000..296fbd54387e --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-white-left.svg @@ -0,0 +1,9 @@ + + + + Arrow left + Created with Sketch. + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-arrow-white-right.svg b/src/qt/pivx/res/img/ic-arrow-white-right.svg new file mode 100644 index 000000000000..43f9487d4c1f --- /dev/null +++ b/src/qt/pivx/res/img/ic-arrow-white-right.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-active.svg b/src/qt/pivx/res/img/ic-check-active.svg new file mode 100755 index 000000000000..bd8dd172d374 --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-active.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-box-dark-active.svg b/src/qt/pivx/res/img/ic-check-box-dark-active.svg new file mode 100755 index 000000000000..790d3fd69f9f --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-box-dark-active.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-box-indeterminate.svg b/src/qt/pivx/res/img/ic-check-box-indeterminate.svg new file mode 100644 index 000000000000..5fe41381e1cb --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-box-indeterminate.svg @@ -0,0 +1,14 @@ + + + + ic-check-active + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-check-box-liliac-indeterminate.svg b/src/qt/pivx/res/img/ic-check-box-liliac-indeterminate.svg new file mode 100644 index 000000000000..5fe41381e1cb --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-box-liliac-indeterminate.svg @@ -0,0 +1,14 @@ + + + + ic-check-active + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-check-box.svg b/src/qt/pivx/res/img/ic-check-box.svg new file mode 100755 index 000000000000..9172a63392d8 --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-box.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-connect-off.svg b/src/qt/pivx/res/img/ic-check-connect-off.svg new file mode 100644 index 000000000000..56ad7753d6be --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-connect-off.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-connect.svg b/src/qt/pivx/res/img/ic-check-connect.svg new file mode 100644 index 000000000000..e8ceb3994f3c --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-connect.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-dark.svg b/src/qt/pivx/res/img/ic-check-dark.svg new file mode 100644 index 000000000000..9b482f82726c --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-dark.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-faq.svg b/src/qt/pivx/res/img/ic-check-faq.svg new file mode 100644 index 000000000000..893072b653c6 --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-faq.svg @@ -0,0 +1,9 @@ + + + + Artboard + Created with Sketch. + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-check-liliac-indeterminate.svg b/src/qt/pivx/res/img/ic-check-liliac-indeterminate.svg new file mode 100644 index 000000000000..9f92d07d05fd --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-liliac-indeterminate.svg @@ -0,0 +1,14 @@ + + + + ic-check-active + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-check-liliac-on.svg b/src/qt/pivx/res/img/ic-check-liliac-on.svg new file mode 100644 index 000000000000..1afc17da03eb --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-liliac-on.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-locked-off.svg b/src/qt/pivx/res/img/ic-check-locked-off.svg new file mode 100644 index 000000000000..6c717ce51997 --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-locked-off.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-locked.svg b/src/qt/pivx/res/img/ic-check-locked.svg new file mode 100644 index 000000000000..f5ff92575263 --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-locked.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-mint-off.svg b/src/qt/pivx/res/img/ic-check-mint-off.svg new file mode 100644 index 000000000000..fcca40ccb6c8 --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-mint-off.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-mint.svg b/src/qt/pivx/res/img/ic-check-mint.svg new file mode 100644 index 000000000000..ab58522046be --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-mint.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-peers-off.svg b/src/qt/pivx/res/img/ic-check-peers-off.svg new file mode 100644 index 000000000000..29558eaeec0d --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-peers-off.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-peers.svg b/src/qt/pivx/res/img/ic-check-peers.svg new file mode 100644 index 000000000000..e3cfbd44bc59 --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-peers.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-staking-off.svg b/src/qt/pivx/res/img/ic-check-staking-off.svg new file mode 100644 index 000000000000..cc049153c456 --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-staking-off.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-staking.svg b/src/qt/pivx/res/img/ic-check-staking.svg new file mode 100644 index 000000000000..1ab6d581e97d --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-staking.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-sync-off.svg b/src/qt/pivx/res/img/ic-check-sync-off.svg new file mode 100644 index 000000000000..f556d41c9b34 --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-sync-off.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-sync.png b/src/qt/pivx/res/img/ic-check-sync.png new file mode 100644 index 000000000000..0b8231152df2 Binary files /dev/null and b/src/qt/pivx/res/img/ic-check-sync.png differ diff --git a/src/qt/pivx/res/img/ic-check-sync.svg b/src/qt/pivx/res/img/ic-check-sync.svg new file mode 100644 index 000000000000..31139c43b884 --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-sync.svg @@ -0,0 +1,12 @@ + + + + Top Bar Sync + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-check-theme-dark.svg b/src/qt/pivx/res/img/ic-check-theme-dark.svg new file mode 100644 index 000000000000..6f0fcf9fad9a --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-theme-dark.svg @@ -0,0 +1,18 @@ + + + + Top BarTheme + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-check-theme-light.svg b/src/qt/pivx/res/img/ic-check-theme-light.svg new file mode 100644 index 000000000000..d9976009c7fc --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-theme-light.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check-white.svg b/src/qt/pivx/res/img/ic-check-white.svg new file mode 100644 index 000000000000..0d81f74e4ebe --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-white.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-check.svg b/src/qt/pivx/res/img/ic-check.svg new file mode 100755 index 000000000000..9b3ce4fbcc3b --- /dev/null +++ b/src/qt/pivx/res/img/ic-check.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-chevron-left.svg b/src/qt/pivx/res/img/ic-chevron-left.svg new file mode 100755 index 000000000000..daba7d0fe050 --- /dev/null +++ b/src/qt/pivx/res/img/ic-chevron-left.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-chevron-right.svg b/src/qt/pivx/res/img/ic-chevron-right.svg new file mode 100755 index 000000000000..bad23c4ee87d --- /dev/null +++ b/src/qt/pivx/res/img/ic-chevron-right.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-clear-liliac.svg b/src/qt/pivx/res/img/ic-clear-liliac.svg new file mode 100644 index 000000000000..410fa82dee02 --- /dev/null +++ b/src/qt/pivx/res/img/ic-clear-liliac.svg @@ -0,0 +1,12 @@ + + + + Clear Purple + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-clear-purple.svg b/src/qt/pivx/res/img/ic-clear-purple.svg new file mode 100644 index 000000000000..addfc069a33e --- /dev/null +++ b/src/qt/pivx/res/img/ic-clear-purple.svg @@ -0,0 +1,12 @@ + + + + Clear Purple + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-close-white.svg b/src/qt/pivx/res/img/ic-close-white.svg new file mode 100644 index 000000000000..31372c756403 --- /dev/null +++ b/src/qt/pivx/res/img/ic-close-white.svg @@ -0,0 +1,14 @@ + + + + ic-close-white + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-close.svg b/src/qt/pivx/res/img/ic-close.svg new file mode 100755 index 000000000000..71269b45de3e --- /dev/null +++ b/src/qt/pivx/res/img/ic-close.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-coin-piv.svg b/src/qt/pivx/res/img/ic-coin-piv.svg new file mode 100755 index 000000000000..c826212e4318 --- /dev/null +++ b/src/qt/pivx/res/img/ic-coin-piv.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-coin-zpiv.png b/src/qt/pivx/res/img/ic-coin-zpiv.png new file mode 100644 index 000000000000..04a6bfbd0d7b Binary files /dev/null and b/src/qt/pivx/res/img/ic-coin-zpiv.png differ diff --git a/src/qt/pivx/res/img/ic-coin-zpiv.svg b/src/qt/pivx/res/img/ic-coin-zpiv.svg new file mode 100755 index 000000000000..4553a33f4fc9 --- /dev/null +++ b/src/qt/pivx/res/img/ic-coin-zpiv.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-combo-box.svg b/src/qt/pivx/res/img/ic-combo-box.svg new file mode 100644 index 000000000000..58d0907b0150 --- /dev/null +++ b/src/qt/pivx/res/img/ic-combo-box.svg @@ -0,0 +1,24 @@ + + + + ComboBox + Created with Sketch. + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-connect.svg b/src/qt/pivx/res/img/ic-connect.svg new file mode 100755 index 000000000000..8638d27bf5b2 --- /dev/null +++ b/src/qt/pivx/res/img/ic-connect.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-contact-arrow-down-white.svg b/src/qt/pivx/res/img/ic-contact-arrow-down-white.svg new file mode 100644 index 000000000000..f40e3a958fff --- /dev/null +++ b/src/qt/pivx/res/img/ic-contact-arrow-down-white.svg @@ -0,0 +1,14 @@ + + + + ic-arrow-down + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-contact-arrow-down.svg b/src/qt/pivx/res/img/ic-contact-arrow-down.svg new file mode 100644 index 000000000000..2dca04ab2591 --- /dev/null +++ b/src/qt/pivx/res/img/ic-contact-arrow-down.svg @@ -0,0 +1,14 @@ + + + + ic-arrow-down + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-copy-big-white.svg b/src/qt/pivx/res/img/ic-copy-big-white.svg new file mode 100644 index 000000000000..b5178dc5af39 --- /dev/null +++ b/src/qt/pivx/res/img/ic-copy-big-white.svg @@ -0,0 +1,16 @@ + + + + Artboard + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-copy-big.svg b/src/qt/pivx/res/img/ic-copy-big.svg new file mode 100644 index 000000000000..87d5337610bb --- /dev/null +++ b/src/qt/pivx/res/img/ic-copy-big.svg @@ -0,0 +1,16 @@ + + + + Artboard + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-copy-liliac.svg b/src/qt/pivx/res/img/ic-copy-liliac.svg new file mode 100644 index 000000000000..7c4c83a89903 --- /dev/null +++ b/src/qt/pivx/res/img/ic-copy-liliac.svg @@ -0,0 +1,17 @@ + + + + Artboard + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-copy.svg b/src/qt/pivx/res/img/ic-copy.svg new file mode 100644 index 000000000000..85b160dbaf8d --- /dev/null +++ b/src/qt/pivx/res/img/ic-copy.svg @@ -0,0 +1,17 @@ + + + + Artboard + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-exit.svg b/src/qt/pivx/res/img/ic-exit.svg new file mode 100644 index 000000000000..8fcb54fc6c15 --- /dev/null +++ b/src/qt/pivx/res/img/ic-exit.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-expand.svg b/src/qt/pivx/res/img/ic-expand.svg new file mode 100755 index 000000000000..8c9ba38b58e2 --- /dev/null +++ b/src/qt/pivx/res/img/ic-expand.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-folder.svg b/src/qt/pivx/res/img/ic-folder.svg new file mode 100755 index 000000000000..b51257a57466 --- /dev/null +++ b/src/qt/pivx/res/img/ic-folder.svg @@ -0,0 +1,12 @@ + + + + Folder + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-label-liliac.svg b/src/qt/pivx/res/img/ic-label-liliac.svg new file mode 100644 index 000000000000..6fb8b720d222 --- /dev/null +++ b/src/qt/pivx/res/img/ic-label-liliac.svg @@ -0,0 +1,14 @@ + + + + Artboard + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-label.svg b/src/qt/pivx/res/img/ic-label.svg new file mode 100644 index 000000000000..15f6498138eb --- /dev/null +++ b/src/qt/pivx/res/img/ic-label.svg @@ -0,0 +1,14 @@ + + + + Artboard + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-menu-hover.svg b/src/qt/pivx/res/img/ic-menu-hover.svg new file mode 100755 index 000000000000..8f7e8e979c13 --- /dev/null +++ b/src/qt/pivx/res/img/ic-menu-hover.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-mint.svg b/src/qt/pivx/res/img/ic-mint.svg new file mode 100644 index 000000000000..5e95cc0e86f0 --- /dev/null +++ b/src/qt/pivx/res/img/ic-mint.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-nav-address-active.svg b/src/qt/pivx/res/img/ic-nav-address-active.svg new file mode 100644 index 000000000000..549c72d86142 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-address-active.svg @@ -0,0 +1,12 @@ + + + + Address Active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-address-hover.svg b/src/qt/pivx/res/img/ic-nav-address-hover.svg new file mode 100644 index 000000000000..edcdb39cf0b9 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-address-hover.svg @@ -0,0 +1,12 @@ + + + + Address + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-address.svg b/src/qt/pivx/res/img/ic-nav-address.svg new file mode 100644 index 000000000000..477c3a07ed56 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-address.svg @@ -0,0 +1,12 @@ + + + + Address + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-dashboard-active.svg b/src/qt/pivx/res/img/ic-nav-dashboard-active.svg new file mode 100644 index 000000000000..23fde4552af6 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-dashboard-active.svg @@ -0,0 +1,19 @@ + + + + Dashboard + Created with Sketch. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-dashboard-hover.svg b/src/qt/pivx/res/img/ic-nav-dashboard-hover.svg new file mode 100644 index 000000000000..a4532867a901 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-dashboard-hover.svg @@ -0,0 +1,11 @@ + + + + Dashboard + Created with Sketch. + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-dashboard.svg b/src/qt/pivx/res/img/ic-nav-dashboard.svg new file mode 100644 index 000000000000..23c10d574681 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-dashboard.svg @@ -0,0 +1,19 @@ + + + + Dashboard + Created with Sketch. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-master-active.svg b/src/qt/pivx/res/img/ic-nav-master-active.svg new file mode 100644 index 000000000000..8406ac69e23c --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-master-active.svg @@ -0,0 +1,12 @@ + + + + Master Active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-master-hover.svg b/src/qt/pivx/res/img/ic-nav-master-hover.svg new file mode 100644 index 000000000000..280388b46697 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-master-hover.svg @@ -0,0 +1,12 @@ + + + + Master Active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-master.svg b/src/qt/pivx/res/img/ic-nav-master.svg new file mode 100644 index 000000000000..a110c3fe43c0 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-master.svg @@ -0,0 +1,12 @@ + + + + Master Active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-privacy-active.svg b/src/qt/pivx/res/img/ic-nav-privacy-active.svg new file mode 100644 index 000000000000..c52bcf093427 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-privacy-active.svg @@ -0,0 +1,12 @@ + + + + Privacy Active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-privacy-hover.svg b/src/qt/pivx/res/img/ic-nav-privacy-hover.svg new file mode 100644 index 000000000000..89684135296b --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-privacy-hover.svg @@ -0,0 +1,12 @@ + + + + Privacy + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-privacy.svg b/src/qt/pivx/res/img/ic-nav-privacy.svg new file mode 100644 index 000000000000..3f07cb853a2d --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-privacy.svg @@ -0,0 +1,12 @@ + + + + Privacy + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-receive-active.svg b/src/qt/pivx/res/img/ic-nav-receive-active.svg new file mode 100644 index 000000000000..eb8df26c3ae4 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-receive-active.svg @@ -0,0 +1,17 @@ + + + + Receive off + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-receive-hover.svg b/src/qt/pivx/res/img/ic-nav-receive-hover.svg new file mode 100644 index 000000000000..ad833eb8fed3 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-receive-hover.svg @@ -0,0 +1,10 @@ + + + + Receive off + Created with Sketch. + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-receive.svg b/src/qt/pivx/res/img/ic-nav-receive.svg new file mode 100644 index 000000000000..0f33711c4b49 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-receive.svg @@ -0,0 +1,17 @@ + + + + Receive off + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-send-active.svg b/src/qt/pivx/res/img/ic-nav-send-active.svg new file mode 100644 index 000000000000..8e7c2c41f2aa --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-send-active.svg @@ -0,0 +1,17 @@ + + + + Send + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-send-hover.svg b/src/qt/pivx/res/img/ic-nav-send-hover.svg new file mode 100644 index 000000000000..bcb637654251 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-send-hover.svg @@ -0,0 +1,10 @@ + + + + Send Off + Created with Sketch. + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-send.svg b/src/qt/pivx/res/img/ic-nav-send.svg new file mode 100644 index 000000000000..54bf56c84faa --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-send.svg @@ -0,0 +1,17 @@ + + + + Send Off Copy + Created with Sketch. + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-settings-active.svg b/src/qt/pivx/res/img/ic-nav-settings-active.svg new file mode 100644 index 000000000000..276fd0e0961b --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-settings-active.svg @@ -0,0 +1,18 @@ + + + + Artboard + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-settings-hover.svg b/src/qt/pivx/res/img/ic-nav-settings-hover.svg new file mode 100644 index 000000000000..4958d0dd18b3 --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-settings-hover.svg @@ -0,0 +1,10 @@ + + + + Settings + Created with Sketch. + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-nav-settings.svg b/src/qt/pivx/res/img/ic-nav-settings.svg new file mode 100644 index 000000000000..76dc23c43e3b --- /dev/null +++ b/src/qt/pivx/res/img/ic-nav-settings.svg @@ -0,0 +1,16 @@ + + + + Settings + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-pending.svg b/src/qt/pivx/res/img/ic-pending.svg new file mode 100644 index 000000000000..66a9b224886f --- /dev/null +++ b/src/qt/pivx/res/img/ic-pending.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-radio-liliac-on.svg b/src/qt/pivx/res/img/ic-radio-liliac-on.svg new file mode 100644 index 000000000000..de79bee20d5c --- /dev/null +++ b/src/qt/pivx/res/img/ic-radio-liliac-on.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-receive-off.svg b/src/qt/pivx/res/img/ic-receive-off.svg new file mode 100644 index 000000000000..ea1b958cd65b --- /dev/null +++ b/src/qt/pivx/res/img/ic-receive-off.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-receive-on.svg b/src/qt/pivx/res/img/ic-receive-on.svg new file mode 100644 index 000000000000..27121f5fa1b1 --- /dev/null +++ b/src/qt/pivx/res/img/ic-receive-on.svg @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-received.svg b/src/qt/pivx/res/img/ic-received.svg new file mode 100644 index 000000000000..fa6c799bd2d9 --- /dev/null +++ b/src/qt/pivx/res/img/ic-received.svg @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-send.svg b/src/qt/pivx/res/img/ic-send.svg new file mode 100644 index 000000000000..4c712cda983c --- /dev/null +++ b/src/qt/pivx/res/img/ic-send.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-submenu-lock.svg b/src/qt/pivx/res/img/ic-submenu-lock.svg new file mode 100644 index 000000000000..714c8980ac50 --- /dev/null +++ b/src/qt/pivx/res/img/ic-submenu-lock.svg @@ -0,0 +1,12 @@ + + + + Sub Menu Locked Copy 2 + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-submenu-staking.svg b/src/qt/pivx/res/img/ic-submenu-staking.svg new file mode 100644 index 000000000000..fc26d9ae1801 --- /dev/null +++ b/src/qt/pivx/res/img/ic-submenu-staking.svg @@ -0,0 +1,14 @@ + + + + Sub Menu Locked Copy + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-submenu-unlock.svg b/src/qt/pivx/res/img/ic-submenu-unlock.svg new file mode 100644 index 000000000000..3d3f619bfdfa --- /dev/null +++ b/src/qt/pivx/res/img/ic-submenu-unlock.svg @@ -0,0 +1,11 @@ + + + + Sub Menu Locked + Created with Sketch. + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-switch-liliac-on.svg b/src/qt/pivx/res/img/ic-switch-liliac-on.svg new file mode 100644 index 000000000000..60ecc539ebd0 --- /dev/null +++ b/src/qt/pivx/res/img/ic-switch-liliac-on.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-switch-off.svg b/src/qt/pivx/res/img/ic-switch-off.svg new file mode 100755 index 000000000000..822b9b08c648 --- /dev/null +++ b/src/qt/pivx/res/img/ic-switch-off.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-switch-on.svg b/src/qt/pivx/res/img/ic-switch-on.svg new file mode 100755 index 000000000000..9424b8240c1d --- /dev/null +++ b/src/qt/pivx/res/img/ic-switch-on.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-transaction-mint-inactive.svg b/src/qt/pivx/res/img/ic-transaction-mint-inactive.svg new file mode 100755 index 000000000000..779ac665f7eb --- /dev/null +++ b/src/qt/pivx/res/img/ic-transaction-mint-inactive.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-transaction-mint.svg b/src/qt/pivx/res/img/ic-transaction-mint.svg new file mode 100755 index 000000000000..b8e53e7d34af --- /dev/null +++ b/src/qt/pivx/res/img/ic-transaction-mint.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-transaction-received-inactive.svg b/src/qt/pivx/res/img/ic-transaction-received-inactive.svg new file mode 100755 index 000000000000..bd41b4de9a85 --- /dev/null +++ b/src/qt/pivx/res/img/ic-transaction-received-inactive.svg @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-transaction-received.svg b/src/qt/pivx/res/img/ic-transaction-received.svg new file mode 100755 index 000000000000..45e847ead432 --- /dev/null +++ b/src/qt/pivx/res/img/ic-transaction-received.svg @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-transaction-sent-inactive.svg b/src/qt/pivx/res/img/ic-transaction-sent-inactive.svg new file mode 100755 index 000000000000..3d09dd10877c --- /dev/null +++ b/src/qt/pivx/res/img/ic-transaction-sent-inactive.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-transaction-sent.svg b/src/qt/pivx/res/img/ic-transaction-sent.svg new file mode 100755 index 000000000000..840c58b77521 --- /dev/null +++ b/src/qt/pivx/res/img/ic-transaction-sent.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-transaction-staked-inactive.svg b/src/qt/pivx/res/img/ic-transaction-staked-inactive.svg new file mode 100755 index 000000000000..dc8517475687 --- /dev/null +++ b/src/qt/pivx/res/img/ic-transaction-staked-inactive.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-transaction-staked.svg b/src/qt/pivx/res/img/ic-transaction-staked.svg new file mode 100755 index 000000000000..84ec87cbb152 --- /dev/null +++ b/src/qt/pivx/res/img/ic-transaction-staked.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-transaction-warning.svg b/src/qt/pivx/res/img/ic-transaction-warning.svg new file mode 100644 index 000000000000..472efe880973 --- /dev/null +++ b/src/qt/pivx/res/img/ic-transaction-warning.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-unlock-staking.svg b/src/qt/pivx/res/img/ic-unlock-staking.svg new file mode 100644 index 000000000000..1b7a79942608 --- /dev/null +++ b/src/qt/pivx/res/img/ic-unlock-staking.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-update-liliac.svg b/src/qt/pivx/res/img/ic-update-liliac.svg new file mode 100644 index 000000000000..17b2d2076a0e --- /dev/null +++ b/src/qt/pivx/res/img/ic-update-liliac.svg @@ -0,0 +1,12 @@ + + + + Artboard + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-update.svg b/src/qt/pivx/res/img/ic-update.svg new file mode 100644 index 000000000000..d893f6f441af --- /dev/null +++ b/src/qt/pivx/res/img/ic-update.svg @@ -0,0 +1,12 @@ + + + + Artboard + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/ic-wallet-status-locked.svg b/src/qt/pivx/res/img/ic-wallet-status-locked.svg new file mode 100644 index 000000000000..46a4698f1795 --- /dev/null +++ b/src/qt/pivx/res/img/ic-wallet-status-locked.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-wallet-status-staking.svg b/src/qt/pivx/res/img/ic-wallet-status-staking.svg new file mode 100644 index 000000000000..bcaae4c295e4 --- /dev/null +++ b/src/qt/pivx/res/img/ic-wallet-status-staking.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-wallet-status-unlocked.svg b/src/qt/pivx/res/img/ic-wallet-status-unlocked.svg new file mode 100644 index 000000000000..2e4184de664f --- /dev/null +++ b/src/qt/pivx/res/img/ic-wallet-status-unlocked.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/pivx/res/img/ic-watch-password-white.svg b/src/qt/pivx/res/img/ic-watch-password-white.svg new file mode 100644 index 000000000000..e49cc734064b --- /dev/null +++ b/src/qt/pivx/res/img/ic-watch-password-white.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/ic-watch-password.svg b/src/qt/pivx/res/img/ic-watch-password.svg new file mode 100644 index 000000000000..837075e25508 --- /dev/null +++ b/src/qt/pivx/res/img/ic-watch-password.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-dashboard-banner.jpg b/src/qt/pivx/res/img/img-dashboard-banner.jpg new file mode 100644 index 000000000000..bbc8979ceeb9 Binary files /dev/null and b/src/qt/pivx/res/img/img-dashboard-banner.jpg differ diff --git a/src/qt/pivx/res/img/img-empty-contacts.svg b/src/qt/pivx/res/img/img-empty-contacts.svg new file mode 100644 index 000000000000..e6549fedd746 --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-contacts.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-dark-contacts.svg b/src/qt/pivx/res/img/img-empty-dark-contacts.svg new file mode 100644 index 000000000000..5f974a391052 --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-dark-contacts.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-dark-error.svg b/src/qt/pivx/res/img/img-empty-dark-error.svg new file mode 100644 index 000000000000..339a4eff617a --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-dark-error.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-dark-masternode.svg b/src/qt/pivx/res/img/img-empty-dark-masternode.svg new file mode 100644 index 000000000000..5d75af90439f --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-dark-masternode.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-dark-multisend.svg b/src/qt/pivx/res/img/img-empty-dark-multisend.svg new file mode 100644 index 000000000000..96f4a0c4136c --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-dark-multisend.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-dark-peers.svg b/src/qt/pivx/res/img/img-empty-dark-peers.svg new file mode 100644 index 000000000000..e6be4290a6d2 --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-dark-peers.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-dark-staking-off.svg b/src/qt/pivx/res/img/img-empty-dark-staking-off.svg new file mode 100644 index 000000000000..a1bf1e401ae4 --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-dark-staking-off.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-dark-staking-on.svg b/src/qt/pivx/res/img/img-empty-dark-staking-on.svg new file mode 100644 index 000000000000..6d47ec1ef8d5 --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-dark-staking-on.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-dark-transactions.svg b/src/qt/pivx/res/img/img-empty-dark-transactions.svg new file mode 100644 index 000000000000..d8581ce24c9f --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-dark-transactions.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-error.svg b/src/qt/pivx/res/img/img-empty-error.svg new file mode 100644 index 000000000000..2f2023a136ba --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-error.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-masternode.svg b/src/qt/pivx/res/img/img-empty-masternode.svg new file mode 100644 index 000000000000..a233b2218597 --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-masternode.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-multisend.svg b/src/qt/pivx/res/img/img-empty-multisend.svg new file mode 100644 index 000000000000..ede610aa793e --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-multisend.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-peers.svg b/src/qt/pivx/res/img/img-empty-peers.svg new file mode 100644 index 000000000000..60d325214b49 --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-peers.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-privacy-dark.svg b/src/qt/pivx/res/img/img-empty-privacy-dark.svg new file mode 100644 index 000000000000..5599a1e1bbf3 --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-privacy-dark.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-privacy.svg b/src/qt/pivx/res/img/img-empty-privacy.svg new file mode 100644 index 000000000000..6bd4665a7972 --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-privacy.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-staking-off.svg b/src/qt/pivx/res/img/img-empty-staking-off.svg new file mode 100644 index 000000000000..83d144563c02 --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-staking-off.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-staking-on.svg b/src/qt/pivx/res/img/img-empty-staking-on.svg new file mode 100644 index 000000000000..63af3251bb61 --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-staking-on.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-empty-transactions.svg b/src/qt/pivx/res/img/img-empty-transactions.svg new file mode 100644 index 000000000000..3d84fe1874fe --- /dev/null +++ b/src/qt/pivx/res/img/img-empty-transactions.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-logo-pivx.png b/src/qt/pivx/res/img/img-logo-pivx.png new file mode 100644 index 000000000000..1c05b17c3de7 Binary files /dev/null and b/src/qt/pivx/res/img/img-logo-pivx.png differ diff --git a/src/qt/pivx/res/img/img-logo-pivx.svg b/src/qt/pivx/res/img/img-logo-pivx.svg new file mode 100644 index 000000000000..f34338588c8d --- /dev/null +++ b/src/qt/pivx/res/img/img-logo-pivx.svg @@ -0,0 +1,21 @@ + + + + Artboard + Created with Sketch. + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/qt/pivx/res/img/img-logo-pivx@2x.png b/src/qt/pivx/res/img/img-logo-pivx@2x.png new file mode 100644 index 000000000000..763534526763 Binary files /dev/null and b/src/qt/pivx/res/img/img-logo-pivx@2x.png differ diff --git a/src/qt/pivx/res/img/img-logo-pivx@3x.png b/src/qt/pivx/res/img/img-logo-pivx@3x.png new file mode 100644 index 000000000000..9993e868ed92 Binary files /dev/null and b/src/qt/pivx/res/img/img-logo-pivx@3x.png differ diff --git a/src/qt/pivx/res/img/img-nav-logo-pivx.png b/src/qt/pivx/res/img/img-nav-logo-pivx.png new file mode 100644 index 000000000000..c2a67de923ac Binary files /dev/null and b/src/qt/pivx/res/img/img-nav-logo-pivx.png differ diff --git a/src/qt/pivx/res/img/img-nav-logo.png b/src/qt/pivx/res/img/img-nav-logo.png new file mode 100644 index 000000000000..c2a67de923ac Binary files /dev/null and b/src/qt/pivx/res/img/img-nav-logo.png differ diff --git a/src/qt/pivx/res/img/img-nav-logo.svg b/src/qt/pivx/res/img/img-nav-logo.svg new file mode 100644 index 000000000000..fef7b8eaac9e --- /dev/null +++ b/src/qt/pivx/res/img/img-nav-logo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-qr-test-big.png b/src/qt/pivx/res/img/img-qr-test-big.png new file mode 100644 index 000000000000..4222a6975353 Binary files /dev/null and b/src/qt/pivx/res/img/img-qr-test-big.png differ diff --git a/src/qt/pivx/res/img/img-qr-test.png b/src/qt/pivx/res/img/img-qr-test.png new file mode 100644 index 000000000000..595c347513b8 Binary files /dev/null and b/src/qt/pivx/res/img/img-qr-test.png differ diff --git a/src/qt/pivx/res/img/img-qr.svg b/src/qt/pivx/res/img/img-qr.svg new file mode 100644 index 000000000000..88869d6321e5 --- /dev/null +++ b/src/qt/pivx/res/img/img-qr.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/res/img/img-welcome-step1.png b/src/qt/pivx/res/img/img-welcome-step1.png new file mode 100644 index 000000000000..c627857b1a2a Binary files /dev/null and b/src/qt/pivx/res/img/img-welcome-step1.png differ diff --git a/src/qt/pivx/res/img/img-welcome-step2.png b/src/qt/pivx/res/img/img-welcome-step2.png new file mode 100644 index 000000000000..9ce584d596b8 Binary files /dev/null and b/src/qt/pivx/res/img/img-welcome-step2.png differ diff --git a/src/qt/pivx/res/img/img-welcome-step3.png b/src/qt/pivx/res/img/img-welcome-step3.png new file mode 100644 index 000000000000..3ea31e1524ac Binary files /dev/null and b/src/qt/pivx/res/img/img-welcome-step3.png differ diff --git a/src/qt/pivx/res/img/img-welcome-step4.png b/src/qt/pivx/res/img/img-welcome-step4.png new file mode 100644 index 000000000000..a0a60b4f08f2 Binary files /dev/null and b/src/qt/pivx/res/img/img-welcome-step4.png differ diff --git a/src/qt/pivx/send.cpp b/src/qt/pivx/send.cpp new file mode 100644 index 000000000000..d450b8670b2f --- /dev/null +++ b/src/qt/pivx/send.cpp @@ -0,0 +1,842 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/send.h" +#include "qt/pivx/forms/ui_send.h" +#include "qt/pivx/addnewcontactdialog.h" +#include "qt/pivx/qtutils.h" +#include "qt/pivx/sendchangeaddressdialog.h" +#include "qt/pivx/optionbutton.h" +#include "qt/pivx/sendconfirmdialog.h" +#include "qt/pivx/myaddressrow.h" +#include "clientmodel.h" +#include "optionsmodel.h" +#include "addresstablemodel.h" +#include "coincontrol.h" +#include "script/standard.h" +#include "zpiv/deterministicmint.h" +#include "openuridialog.h" +#include "zpivcontroldialog.h" + +SendWidget::SendWidget(PIVXGUI* parent) : + PWidget(parent), + ui(new Ui::send), + coinIcon(new QPushButton()), + btnContacts(new QPushButton()) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + /* Containers */ + setCssProperty(ui->left, "container"); + ui->left->setContentsMargins(0,20,0,20); + setCssProperty(ui->right, "container-right"); + ui->right->setContentsMargins(20,10,20,20); + + /* Light Font */ + QFont fontLight; + fontLight.setWeight(QFont::Light); + + /* Title */ + ui->labelTitle->setText(tr("Send")); + setCssProperty(ui->labelTitle, "text-title-screen"); + ui->labelTitle->setFont(fontLight); + + /* Button Group */ + ui->pushLeft->setText("PIV"); + setCssProperty(ui->pushLeft, "btn-check-left"); + ui->pushLeft->setChecked(true); + ui->pushRight->setText("zPIV"); + setCssProperty(ui->pushRight, "btn-check-right"); + + /* Subtitle */ + ui->labelSubtitle1->setText(tr("You can transfer public coins (PIV) or private coins (zPIV)")); + setCssProperty(ui->labelSubtitle1, "text-subtitle"); + + ui->labelSubtitle2->setText(tr("Select coin type to spend")); + setCssProperty(ui->labelSubtitle2, "text-subtitle"); + + /* Address */ + ui->labelSubtitleAddress->setText(tr("Enter a PIVX address or contact label")); + setCssProperty(ui->labelSubtitleAddress, "text-title"); + + + /* Amount */ + ui->labelSubtitleAmount->setText(tr("Amount")); + setCssProperty(ui->labelSubtitleAmount, "text-title"); + + /* Buttons */ + ui->pushButtonFee->setText(tr("Customize fee")); + setCssBtnSecondary(ui->pushButtonFee); + + ui->pushButtonClear->setText(tr("Clear all")); + setCssProperty(ui->pushButtonClear, "btn-secundary-clear"); + + ui->pushButtonAddRecipient->setText(tr("Add recipient")); + setCssProperty(ui->pushButtonAddRecipient, "btn-secundary-add"); + + setCssBtnPrimary(ui->pushButtonSave); + ui->pushButtonReset->setText(tr("Reset to default")); + setCssBtnSecondary(ui->pushButtonReset); + + // Coin control + ui->btnCoinControl->setTitleClassAndText("btn-title-grey", "Coin Control"); + ui->btnCoinControl->setSubTitleClassAndText("text-subtitle", "Select the source of the coins."); + + // Change address option + ui->btnChangeAddress->setTitleClassAndText("btn-title-grey", "Change Address"); + ui->btnChangeAddress->setSubTitleClassAndText("text-subtitle", "Customize the change address."); + + // Uri + ui->btnUri->setTitleClassAndText("btn-title-grey", "Open URI"); + ui->btnUri->setSubTitleClassAndText("text-subtitle", "Parse a payment request."); + + connect(ui->pushButtonFee, SIGNAL(clicked()), this, SLOT(onChangeCustomFeeClicked())); + connect(ui->btnCoinControl, SIGNAL(clicked()), this, SLOT(onCoinControlClicked())); + connect(ui->btnChangeAddress, SIGNAL(clicked()), this, SLOT(onChangeAddressClicked())); + connect(ui->btnUri, SIGNAL(clicked()), this, SLOT(onOpenUriClicked())); + connect(ui->pushButtonReset, SIGNAL(clicked()), this, SLOT(onResetCustomOptions())); + + setCssProperty(ui->coinWidget, "container-coin-type"); + setCssProperty(ui->labelLine, "container-divider"); + + + // Total Send + ui->labelTitleTotalSend->setText(tr("Total to send")); + setCssProperty(ui->labelTitleTotalSend, "text-title"); + + ui->labelAmountSend->setText("0.00 PIV"); + setCssProperty(ui->labelAmountSend, "text-body1"); + + // Total Remaining + setCssProperty(ui->labelTitleTotalRemaining, "text-title"); + + setCssProperty(ui->labelAmountRemaining, "text-body1"); + + // Icon Send + ui->stackedWidget->addWidget(coinIcon); + coinIcon->show(); + coinIcon->raise(); + + setCssProperty(coinIcon, "coin-icon-piv"); + + QSize BUTTON_SIZE = QSize(24, 24); + coinIcon->setMinimumSize(BUTTON_SIZE); + coinIcon->setMaximumSize(BUTTON_SIZE); + + int posX = 0; + int posY = 20; + coinIcon->move(posX, posY); + + // Entry + addEntry(); + + // Connect + connect(ui->pushLeft, &QPushButton::clicked, [this](){onPIVSelected(true);}); + connect(ui->pushRight, &QPushButton::clicked, [this](){onPIVSelected(false);}); + connect(ui->pushButtonSave, SIGNAL(clicked()), this, SLOT(onSendClicked())); + connect(ui->pushButtonAddRecipient, SIGNAL(clicked()), this, SLOT(onAddEntryClicked())); + connect(ui->pushButtonClear, SIGNAL(clicked()), this, SLOT(clearAll())); +} + +void SendWidget::refreshView(){ + QString btnText; + if(ui->pushLeft->isChecked()){ + btnText = tr("Send PIV"); + ui->pushButtonAddRecipient->setVisible(true); + }else{ + btnText = tr("Send zPIV"); + ui->pushButtonAddRecipient->setVisible(false); + } + ui->pushButtonSave->setText(btnText); + + refreshAmounts(); +} + +void SendWidget::refreshAmounts() { + + CAmount total = 0; + QMutableListIterator it(entries); + while (it.hasNext()) { + SendMultiRow* entry = it.next(); + CAmount amount = entry->getAmountValue(); + if (amount > 0) + total += amount; + } + + bool isZpiv = ui->pushRight->isChecked(); + nDisplayUnit = walletModel->getOptionsModel()->getDisplayUnit(); + + ui->labelAmountSend->setText(GUIUtil::formatBalance(total, nDisplayUnit, isZpiv)); + + CAmount totalAmount = 0; + if (CoinControlDialog::coinControl->HasSelected()){ + // Set remaining balance to the sum of the coinControl selected inputs + totalAmount = walletModel->getBalance(CoinControlDialog::coinControl) - total; + ui->labelTitleTotalRemaining->setText(tr("Total remaining from the selected UTXO")); + } else { + // Wallet's balance + totalAmount = (isZpiv ? walletModel->getZerocoinBalance() : walletModel->getBalance()) - total; + ui->labelTitleTotalRemaining->setText(tr("Total remaining")); + } + ui->labelAmountRemaining->setText( + GUIUtil::formatBalance( + totalAmount, + nDisplayUnit, + isZpiv + ) + ); +} + +void SendWidget::loadClientModel(){ + if (clientModel) { + connect(clientModel, &ClientModel::numBlocksChanged, [this](){ + if (customFeeDialog) customFeeDialog->updateFee(); + }); + } +} + +void SendWidget::loadWalletModel() { + if (walletModel && walletModel->getOptionsModel()) { + // display unit + nDisplayUnit = walletModel->getOptionsModel()->getDisplayUnit(); + + for(SendMultiRow *entry : entries){ + if(entry){ + entry->setWalletModel(walletModel); + } + } + + // Refresh view + refreshView(); + + // TODO: This only happen when the coin control features are modified in other screen, check before do this if the wallet has another screen modifying it. + // Coin Control + //connect(model->getOptionsModel(), SIGNAL(coinControlFeaturesChanged(bool)), this, SLOT(coinControlFeatureChanged(bool))); + //ui->frameCoinControl->setVisible(model->getOptionsModel()->getCoinControlFeatures()); + //coinControlUpdateLabels(); + } +} + +void SendWidget::clearAll(){ + onResetCustomOptions(); + if(customFeeDialog) customFeeDialog->clear(); + ui->pushButtonFee->setText(tr("Customize Fee")); + if(walletModel) walletModel->setWalletDefaultFee(); + clearEntries(); + refreshAmounts(); +} + +void SendWidget::onResetCustomOptions(){ + CoinControlDialog::coinControl->SetNull(); + ui->btnChangeAddress->setActive(false); + ui->btnCoinControl->setActive(false); +} + +void SendWidget::clearEntries(){ + int num = entries.length(); + for (int i = 0; i < num; ++i) { + ui->scrollAreaWidgetContents->layout()->takeAt(0)->widget()->deleteLater(); + } + entries.clear(); + + addEntry(); +} + +void SendWidget::addEntry(){ + if(entries.isEmpty()){ + createEntry(); + } else { + if (entries.length() == 1) { + SendMultiRow *entry = entries.at(0); + entry->hideLabels(); + entry->setNumber(1); + }else if(entries.length() == MAX_SEND_POPUP_ENTRIES){ + inform(tr("Maximum amount of outputs reached")); + return; + } + + SendMultiRow *sendMultiRow = createEntry(); + sendMultiRow->setNumber(entries.length()); + sendMultiRow->hideLabels(); + } +} + +SendMultiRow* SendWidget::createEntry(){ + SendMultiRow *sendMultiRow = new SendMultiRow(this); + if(this->walletModel) sendMultiRow->setWalletModel(this->walletModel); + entries.append(sendMultiRow); + ui->scrollAreaWidgetContents->layout()->addWidget(sendMultiRow); + connect(sendMultiRow, &SendMultiRow::onContactsClicked, this, &SendWidget::onContactsClicked); + connect(sendMultiRow, &SendMultiRow::onMenuClicked, this, &SendWidget::onMenuClicked); + connect(sendMultiRow, &SendMultiRow::onValueChanged, this, &SendWidget::onValueChanged); + return sendMultiRow; +} + +void SendWidget::onAddEntryClicked(){ + // Check prev valid entries before add a new one. + for (SendMultiRow* entry : entries){ + if(!entry || !entry->validate()) { + inform(tr("Invalid entry, previous entries must be valid before add a new one")); + return; + } + } + addEntry(); +} + +void SendWidget::resizeEvent(QResizeEvent *event){ + resizeMenu(); + QWidget::resizeEvent(event); +} + + +void SendWidget::onSendClicked(){ + + if (!walletModel || !walletModel->getOptionsModel()) + return; + + QList recipients; + + for (SendMultiRow* entry : entries){ + // TODO: Check UTXO splitter here.. + // Validate send.. + if(entry && entry->validate()) { + recipients.append(entry->getValue()); + }else{ + inform(tr("Invalid entry")); + return; + } + } + + if (recipients.isEmpty()) { + inform(tr("No set recipients")); + return; + } + + bool sendPiv = ui->pushLeft->isChecked(); + + // request unlock only if was locked or unlocked for mixing: + // this way we let users unlock by walletpassphrase or by menu + // and make many transactions while unlocking through this dialog + // will call relock + if(!GUIUtil::requestUnlock(walletModel, sendPiv ? AskPassphraseDialog::Context::Send_PIV : AskPassphraseDialog::Context::Send_zPIV, true)){ + // Unlock wallet was cancelled + inform(tr("Cannot send, wallet locked")); + return; + } + + if((sendPiv) ? send(recipients) : sendZpiv(recipients)) { + updateEntryLabels(recipients); + } +} + +bool SendWidget::send(QList recipients){ + // prepare transaction for getting txFee earlier + WalletModelTransaction currentTransaction(recipients); + WalletModel::SendCoinsReturn prepareStatus; + + prepareStatus = walletModel->prepareTransaction(currentTransaction, CoinControlDialog::coinControl); + + // process prepareStatus and on error generate message shown to user + processSendCoinsReturn(prepareStatus, + BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), + currentTransaction.getTransactionFee()), + true + ); + + if (prepareStatus.status != WalletModel::OK) { + inform(tr("Cannot create transaction.")); + return false; + } + + showHideOp(true); + TxDetailDialog* dialog = new TxDetailDialog(window); + dialog->setDisplayUnit(walletModel->getOptionsModel()->getDisplayUnit()); + dialog->setData(walletModel, currentTransaction); + dialog->adjustSize(); + openDialogWithOpaqueBackgroundY(dialog, window, 3, 5); + + if(dialog->isConfirm()){ + // now send the prepared transaction + WalletModel::SendCoinsReturn sendStatus = dialog->getStatus(); + // process sendStatus and on error generate message shown to user + processSendCoinsReturn(sendStatus); + + if (sendStatus.status == WalletModel::OK) { + CoinControlDialog::coinControl->UnSelectAll(); + clearAll(); + inform(tr("Transaction sent")); + return true; + } + } + + dialog->deleteLater(); + return false; +} + +bool SendWidget::sendZpiv(QList recipients){ + if (!walletModel || !walletModel->getOptionsModel()) + return false; + + if(GetAdjustedTime() > GetSporkValue(SPORK_16_ZEROCOIN_MAINTENANCE_MODE)) { + emit message(tr("Spend Zerocoin"), tr("zPIV is currently undergoing maintenance."), CClientUIInterface::MSG_ERROR); + return false; + } + + std::list> outputs; + CAmount total = 0; + for (SendCoinsRecipient rec : recipients){ + total += rec.amount; + outputs.push_back(std::pair(new CBitcoinAddress(rec.address.toStdString()),rec.amount)); + } + + // use mints from zPIV selector if applicable + std::vector vMintsToFetch; + std::vector vMintsSelected; + if (!ZPivControlDialog::setSelectedMints.empty()) { + vMintsToFetch = ZPivControlDialog::GetSelectedMints(); + + for (auto& meta : vMintsToFetch) { + CZerocoinMint mint; + if (!walletModel->getMint(meta.hashSerial, mint)){ + inform(tr("Coin control mint not found")); + return false; + } + vMintsSelected.emplace_back(mint); + } + } + + QString sendBody = outputs.size() == 1 ? + tr("Sending %1 to address %2\n") + .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), total, false, BitcoinUnits::separatorAlways)) + .arg(recipients.first().address) + : + tr("Sending %1 to addresses:\n%2") + .arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), total, false, BitcoinUnits::separatorAlways)) + .arg(recipientsToString(recipients)); + + bool ret = false; + emit message( + tr("Spend Zerocoin"), + sendBody, + CClientUIInterface::MSG_INFORMATION | CClientUIInterface::BTN_MASK | CClientUIInterface::MODAL, + &ret); + + if(!ret) return false; + + CZerocoinSpendReceipt receipt; + + std::string changeAddress = ""; + if(!boost::get(&CoinControlDialog::coinControl->destChange)){ + changeAddress = CBitcoinAddress(CoinControlDialog::coinControl->destChange).ToString(); + }else{ + changeAddress = walletModel->getAddressTableModel()->getLastUnusedAddress().toStdString(); + } + + if (walletModel->sendZpiv( + vMintsSelected, + true, + true, + receipt, + outputs, + changeAddress + ) + ) { + inform(tr("zPIV transaction sent!")); + ZPivControlDialog::setSelectedMints.clear(); + clearAll(); + return true; + } else { + QString body; + if (receipt.GetStatus() == ZPIV_SPEND_V1_SEC_LEVEL) { + body = tr("Version 1 zPIV require a security level of 100 to successfully spend."); + } else { + int nNeededSpends = receipt.GetNeededSpends(); // Number of spends we would need for this transaction + const int nMaxSpends = Params().Zerocoin_MaxSpendsPerTransaction(); // Maximum possible spends for one zPIV transaction + if (nNeededSpends > nMaxSpends) { + body = tr("Too much inputs (") + QString::number(nNeededSpends, 10) + + tr(") needed.\nMaximum allowed: ") + QString::number(nMaxSpends, 10); + body += tr( + "\nEither mint higher denominations (so fewer inputs are needed) or reduce the amount to spend."); + } else { + body = QString::fromStdString(receipt.GetStatusMessage()); + } + } + emit message("zPIV transaction failed", body, CClientUIInterface::MSG_ERROR); + return false; + } +} + +QString SendWidget::recipientsToString(QList recipients){ + QString s = ""; + for (SendCoinsRecipient rec : recipients){ + s += rec.address + " -> " + BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), rec.amount, false, BitcoinUnits::separatorAlways) + "\n"; + } + return s; +} + +void SendWidget::updateEntryLabels(QList recipients){ + for (SendCoinsRecipient rec : recipients){ + QString label = rec.label; + if(!label.isNull()) { + QString labelOld = walletModel->getAddressTableModel()->labelForAddress(rec.address); + if(label.compare(labelOld) != 0) { + CTxDestination dest = CBitcoinAddress(rec.address.toStdString()).Get(); + if (!walletModel->updateAddressBookLabels(dest, label.toStdString(), + this->walletModel->isMine(dest) ? "receive" : "send")) { + // Label update failed + emit message("", tr("Address label update failed for address: %1").arg(rec.address), CClientUIInterface::MSG_ERROR); + return; + } + } + } + + } +} + +void SendWidget::processSendCoinsReturn(const WalletModel::SendCoinsReturn& sendCoinsReturn, const QString& msgArg, bool fPrepare) +{ + bool fAskForUnlock = false; + + QPair msgParams; + // Default to a warning message, override if error message is needed + msgParams.second = CClientUIInterface::MSG_WARNING; + + // This comment is specific to SendCoinsDialog usage of WalletModel::SendCoinsReturn. + // WalletModel::TransactionCommitFailed is used only in WalletModel::sendCoins() + // all others are used only in WalletModel::prepareTransaction() + switch (sendCoinsReturn.status) { + case WalletModel::InvalidAddress: + msgParams.first = tr("The recipient address is not valid, please recheck."); + break; + case WalletModel::InvalidAmount: + msgParams.first = tr("The amount to pay must be larger than 0."); + break; + case WalletModel::AmountExceedsBalance: + msgParams.first = tr("The amount exceeds your balance."); + break; + case WalletModel::AmountWithFeeExceedsBalance: + msgParams.first = tr("The total exceeds your balance when the %1 transaction fee is included.").arg(msgArg); + break; + case WalletModel::DuplicateAddress: + msgParams.first = tr("Duplicate address found, can only send to each address once per send operation."); + break; + case WalletModel::TransactionCreationFailed: + msgParams.first = tr("Transaction creation failed!"); + msgParams.second = CClientUIInterface::MSG_ERROR; + break; + case WalletModel::TransactionCommitFailed: + msgParams.first = tr("The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); + msgParams.second = CClientUIInterface::MSG_ERROR; + break; + case WalletModel::AnonymizeOnlyUnlocked: + // Unlock is only need when the coins are send + if(!fPrepare) + fAskForUnlock = true; + else + msgParams.first = tr("Error: The wallet was unlocked only to anonymize coins."); + break; + + case WalletModel::InsaneFee: + msgParams.first = tr("A fee %1 times higher than %2 per kB is considered an insanely high fee.").arg(10000).arg(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), ::minRelayTxFee.GetFeePerK())); + break; + // included to prevent a compiler warning. + case WalletModel::OK: + default: + return; + } + + // Unlock wallet if it wasn't fully unlocked already + if(fAskForUnlock) { + walletModel->requestUnlock(AskPassphraseDialog::Context::Unlock_Full, false); + if(walletModel->getEncryptionStatus () != WalletModel::Unlocked) { + msgParams.first = tr("Error: The wallet was unlocked only to anonymize coins. Unlock canceled."); + } + else { + // Wallet unlocked + return; + } + } + + emit message(tr("Send Coins"), msgParams.first, msgParams.second); +} + + +void SendWidget::onChangeAddressClicked(){ + showHideOp(true); + SendChangeAddressDialog* dialog = new SendChangeAddressDialog(window); + if(!boost::get(&CoinControlDialog::coinControl->destChange)){ + dialog->setAddress(QString::fromStdString(CBitcoinAddress(CoinControlDialog::coinControl->destChange).ToString())); + } + if(openDialogWithOpaqueBackgroundY(dialog, window, 3, 5)) { + if(dialog->selected) { + QString ret; + if (dialog->getAddress(walletModel, &ret)) { + CoinControlDialog::coinControl->destChange = CBitcoinAddress(ret.toStdString()).Get(); + ui->btnChangeAddress->setActive(true); + }else{ + inform(tr("Invalid change address")); + ui->btnChangeAddress->setActive(false); + } + } + } + dialog->deleteLater(); +} + +void SendWidget::onOpenUriClicked(){ + showHideOp(true); + OpenURIDialog *dlg = new OpenURIDialog(window); + if (openDialogWithOpaqueBackgroundY(dlg, window, 3, 5)) { + + SendCoinsRecipient rcp; + if (!GUIUtil::parseBitcoinURI(dlg->getURI(), &rcp)) { + inform(tr("Invalid URI")); + return; + } + if (!walletModel->validateAddress(rcp.address)) { + inform(tr("Invalid address in URI")); + return; + } + + int listSize = entries.size(); + if (listSize == 1) { + SendMultiRow *entry = entries[0]; + entry->setAddressAndLabelOrDescription(rcp.address, rcp.message); + entry->setAmount(BitcoinUnits::format(nDisplayUnit, rcp.amount, false)); + } else { + // Use the last one if it's invalid or add a new one + SendMultiRow *entry = entries[listSize - 1]; + if (!entry->validate()) { + addEntry(); + entry = entries[listSize]; + } + entry->setAddressAndLabelOrDescription(rcp.address, rcp.message); + entry->setAmount(BitcoinUnits::format(nDisplayUnit, rcp.amount, false)); + } + emit receivedURI(dlg->getURI()); + } + dlg->deleteLater(); +} + +void SendWidget::onChangeCustomFeeClicked(){ + showHideOp(true); + if (!customFeeDialog) { + customFeeDialog = new SendCustomFeeDialog(window); + customFeeDialog->setWalletModel(walletModel); + } + if (openDialogWithOpaqueBackgroundY(customFeeDialog, window, 3, 5)){ + ui->pushButtonFee->setText(tr("Custom Fee %1").arg(BitcoinUnits::formatWithUnit(nDisplayUnit, customFeeDialog->getFeeRate().GetFeePerK()) + "/kB")); + isCustomFeeSelected = true; + walletModel->setWalletDefaultFee(customFeeDialog->getFeeRate().GetFeePerK()); + } else { + ui->pushButtonFee->setText(tr("Customize Fee")); + isCustomFeeSelected = false; + walletModel->setWalletDefaultFee(); + } +} + +void SendWidget::onCoinControlClicked(){ + if(isPIV){ + if (walletModel->getBalance() > 0) { + if (!coinControlDialog) { + coinControlDialog = new CoinControlDialog(); + coinControlDialog->setModel(walletModel); + } + coinControlDialog->exec(); + ui->btnCoinControl->setActive(CoinControlDialog::coinControl->HasSelected()); + refreshAmounts(); + } else { + inform(tr("You don't have any PIV to select.")); + } + }else{ + if (walletModel->getZerocoinBalance() > 0) { + ZPivControlDialog *zPivControl = new ZPivControlDialog(this); + zPivControl->setModel(walletModel); + zPivControl->exec(); + ui->btnCoinControl->setActive(!ZPivControlDialog::setSelectedMints.empty()); + zPivControl->deleteLater(); + } else { + inform(tr("You don't have any zPIV in your balance to select.")); + } + } +} + +void SendWidget::onValueChanged() { + refreshAmounts(); +} + +void SendWidget::onPIVSelected(bool _isPIV){ + isPIV = _isPIV; + setCssProperty(coinIcon, _isPIV ? "coin-icon-piv" : "coin-icon-zpiv"); + refreshView(); + updateStyle(coinIcon); +} + +void SendWidget::onContactsClicked(SendMultiRow* entry){ + focusedEntry = entry; + if(menu && menu->isVisible()){ + menu->hide(); + } + + int contactsSize = walletModel->getAddressTableModel()->sizeSend(); + if(contactsSize == 0) { + inform(tr("No contacts available, you can go to the contacts screen and add some there!")); + return; + } + + int height = (contactsSize <= 2) ? entry->getEditHeight() * ( 2 * (contactsSize + 1 )) : entry->getEditHeight() * 4; + int width = entry->getEditWidth(); + + if(!menuContacts){ + menuContacts = new ContactsDropdown( + width, + height, + this + ); + menuContacts->setWalletModel(walletModel, AddressTableModel::Send); + connect(menuContacts, &ContactsDropdown::contactSelected, [this](QString address, QString label){ + if(focusedEntry){ + focusedEntry->setLabel(label); + focusedEntry->setAddress(address); + } + }); + + } + + if(menuContacts->isVisible()){ + menuContacts->hide(); + return; + } + + menuContacts->resizeList(width, height); + menuContacts->setStyleSheet(this->styleSheet()); + menuContacts->adjustSize(); + + QPoint pos; + if (entries.size() > 1){ + pos = entry->pos(); + pos.setY((pos.y() + (focusedEntry->getEditHeight() - 12) * 4)); + } else { + pos = focusedEntry->getEditLineRect().bottomLeft(); + pos.setY((pos.y() + (focusedEntry->getEditHeight() - 12) * 3)); + } + pos.setX(pos.x() + 20); + menuContacts->move(pos); + menuContacts->show(); +} + +void SendWidget::onMenuClicked(SendMultiRow* entry){ + focusedEntry = entry; + if(menuContacts && menuContacts->isVisible()){ + menuContacts->hide(); + } + QPoint pos = entry->pos(); + pos.setX(pos.x() + (entry->width() - entry->getMenuBtnWidth())); + pos.setY(pos.y() + entry->height() + (entry->getMenuBtnWidth())); + + if(!this->menu){ + this->menu = new TooltipMenu(window, this); + this->menu->setCopyBtnVisible(false); + this->menu->setEditBtnText(tr("Save contact")); + this->menu->setMinimumSize(this->menu->width() + 30,this->menu->height()); + connect(this->menu, &TooltipMenu::message, this, &AddressesWidget::message); + connect(this->menu, SIGNAL(onEditClicked()), this, SLOT(onContactMultiClicked())); + connect(this->menu, SIGNAL(onDeleteClicked()), this, SLOT(onDeleteClicked())); + }else { + this->menu->hide(); + } + menu->move(pos); + menu->show(); +} + +void SendWidget::onContactMultiClicked(){ + if(focusedEntry) { + QString address = focusedEntry->getAddress(); + if (address.isEmpty()) { + inform(tr("Address field is empty")); + return; + } + if (!walletModel->validateAddress(address)) { + inform(tr("Invalid address")); + return; + } + CBitcoinAddress pivAdd = CBitcoinAddress(address.toStdString()); + if (walletModel->isMine(pivAdd)) { + inform(tr("Cannot store your own address as contact")); + return; + } + + showHideOp(true); + AddNewContactDialog *dialog = new AddNewContactDialog(window); + QString label = walletModel->getAddressTableModel()->labelForAddress(address); + if (!label.isNull()){ + dialog->setTexts(tr("Update Contact"), "Edit label for the selected address:\n%1"); + dialog->setData(address, label); + } else { + dialog->setTexts(tr("Create New Contact"), "Save label for the selected address:\n%1"); + dialog->setData(address, ""); + } + openDialogWithOpaqueBackgroundY(dialog, window, 3, 5); + if (dialog->res) { + if (label == dialog->getLabel()) { + return; + } + if (walletModel->updateAddressBookLabels(pivAdd.Get(), dialog->getLabel().toStdString(), "send")) { + inform(tr("New Contact Stored")); + } else { + inform(tr("Error Storing Contact")); + } + } + dialog->deleteLater(); + } + +} + +void SendWidget::onDeleteClicked(){ + if (focusedEntry) { + focusedEntry->hide(); + focusedEntry->deleteLater(); + int entryNumber = focusedEntry->getNumber(); + + // Refresh amount total + rest of rows numbers. + QMutableListIterator it(entries); + while (it.hasNext()) { + SendMultiRow* entry = it.next(); + if (focusedEntry == entry){ + it.remove(); + } else if (focusedEntry && entry->getNumber() > entryNumber){ + entry->setNumber(entry->getNumber() - 1); + } + } + + if (entries.size() == 1) { + SendMultiRow* sendMultiRow = QMutableListIterator(entries).next(); + sendMultiRow->setNumber(entries.length()); + sendMultiRow->showLabels(); + } + + focusedEntry = nullptr; + } +} + +void SendWidget::resizeMenu(){ + if(menuContacts && menuContacts->isVisible() && focusedEntry){ + int width = focusedEntry->getEditWidth(); + menuContacts->resizeList(width, menuContacts->height()); + menuContacts->resize(width, menuContacts->height()); + QPoint pos = focusedEntry->getEditLineRect().bottomLeft(); + pos.setX(pos.x() + 20); + pos.setY(pos.y() + ((focusedEntry->getEditHeight() - 12) * 3)); + menuContacts->move(pos); + } +} + +void SendWidget::changeTheme(bool isLightTheme, QString& theme){ + if (coinControlDialog) coinControlDialog->setStyleSheet(theme); +} + +SendWidget::~SendWidget(){ + delete ui; +} diff --git a/src/qt/pivx/send.h b/src/qt/pivx/send.h new file mode 100644 index 000000000000..0747d9c3fb16 --- /dev/null +++ b/src/qt/pivx/send.h @@ -0,0 +1,104 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SEND_H +#define SEND_H + +#include +#include + +#include "qt/pivx/pwidget.h" +#include "qt/pivx/contactsdropdown.h" +#include "qt/pivx/sendmultirow.h" +#include "qt/pivx/sendcustomfeedialog.h" +#include "walletmodel.h" +#include "coincontroldialog.h" +#include "zpivcontroldialog.h" +#include "qt/pivx/tooltipmenu.h" + +static const int MAX_SEND_POPUP_ENTRIES = 8; + +class PIVXGUI; +class ClientModel; +class WalletModel; +class WalletModelTransaction; + +namespace Ui { +class send; +class QPushButton; +} + +class SendWidget : public PWidget +{ + Q_OBJECT + +public: + explicit SendWidget(PIVXGUI* parent); + ~SendWidget(); + + void addEntry(); + + void loadClientModel() override; + void loadWalletModel() override; + +signals: + /** Signal raised when a URI was entered or dragged to the GUI */ + void receivedURI(const QString& uri); + +public slots: + void onChangeAddressClicked(); + void onChangeCustomFeeClicked(); + void onCoinControlClicked(); + void onOpenUriClicked(); + void onValueChanged(); + void refreshAmounts(); + void changeTheme(bool isLightTheme, QString &theme) override; + +protected: + void resizeEvent(QResizeEvent *event) override; + +private slots: + void onPIVSelected(bool _isPIV); + void onSendClicked(); + void onContactsClicked(SendMultiRow* entry); + void onMenuClicked(SendMultiRow* entry); + void onAddEntryClicked(); + void clearEntries(); + void clearAll(); + void refreshView(); + void onContactMultiClicked(); + void onDeleteClicked(); + void onResetCustomOptions(); +private: + Ui::send *ui; + QPushButton *coinIcon; + QPushButton *btnContacts; + + SendCustomFeeDialog* customFeeDialog = nullptr; + bool isCustomFeeSelected = false; + + int nDisplayUnit; + QList entries; + CoinControlDialog *coinControlDialog = nullptr; + + ContactsDropdown *menuContacts = nullptr; + TooltipMenu *menu = nullptr; + // Current focus entry + SendMultiRow* focusedEntry = nullptr; + + bool isPIV = true; + void resizeMenu(); + QString recipientsToString(QList recipients); + SendMultiRow* createEntry(); + bool send(QList recipients); + bool sendZpiv(QList recipients); + void updateEntryLabels(QList recipients); + + // Process WalletModel::SendCoinsReturn and generate a pair consisting + // of a message and message flags for use in emit message(). + // Additional parameter msgArg can be used via .arg(msgArg). + void processSendCoinsReturn(const WalletModel::SendCoinsReturn& sendCoinsReturn, const QString& msgArg = QString(), bool fPrepare = false); +}; + +#endif // SEND_H diff --git a/src/qt/pivx/sendchangeaddressdialog.cpp b/src/qt/pivx/sendchangeaddressdialog.cpp new file mode 100644 index 000000000000..329f3f4a68e2 --- /dev/null +++ b/src/qt/pivx/sendchangeaddressdialog.cpp @@ -0,0 +1,58 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/sendchangeaddressdialog.h" +#include "qt/pivx/forms/ui_sendchangeaddressdialog.h" +#include "walletmodel.h" +#include "qt/pivx/qtutils.h" + +SendChangeAddressDialog::SendChangeAddressDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SendChangeAddressDialog) +{ + ui->setupUi(this); + this->setStyleSheet(parent->styleSheet()); + + // Container + ui->frame->setProperty("cssClass", "container-dialog"); + + // Text + ui->labelTitle->setText(tr("Custom Change Address")); + ui->labelTitle->setProperty("cssClass", "text-title-dialog"); + + ui->labelMessage->setText(tr("The remainder of the value resultant from the inputs minus the outputs value goes to the \"change\" PIVX address")); + ui->labelMessage->setProperty("cssClass", "text-main-grey"); + + ui->lineEditAddress->setPlaceholderText("Enter a PIVX address (e.g D7VFR83SQbiezrW72hjc… "); + initCssEditLine(ui->lineEditAddress, true); + + // Buttons + ui->btnEsc->setText(""); + ui->btnEsc->setProperty("cssClass", "ic-close"); + + ui->btnCancel->setProperty("cssClass", "btn-dialog-cancel"); + ui->btnSave->setText("SAVE"); + setCssBtnPrimary(ui->btnSave); + + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnSave, &QPushButton::clicked, [this](){ selected = true; accept(); }); +} + +void SendChangeAddressDialog::setAddress(QString address){ + ui->lineEditAddress->setText(address); +} + +bool SendChangeAddressDialog::getAddress(WalletModel *model, QString *retAddress){ + QString address = ui->lineEditAddress->text(); + if(!address.isEmpty() && model->validateAddress(address)){ + *retAddress = address; + return true; + } + return false; +} + +SendChangeAddressDialog::~SendChangeAddressDialog(){ + delete ui; +} diff --git a/src/qt/pivx/sendchangeaddressdialog.h b/src/qt/pivx/sendchangeaddressdialog.h new file mode 100644 index 000000000000..218535b65f0b --- /dev/null +++ b/src/qt/pivx/sendchangeaddressdialog.h @@ -0,0 +1,32 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SENDCHANGEADDRESSDIALOG_H +#define SENDCHANGEADDRESSDIALOG_H + +#include + +class WalletModel; + +namespace Ui { +class SendChangeAddressDialog; +} + +class SendChangeAddressDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SendChangeAddressDialog(QWidget *parent = nullptr); + ~SendChangeAddressDialog(); + + void setAddress(QString address); + bool getAddress(WalletModel *model, QString *retAddress); + bool selected = false; + +private: + Ui::SendChangeAddressDialog *ui; +}; + +#endif // SENDCHANGEADDRESSDIALOG_H diff --git a/src/qt/pivx/sendconfirmdialog.cpp b/src/qt/pivx/sendconfirmdialog.cpp new file mode 100644 index 000000000000..fe2111cfdacb --- /dev/null +++ b/src/qt/pivx/sendconfirmdialog.cpp @@ -0,0 +1,218 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/sendconfirmdialog.h" +#include "qt/pivx/forms/ui_sendconfirmdialog.h" +#include "bitcoinunits.h" +#include "walletmodel.h" +#include "transactiontablemodel.h" +#include "transactionrecord.h" +#include "wallet/wallet.h" +#include "guiutil.h" +#include "qt/pivx/qtutils.h" +#include +#include + +TxDetailDialog::TxDetailDialog(QWidget *parent, bool isConfirmDialog) : + QDialog(parent), + ui(new Ui::TxDetailDialog) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + // Container + setCssProperty(ui->frame, "container-dialog"); + setCssProperty(ui->labelTitle, "text-title-dialog"); + + // Labels + setCssTextBodyDialog({ui->labelAmount, ui->labelSend, ui->labelInputs, ui->labelFee, ui->labelChange, ui->labelId, ui->labelSize, ui->labelStatus, ui->labelConfirmations, ui->labelDate}); + setCssProperty({ui->labelDivider1, ui->labelDivider2, ui->labelDivider3, ui->labelDivider4, ui->labelDivider5, ui->labelDivider6, ui->labelDivider7, ui->labelDivider8, ui->labelDivider9}, "container-divider"); + setCssTextBodyDialog({ui->textAmount, ui->textSend, ui->textInputs, ui->textFee, ui->textChange, ui->textId, ui->textSize, ui->textStatus, ui->textConfirmations, ui->textDate}); + + setCssProperty(ui->pushCopy, "ic-copy-big"); + setCssProperty({ui->pushInputs, ui->pushOutputs}, "ic-arrow-down"); + setCssProperty(ui->btnEsc, "ic-close"); + + ui->gridInputs->setVisible(false); + ui->outputsScrollArea->setVisible(false); + ui->contentChangeAddress->setVisible(false); + ui->labelDivider4->setVisible(false); + + setCssProperty({ui->labelOutputIndex, ui->labelTitlePrevTx}, "text-body2-dialog"); + + if(isConfirmDialog){ + ui->labelTitle->setText(tr("Confirm Your Transaction")); + setCssProperty(ui->btnCancel, "btn-dialog-cancel"); + ui->btnSave->setText(tr("SEND")); + setCssBtnPrimary(ui->btnSave); + + // hide change address for now + ui->contentConfirmations->setVisible(false); + ui->contentStatus->setVisible(false); + ui->contentDate->setVisible(false); + ui->contentSize->setVisible(false); + ui->contentConfirmations->setVisible(false); + ui->contentID->setVisible(false); + ui->labelDivider7->setVisible(false); + ui->labelDivider5->setVisible(false); + ui->labelDivider3->setVisible(false); + ui->labelDivider9->setVisible(false); + + connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnSave, &QPushButton::clicked, [this](){acceptTx();}); + }else{ + ui->labelTitle->setText(tr("Transaction Details")); + ui->containerButtons->setVisible(false); + } + + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(closeDialog())); + connect(ui->pushInputs, SIGNAL(clicked()), this, SLOT(onInputsClicked())); + connect(ui->pushOutputs, SIGNAL(clicked()), this, SLOT(onOutputsClicked())); +} + +void TxDetailDialog::setData(WalletModel *model, QModelIndex &index){ + this->model = model; + TransactionRecord *rec = static_cast(index.internalPointer()); + QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime(); + QString address = index.data(Qt::DisplayRole).toString(); + qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong(); + QString amountText = BitcoinUnits::formatWithUnit(nDisplayUnit, amount, true, BitcoinUnits::separatorAlways); + ui->textAmount->setText(amountText); + + const CWalletTx* tx = model->getTx(rec->hash); + if(tx) { + this->txHash = rec->hash; + QString hash = QString::fromStdString(tx->GetHash().GetHex()); + ui->textId->setText(hash.left(20) + "..." + hash.right(20)); + ui->textId->setTextInteractionFlags(Qt::TextSelectableByMouse); + if (tx->vout.size() == 1) { + ui->textSend->setText(address); + } else { + ui->textSend->setText(QString::number(tx->vout.size()) + " recipients"); + } + ui->textInputs->setText(QString::number(tx->vin.size())); + ui->textConfirmations->setText(QString::number(tx->GetDepthInMainChain())); + ui->textDate->setText(GUIUtil::dateTimeStr(date)); + ui->textStatus->setText(QString::fromStdString(rec->statusToString())); + ui->textSize->setText(QString::number(rec->size) + " bytes"); + + connect(ui->pushCopy, &QPushButton::clicked, [this](){ + GUIUtil::setClipboard(QString::fromStdString(this->txHash.GetHex())); + if (!snackBar) snackBar = new SnackBar(nullptr, this); + snackBar->setText(tr("ID copied")); + snackBar->resize(this->width(), snackBar->height()); + openDialog(snackBar, this); + }); + } + +} + +void TxDetailDialog::setData(WalletModel *model, WalletModelTransaction &tx){ + this->model = model; + this->tx = &tx; + CAmount txFee = tx.getTransactionFee(); + CAmount totalAmount = tx.getTotalTransactionAmount() + txFee; + + ui->textAmount->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, totalAmount, false, BitcoinUnits::separatorAlways) + " (Fee included)"); + if(tx.getRecipients().size() == 1){ + ui->textSend->setText(tx.getRecipients().at(0).address); + ui->pushOutputs->setVisible(false); + }else{ + ui->textSend->setText(QString::number(tx.getRecipients().size()) + " recipients"); + } + ui->textInputs->setText(QString::number(tx.getTransaction()->vin.size())); + ui->textFee->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, txFee, false, BitcoinUnits::separatorAlways)); +} + +void TxDetailDialog::acceptTx(){ + this->confirm = true; + this->sendStatus = model->sendCoins(*this->tx); + accept(); +} + +void TxDetailDialog::onInputsClicked() { + if (ui->gridInputs->isVisible()) { + ui->gridInputs->setVisible(false); + ui->contentInputs->layout()->setContentsMargins(0,9,12,9); + } else { + ui->gridInputs->setVisible(true); + ui->contentInputs->layout()->setContentsMargins(0,9,12,0); + if (!inputsLoaded) { + inputsLoaded = true; + const CWalletTx* tx = (this->tx) ? this->tx->getTransaction() : model->getTx(this->txHash); + if(tx) { + ui->gridInputs->setMinimumHeight(50 + (50 * tx->vin.size())); + int i = 1; + for (const CTxIn &in : tx->vin) { + QString hash = QString::fromStdString(in.prevout.hash.GetHex()); + QLabel *label = new QLabel(hash.left(18) + "..." + hash.right(18)); + QLabel *label1 = new QLabel(QString::number(in.prevout.n)); + label1->setAlignment(Qt::AlignCenter); + setCssProperty({label, label1}, "text-body2-dialog"); + + ui->gridLayoutInput->addWidget(label,i,0); + ui->gridLayoutInput->addWidget(label1,i,1, Qt::AlignCenter); + i++; + } + } + } + } +} + +void TxDetailDialog::onOutputsClicked() { + if (ui->outputsScrollArea->isVisible()) { + ui->outputsScrollArea->setVisible(false); + } else { + ui->outputsScrollArea->setVisible(true); + if (!outputsLoaded) { + outputsLoaded = true; + QVBoxLayout* layoutVertical = new QVBoxLayout(); + layoutVertical->setContentsMargins(0,0,12,0); + layoutVertical->setSpacing(6); + ui->container_outputs_base->setLayout(layoutVertical); + + const CWalletTx* tx = model->getTx(this->txHash); + if(tx) { + for (const CTxOut &out : tx->vout) { + QFrame *frame = new QFrame(ui->container_outputs_base); + + QHBoxLayout *layout = new QHBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(12); + frame->setLayout(layout); + + QLabel *label = nullptr; + QString labelRes; + CTxDestination dest; + if (ExtractDestination(out.scriptPubKey, dest)) { + std::string address = CBitcoinAddress(dest).ToString(); + labelRes = QString::fromStdString(address); + labelRes = labelRes.left(16) + "..." + labelRes.right(16); + } else { + labelRes = tr("Unknown"); + } + label = new QLabel(labelRes); + QLabel *label1 = new QLabel(BitcoinUnits::formatWithUnit(nDisplayUnit, out.nValue, false, BitcoinUnits::separatorAlways)); + label1->setAlignment(Qt::AlignCenter | Qt::AlignRight); + setCssProperty({label, label1}, "text-body2-dialog"); + + layout->addWidget(label); + layout->addWidget(label1); + layoutVertical->addWidget(frame); + } + } + } + } +} + +void TxDetailDialog::closeDialog(){ + if(snackBar && snackBar->isVisible()) snackBar->hide(); + close(); +} + +TxDetailDialog::~TxDetailDialog(){ + if(snackBar) delete snackBar; + delete ui; +} diff --git a/src/qt/pivx/sendconfirmdialog.h b/src/qt/pivx/sendconfirmdialog.h new file mode 100644 index 000000000000..34dcd30664bf --- /dev/null +++ b/src/qt/pivx/sendconfirmdialog.h @@ -0,0 +1,58 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SENDCONFIRMDIALOG_H +#define SENDCONFIRMDIALOG_H + +#include +#include "walletmodeltransaction.h" +#include "qt/pivx/snackbar.h" + +class WalletModelTransaction; +class WalletModel; + +namespace Ui { +class TxDetailDialog; +} + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +class TxDetailDialog : public QDialog +{ + Q_OBJECT + +public: + explicit TxDetailDialog(QWidget *parent = nullptr, bool isConfirmDialog = true); + ~TxDetailDialog(); + + bool isConfirm() { return this->confirm;} + WalletModel::SendCoinsReturn getStatus() { return this->sendStatus;} + + void setData(WalletModel *model, WalletModelTransaction &tx); + void setData(WalletModel *model, QModelIndex &index); + void setDisplayUnit(int unit){this->nDisplayUnit = unit;}; + +public slots: + void acceptTx(); + void onInputsClicked(); + void onOutputsClicked(); + void closeDialog(); + +private: + Ui::TxDetailDialog *ui; + SnackBar *snackBar = nullptr; + int nDisplayUnit = 0; + bool confirm = false; + WalletModel *model = nullptr; + WalletModel::SendCoinsReturn sendStatus; + WalletModelTransaction *tx = nullptr; + uint256 txHash = 0; + + bool inputsLoaded = false; + bool outputsLoaded = false; +}; + +#endif // SENDCONFIRMDIALOG_H diff --git a/src/qt/pivx/sendcustomfeedialog.cpp b/src/qt/pivx/sendcustomfeedialog.cpp new file mode 100644 index 000000000000..2458d2659b84 --- /dev/null +++ b/src/qt/pivx/sendcustomfeedialog.cpp @@ -0,0 +1,126 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/sendcustomfeedialog.h" +#include "qt/pivx/forms/ui_sendcustomfeedialog.h" +#include "qt/pivx/qtutils.h" +#include "walletmodel.h" +#include "optionsmodel.h" +#include "guiutil.h" +#include +#include + +SendCustomFeeDialog::SendCustomFeeDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SendCustomFeeDialog) +{ + ui->setupUi(this); + + // Stylesheet + this->setStyleSheet(parent->styleSheet()); + setCssProperty(ui->frame, "container-dialog"); + + // Text + ui->labelTitle->setText(tr("Customize Fee")); + ui->labelMessage->setText(tr("Customize the transaction fee at your to your liking, depending on the fee value your transaction will be included or not in the blockchain.")); + setCssProperty(ui->labelTitle, "text-title-dialog"); + setCssProperty(ui->labelMessage, "text-main-grey"); + + // Recommended + setCssProperty(ui->labelFee, "text-main-grey-big"); + setCssProperty(ui->comboBoxRecommended, "btn-combo-dialog"); + ui->comboBoxRecommended->setView(new QListView()); + ui->comboBoxRecommended->addItem(tr("Normal"), 5); + ui->comboBoxRecommended->addItem(tr("Slow"), 20); + ui->comboBoxRecommended->addItem(tr("Fast"), 1); + + // Custom + setCssProperty(ui->labelCustomFee, "label-subtitle-dialog"); + ui->lineEditCustomFee->setPlaceholderText("0.000001 PIV"); + initCssEditLine(ui->lineEditCustomFee, true); + + // Buttons + setCssProperty(ui->btnEsc, "ic-close"); + setCssProperty(ui->btnCancel, "btn-dialog-cancel"); + ui->btnSave->setText(tr("SAVE")); + setCssBtnPrimary(ui->btnSave); + + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnSave, SIGNAL(clicked()), this, SLOT(accept())); + connect(ui->checkBoxCustom, SIGNAL(clicked()), this, SLOT(onCustomChecked())); + connect(ui->checkBoxRecommended, SIGNAL(clicked()), this, SLOT(onRecommendedChecked())); + connect(ui->comboBoxRecommended, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(updateFee())); + if(parent) connect(parent, SIGNAL(themeChanged(bool, QString&)), this, SLOT(onChangeTheme(bool, QString&))); + ui->checkBoxRecommended->setChecked(true); +} + +void SendCustomFeeDialog::setWalletModel(WalletModel* walletModel){ + this->walletModel = walletModel; +} + +void SendCustomFeeDialog::showEvent(QShowEvent *event){ + updateFee(); +} + +void SendCustomFeeDialog::onCustomChecked(){ + bool isChecked = ui->checkBoxCustom->checkState() == Qt::Checked; + ui->lineEditCustomFee->setEnabled(isChecked); + ui->comboBoxRecommended->setEnabled(!isChecked); + ui->checkBoxRecommended->setChecked(!isChecked); + + if(walletModel && ui->lineEditCustomFee->text().isEmpty()) { + feeRate = CWallet::minTxFee; + ui->lineEditCustomFee->setText(BitcoinUnits::format(walletModel->getOptionsModel()->getDisplayUnit(), feeRate.GetFeePerK())); + } +} + +void SendCustomFeeDialog::onRecommendedChecked(){ + bool isChecked = ui->checkBoxRecommended->checkState() == Qt::Checked; + ui->lineEditCustomFee->setEnabled(!isChecked); + ui->comboBoxRecommended->setEnabled(isChecked); + ui->checkBoxCustom->setChecked(!isChecked); +} + +// Fast = 1. +// Medium = 5 +// Slow = 20 +void SendCustomFeeDialog::updateFee(){ + if (!walletModel || !walletModel->getOptionsModel()) return; + + QVariant num = ui->comboBoxRecommended->currentData(); + bool res = false; + int nBlocksToConfirm = num.toInt(&res); + if (res) { + feeRate = mempool.estimateFee(nBlocksToConfirm); + if (feeRate <= CFeeRate(0)) { // not enough data => minfee + feeRate = CWallet::minTxFee; + ui->labelFee->setText(BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), + feeRate.GetFeePerK()) + "/kB"); + } else { + ui->labelFee->setText( + BitcoinUnits::formatWithUnit(walletModel->getOptionsModel()->getDisplayUnit(), + feeRate.GetFeePerK()) + "/kB"); + } + } +} + +void SendCustomFeeDialog::clear(){ + onRecommendedChecked(); + updateFee(); +} + +CFeeRate SendCustomFeeDialog::getFeeRate(){ + return ui->checkBoxRecommended->isChecked() ? + feeRate : CFeeRate(GUIUtil::parseValue(ui->lineEditCustomFee->text(), walletModel->getOptionsModel()->getDisplayUnit())); +} + +void SendCustomFeeDialog::onChangeTheme(bool isLightTheme, QString& theme){ + this->setStyleSheet(theme); + updateStyle(this); +} + +SendCustomFeeDialog::~SendCustomFeeDialog(){ + delete ui; +} diff --git a/src/qt/pivx/sendcustomfeedialog.h b/src/qt/pivx/sendcustomfeedialog.h new file mode 100644 index 000000000000..3718e99498f0 --- /dev/null +++ b/src/qt/pivx/sendcustomfeedialog.h @@ -0,0 +1,41 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SENDCUSTOMFEEDIALOG_H +#define SENDCUSTOMFEEDIALOG_H + +#include +#include "amount.h" + +class WalletModel; + +namespace Ui { +class SendCustomFeeDialog; +} + +class SendCustomFeeDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SendCustomFeeDialog(QWidget *parent = nullptr); + ~SendCustomFeeDialog(); + + void setWalletModel(WalletModel* model); + void showEvent(QShowEvent *event) override; + CFeeRate getFeeRate(); + void clear(); + +public slots: + void onRecommendedChecked(); + void onCustomChecked(); + void updateFee(); + void onChangeTheme(bool isLightTheme, QString& theme); +private: + Ui::SendCustomFeeDialog *ui; + WalletModel* walletModel = nullptr; + CFeeRate feeRate; +}; + +#endif // SENDCUSTOMFEEDIALOG_H diff --git a/src/qt/pivx/sendmultirow.cpp b/src/qt/pivx/sendmultirow.cpp new file mode 100644 index 000000000000..c04a5703c2bc --- /dev/null +++ b/src/qt/pivx/sendmultirow.cpp @@ -0,0 +1,289 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/sendmultirow.h" +#include "qt/pivx/forms/ui_sendmultirow.h" +#include + +#include "optionsmodel.h" +#include "addresstablemodel.h" +#include "guiutil.h" +#include "bitcoinunits.h" +#include "qt/pivx/qtutils.h" + +SendMultiRow::SendMultiRow(PWidget *parent) : + PWidget(parent), + ui(new Ui::SendMultiRow), + iconNumber(new QPushButton()) +{ + ui->setupUi(this); + this->setStyleSheet(parent->styleSheet()); + + ui->lineEditAddress->setPlaceholderText(tr("Add address")); + setCssProperty(ui->lineEditAddress, "edit-primary-multi-book"); + ui->lineEditAddress->setAttribute(Qt::WA_MacShowFocusRect, 0); + setShadow(ui->stackedAddress); + + ui->lineEditAmount->setPlaceholderText("0.00 PIV "); + initCssEditLine(ui->lineEditAmount); + QDoubleValidator *doubleValidator = new QDoubleValidator(0, 9999999, 7, this); + doubleValidator->setNotation(QDoubleValidator::StandardNotation); + ui->lineEditAmount->setValidator(doubleValidator); + + /* Description */ + ui->labelSubtitleDescription->setText("Label address (optional)"); + setCssProperty(ui->labelSubtitleDescription, "text-title"); + ui->lineEditDescription->setPlaceholderText(tr("Add description")); + initCssEditLine(ui->lineEditDescription); + + // Button menu + setCssProperty(ui->btnMenu, "btn-menu"); + ui->btnMenu->setVisible(false); + + // Button Contact + btnContact = ui->lineEditAddress->addAction(QIcon("://ic-contact-arrow-down"), QLineEdit::TrailingPosition); + // Icon Number + ui->stackedAddress->addWidget(iconNumber); + iconNumber->show(); + iconNumber->raise(); + + setCssProperty(iconNumber, "ic-multi-number"); + iconNumber->setText("1"); + iconNumber->setVisible(false); + QSize size = QSize(24, 24); + iconNumber->setMinimumSize(size); + iconNumber->setMaximumSize(size); + + int posIconX = 0; + int posIconY = 14; + iconNumber->move(posIconX, posIconY); + + connect(ui->lineEditAmount, SIGNAL(textChanged(const QString&)), this, SLOT(amountChanged(const QString&))); + connect(ui->lineEditAddress, SIGNAL(textChanged(const QString&)), this, SLOT(addressChanged(const QString&))); + connect(btnContact, &QAction::triggered, [this](){emit onContactsClicked(this);}); + connect(ui->btnMenu, &QPushButton::clicked, [this](){emit onMenuClicked(this);}); +} + +void SendMultiRow::amountChanged(const QString& amount){ + if(!amount.isEmpty()) { + CAmount value = getAmountValue(amount); + if (value > 0) { + ui->lineEditAmount->setText(amount); + setCssEditLine(ui->lineEditAmount, true, true); + } + } + emit onValueChanged(); +} + +/** + * Returns -1 if the value is invalid + */ +CAmount SendMultiRow::getAmountValue(QString amount){ + bool isValid = false; + CAmount value = GUIUtil::parseValue(amount, displayUnit, &isValid); + return isValid ? value : -1; +} + +bool SendMultiRow::addressChanged(const QString& str){ + if(!str.isEmpty()) { + QString trimmedStr = str.trimmed(); + bool valid = walletModel->validateAddress(trimmedStr); + if (!valid) { + // check URI + SendCoinsRecipient rcp; + if (GUIUtil::parseBitcoinURI(trimmedStr, &rcp)) { + ui->lineEditAddress->setText(rcp.address); + ui->lineEditAmount->setText(BitcoinUnits::format(displayUnit, rcp.amount, false)); + + QString label = walletModel->getAddressTableModel()->labelForAddress(rcp.address); + if (!label.isNull() && !label.isEmpty()){ + ui->lineEditDescription->setText(label); + } else if(!rcp.message.isEmpty()) + ui->lineEditDescription->setText(rcp.message); + + emit onUriParsed(rcp); + } else { + setCssProperty(ui->lineEditAddress, "edit-primary-multi-book-error"); + } + } else { + setCssProperty(ui->lineEditAddress, "edit-primary-multi-book"); + QString label = walletModel->getAddressTableModel()->labelForAddress(trimmedStr); + if (!label.isNull()){ + ui->lineEditDescription->setText(label); + } + } + updateStyle(ui->lineEditAddress); + return valid; + } + return false; +} + + +void SendMultiRow::loadWalletModel() { + if (walletModel && walletModel->getOptionsModel()) { + displayUnit = walletModel->getOptionsModel()->getDisplayUnit(); + connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + } + clear(); +} + +void SendMultiRow::updateDisplayUnit(){ + // Update edit text.. + displayUnit = walletModel->getOptionsModel()->getDisplayUnit(); +} + +void SendMultiRow::deleteClicked() { + emit removeEntry(this); +} + +void SendMultiRow::clear() { + ui->lineEditAddress->clear(); + ui->lineEditAmount->clear(); + ui->lineEditDescription->clear(); +} + +bool SendMultiRow::validate() +{ + if (!walletModel) + return false; + + // Check input validity + bool retval = true; + + // Skip checks for payment request + if (recipient.paymentRequest.IsInitialized()) + return retval; + + // Check address validity, returns false if it's invalid + QString address = ui->lineEditAddress->text(); + if (address.isEmpty()){ + retval = false; + setCssProperty(ui->lineEditAddress, "edit-primary-multi-book-error", true); + } else + retval = addressChanged(address); + + CAmount value = getAmountValue(ui->lineEditAmount->text()); + + // Sending a zero amount is invalid + if (value <= 0) { + setCssEditLine(ui->lineEditAmount, false, true); + retval = false; + } + + // Reject dust outputs: + if (retval && GUIUtil::isDust(address, value)) { + setCssEditLine(ui->lineEditAmount, false, true); + retval = false; + } + + return retval; +} + +SendCoinsRecipient SendMultiRow::getValue() { + // Payment request + if (recipient.paymentRequest.IsInitialized()) + return recipient; + + // Normal payment + recipient.address = getAddress(); + recipient.label = ui->lineEditDescription->text(); + recipient.amount = getAmountValue();; + return recipient; +} + +QString SendMultiRow::getAddress() { + return ui->lineEditAddress->text().trimmed(); +} + +CAmount SendMultiRow::getAmountValue() { + return getAmountValue(ui->lineEditAmount->text()); +} + +QRect SendMultiRow::getEditLineRect(){ + return ui->lineEditAddress->rect(); +} + +int SendMultiRow::getEditHeight(){ + return ui->stackedAddress->height(); +} + +int SendMultiRow::getEditWidth(){ + return ui->lineEditAddress->width(); +} + +int SendMultiRow::getNumber(){ + return number; +} + +void SendMultiRow::setAddress(const QString& address) { + ui->lineEditAddress->setText(address); + ui->lineEditAmount->setFocus(); +} + +void SendMultiRow::setAmount(const QString& amount){ + ui->lineEditAmount->setText(amount); +} + +void SendMultiRow::setAddressAndLabelOrDescription(const QString& address, const QString& message){ + QString label = walletModel->getAddressTableModel()->labelForAddress(address); + if (!label.isNull() && !label.isEmpty()){ + ui->lineEditDescription->setText(label); + } else if(!message.isEmpty()) + ui->lineEditDescription->setText(message); + setAddress(address); +} + +void SendMultiRow::setLabel(const QString& label){ + ui->lineEditDescription->setText(label); +} + +bool SendMultiRow::isClear(){ + return ui->lineEditAddress->text().isEmpty(); +} + +void SendMultiRow::setFocus(){ + ui->lineEditAddress->setFocus(); +} + + +void SendMultiRow::setNumber(int _number){ + number = _number; + iconNumber->setText(QString::number(_number)); +} + +void SendMultiRow::hideLabels(){ + ui->layoutLabel->setVisible(false); + iconNumber->setVisible(true); +} + +void SendMultiRow::showLabels(){ + ui->layoutLabel->setVisible(true); + iconNumber->setVisible(false); +} + +void SendMultiRow::resizeEvent(QResizeEvent *event) { + QWidget::resizeEvent(event); +} + +void SendMultiRow::enterEvent(QEvent *) { + if(!this->isExpanded && iconNumber->isVisible()){ + isExpanded = true; + ui->btnMenu->setVisible(isExpanded); + } +} + +void SendMultiRow::leaveEvent(QEvent *) { + if(isExpanded){ + isExpanded = false; + ui->btnMenu->setVisible(isExpanded); + } +} + +int SendMultiRow::getMenuBtnWidth(){ + return ui->btnMenu->width(); +} + +SendMultiRow::~SendMultiRow(){ + delete ui; +} diff --git a/src/qt/pivx/sendmultirow.h b/src/qt/pivx/sendmultirow.h new file mode 100644 index 000000000000..447c42904a7f --- /dev/null +++ b/src/qt/pivx/sendmultirow.h @@ -0,0 +1,93 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SENDMULTIROW_H +#define SENDMULTIROW_H + +#include +#include +#include +#include "walletmodel.h" +#include "amount.h" +#include "qt/pivx/pwidget.h" + +class WalletModel; +class SendCoinsRecipient; + +namespace Ui { +class SendMultiRow; +class QPushButton; +} + +class SendMultiRow : public PWidget +{ + Q_OBJECT + +public: + explicit SendMultiRow(PWidget *parent = nullptr); + ~SendMultiRow(); + + void hideLabels(); + void showLabels(); + void setNumber(int number); + int getNumber(); + + void loadWalletModel() override; + bool validate(); + SendCoinsRecipient getValue(); + QString getAddress(); + CAmount getAmountValue(); + + /** Return whether the entry is still empty and unedited */ + bool isClear(); + CAmount getAmountValue(QString str); + + void setAddress(const QString& address); + void setLabel(const QString& label); + void setAmount(const QString& amount); + void setAddressAndLabelOrDescription(const QString& address, const QString& message); + void setFocus(); + + QRect getEditLineRect(); + int getEditHeight(); + int getEditWidth(); + int getMenuBtnWidth(); + +public slots: + void clear(); + void updateDisplayUnit(); + +signals: + void removeEntry(SendMultiRow* entry); + void onContactsClicked(SendMultiRow* entry); + void onMenuClicked(SendMultiRow* entry); + void onValueChanged(); + void onUriParsed(SendCoinsRecipient rcp); + +protected: + void resizeEvent(QResizeEvent *event) override; + virtual void enterEvent(QEvent *) override ; + virtual void leaveEvent(QEvent *) override ; + +private slots: + void amountChanged(const QString&); + bool addressChanged(const QString&); + void deleteClicked(); + //void on_payTo_textChanged(const QString& address); + //void on_addressBookButton_clicked(); + +private: + Ui::SendMultiRow *ui; + QPushButton *iconNumber; + QAction *btnContact; + + int displayUnit; + int number = 0; + bool isExpanded = false; + + SendCoinsRecipient recipient; + +}; + +#endif // SENDMULTIROW_H diff --git a/src/qt/pivx/settings/forms/settingsbackupwallet.ui b/src/qt/pivx/settings/forms/settingsbackupwallet.ui new file mode 100644 index 000000000000..f1dc7d66678d --- /dev/null +++ b/src/qt/pivx/settings/forms/settingsbackupwallet.ui @@ -0,0 +1,313 @@ + + + SettingsBackupWallet + + + + 0 + 0 + 400 + 410 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + 5 + + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + PushButton + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + PushButton + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 10 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + PushButton + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingsbittoolwidget.ui b/src/qt/pivx/settings/forms/settingsbittoolwidget.ui new file mode 100644 index 000000000000..0dc7159bb7cf --- /dev/null +++ b/src/qt/pivx/settings/forms/settingsbittoolwidget.ui @@ -0,0 +1,922 @@ + + + SettingsBitToolWidget + + + + 0 + 0 + 490 + 624 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 40 + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 120 + 30 + + + + + 120 + 30 + + + + PushButton + + + true + + + true + + + + + + + + 120 + 30 + + + + + 120 + 30 + + + + PushButton + + + true + + + true + + + true + + + + + + + + + + + + 1 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 100 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 0 + + + + + 9 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 9 + + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + + 9 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + Decrypt Address Result + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 50 + + + + + + + + + 140 + 40 + + + + Import Address + + + + + + + + + + + + + + 16777215 + 40 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 20 + + + + + + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + Clear + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + PushButton + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 5 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 5 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 75 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + + + + + + + TextLabel + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 0 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + Clear + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + PushButton + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingsconsolewidget.ui b/src/qt/pivx/settings/forms/settingsconsolewidget.ui new file mode 100644 index 000000000000..499162ef263e --- /dev/null +++ b/src/qt/pivx/settings/forms/settingsconsolewidget.ui @@ -0,0 +1,225 @@ + + + SettingsConsoleWidget + + + + 0 + 0 + 418 + 434 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 20 + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + PushButton + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + PushButton + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 300 + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 0 + + + + + + 45 + 45 + + + + + 45 + 45 + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 45 + + + + + 16777215 + 45 + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingsdisplayoptionswidget.ui b/src/qt/pivx/settings/forms/settingsdisplayoptionswidget.ui new file mode 100644 index 000000000000..9664d99d2b7b --- /dev/null +++ b/src/qt/pivx/settings/forms/settingsdisplayoptionswidget.ui @@ -0,0 +1,425 @@ + + + SettingsDisplayOptionsWidget + + + + 0 + 0 + 493 + 434 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 0 + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 380 + 0 + + + + + 280 + 16777215 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 180 + 0 + + + + + 180 + 16777215 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 180 + 0 + + + + + 180 + 16777215 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 14 + + + + + + + + + 0 + 30 + + + + PushButton + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Preferred + + + + 20 + 14 + + + + + + + + 0 + + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 12 + + + + + + 160 + 50 + + + + + 50 + 16777215 + + + + Reset to default + + + + + + + + 0 + 50 + + + + Discard changes + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + PushButton + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingsfaqwidget.ui b/src/qt/pivx/settings/forms/settingsfaqwidget.ui new file mode 100644 index 000000000000..e0e9014acf46 --- /dev/null +++ b/src/qt/pivx/settings/forms/settingsfaqwidget.ui @@ -0,0 +1,1589 @@ + + + SettingsFaqWidget + + + + 0 + 0 + 1203 + 1741 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 36 + + + 44 + + + 36 + + + 44 + + + + + 0 + + + 10 + + + 10 + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + PushButton + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + 1) What is PIVX? + + + true + + + true + + + true + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + 2) Why are my PIV unspendable? + + + true + + + true + + + + + + + + 0 + 50 + + + + + 16777215 + 16777215 + + + + 3) PIVX privacy? What is Zerocoin (zPIV)? + + + true + + + true + + + + + + + + 0 + 50 + + + + + 16777215 + 16777215 + + + + 4) Why are my zPIV unspendable? + + + true + + + true + + + + + + + + 0 + 50 + + + + 5) Why did my wallet convert the balance + into zPIV automatically? + + + true + + + true + + + + + + + + 0 + 50 + + + + 6) How do I receive PIV/zPIV? + + + true + + + true + + + + + + + + 0 + 50 + + + + 7) How do I stake PIV/zPIV? + + + true + + + true + + + + + + + + 0 + 50 + + + + 8) Where I should go if I need support? + + + true + + + true + + + + + + + + 0 + 50 + + + + 9) What is a Master Node? + + + true + + + true + + + + + + + + 0 + 50 + + + + 10) What is a Master Node Controller? + + + true + + + true + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + TextLabel + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 10 + 20 + + + + + + + + PushButton + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 40 + 20 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + #scrollAreaFaq { background:transparent; } + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustIgnored + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 628 + 2344 + + + + false + + + #scrollAreaWidgetContents { background:transparent; } + + + + 0 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 300 + 0 + + + + + + + + 24 + 24 + + + + + 16777215 + 24 + + + + 1 + + + Qt::AlignCenter + + + + + + + 20 + + + 20 + + + + + What is PIVX? + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + <html><head/><body><p align="justify"> + PIVX is a form of digital online money using blockchain technology + that can be easily transferred globally, instantly, and with near + zero fees. PIVX incorporates market leading security & + privacy and is also the first PoS (Proof of Stake) Cryptocurrency + to implement ZeroCoin(zPIV) and Zerocoin staking. + </p><p align="justify"> + PIVX utilizes a Proof of Stake (PoS) consensus system algorithm, + allowing all owners of PIVX to participate in earning block rewards + while securing the network with full node wallets, as well as to + run Masternodes to create and vote on proposals. + </p></body></html> + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + 24 + 24 + + + + + 16777215 + 24 + + + + 2 + + + Qt::AlignCenter + + + + + + + 0 + + + 20 + + + 20 + + + + + Why are my PIV unspendable? + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + <html><head/><body><p align="justify"> + Newly received PIVX requires 6 confirmations on the network + to become eligible for spending which can take ~6 minutes. + </p><p align="justify"> + Your PIVX wallet also needs to be completely synchronized + to see and spend balances on the network. + </p></body></html> + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + 24 + 24 + + + + + 16777215 + 24 + + + + 3 + + + Qt::AlignCenter + + + + + + + 20 + + + 20 + + + + + PIVX privacy? What is Zerocoin (zPIV)? + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + <html><head/><body><p align="justify"> + zPIV is an optional privacy-centric method of coin mixing on the + PIVX blockchain. Basically all your transactions cannot be tracked + on to any block explorer. You can read more about the technicals in the + <a style='color: #b088ff' href='https://PIVX.org/zpiv/'> + "PIVX Zerocoin (zPIV) Technical Paper"</a>. + </p></body></html> + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + 24 + 24 + + + + + 16777215 + 24 + + + + 4 + + + Qt::AlignCenter + + + + + + + 20 + + + 20 + + + + + Why are my zPIV unspendable? + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + <html><head/><body><p align="justify"> + After minting, zPIV will require 20 confirmations as well as 1 + additional mint of the same denomination on the network to + become eligible for spending. + </p></body></html> + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + 24 + 24 + + + + + 16777215 + 24 + + + + 5 + + + Qt::AlignCenter + + + + + + + 20 + + + 20 + + + + + Why did my wallet convert the balance into zPIV automatically? + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + <html><head/><body><p align="justify"> + By default the PIVX wallet will convert 10% of your entire PIV + balance to zPIV to assist the network. If you do not wish to + stake zPIV or take advantage of the privacy benefit it brings, + you can disable the automatic minting in your PIVX wallet by + going to Settings->Options and deselecting “Enable zPIV Automint”. + If you are not making use of the PIVX-QT or GUI you can simply open + your pivx.conf file and add <i>enablezeromint=0</i> Without the quotation + marks and restart your wallet to disable automint.</p> + </p><p align="justify"> + You can read more about zPIV in the + <a style='color: #b088ff' href='https://PIVX.org/zpiv/'> "PIVX Zerocoin (zPIV) Technical Paper"</a>. + If you would like to keep and stake your zPIV, please read the "How do I stake" + section of the FAQ below. + </p></body></html> + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + 24 + 24 + + + + + 16777215 + 24 + + + + 6 + + + Qt::AlignCenter + + + + + + + 0 + + + 20 + + + 20 + + + + + How do I receive PIV/zPIV? + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + <html><head/><body><p align="justify"> + zPIV can be spent and sent to any PIVX address. The receiver will + receive standard PIVX but the origin of the PIVX is anonymized by the zPIV Protocol. + </p><p align="justify"> + If you want more zPIV you will need to mint your balance in the “Privacy” tab. + </p></body></html> + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + 24 + 24 + + + + + 16777215 + 24 + + + + 7 + + + Qt::AlignCenter + + + + + + + 20 + + + 20 + + + + + How do I stake PIV/zPIV? + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + <html><head/><body><p align="justify"> + To Stake PIVX: + </p><p align="justify"> + <ol><li> + Make sure your wallet is completely synchronized and you are using the latest release. + <li> + You must have a balance of PIVX with a minimum of 101 confirmations. + <li> + Your wallet must stay online and be unlocked for anonymization and staking purposes. + <li> + Once all those steps are followed staking should be enabled. + <li> + You can see the status of staking in the wallet by mousing over the package icon in the row on the top left of the wallet interface. There package will be lit up and will state "Staking Enabled" to indicate it is staking. Using the command line interface (pivx-cli); the command <i>getstakingstatus</i> will confirm that staking is active. + </li></ol> + </p><p align="justify"> + To Stake zPIV: + </p><p align="justify"> + <ol><li> + Make sure your wallet is completely synchronized and you are using the latest release. + <li> + Your newly minted or existing zPIV balance must have a minimum of 200 confirmations. + <li> + Your wallet must stay online and be unlocked for anonymization and staking purposes. + Staking should now be enabled. + </li></ol> + </p></body></html> + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + 24 + 24 + + + + + 16777215 + 24 + + + + 8 + + + Qt::AlignCenter + + + + + + + 20 + + + 20 + + + + + Where I should go if I need support? + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + <html><head/><body><p align="justify"> + We have support channels in most of our official chat groups, for example + <a style='color: #b088ff' href='https://Discord.PIVX.com'> + #support in our Discord</a>. + If you prefer to submit a ticket, One can be + <a style='color: #b088ff' href='https://PIVX.FreshDesk.com'> + our Freshdesk support site</a>. + </p></body></html> + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + 24 + 24 + + + + + 16777215 + 24 + + + + 9 + + + Qt::AlignCenter + + + + + + + 20 + + + 20 + + + + + What is a Master Node? + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + <html><head/><body><p align="justify"> + A masternode is a computer running a full node PIVX core wallet with a + requirement of 10,000 PIV secured collateral to provide extra services + to the network and in return, receive a portion of the block reward + regularly. These services include: + </p><p align="justify"> + + <ul> + <li>Instant transactions (SwiftX)</li> + <li>A decentralized governance (Proposal Voting)</li> + <li>A decentralized budgeting system (Treasury)</li> + <li>Validation of transactions within each block</li> + <li>Act as an additional full node in the network</li> + </ul> + + </p><p align="justify"> + For providing such services, masternodes are also paid a certain portion + of reward for each block. This can serve as a passive income to the + masternode owners minus their running cost. + </p><p align="justify"> + + Masternode Perks: + </p><p align="justify"> + <ul> + <li>Participate in PIVX Governance</li> + <li>Earn Masternode Rewards</li> + <li>Commodity option for future sale</li> + <li>Help secure the PIVX network</li> + </ul> + </p><p align="justify"> + + Requirements: + </p><p align="justify"> + <ul> + <li>10,000 PIV per single Masternode instance</li> + <li>Must be stored in a core wallet</li> + <li>Need dedicated IP address</li> + <li>Masternode wallet to remain online</li> + </ul> + </p></body></html> + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + 24 + 24 + + + + + 16777215 + 24 + + + + 10 + + + Qt::AlignCenter + + + + + + + 20 + + + 20 + + + + + What is a Master Node Controller? + + + true + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + <html><head/><body><p align="justify">A Masternode Controller wallet is where the 10,000 PIV collateral can reside during a Controller-Remote masternode setup. It is a wallet that can activate the remote masternode wallet/s and allows you to keep your collateral coins offline while the remote masternode remains online. </p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingsinformationwidget.ui b/src/qt/pivx/settings/forms/settingsinformationwidget.ui new file mode 100644 index 000000000000..56e5d18bdf0e --- /dev/null +++ b/src/qt/pivx/settings/forms/settingsinformationwidget.ui @@ -0,0 +1,665 @@ + + + SettingsInformationWidget + + + + 0 + 0 + 469 + 454 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 0 + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 20 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 120 + 30 + + + + Network Monitor + + + + + + + + 120 + 30 + + + + + 120 + 30 + + + + PushButton + + + false + + + false + + + + + + + + 125 + 30 + + + + + 125 + 30 + + + + PushButton + + + false + + + false + + + false + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + + 5 + + + 0 + + + 0 + + + 0 + + + 10 + + + + + TextLabel + + + + + + + 0 + + + + + + 290 + 0 + + + + + 290 + 16777215 + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + 0 + + + + + + 290 + 0 + + + + + 290 + 16777215 + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + 0 + + + + + + 290 + 0 + + + + + 290 + 16777215 + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + 0 + + + + + + 290 + 0 + + + + + 290 + 16777215 + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + 0 + + + + + + 290 + 0 + + + + + 290 + 16777215 + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 20 + + + + + + + + TextLabel + + + + + + + 0 + + + + + + 290 + 0 + + + + + 290 + 16777215 + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 10 + + + + + + 290 + 0 + + + + + 290 + 16777215 + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 20 + + + + + + + + TextLabel + + + + + + + 0 + + + + + + 290 + 0 + + + + + 290 + 16777215 + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 10 + + + + + + 290 + 0 + + + + + 290 + 16777215 + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + TextLabel + + + + + + + 0 + + + + + + 290 + 0 + + + + + 290 + 16777215 + + + + TextLabel + + + + + + + TextLabel + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingsmainoptionswidget.ui b/src/qt/pivx/settings/forms/settingsmainoptionswidget.ui new file mode 100644 index 000000000000..a2a25e5e1f65 --- /dev/null +++ b/src/qt/pivx/settings/forms/settingsmainoptionswidget.ui @@ -0,0 +1,452 @@ + + + SettingsMainOptionsWidget + + + + 0 + 0 + 428 + 434 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 0 + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + + + + true + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 120 + 0 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 14 + + + + + + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 120 + 0 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 0 + + + + + 5 + + + + + Window + + + + + + + Customize the application window options + + + true + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + CheckBox + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + CheckBox + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 12 + + + + + + 160 + 50 + + + + + 50 + 16777215 + + + + Reset to default + + + + + + + + 0 + 50 + + + + Discard changes + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + SAVE + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingsmultisenddialog.ui b/src/qt/pivx/settings/forms/settingsmultisenddialog.ui new file mode 100644 index 000000000000..fb638cf2e2df --- /dev/null +++ b/src/qt/pivx/settings/forms/settingsmultisenddialog.ui @@ -0,0 +1,424 @@ + + + SettingsMultisendDialog + + + + 0 + 0 + 500 + 428 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 30 + + + 20 + + + 30 + + + 20 + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + padding-left:24px; + + + Transaction Details + + + Qt::AlignCenter + + + 7 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + + 16777215 + 90 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 3 + + + + + + 0 + 0 + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 40 + 20 + + + + + + + + 3 + + + + + + 0 + 0 + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 5 + + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 50 + + + + + 200 + 16777215 + + + + CANCEL + + + + + + + + 0 + 50 + + + + + 200 + 16777215 + + + + SAVE + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingsmultisendwidget.ui b/src/qt/pivx/settings/forms/settingsmultisendwidget.ui new file mode 100644 index 000000000000..d78f8c58ea60 --- /dev/null +++ b/src/qt/pivx/settings/forms/settingsmultisendwidget.ui @@ -0,0 +1,482 @@ + + + SettingsMultisendWidget + + + + 0 + 0 + 437 + 434 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + + 40 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 120 + 30 + + + + + 120 + 30 + + + + PushButton + + + true + + + true + + + + + + + + 120 + 30 + + + + + 120 + 30 + + + + PushButton + + + true + + + true + + + true + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + QAbstractItemView::NoSelection + + + + + + + + 0 + 100 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Vertical + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 30 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 100 + 100 + + + + + 100 + 100 + + + + + + + + 100 + 100 + + + + + + + + + + + No active Master Node yet + + + Qt::AlignCenter + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + CheckBox + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 0 + + + + CheckBox + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 12 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + PushButton + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + PushButton + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingssignmessagewidgets.ui b/src/qt/pivx/settings/forms/settingssignmessagewidgets.ui new file mode 100644 index 000000000000..f3cce618ff9d --- /dev/null +++ b/src/qt/pivx/settings/forms/settingssignmessagewidgets.ui @@ -0,0 +1,520 @@ + + + SettingsSignMessageWidgets + + + + 0 + 0 + 438 + 574 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 1 + + + 1 + + + 1 + + + 1 + + + + + 40 + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + #containerSwitch{ + padding-top:9px; +} + + + + 4 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + + + Qt::AlignRight|Qt::AlignTop|Qt::AlignTrailing + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 120 + 30 + + + + + 120 + 30 + + + + PushButton + + + true + + + true + + + + + + + + 120 + 30 + + + + + 120 + 30 + + + + PushButton + + + true + + + true + + + true + + + + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + + 0 + 0 + + + + + 15 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 5 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 140 + + + + + 16777215 + 140 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 75 + + + + + 16777215 + 16777215 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 20 + + + + + 16777215 + 20 + + + + TextLabel + + + + + + + + 0 + 50 + + + + + + + + + + + padding-top:5px; + + + TextLabel + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 9 + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + Clear + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + PushButton + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingswalletoptionswidget.ui b/src/qt/pivx/settings/forms/settingswalletoptionswidget.ui new file mode 100644 index 000000000000..475f0a8a240b --- /dev/null +++ b/src/qt/pivx/settings/forms/settingswalletoptionswidget.ui @@ -0,0 +1,502 @@ + + + SettingsWalletOptionsWidget + + + + 0 + 0 + 493 + 654 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 0 + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 9 + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 1 + + + 999999 + + + + + + + + + + + + + 20 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + CheckBox + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + 0 + 1 + + + + + 16777215 + 1 + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 0 + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + + + 20 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + RadioButton + + + + + + + RadioButton + + + + + + + RadioButton + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 0 + + + + + 10 + + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 10 + + + + + TextLabel + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + 12 + + + + + + 160 + 50 + + + + + 50 + 16777215 + + + + Reset to default + + + + + + + + 0 + 50 + + + + Discard changes + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + + + + 200 + 50 + + + + + 200 + 50 + + + + PushButton + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingswalletrepairwidget.ui b/src/qt/pivx/settings/forms/settingswalletrepairwidget.ui new file mode 100644 index 000000000000..1a766eb0cf8f --- /dev/null +++ b/src/qt/pivx/settings/forms/settingswalletrepairwidget.ui @@ -0,0 +1,590 @@ + + + SettingsWalletRepairWidget + + + + 0 + 0 + 400 + 622 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustIgnored + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 398 + 620 + + + + true + + + + 0 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 5 + + + + + TextLabel + + + + + + + TextLabel + + + true + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 40 + + + + + + + + 20 + + + + + 5 + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + PushButton + + + + + + + + + TextLabel + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 20 + + + + + 5 + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + PushButton + + + + + + + + + TextLabel + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 20 + + + + + 5 + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + PushButton + + + + + + + + + TextLabel + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 20 + + + + + 5 + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + PushButton + + + + + + + + + TextLabel + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 20 + + + + + 5 + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + PushButton + + + + + + + + + TextLabel + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 20 + + + + + 5 + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + PushButton + + + + + + + + + TextLabel + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + 20 + + + + + 0 + + + + + + 0 + 40 + + + + + 16777215 + 40 + + + + PushButton + + + + + + + + + + 0 + 0 + + + + TextLabel + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/forms/settingswidget.ui b/src/qt/pivx/settings/forms/settingswidget.ui new file mode 100644 index 000000000000..f466fe31a53d --- /dev/null +++ b/src/qt/pivx/settings/forms/settingswidget.ui @@ -0,0 +1,854 @@ + + + SettingsWidget + + + + 0 + 0 + 629 + 430 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 250 + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 0 + + + 20 + + + 20 + + + + + TextLabel + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + + + + 0 + 0 + + + + + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustIgnored + + + true + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + 0 + 0 + 230 + 887 + + + + + 0 + 0 + + + + true + + + + 0 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 0 + 0 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 20 + + + 20 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Wallet Data + + + true + + + false + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Wallet + + + true + + + false + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Multisend + + + true + + + false + + + + + + + + + + 0 + + + 20 + + + 20 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Tools + + + true + + + false + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Sign/Verify Message + + + true + + + false + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + BIP38 Tool + + + true + + + false + + + + + + + + + + 0 + + + 20 + + + 20 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Options + + + true + + + false + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Main + + + true + + + false + + + false + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Wallet + + + true + + + false + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Display + + + true + + + false + + + + + + + + + + 0 + + + 20 + + + 20 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Debug + + + true + + + false + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Information + + + true + + + false + + + false + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Console + + + true + + + false + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Wallet Repair + + + true + + + false + + + + + + + + + + 0 + + + 20 + + + 20 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + Help + + + true + + + false + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + FAQ + + + false + + + false + + + false + + + + + + + + 0 + 50 + + + + + 16777215 + 50 + + + + About PIVX + + + false + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + + + + + + + + + + + + + + + + diff --git a/src/qt/pivx/settings/settingsbackupwallet.cpp b/src/qt/pivx/settings/settingsbackupwallet.cpp new file mode 100644 index 000000000000..cae2a9c2859b --- /dev/null +++ b/src/qt/pivx/settings/settingsbackupwallet.cpp @@ -0,0 +1,98 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingsbackupwallet.h" +#include "qt/pivx/settings/forms/ui_settingsbackupwallet.h" +#include +#include +#include "guiutil.h" +#include "qt/pivx/qtutils.h" +#include "guiinterface.h" +#include "qt/pivx/qtutils.h" +SettingsBackupWallet::SettingsBackupWallet(PIVXGUI* _window, QWidget *parent) : + PWidget(_window, parent), + ui(new Ui::SettingsBackupWallet) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + /* Containers */ + ui->left->setProperty("cssClass", "container"); + ui->left->setContentsMargins(10,10,10,10); + + // Title + ui->labelTitle->setText(tr("Backup Wallet ")); + ui->labelTitle->setProperty("cssClass", "text-title-screen"); + + ui->labelTitle_2->setText(tr("Change Wallet Passphrase")); + ui->labelTitle_2->setProperty("cssClass", "text-title-screen"); + ui->labelDivider->setProperty("cssClass", "container-divider"); + + // Subtitle + ui->labelSubtitle1->setText(tr("Keep your wallet safe doing regular backups, store your backup file externally.\nThis option creates a wallet.dat file that can be used to recover your whole balance (transactions and addresses) from another device.")); + ui->labelSubtitle1->setProperty("cssClass", "text-subtitle"); + + ui->labelSubtitle_2->setText(tr("Change your wallet encryption passphrase for another one that you like. This will decrypt and encrypt your whole data under the new passphrase.\nRemember to write it down to not lose access to your funds.")); + ui->labelSubtitle_2->setProperty("cssClass", "text-subtitle"); + + // Location + ui->labelSubtitleLocation->setText(tr("Where")); + ui->labelSubtitleLocation->setProperty("cssClass", "text-title"); + + ui->pushButtonDocuments->setText(tr("Set a folder location")); + ui->pushButtonDocuments->setProperty("cssClass", "btn-edit-primary-folder"); + setShadow(ui->pushButtonDocuments); + + // Buttons + ui->pushButtonSave->setText(tr("Backup")); + setCssBtnPrimary(ui->pushButtonSave); + + ui->pushButtonSave_2->setText(tr("Change Passphrase")); + setCssBtnPrimary(ui->pushButtonSave_2); + + connect(ui->pushButtonSave, SIGNAL(clicked()), this, SLOT(backupWallet())); + connect(ui->pushButtonDocuments, SIGNAL(clicked()), this, SLOT(selectFileOutput())); + connect(ui->pushButtonSave_2, SIGNAL(clicked()), this, SLOT(changePassphrase())); +} + +void SettingsBackupWallet::selectFileOutput(){ + QString filenameRet = GUIUtil::getSaveFileName(this, + tr("Backup Wallet"), QString(), + tr("Wallet Data (*.dat)"), NULL); + + if (!filenameRet.isEmpty()) { + filename = filenameRet; + ui->pushButtonDocuments->setText(filename); + } +} + +void SettingsBackupWallet::backupWallet(){ + if(walletModel && !filename.isEmpty()) { + inform(walletModel->backupWallet(filename) ? tr("Backup created") : tr("Backup creation failed")); + filename = QString(); + ui->pushButtonDocuments->setText(tr("Set a folder location")); + } else { + inform(tr("Please select a folder to export the backup first.")); + } +} + +void SettingsBackupWallet::changePassphrase(){ + showHideOp(true); + AskPassphraseDialog *dlg = nullptr; + if (walletModel->getEncryptionStatus() == WalletModel::Unencrypted) { + dlg = new AskPassphraseDialog(AskPassphraseDialog::Mode::ChangePass, window, + walletModel, AskPassphraseDialog::Context::ChangePass); + } else { + dlg = new AskPassphraseDialog(AskPassphraseDialog::Mode::Encrypt, window, + walletModel, AskPassphraseDialog::Context::Encrypt); + } + dlg->adjustSize(); + emit execDialog(dlg); + dlg->deleteLater(); +} + +SettingsBackupWallet::~SettingsBackupWallet(){ + delete ui; +} diff --git a/src/qt/pivx/settings/settingsbackupwallet.h b/src/qt/pivx/settings/settingsbackupwallet.h new file mode 100644 index 000000000000..c7aea3fe7f85 --- /dev/null +++ b/src/qt/pivx/settings/settingsbackupwallet.h @@ -0,0 +1,33 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSBACKUPWALLET_H +#define SETTINGSBACKUPWALLET_H + +#include +#include "qt/pivx/pwidget.h" + +namespace Ui { +class SettingsBackupWallet; +} + +class SettingsBackupWallet : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsBackupWallet(PIVXGUI* _window, QWidget *parent = nullptr); + ~SettingsBackupWallet(); + +private slots: + void backupWallet(); + void selectFileOutput(); + void changePassphrase(); + +private: + Ui::SettingsBackupWallet *ui; + QString filename; +}; + +#endif // SETTINGSBACKUPWALLET_H diff --git a/src/qt/pivx/settings/settingsbittoolwidget.cpp b/src/qt/pivx/settings/settingsbittoolwidget.cpp new file mode 100644 index 000000000000..fb89b6383b32 --- /dev/null +++ b/src/qt/pivx/settings/settingsbittoolwidget.cpp @@ -0,0 +1,344 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingsbittoolwidget.h" +#include "qt/pivx/settings/forms/ui_settingsbittoolwidget.h" +#include "qt/pivx/qtutils.h" + +#include "guiutil.h" +#include "walletmodel.h" + +#include "base58.h" +#include "bip38.h" +#include "init.h" +#include "wallet/wallet.h" +#include "askpassphrasedialog.h" + +#include +#include + + +SettingsBitToolWidget::SettingsBitToolWidget(PIVXGUI* _window, QWidget *parent) : + PWidget(_window, parent), + ui(new Ui::SettingsBitToolWidget) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + /* Containers */ + setCssProperty(ui->left, "container"); + ui->left->setContentsMargins(10,10,10,10); + + /* Title */ + ui->labelTitle->setText(tr("BIP38 Tool")); + setCssTitleScreen(ui->labelTitle); + + //Button Group + ui->pushLeft->setText(tr("Encrypt")); + setCssProperty(ui->pushLeft, "btn-check-left"); + ui->pushRight->setText(tr("Decrypt")); + setCssProperty(ui->pushRight, "btn-check-right"); + ui->pushLeft->setChecked(true); + + // Subtitle + ui->labelSubtitle1->setText("Encrypt your PIVX addresses (key pair actually) using BIP38 encryption.\nUsing this mechanism you can share your keys without middle-man risk, only need to store your passphrase safely."); + setCssSubtitleScreen(ui->labelSubtitle1); + + // Key + ui->labelSubtitleKey->setText(tr("Encrypted key")); + setCssProperty(ui->labelSubtitleKey, "text-title"); + ui->lineEditKey->setPlaceholderText(tr("Enter a encrypted key")); + initCssEditLine(ui->lineEditKey); + + // Passphrase + ui->labelSubtitlePassphrase->setText(tr("Passphrase")); + setCssProperty(ui->labelSubtitlePassphrase, "text-title"); + + ui->lineEditPassphrase->setPlaceholderText(tr("Enter a passphrase ")); + initCssEditLine(ui->lineEditPassphrase); + + // Decrypt controls + ui->labelSubtitleDecryptResult->setText(tr("Decrypted address result")); + setCssProperty(ui->labelSubtitleDecryptResult, "text-title"); + ui->lineEditDecryptResult->setPlaceholderText(tr("Decrypted Address")); + ui->lineEditDecryptResult->setAttribute(Qt::WA_MacShowFocusRect, 0); + ui->lineEditDecryptResult->setReadOnly(true); + initCssEditLine(ui->lineEditDecryptResult); + + // Buttons + ui->pushButtonDecrypt->setText(tr("DECRYPT KEY")); + setCssBtnPrimary(ui->pushButtonDecrypt); + + ui->pushButtonImport->setText(tr("Import Address")); + setCssProperty(ui->pushButtonImport, "btn-text-primary"); + + connect(ui->pushLeft, &QPushButton::clicked, [this](){onEncryptSelected(true);}); + connect(ui->pushRight, &QPushButton::clicked, [this](){onEncryptSelected(false);}); + + + // Encrypt + + // Address + ui->labelSubtitleAddress->setText(tr("Enter a PIVX address")); + setCssProperty(ui->labelSubtitleAddress, "text-title"); + + ui->addressIn_ENC->setPlaceholderText(tr("Add address")); + setCssProperty(ui->addressIn_ENC, "edit-primary-multi-book"); + ui->addressIn_ENC->setAttribute(Qt::WA_MacShowFocusRect, 0); + setShadow(ui->addressIn_ENC); + + // Message + ui->labelSubtitleMessage->setText(tr("Passphrase")); + setCssProperty(ui->labelSubtitleMessage, "text-title"); + + setCssProperty(ui->passphraseIn_ENC, "edit-primary"); + ui->passphraseIn_ENC->setPlaceholderText(tr("Write a message")); + setCssProperty(ui->passphraseIn_ENC,"edit-primary"); + setShadow(ui->passphraseIn_ENC); + ui->passphraseIn_ENC->setAttribute(Qt::WA_MacShowFocusRect, 0); + + ui->labelSubtitleEncryptedKey->setText(tr("Encrypted Key")); + setCssProperty(ui->labelSubtitleEncryptedKey, "text-title"); + ui->encryptedKeyOut_ENC->setPlaceholderText(tr("Encrypted key")); + ui->encryptedKeyOut_ENC->setAttribute(Qt::WA_MacShowFocusRect, 0); + ui->encryptedKeyOut_ENC->setReadOnly(true); + initCssEditLine(ui->encryptedKeyOut_ENC); + + btnContact = ui->addressIn_ENC->addAction(QIcon("://ic-contact-arrow-down"), QLineEdit::TrailingPosition); + ui->pushButtonEncrypt->setText(tr("ENCRYPT")); + ui->pushButtonClear->setText(tr("CLEAR ALL")); + ui->pushButtonDecryptClear->setText(tr("CLEAR")); + setCssBtnPrimary(ui->pushButtonEncrypt); + setCssBtnSecondary(ui->pushButtonClear); + setCssBtnSecondary(ui->pushButtonDecryptClear); + + ui->statusLabel_ENC->setStyleSheet("QLabel { color: transparent; }"); + ui->statusLabel_DEC->setStyleSheet("QLabel { color: transparent; }"); + + connect(ui->pushButtonEncrypt, &QPushButton::clicked, this, &SettingsBitToolWidget::onEncryptKeyButtonENCClicked); + connect(ui->pushButtonDecrypt, SIGNAL(clicked()), this, SLOT(onDecryptClicked())); + connect(ui->pushButtonImport, SIGNAL(clicked()), this, SLOT(importAddressFromDecKey())); + connect(btnContact, SIGNAL(triggered()), this, SLOT(onAddressesClicked())); + connect(ui->pushButtonClear, &QPushButton::clicked, this, &SettingsBitToolWidget::onClearAll); + connect(ui->pushButtonDecryptClear, SIGNAL(clicked()), this, SLOT(onClearDecrypt())); +} + +void SettingsBitToolWidget::setAddress_ENC(const QString& address){ + ui->addressIn_ENC->setText(address); + ui->passphraseIn_ENC->setFocus(); +} + +void SettingsBitToolWidget::onEncryptSelected(bool isEncr) { + ui->stackedWidget->setCurrentIndex(isEncr); +} + +QString specialChar = "\"@!#$%&'()*+,-./:;<=>?`{|}~^_[]\\"; +QString validChar = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + specialChar; +bool isValidPassphrase(QString strPassphrase, QString& strInvalid) +{ + for (int i = 0; i < strPassphrase.size(); i++) { + if (!validChar.contains(strPassphrase[i], Qt::CaseSensitive)) { + if (QString("\"'").contains(strPassphrase[i])) + continue; + + strInvalid = strPassphrase[i]; + return false; + } + } + + return true; +} + +void SettingsBitToolWidget::onEncryptKeyButtonENCClicked() +{ + if (!walletModel) + return; + + QString qstrPassphrase = ui->passphraseIn_ENC->text(); + QString strInvalid; + if (!isValidPassphrase(qstrPassphrase, strInvalid)) { + ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_ENC->setText(tr("The entered passphrase is invalid. ") + strInvalid + QString(" is not valid") + QString(" ") + tr("Allowed: 0-9,a-z,A-Z,") + specialChar); + return; + } + + CBitcoinAddress addr(ui->addressIn_ENC->text().toStdString()); + if (!addr.IsValid()) { + ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_ENC->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); + return; + } + + CKeyID keyID; + if (!addr.GetKeyID(keyID)) { + //ui->addressIn_ENC->setValid(false); + ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_ENC->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); + return; + } + + WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::BIP_38, true)); + if (!ctx.isValid()) { + ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_ENC->setText(tr("Wallet unlock was cancelled.")); + return; + } + + CKey key; + if (!pwalletMain->GetKey(keyID, key)) { + ui->statusLabel_ENC->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_ENC->setText(tr("Private key for the entered address is not available.")); + return; + } + + std::string encryptedKey = BIP38_Encrypt(addr.ToString(), qstrPassphrase.toStdString(), key.GetPrivKey_256(), key.IsCompressed()); + ui->encryptedKeyOut_ENC->setText(QString::fromStdString(encryptedKey)); + + ui->statusLabel_ENC->setStyleSheet("QLabel { color: green; }"); + ui->statusLabel_ENC->setText(QString("") + tr("Address encrypted.") + QString("")); +} + +void SettingsBitToolWidget::onClearAll(){ + ui->addressIn_ENC->clear(); + ui->passphraseIn_ENC->clear(); + ui->encryptedKeyOut_ENC->clear(); + ui->statusLabel_ENC->clear(); + ui->addressIn_ENC->setFocus(); +} + +void SettingsBitToolWidget::onAddressesClicked(){ + int addressSize = walletModel->getAddressTableModel()->sizeRecv(); + if(addressSize == 0) { + inform(tr("No addresses available, you can go to the receive screen and add some there!")); + return; + } + + int height = (addressSize <= 2) ? ui->addressIn_ENC->height() * ( 2 * (addressSize + 1 )) : ui->addressIn_ENC->height() * 4; + int width = ui->containerAddressEnc->width(); + + if(!menuContacts){ + menuContacts = new ContactsDropdown( + width, + height, + this + ); + menuContacts->setWalletModel(walletModel, AddressTableModel::Receive); + connect(menuContacts, &ContactsDropdown::contactSelected, [this](QString address, QString label){ + setAddress_ENC(address); + }); + + } + + if(menuContacts->isVisible()){ + menuContacts->hide(); + return; + } + + menuContacts->resizeList(width, height); + menuContacts->setStyleSheet(this->styleSheet()); + menuContacts->adjustSize(); + + QPoint pos = ui->containerAddressEnc->rect().bottomLeft(); + pos.setY(pos.y() + ui->containerAddressEnc->height()); + pos.setX(pos.x() + 10); + menuContacts->move(pos); + menuContacts->show(); +} + +void SettingsBitToolWidget::resizeMenu(){ + if(menuContacts && menuContacts->isVisible()){ + int width = ui->containerAddress->width(); + menuContacts->resizeList(width, menuContacts->height()); + menuContacts->resize(width, menuContacts->height()); + QPoint pos = ui->containerAddressEnc->rect().bottomLeft(); + pos.setY(pos.y() + ui->containerAddressEnc->height()); + pos.setX(pos.x() + 10); + menuContacts->move(pos); + } +} + +void SettingsBitToolWidget::onClearDecrypt(){ + ui->lineEditKey->clear(); + ui->lineEditDecryptResult->clear(); + ui->lineEditPassphrase->clear(); + key = CKey(); +} + +void SettingsBitToolWidget::onDecryptClicked(){ + std::string strPassphrase = ui->lineEditPassphrase->text().toStdString(); + std::string strKey = ui->lineEditKey->text().toStdString(); + + uint256 privKey; + bool fCompressed; + if (!BIP38_Decrypt(strPassphrase, strKey, privKey, fCompressed)) { + ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_DEC->setText(tr("Failed to decrypt.") + QString(" ") + tr("Please check the key and passphrase and try again.")); + return; + } + + key.Set(privKey.begin(), privKey.end(), fCompressed); + CPubKey pubKey = key.GetPubKey(); + CBitcoinAddress address(pubKey.GetID()); + ui->lineEditDecryptResult->setText(QString::fromStdString(address.ToString())); +} + +void SettingsBitToolWidget::importAddressFromDecKey(){ + WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::BIP_38, true)); + if (!ctx.isValid()) { + ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_DEC->setText(tr("Wallet unlock was cancelled.")); + return; + } + + CBitcoinAddress address(ui->lineEditDecryptResult->text().toStdString()); + CPubKey pubkey = key.GetPubKey(); + + if (!address.IsValid() || !key.IsValid() || CBitcoinAddress(pubkey.GetID()).ToString() != address.ToString()) { + ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_DEC->setText(tr("Data Not Valid.") + QString(" ") + tr("Please try again.")); + return; + } + + CKeyID vchAddress = pubkey.GetID(); + { + ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_DEC->setText(tr("Please wait while key is imported")); + + pwalletMain->MarkDirty(); + pwalletMain->SetAddressBook(vchAddress, "", "receive"); + + // Don't throw error in case a key is already there + if (pwalletMain->HaveKey(vchAddress)) { + ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_DEC->setText(tr("Cannot import address, key already held by the wallet")); + return; + } + + pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; + + if (!pwalletMain->AddKeyPubKey(key, pubkey)) { + ui->statusLabel_DEC->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_DEC->setText(tr("Error adding key to the wallet")); + return; + } + + // whenever a key is imported, we need to scan the whole chain + pwalletMain->nTimeFirstKey = 1; // 0 would be considered 'no value' + pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); + } + + ui->statusLabel_DEC->setStyleSheet("QLabel { color: green; }"); + ui->statusLabel_DEC->setText(tr("Successfully added pivate key to the wallet")); +} + +void SettingsBitToolWidget::resizeEvent(QResizeEvent *event){ + resizeMenu(); + QWidget::resizeEvent(event); +} + +SettingsBitToolWidget::~SettingsBitToolWidget() +{ + delete ui; +} diff --git a/src/qt/pivx/settings/settingsbittoolwidget.h b/src/qt/pivx/settings/settingsbittoolwidget.h new file mode 100644 index 000000000000..3c4178aa01db --- /dev/null +++ b/src/qt/pivx/settings/settingsbittoolwidget.h @@ -0,0 +1,47 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSBITTOOLWIDGET_H +#define SETTINGSBITTOOLWIDGET_H + +#include +#include "qt/pivx/pwidget.h" +#include "qt/pivx/contactsdropdown.h" +#include "key.h" + +namespace Ui { +class SettingsBitToolWidget; +} + +class SettingsBitToolWidget : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsBitToolWidget(PIVXGUI* _window, QWidget *parent = nullptr); + ~SettingsBitToolWidget(); +protected: + void resizeEvent(QResizeEvent *event) override; +public slots: + void onEncryptSelected(bool isEncr); + void setAddress_ENC(const QString& address); + void onEncryptKeyButtonENCClicked(); + void onClearAll(); + void onClearDecrypt(); + void onAddressesClicked(); + void onDecryptClicked(); + void importAddressFromDecKey(); + +private: + Ui::SettingsBitToolWidget *ui; + QAction *btnContact; + ContactsDropdown *menuContacts = nullptr; + + // Cached key + CKey key; + + void resizeMenu(); +}; + +#endif // SETTINGSBITTOOLWIDGET_H diff --git a/src/qt/pivx/settings/settingsconsolewidget.cpp b/src/qt/pivx/settings/settingsconsolewidget.cpp new file mode 100644 index 000000000000..ead9a5a13b90 --- /dev/null +++ b/src/qt/pivx/settings/settingsconsolewidget.cpp @@ -0,0 +1,536 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingsconsolewidget.h" +#include "qt/pivx/settings/forms/ui_settingsconsolewidget.h" +#include "QGraphicsDropShadowEffect" +#include "qt/pivx/qtutils.h" + +#include "clientmodel.h" +#include "guiutil.h" + +#include "chainparams.h" +#include "main.h" +#include "rpc/client.h" +#include "rpc/server.h" +#include "util.h" +#ifdef ENABLE_WALLET +#include "wallet/wallet.h" +#endif // ENABLE_WALLET + +#include + +#include + +#ifdef ENABLE_WALLET +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qt/pivx/qtutils.h" +#include "utilitydialog.h" + +const int CONSOLE_HISTORY = 50; + +const struct { + const char* url; + const char* source; +} ICON_MAPPING[] = { + {"cmd-request", ":/icons/ic-transaction-received"}, + {"cmd-reply", ":/icons/ic-transaction-sent"}, + {"cmd-error", ":/icons/ic-transaction-sent"}, + {"misc", ":/icons/ic-transaction-staked"}, + {NULL, NULL}}; + +/* Object for executing console RPC commands in a separate thread. +*/ +class RPCExecutor : public QObject +{ + Q_OBJECT + +public slots: + void requestCommand(const QString& command); + +signals: + void reply(int category, const QString& command); +}; + +/** Class for handling RPC timers + * (used for e.g. re-locking the wallet after a timeout) + */ +class QtRPCTimerBase: public QObject, public RPCTimerBase +{ + Q_OBJECT +public: + QtRPCTimerBase(boost::function& func, int64_t millis): + func(func) + { + timer.setSingleShot(true); + connect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); + timer.start(millis); + } + ~QtRPCTimerBase() {} +private slots: + void timeout() { func(); } +private: + QTimer timer; + boost::function func; +}; + +class QtRPCTimerInterface: public RPCTimerInterface +{ +public: + ~QtRPCTimerInterface() {} + const char *Name() { return "Qt"; } + RPCTimerBase* NewTimer(boost::function& func, int64_t millis) + { + return new QtRPCTimerBase(func, millis); + } +}; + +#include "qt/pivx/settings/moc_settingsconsolewidget.cpp" + +/** + * Split shell command line into a list of arguments. Aims to emulate \c bash and friends. + * + * - Arguments are delimited with whitespace + * - Extra whitespace at the beginning and end and between arguments will be ignored + * - Text can be "double" or 'single' quoted + * - The backslash \c \ is used as escape character + * - Outside quotes, any character can be escaped + * - Within double quotes, only escape \c " and backslashes before a \c " or another backslash + * - Within single quotes, no escaping is possible and no special interpretation takes place + * + * @param[out] args Parsed arguments will be appended to this list + * @param[in] strCommand Command line to split + */ +bool parseCommandLineSettings(std::vector& args, const std::string& strCommand) +{ + enum CmdParseState { + STATE_EATING_SPACES, + STATE_ARGUMENT, + STATE_SINGLEQUOTED, + STATE_DOUBLEQUOTED, + STATE_ESCAPE_OUTER, + STATE_ESCAPE_DOUBLEQUOTED + } state = STATE_EATING_SPACES; + std::string curarg; + foreach (char ch, strCommand) { + switch (state) { + case STATE_ARGUMENT: // In or after argument + case STATE_EATING_SPACES: // Handle runs of whitespace + switch (ch) { + case '"': + state = STATE_DOUBLEQUOTED; + break; + case '\'': + state = STATE_SINGLEQUOTED; + break; + case '\\': + state = STATE_ESCAPE_OUTER; + break; + case ' ': + case '\n': + case '\t': + if (state == STATE_ARGUMENT) // Space ends argument + { + args.push_back(curarg); + curarg.clear(); + } + state = STATE_EATING_SPACES; + break; + default: + curarg += ch; + state = STATE_ARGUMENT; + } + break; + case STATE_SINGLEQUOTED: // Single-quoted string + switch (ch) { + case '\'': + state = STATE_ARGUMENT; + break; + default: + curarg += ch; + } + break; + case STATE_DOUBLEQUOTED: // Double-quoted string + switch (ch) { + case '"': + state = STATE_ARGUMENT; + break; + case '\\': + state = STATE_ESCAPE_DOUBLEQUOTED; + break; + default: + curarg += ch; + } + break; + case STATE_ESCAPE_OUTER: // '\' outside quotes + curarg += ch; + state = STATE_ARGUMENT; + break; + case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text + if (ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself + curarg += ch; + state = STATE_DOUBLEQUOTED; + break; + } + } + switch (state) // final state + { + case STATE_EATING_SPACES: + return true; + case STATE_ARGUMENT: + args.push_back(curarg); + return true; + default: // ERROR to end in one of the other states + return false; + } +} + +void RPCExecutor::requestCommand(const QString& command) +{ + std::vector args; + if (!parseCommandLineSettings(args, command.toStdString())) { + emit reply(SettingsConsoleWidget::CMD_ERROR, QString("Parse error: unbalanced ' or \"")); + return; + } + if (args.empty()) + return; // Nothing to do + try { + std::string strPrint; + // Convert argument list to JSON objects in method-dependent way, + // and pass it along with the method name to the dispatcher. + UniValue result = tableRPC.execute( + args[0], + RPCConvertValues(args[0], std::vector(args.begin() + 1, args.end()))); + + // Format result reply + if (result.isNull()) + strPrint = ""; + else if (result.isStr()) + strPrint = result.get_str(); + else + strPrint = result.write(2); + + emit reply(SettingsConsoleWidget::CMD_REPLY, QString::fromStdString(strPrint)); + } catch (UniValue& objError) { + try // Nice formatting for standard-format error + { + int code = find_value(objError, "code").get_int(); + std::string message = find_value(objError, "message").get_str(); + emit reply(SettingsConsoleWidget::CMD_ERROR, QString::fromStdString(message) + " (code " + QString::number(code) + ")"); + } catch (std::runtime_error&) // raised when converting to invalid type, i.e. missing code or message + { // Show raw JSON object + emit reply(SettingsConsoleWidget::CMD_ERROR, QString::fromStdString(objError.write())); + } + } catch (std::exception& e) { + emit reply(SettingsConsoleWidget::CMD_ERROR, QString("Error: ") + QString::fromStdString(e.what())); + } +} + +SettingsConsoleWidget::SettingsConsoleWidget(PIVXGUI* _window, QWidget *parent) : + PWidget(_window,parent), + ui(new Ui::SettingsConsoleWidget) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + // Containers + ui->left->setProperty("cssClass", "container"); + ui->left->setContentsMargins(10,10,10,10); + ui->messagesWidget->setProperty("cssClass", "container"); + + // Title + ui->labelTitle->setText(tr("Console")); + setCssTitleScreen(ui->labelTitle); + + // Console container + ui->consoleWidget->setProperty("cssClass", "container-square"); + setShadow(ui->consoleWidget); + + // Edit + ui->lineEdit->setPlaceholderText(tr("Console input")); + initCssEditLine(ui->lineEdit); + + // Buttons + ui->pushButton->setProperty("cssClass", "ic-arrow"); + ui->pushButtonCommandOptions->setText(tr("Command Line Options ")); + ui->pushButtonOpenDebug->setText(tr("Open Debug File")); + setCssBtnSecondary(ui->pushButtonOpenDebug); + setCssBtnSecondary(ui->pushButtonCommandOptions); + + connect(ui->pushButtonOpenDebug, &QPushButton::clicked, [this](){ + if(!GUIUtil::openDebugLogfile()){ + inform(tr("Cannot open debug file.\nVerify that you have installed a predetermined text editor.")); + } + }); + connect(ui->pushButtonCommandOptions, SIGNAL(clicked()), this, SLOT(onCommandsClicked())); + + // Install event filter for up and down arrow + ui->lineEdit->installEventFilter(this); + ui->messagesWidget->installEventFilter(this); + + // Register RPC timer interface + rpcTimerInterface = new QtRPCTimerInterface(); + // avoid accidentally overwriting an existing, non QTThread + // based timer interface + RPCSetTimerInterfaceIfUnset(rpcTimerInterface); + + startExecutor(); + clear(); +} + +SettingsConsoleWidget::~SettingsConsoleWidget() +{ + GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this); + emit stopExecutor(); + RPCUnsetTimerInterface(rpcTimerInterface); + delete rpcTimerInterface; + delete ui; +} + + +bool SettingsConsoleWidget::eventFilter(QObject* obj, QEvent* event) +{ + if (event->type() == QEvent::KeyPress) // Special key handling + { + QKeyEvent* keyevt = static_cast(event); + int key = keyevt->key(); + Qt::KeyboardModifiers mod = keyevt->modifiers(); + switch (key) { + case Qt::Key_Up: + if (obj == ui->lineEdit) { + browseHistory(-1); + return true; + } + break; + case Qt::Key_Down: + if (obj == ui->lineEdit) { + browseHistory(1); + return true; + } + break; + case Qt::Key_PageUp: /* pass paging keys to messages widget */ + case Qt::Key_PageDown: + if (obj == ui->lineEdit) { + QApplication::postEvent(ui->messagesWidget, new QKeyEvent(*keyevt)); + return true; + } + break; + case Qt::Key_Return: + case Qt::Key_Enter: + // forward these events to lineEdit + if(obj == autoCompleter->popup()) { + QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt)); + return true; + } + break; + default: + // Typing in messages widget brings focus to line edit, and redirects key there + // Exclude most combinations and keys that emit no text, except paste shortcuts + if (obj == ui->messagesWidget && ((!mod && !keyevt->text().isEmpty() && key != Qt::Key_Tab) || + ((mod & Qt::ControlModifier) && key == Qt::Key_V) || + ((mod & Qt::ShiftModifier) && key == Qt::Key_Insert))) { + ui->lineEdit->setFocus(); + QApplication::postEvent(ui->lineEdit, new QKeyEvent(*keyevt)); + return true; + } + } + } + return QWidget::eventFilter(obj, event); +} + +void SettingsConsoleWidget::loadClientModel() { + if (clientModel){ + + //Setup autocomplete and attach it + QStringList wordList; + std::vector commandList = tableRPC.listCommands(); + for (size_t i = 0; i < commandList.size(); ++i) + { + wordList << commandList[i].c_str(); + } + + autoCompleter = new QCompleter(wordList, this); + ui->lineEdit->setCompleter(autoCompleter); + + // clear the lineEdit after activating from QCompleter + autoCompleter->popup()->installEventFilter(this); + } +} + +static QString categoryClass(int category) +{ + switch (category) { + case SettingsConsoleWidget::CMD_REQUEST: + return "cmd-request"; + case SettingsConsoleWidget::CMD_REPLY: + return "cmd-reply"; + case SettingsConsoleWidget::CMD_ERROR: + return "cmd-error"; + default: + return "misc"; + } +} + +void SettingsConsoleWidget::clear(){ + ui->messagesWidget->clear(); + history.clear(); + historyPtr = 0; + ui->lineEdit->clear(); + ui->lineEdit->setFocus(); + + // Add smoothly scaled icon images. + // (when using width/height on an img, Qt uses nearest instead of linear interpolation) + for (int i = 0; ICON_MAPPING[i].url; ++i) { + ui->messagesWidget->document()->addResource( + QTextDocument::ImageResource, + QUrl(ICON_MAPPING[i].url), + QImage(ICON_MAPPING[i].source)); + } + + QString theme; + changeTheme(isLightTheme(), theme); + +#ifdef Q_OS_MAC + QString clsKey = "(⌘)-L"; +#else + QString clsKey = "Ctrl-L"; +#endif + + message(CMD_REPLY, (tr("Welcome to the PIVX RPC console.") + "
" + + tr("Use up and down arrows to navigate history, and %1 to clear screen.").arg(""+clsKey+"") + "
" + + tr("Type help for an overview of available commands.") + + "

" + + tr("WARNING: Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramifications of a command.") + + "
"), + true); +} + +void SettingsConsoleWidget::message(int category, const QString& message, bool html) +{ + QTime time = QTime::currentTime(); + QString timeString = time.toString(); + QString out; + out += ""; + out += ""; + out += "
" + timeString + ""; + if (html) + out += message; + else + out += GUIUtil::HtmlEscape(message, true); + out += "
"; + ui->messagesWidget->append(out); +} + +void SettingsConsoleWidget::on_lineEdit_returnPressed() +{ + QString cmd = ui->lineEdit->text(); + ui->lineEdit->clear(); + + if (!cmd.isEmpty()) { + message(CMD_REQUEST, cmd); + emit cmdCommandRequest(cmd); + // Remove command, if already in history + history.removeOne(cmd); + // Append command to history + history.append(cmd); + // Enforce maximum history size + while (history.size() > CONSOLE_HISTORY) + history.removeFirst(); + // Set pointer to end of history + historyPtr = history.size(); + // Scroll console view to end + scrollToEnd(); + } +} + + +void SettingsConsoleWidget::browseHistory(int offset) +{ + historyPtr += offset; + if (historyPtr < 0) + historyPtr = 0; + if (historyPtr > history.size()) + historyPtr = history.size(); + QString cmd; + if (historyPtr < history.size()) + cmd = history.at(historyPtr); + ui->lineEdit->setText(cmd); +} + +void SettingsConsoleWidget::startExecutor() +{ + QThread* thread = new QThread; + RPCExecutor* executor = new RPCExecutor(); + executor->moveToThread(thread); + + // Replies from executor object must go to this object + connect(executor, SIGNAL(reply(int, QString)), this, SLOT(message(int, QString))); + // Requests from this object must go to executor + connect(this, &SettingsConsoleWidget::cmdCommandRequest, executor, &RPCExecutor::requestCommand); + + // On stopExecutor signal + // - queue executor for deletion (in execution thread) + // - quit the Qt event loop in the execution thread + connect(this, SIGNAL(stopExecutor()), executor, SLOT(deleteLater())); + connect(this, SIGNAL(stopExecutor()), thread, SLOT(quit())); + // Queue the thread for deletion (in this thread) when it is finished + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + // Default implementation of QThread::run() simply spins up an event loop in the thread, + // which is what we want. + thread->start(); +} + +void SettingsConsoleWidget::scrollToEnd() +{ + QScrollBar* scrollbar = ui->messagesWidget->verticalScrollBar(); + scrollbar->setValue(scrollbar->maximum()); +} + + +void SettingsConsoleWidget::changeTheme(bool isLightTheme, QString &theme) +{ + // Set default style sheet + if (isLightTheme) { + ui->messagesWidget->document()->setDefaultStyleSheet( + "table { color: #707070; }" + "td.time { color: #808080; padding-top: 3px; } " + "td.message { color: #707070;font-family: Courier, Courier New, Lucida Console, monospace; font-size: 12px; } " // Todo: Remove fixed font-size + "td.cmd-request { color: #006060; } " + "td.cmd-error { color: red; } " + ".secwarning { color: red; }" + "b { color: #707070; } "); + } else { + ui->messagesWidget->document()->setDefaultStyleSheet( + "table { color: #FFFFFF; }" + "td.time { color: #808080; padding-top: 3px; } " + "td.message { color: #FFFFFF;font-family: Courier, Courier New, Lucida Console, monospace; font-size: 12px; } " // Todo: Remove fixed font-size + "td.cmd-request { color: #006060; } " + "td.cmd-error { color: red; } " + ".secwarning { color: red; }" + "b { color: #FFFFFF; } "); + } + updateStyle(ui->messagesWidget); +} + +void SettingsConsoleWidget::onCommandsClicked() { + if (!clientModel) + return; + + HelpMessageDialog dlg(this, false); + dlg.exec(); + +} diff --git a/src/qt/pivx/settings/settingsconsolewidget.h b/src/qt/pivx/settings/settingsconsolewidget.h new file mode 100644 index 000000000000..861220dc630f --- /dev/null +++ b/src/qt/pivx/settings/settingsconsolewidget.h @@ -0,0 +1,80 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSCONSOLEWIDGET_H +#define SETTINGSCONSOLEWIDGET_H + +#include +#include "qt/pivx/pwidget.h" +#include "guiutil.h" +#include "net.h" +#include + +class ClientModel; +class RPCTimerInterface; + +namespace Ui { +class SettingsConsoleWidget; +} + +QT_BEGIN_NAMESPACE +class QMenu; +class QItemSelection; +QT_END_NAMESPACE + +class SettingsConsoleWidget : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsConsoleWidget(PIVXGUI* _window, QWidget *parent = nullptr); + ~SettingsConsoleWidget(); + + void loadClientModel() override; + + enum MessageClass { + MC_ERROR, + MC_DEBUG, + CMD_REQUEST, + CMD_REPLY, + CMD_ERROR + }; + +public slots: + void clear(); + void message(int category, const QString& message, bool html = false); + /** Go forward or back in history */ + void browseHistory(int offset); + /** Scroll console view to end */ + void scrollToEnd(); + void onCommandsClicked(); + +protected: + virtual bool eventFilter(QObject* obj, QEvent* event) override; + +protected slots: + void changeTheme(bool isLightTheme, QString &theme) override; + +signals: + // For RPC command executor + void stopExecutor(); + void cmdCommandRequest(const QString& command); + +private: + Ui::SettingsConsoleWidget *ui; + + QStringList history; + int historyPtr; + RPCTimerInterface *rpcTimerInterface; + QCompleter *autoCompleter; + + void startExecutor(); + +private slots: + void on_lineEdit_returnPressed(); + + +}; + +#endif // SETTINGSCONSOLEWIDGET_H diff --git a/src/qt/pivx/settings/settingsdisplayoptionswidget.cpp b/src/qt/pivx/settings/settingsdisplayoptionswidget.cpp new file mode 100644 index 000000000000..4d6ba5569558 --- /dev/null +++ b/src/qt/pivx/settings/settingsdisplayoptionswidget.cpp @@ -0,0 +1,148 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingsdisplayoptionswidget.h" +#include "qt/pivx/settings/forms/ui_settingsdisplayoptionswidget.h" +#include +#include +#include +#include "guiutil.h" +#include "clientmodel.h" +#include "optionsmodel.h" +#include "bitcoinunits.h" +#include "qt/pivx/qtutils.h" + +SettingsDisplayOptionsWidget::SettingsDisplayOptionsWidget(PIVXGUI* _window, QWidget *parent) : + PWidget(_window,parent), + ui(new Ui::SettingsDisplayOptionsWidget) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + // Containers + ui->left->setProperty("cssClass", "container"); + ui->left->setContentsMargins(10,10,10,10); + + // Title + ui->labelTitle->setText(tr("Display")); + setCssTitleScreen(ui->labelTitle); + + // Subtitle + ui->labelSubtitle1->setText(tr("Customize the display view options")); + setCssSubtitleScreen(ui->labelSubtitle1); + + ui->labelTitleLanguage->setText(tr("Language")); + ui->labelTitleLanguage->setProperty("cssClass", "text-main-settings"); + + ui->labelTitleUnit->setText(tr("Unit to show amount")); + ui->labelTitleUnit->setProperty("cssClass", "text-main-settings"); + + ui->labelTitleDigits->setText(tr("Decimal digits")); + ui->labelTitleDigits->setProperty("cssClass", "text-main-settings"); + + ui->labelTitleUrl->setText(tr("Third party transactions URLs")); + ui->labelTitleUrl->setProperty("cssClass", "text-main-settings"); + + // Switch + ui->pushButtonSwitchBalance->setText(tr("Hide empty balances")); + ui->pushButtonSwitchBalance->setProperty("cssClass", "btn-switch"); + + // Combobox + ui->comboBoxLanguage->setProperty("cssClass", "btn-combo"); + ui->comboBoxLanguage->setView(new QListView()); + ui->comboBoxLanguage->setEditable(true); + QLineEdit* LanguageEdit = new QLineEdit(ui->comboBoxLanguage); + LanguageEdit->setReadOnly(true); + LanguageEdit->setAlignment(Qt::AlignRight); + ui->comboBoxLanguage->setLineEdit(LanguageEdit); + + ui->comboBoxUnit->setProperty("cssClass", "btn-combo"); + ui->comboBoxUnit->setView(new QListView()); + ui->comboBoxUnit->setModel(new BitcoinUnits(this)); + ui->comboBoxUnit->setModelColumn(Qt::DisplayRole); + ui->comboBoxUnit->setEditable(true); + QLineEdit* UnitEdit = new QLineEdit(ui->comboBoxUnit); + UnitEdit->setReadOnly(true); + UnitEdit->setAlignment(Qt::AlignRight); + ui->comboBoxUnit->setLineEdit(UnitEdit); + + ui->comboBoxDigits->setProperty("cssClass", "btn-combo-options"); + + ui->comboBoxDigits->setView(new QListView()); + ui->comboBoxDigits->setEditable(true); + QLineEdit* DigitsEdit = new QLineEdit(ui->comboBoxDigits); + DigitsEdit->setReadOnly(true); + DigitsEdit->setAlignment(Qt::AlignRight); + ui->comboBoxDigits->setLineEdit(DigitsEdit); + + /* Number of displayed decimal digits selector */ + QString digits; + for (int index = 2; index <= 8; index++) { + digits.setNum(index); + ui->comboBoxDigits->addItem(digits, digits); + } + + // Urls + ui->lineEditUrl->setPlaceholderText("e.g. https://example.com/tx/%s"); + initCssEditLine(ui->lineEditUrl); + + // Buttons + ui->pushButtonSave->setText(tr("SAVE")); + ui->pushButtonReset->setText(tr("Reset to default")); + setCssBtnPrimary(ui->pushButtonSave); + setCssBtnSecondary(ui->pushButtonReset); + setCssBtnSecondary(ui->pushButtonClean); + + initLanguages(); + connect(ui->pushButtonSave, SIGNAL(clicked()), parent, SLOT(onSaveOptionsClicked())); + connect(ui->pushButtonReset, SIGNAL(clicked()), this, SLOT(onResetClicked())); + connect(ui->pushButtonClean, SIGNAL(clicked()), parent, SLOT(onDiscardChanges())); +} + +void SettingsDisplayOptionsWidget::initLanguages(){ + /* Language selector */ + QDir translations(":translations"); + QString defaultStr = QString("(") + tr("default") + QString(")"); + ui->comboBoxLanguage->addItem(defaultStr, QVariant("")); + foreach (const QString& langStr, translations.entryList()) { + QLocale locale(langStr); + + /** check if the locale name consists of 2 parts (language_country) */ + if(langStr.contains("_")){ + /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */ + ui->comboBoxLanguage->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr)); + } + else{ + /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */ + ui->comboBoxLanguage->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr)); + } + } +} + +void SettingsDisplayOptionsWidget::onResetClicked() { + if (clientModel) { + OptionsModel *optionsModel = clientModel->getOptionsModel(); + QSettings settings; + optionsModel->setDisplayDefaultOptions(settings, true); + inform(tr("Options reset succeed")); + } +} + +void SettingsDisplayOptionsWidget::setMapper(QDataWidgetMapper *mapper){ + mapper->addMapping(ui->comboBoxDigits, OptionsModel::Digits); + mapper->addMapping(ui->comboBoxLanguage, OptionsModel::Language); + mapper->addMapping(ui->comboBoxUnit, OptionsModel::DisplayUnit); + mapper->addMapping(ui->pushButtonSwitchBalance, OptionsModel::HideZeroBalances); +} + +void SettingsDisplayOptionsWidget::loadClientModel(){ + if(clientModel) { + ui->comboBoxUnit->setCurrentIndex(this->clientModel->getOptionsModel()->getDisplayUnit()); + } +} + +SettingsDisplayOptionsWidget::~SettingsDisplayOptionsWidget(){ + delete ui; +} diff --git a/src/qt/pivx/settings/settingsdisplayoptionswidget.h b/src/qt/pivx/settings/settingsdisplayoptionswidget.h new file mode 100644 index 000000000000..f3852f99a6b8 --- /dev/null +++ b/src/qt/pivx/settings/settingsdisplayoptionswidget.h @@ -0,0 +1,35 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSDISPLAYOPTIONSWIDGET_H +#define SETTINGSDISPLAYOPTIONSWIDGET_H + +#include +#include +#include "qt/pivx/pwidget.h" + +namespace Ui { +class SettingsDisplayOptionsWidget; +} + +class SettingsDisplayOptionsWidget : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsDisplayOptionsWidget(PIVXGUI* _window = nullptr, QWidget *parent = nullptr); + ~SettingsDisplayOptionsWidget(); + + void setMapper(QDataWidgetMapper *mapper); + void initLanguages(); + void loadClientModel() override; + +public slots: + void onResetClicked(); + +private: + Ui::SettingsDisplayOptionsWidget *ui; +}; + +#endif // SETTINGSDISPLAYOPTIONSWIDGET_H diff --git a/src/qt/pivx/settings/settingsfaqwidget.cpp b/src/qt/pivx/settings/settingsfaqwidget.cpp new file mode 100644 index 000000000000..b7d518b1d4ed --- /dev/null +++ b/src/qt/pivx/settings/settingsfaqwidget.cpp @@ -0,0 +1,189 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingsfaqwidget.h" +#include "qt/pivx/settings/forms/ui_settingsfaqwidget.h" +#include +#include +#include "qt/pivx/qtutils.h" + +SettingsFaqWidget::SettingsFaqWidget(QWidget *parent) : + QDialog(parent), + ui(new Ui::SettingsFaqWidget) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + ui->labelTitle->setText(tr("Frequently Asked Questions")); + ui->labelWebLink->setText(tr("You can read more here")); + setCssProperty(ui->container, "container-welcome"); + setCssProperty(ui->labelTitle, "text-title-faq"); + setCssProperty(ui->labelWebLink, "text-content-white"); + + // Content + setCssProperty({ + ui->labelNumber1, + ui->labelNumber2, + ui->labelNumber3, + ui->labelNumber4, + ui->labelNumber5, + ui->labelNumber6, + ui->labelNumber7, + ui->labelNumber8, + ui->labelNumber9, + ui->labelNumber10 + }, "container-number-faq"); + + setCssProperty({ + ui->labelSubtitle1, + ui->labelSubtitle2, + ui->labelSubtitle3, + ui->labelSubtitle4, + ui->labelSubtitle5, + ui->labelSubtitle6, + ui->labelSubtitle7, + ui->labelSubtitle8, + ui->labelSubtitle9, + ui->labelSubtitle10 + }, "text-subtitle-faq"); + + + setCssProperty({ + ui->labelContent1, + ui->labelContent2, + ui->labelContent3, + ui->labelContent4, + ui->labelContent5, + ui->labelContent6, + ui->labelContent7, + ui->labelContent8, + ui->labelContent9, + ui->labelContent10 + }, "text-content-faq"); + + + setCssProperty({ + ui->pushButtonFaq1, + ui->pushButtonFaq2, + ui->pushButtonFaq3, + ui->pushButtonFaq4, + ui->pushButtonFaq5, + ui->pushButtonFaq6, + ui->pushButtonFaq7, + ui->pushButtonFaq8, + ui->pushButtonFaq9, + ui->pushButtonFaq10 + }, "btn-faq-options"); + + ui->labelContent3->setOpenExternalLinks(true); + ui->labelContent5->setOpenExternalLinks(true); + ui->labelContent8->setOpenExternalLinks(true); + + // Exit button + ui->pushButtonExit->setText(tr("Exit")); + setCssProperty(ui->pushButtonExit, "btn-faq-exit"); + + // Web Link + ui->pushButtonWebLink->setText("https://PIVX.org/"); + setCssProperty(ui->pushButtonWebLink, "btn-faq-web"); + setCssProperty(ui->containerButtons, "container-faq-buttons"); + + // Buttons + connect(ui->pushButtonExit, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->pushButtonFaq1, SIGNAL(clicked()), this, SLOT(onFaq1Clicked())); + connect(ui->pushButtonFaq2, SIGNAL(clicked()), this, SLOT(onFaq2Clicked())); + connect(ui->pushButtonFaq3, SIGNAL(clicked()), this, SLOT(onFaq3Clicked())); + connect(ui->pushButtonFaq4, SIGNAL(clicked()), this, SLOT(onFaq4Clicked())); + connect(ui->pushButtonFaq5, SIGNAL(clicked()), this, SLOT(onFaq5Clicked())); + connect(ui->pushButtonFaq6, SIGNAL(clicked()), this, SLOT(onFaq6Clicked())); + connect(ui->pushButtonFaq7, SIGNAL(clicked()), this, SLOT(onFaq7Clicked())); + connect(ui->pushButtonFaq8, SIGNAL(clicked()), this, SLOT(onFaq8Clicked())); + connect(ui->pushButtonFaq9, SIGNAL(clicked()), this, SLOT(onFaq9Clicked())); + connect(ui->pushButtonFaq10, SIGNAL(clicked()), this, SLOT(onFaq10Clicked())); + + if (parent) + connect(parent, SIGNAL(windowResizeEvent(QResizeEvent*)), this, SLOT(windowResizeEvent(QResizeEvent*))); +} + +void SettingsFaqWidget::showEvent(QShowEvent *event){ + if(pos != 0){ + QPushButton* btn = getButtons()[pos - 1]; + QMetaObject::invokeMethod(btn, "setChecked", Qt::QueuedConnection, Q_ARG(bool, true)); + QMetaObject::invokeMethod(btn, "clicked", Qt::QueuedConnection); + } +} + +void SettingsFaqWidget::setSection(int num){ + if (num < 1 || num > 10) + return; + pos = num; +} + +void SettingsFaqWidget::onFaq1Clicked(){ + ui->scrollAreaFaq->verticalScrollBar()->setValue(ui->widgetFaq1->y()); +} + +void SettingsFaqWidget::onFaq2Clicked(){ + ui->scrollAreaFaq->verticalScrollBar()->setValue(ui->widgetFaq2->y()); +} + +void SettingsFaqWidget::onFaq3Clicked(){ + ui->scrollAreaFaq->verticalScrollBar()->setValue(ui->widgetFaq3->y()); +} + +void SettingsFaqWidget::onFaq4Clicked(){ + ui->scrollAreaFaq->verticalScrollBar()->setValue(ui->widgetFaq4->y()); +} + +void SettingsFaqWidget::onFaq5Clicked(){ + ui->scrollAreaFaq->verticalScrollBar()->setValue(ui->widgetFaq5->y()); +} + +void SettingsFaqWidget::onFaq6Clicked(){ + ui->scrollAreaFaq->verticalScrollBar()->setValue(ui->widgetFaq6->y()); +} + +void SettingsFaqWidget::onFaq7Clicked(){ + ui->scrollAreaFaq->verticalScrollBar()->setValue(ui->widgetFaq7->y()); +} + +void SettingsFaqWidget::onFaq8Clicked(){ + ui->scrollAreaFaq->verticalScrollBar()->setValue(ui->widgetFaq8->y()); +} + +void SettingsFaqWidget::onFaq9Clicked(){ + ui->scrollAreaFaq->verticalScrollBar()->setValue(ui->widgetFaq9->y()); +} + +void SettingsFaqWidget::onFaq10Clicked(){ + ui->scrollAreaFaq->verticalScrollBar()->setValue(ui->widgetFaq10->y()); +} + +void SettingsFaqWidget::windowResizeEvent(QResizeEvent* event){ + QWidget* w = qobject_cast(parent()); + this->resize(w->width(), w->height()); + this->move(QPoint(0, 0)); +} + +std::vector SettingsFaqWidget::getButtons(){ + return { + ui->pushButtonFaq1, + ui->pushButtonFaq2, + ui->pushButtonFaq3, + ui->pushButtonFaq4, + ui->pushButtonFaq5, + ui->pushButtonFaq6, + ui->pushButtonFaq7, + ui->pushButtonFaq8, + ui->pushButtonFaq9, + ui->pushButtonFaq10 + }; +} + +SettingsFaqWidget::~SettingsFaqWidget(){ + delete ui; +} + + diff --git a/src/qt/pivx/settings/settingsfaqwidget.h b/src/qt/pivx/settings/settingsfaqwidget.h new file mode 100644 index 000000000000..c994f6fbaa6e --- /dev/null +++ b/src/qt/pivx/settings/settingsfaqwidget.h @@ -0,0 +1,45 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSFAQWIDGET_H +#define SETTINGSFAQWIDGET_H + +#include + +namespace Ui { +class SettingsFaqWidget; +} + +class SettingsFaqWidget : public QDialog +{ + Q_OBJECT + +public: + explicit SettingsFaqWidget(QWidget *parent = nullptr); + ~SettingsFaqWidget(); + + void showEvent(QShowEvent *event) override; + +public slots: + void windowResizeEvent(QResizeEvent* event); + void setSection(int num); +private slots: + void onFaq1Clicked(); + void onFaq2Clicked(); + void onFaq3Clicked(); + void onFaq4Clicked(); + void onFaq5Clicked(); + void onFaq6Clicked(); + void onFaq7Clicked(); + void onFaq8Clicked(); + void onFaq9Clicked(); + void onFaq10Clicked(); +private: + Ui::SettingsFaqWidget *ui; + int pos = 0; + + std::vector getButtons(); +}; + +#endif // SETTINGSFAQWIDGET_H diff --git a/src/qt/pivx/settings/settingsinformationwidget.cpp b/src/qt/pivx/settings/settingsinformationwidget.cpp new file mode 100644 index 000000000000..ad98e04248a2 --- /dev/null +++ b/src/qt/pivx/settings/settingsinformationwidget.cpp @@ -0,0 +1,160 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingsinformationwidget.h" +#include "qt/pivx/settings/forms/ui_settingsinformationwidget.h" +#include "clientmodel.h" +#include "chainparams.h" +#include "db.h" +#include "util.h" +#include "guiutil.h" +#include "qt/pivx/qtutils.h" +#include + +SettingsInformationWidget::SettingsInformationWidget(PIVXGUI* _window,QWidget *parent) : + PWidget(_window,parent), + ui(new Ui::SettingsInformationWidget) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + // Containers + setCssProperty(ui->left, "container"); + ui->left->setContentsMargins(10,10,10,10); + setCssProperty({ui->layoutOptions1, ui->layoutOptions2, ui->layoutOptions3}, "container-options"); + + // Title + ui->labelTitle->setText(tr("Information")); + setCssTitleScreen(ui->labelTitle); + + ui->labelTitleGeneral->setText(tr("General")); + ui->labelTitleClient->setText(tr("Client Version: ")); + ui->labelTitleAgent->setText(tr("User Agent:")); + ui->labelTitleBerkeley->setText(tr("Using BerkeleyDB version:")); + ui->labelTitleDataDir->setText(tr("Datadir: ")); + ui->labelTitleTime->setText(tr("Startup Time: ")); + ui->labelTitleNetwork->setText(tr("Network")); + ui->labelTitleName->setText(tr("Name:")); + ui->labelTitleConnections->setText(tr("Number Connections:")); + + setCssProperty({ + ui->labelTitleDataDir, + ui->labelTitleBerkeley, + ui->labelTitleAgent, + ui->labelTitleClient, + ui->labelTitleTime, + ui->labelTitleName, + ui->labelTitleConnections, + ui->labelTitleBlockNumber, + ui->labelTitleBlockTime, + ui->labelTitleNumberTransactions, + ui->labelInfoNumberTransactions, + ui->labelInfoClient, + ui->labelInfoAgent, + ui->labelInfoBerkeley, + ui->labelInfoDataDir, + ui->labelInfoTime, + ui->labelInfoConnections, + ui->labelInfoBlockNumber + }, "text-main-settings"); + + setCssProperty({ + ui->labelTitleGeneral, + ui->labelTitleNetwork, + ui->labelTitleBlockchain, + ui->labelTitleMemory, + + },"text-title"); + + ui->labelTitleBlockchain->setText(tr("Blockchain")); + ui->labelTitleBlockNumber->setText(tr("Current Number of Blocks:")); + ui->labelTitleBlockTime->setText(tr("Last Block Time:")); + + ui->labelTitleMemory->setText(tr("Memory Pool")); + ui->labelTitleMemory->setVisible(false); + + ui->labelTitleNumberTransactions->setText(tr("Current Number of Transactions:")); + ui->labelTitleNumberTransactions->setVisible(false); + + ui->labelInfoNumberTransactions->setText("0"); + ui->labelInfoNumberTransactions->setVisible(false); + + // Information Network + ui->labelInfoName->setText(tr("Main")); + ui->labelInfoName->setProperty("cssClass", "text-main-settings"); + ui->labelInfoConnections->setText("0 (In: 0 / Out:0)"); + + // Information Blockchain + ui->labelInfoBlockNumber->setText("0"); + ui->labelInfoBlockTime->setText("Sept 6, 2018. Thursday, 8:21:49 PM"); + ui->labelInfoBlockTime->setProperty("cssClass", "text-main-grey"); + + // Buttons + ui->pushButtonFile->setText(tr("Wallet Conf")); + ui->pushButtonNetworkMonitor->setText(tr("Network Monitor")); + ui->pushButtonBackups->setText(tr("Backups")); + setCssBtnSecondary(ui->pushButtonBackups); + setCssBtnSecondary(ui->pushButtonFile); + setCssBtnSecondary(ui->pushButtonNetworkMonitor); + + // Data +#ifdef ENABLE_WALLET + // Wallet data -- remove it with if it's needed + ui->labelInfoBerkeley->setText(DbEnv::version(0, 0, 0)); + ui->labelInfoDataDir->setText(QString::fromStdString(GetDataDir().string() + QDir::separator().toLatin1() + GetArg("-wallet", "wallet.dat"))); +#else + ui->labelInfoBerkeley->setText(tr("No information")); +#endif + + connect(ui->pushButtonBackups, &QPushButton::clicked, [](){GUIUtil::showBackups();}); + connect(ui->pushButtonFile, &QPushButton::clicked, [](){GUIUtil::openConfigfile();}); + connect(ui->pushButtonNetworkMonitor, SIGNAL(clicked()), this, SLOT(openNetworkMonitor())); +} + + +void SettingsInformationWidget::loadClientModel(){ + if (clientModel && clientModel->getPeerTableModel() && clientModel->getBanTableModel()) { + // Provide initial values + ui->labelInfoClient->setText(clientModel->formatFullVersion()); + ui->labelInfoAgent->setText(clientModel->clientName()); + ui->labelInfoTime->setText(clientModel->formatClientStartupTime()); + ui->labelInfoName->setText(QString::fromStdString(Params().NetworkIDString())); + + setNumConnections(clientModel->getNumConnections()); + connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); + + setNumBlocks(clientModel->getNumBlocks()); + connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int))); + } +} + +void SettingsInformationWidget::setNumConnections(int count){ + if (!clientModel) + return; + + QString connections = QString::number(count) + " ("; + connections += tr("In:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_IN)) + " / "; + connections += tr("Out:") + " " + QString::number(clientModel->getNumConnections(CONNECTIONS_OUT)) + ")"; + + ui->labelInfoConnections->setText(connections); +} + +void SettingsInformationWidget::setNumBlocks(int count){ + ui->labelInfoBlockNumber->setText(QString::number(count)); + if (clientModel) + ui->labelInfoBlockTime->setText(clientModel->getLastBlockDate().toString()); +} + +void SettingsInformationWidget::openNetworkMonitor(){ + if(!rpcConsole){ + rpcConsole = new RPCConsole(0); + rpcConsole->setClientModel(clientModel); + } + rpcConsole->showNetwork(); +} + +SettingsInformationWidget::~SettingsInformationWidget(){ + delete ui; +} diff --git a/src/qt/pivx/settings/settingsinformationwidget.h b/src/qt/pivx/settings/settingsinformationwidget.h new file mode 100644 index 000000000000..9c1487d3fa50 --- /dev/null +++ b/src/qt/pivx/settings/settingsinformationwidget.h @@ -0,0 +1,36 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSINFORMATIONWIDGET_H +#define SETTINGSINFORMATIONWIDGET_H + +#include +#include "qt/pivx/pwidget.h" +#include "rpcconsole.h" + +namespace Ui { +class SettingsInformationWidget; +} + +class SettingsInformationWidget : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsInformationWidget(PIVXGUI* _window, QWidget *parent = nullptr); + ~SettingsInformationWidget(); + + void loadClientModel() override; + +private slots: + void setNumConnections(int count); + void setNumBlocks(int count); + void openNetworkMonitor(); + +private: + Ui::SettingsInformationWidget *ui; + RPCConsole *rpcConsole = nullptr; +}; + +#endif // SETTINGSINFORMATIONWIDGET_H diff --git a/src/qt/pivx/settings/settingsmainoptionswidget.cpp b/src/qt/pivx/settings/settingsmainoptionswidget.cpp new file mode 100644 index 000000000000..e8ebb52c3468 --- /dev/null +++ b/src/qt/pivx/settings/settingsmainoptionswidget.cpp @@ -0,0 +1,125 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingsmainoptionswidget.h" +#include "qt/pivx/settings/forms/ui_settingsmainoptionswidget.h" +#include "QListView" + +#if defined(HAVE_CONFIG_H) +#include "config/pivx-config.h" +#endif + +#include "bitcoinunits.h" +#include "guiutil.h" +#include "optionsmodel.h" +#include "clientmodel.h" +#include "qt/pivx/qtutils.h" + +#include "main.h" // for MAX_SCRIPTCHECK_THREADS +#include "netbase.h" +#include "txdb.h" // for -dbcache defaults + +#ifdef ENABLE_WALLET +#include "wallet/wallet.h" // for CWallet::minTxFee +#endif + +#include + +#include +#include +#include +#include + + +SettingsMainOptionsWidget::SettingsMainOptionsWidget(PIVXGUI* _window, QWidget *parent) : + PWidget(_window, parent), + ui(new Ui::SettingsMainOptionsWidget) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + // Containers + ui->left->setProperty("cssClass", "container"); + ui->left->setContentsMargins(10,10,10,10); + ui->labelDivider->setProperty("cssClass", "container-divider"); + + // Title + ui->labelTitle->setText(tr("Main")); + ui->labelSubtitle1->setText("Customize the main application options"); + + setCssTitleScreen(ui->labelTitle); + setCssSubtitleScreen(ui->labelSubtitle1); + setCssTitleScreen(ui->labelTitleDown); + setCssSubtitleScreen(ui->labelSubtitleDown); + + ui->labelTitleSizeDb->setText(tr("Size of database cache")); + ui->labelTitleSizeDb->setProperty("cssClass", "text-main-settings"); + + ui->labelTitleThreads->setText(tr("Number of script verification threads")); + ui->labelTitleThreads->setProperty("cssClass", "text-main-settings"); + + // Switch + ui->pushSwitchStart->setText(tr("Start PIVX on system login")); + ui->pushSwitchStart->setProperty("cssClass", "btn-switch"); + + // Combobox + ui->databaseCache->setProperty("cssClass", "btn-spin-box"); + ui->databaseCache->setAttribute(Qt::WA_MacShowFocusRect, 0); + setShadow(ui->databaseCache); + ui->threadsScriptVerif->setProperty("cssClass", "btn-spin-box"); + ui->threadsScriptVerif->setAttribute(Qt::WA_MacShowFocusRect, 0); + setShadow(ui->threadsScriptVerif); + + // CheckBox + ui->checkBoxMinTaskbar->setText(tr("Minimize to the tray instead of the taskbar")); + ui->checkBoxMinClose->setText(tr("Minimize on close")); + + // Buttons + ui->pushButtonSave->setText(tr("SAVE")); + ui->pushButtonReset->setText(tr("Reset to default")); + setCssBtnPrimary(ui->pushButtonSave); + setCssBtnSecondary(ui->pushButtonReset); + setCssBtnSecondary(ui->pushButtonClean); + + /* Main elements init */ + ui->databaseCache->setMinimum(nMinDbCache); + ui->databaseCache->setMaximum(nMaxDbCache); + ui->threadsScriptVerif->setMinimum(-(int)boost::thread::hardware_concurrency()); + ui->threadsScriptVerif->setMaximum(MAX_SCRIPTCHECK_THREADS); + + connect(ui->pushButtonSave, SIGNAL(clicked()), parent, SLOT(onSaveOptionsClicked())); + connect(ui->pushButtonReset, SIGNAL(clicked()), this, SLOT(onResetClicked())); + connect(ui->pushButtonClean, SIGNAL(clicked()), parent, SLOT(onDiscardChanges())); +} + +void SettingsMainOptionsWidget::onResetClicked(){ + if(clientModel) { + if (!ask(tr("Reset Options"), tr("You are just about to reset the app\'s options to the default values.\n\nAre you sure?\n"))) + return; + OptionsModel *optionsModel = clientModel->getOptionsModel(); + QSettings settings; + // default setting for OptionsModel::StartAtStartup - disabled + if (GUIUtil::GetStartOnSystemStartup()) + GUIUtil::SetStartOnSystemStartup(false); + optionsModel->setMainDefaultOptions(settings, true); + optionsModel->setWindowDefaultOptions(settings, true); + inform(tr("Options reset succeed")); + } +} + +void SettingsMainOptionsWidget::setMapper(QDataWidgetMapper *mapper){ + mapper->addMapping(ui->pushSwitchStart, OptionsModel::StartAtStartup); + mapper->addMapping(ui->threadsScriptVerif, OptionsModel::ThreadsScriptVerif); + mapper->addMapping(ui->databaseCache, OptionsModel::DatabaseCache); + /* Window */ +#ifndef Q_OS_MAC + mapper->addMapping(ui->checkBoxMinTaskbar, OptionsModel::MinimizeToTray); + mapper->addMapping(ui->checkBoxMinClose, OptionsModel::MinimizeOnClose); +#endif +} + +SettingsMainOptionsWidget::~SettingsMainOptionsWidget(){ + delete ui; +} diff --git a/src/qt/pivx/settings/settingsmainoptionswidget.h b/src/qt/pivx/settings/settingsmainoptionswidget.h new file mode 100644 index 000000000000..ea4b2360c9e4 --- /dev/null +++ b/src/qt/pivx/settings/settingsmainoptionswidget.h @@ -0,0 +1,37 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSMAINOPTIONSWIDGET_H +#define SETTINGSMAINOPTIONSWIDGET_H + +#include "qt/pivx/pwidget.h" + +#include + +QT_BEGIN_NAMESPACE +class QDataWidgetMapper; +QT_END_NAMESPACE + +namespace Ui { +class SettingsMainOptionsWidget; +} + +class SettingsMainOptionsWidget : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsMainOptionsWidget(PIVXGUI* _window, QWidget *parent = nullptr); + ~SettingsMainOptionsWidget(); + + void setMapper(QDataWidgetMapper *mapper); + +public slots: + void onResetClicked(); + +private: + Ui::SettingsMainOptionsWidget *ui; +}; + +#endif // SETTINGSMAINOPTIONSWIDGET_H diff --git a/src/qt/pivx/settings/settingsmultisenddialog.cpp b/src/qt/pivx/settings/settingsmultisenddialog.cpp new file mode 100644 index 000000000000..208e126ec5c7 --- /dev/null +++ b/src/qt/pivx/settings/settingsmultisenddialog.cpp @@ -0,0 +1,76 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingsmultisenddialog.h" +#include "qt/pivx/settings/forms/ui_settingsmultisenddialog.h" +#include +#include +#include "qt/pivx/qtutils.h" + +SettingsMultisendDialog::SettingsMultisendDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::SettingsMultisendDialog) +{ + ui->setupUi(this); + + // Stylesheet + this->setStyleSheet(parent->styleSheet()); + + // Container + setCssProperty(ui->frame, "container-dialog"); + + // Text + ui->labelTitle->setText(tr("New recipient for multisend")); + setCssProperty(ui->labelTitle, "text-title-dialog"); + + // Label + ui->labelSubtitleLabel->setText(tr("Label (optional)")); + setCssProperty(ui->labelSubtitleLabel, "text-title2-dialog"); + + ui->lineEditLabel->setPlaceholderText(tr("Enter a label to add this address in your address book")); + initCssEditLine(ui->lineEditLabel, true); + + // Address + ui->labelSubtitleAddress->setText("Enter a PIVX address or contact label"); + setCssProperty(ui->labelSubtitleAddress, "text-title2-dialog"); + ui->lineEditAddress->setPlaceholderText("e.g D7VFR83SQbiezrW72hjc… "); + initCssEditLine(ui->lineEditAddress, true); + ui->lineEditAddress->setValidator(new QRegExpValidator(QRegExp("^[A-Za-z0-9]+"), ui->lineEditAddress)); + + + ui->labelSubtitlePercentage->setText(tr("Percentage")); + setCssProperty(ui->labelSubtitlePercentage, "text-title2-dialog"); + ui->lineEditPercentage->setPlaceholderText("10%"); + initCssEditLine(ui->lineEditPercentage, true); + ui->lineEditPercentage->setValidator(new QIntValidator(0, 100, ui->lineEditPercentage)); + + // Buttons + setCssProperty(ui->btnEsc, "ic-close"); + setCssProperty(ui->btnCancel, "btn-dialog-cancel"); + ui->btnSave->setText("ADD"); + setCssBtnPrimary(ui->btnSave); + + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnSave, &QPushButton::clicked, [this](){ + this->isOk = true; + accept(); + }); +} + +QString SettingsMultisendDialog::getAddress(){ + return ui->lineEditAddress->text(); +} +QString SettingsMultisendDialog::getLabel(){ + return ui->lineEditLabel->text(); +} +int SettingsMultisendDialog::getPercentage(){ + QString percentage = ui->lineEditPercentage->text(); + if (percentage.isEmpty()) return 0; + return percentage.toInt(); +} + +SettingsMultisendDialog::~SettingsMultisendDialog(){ + delete ui; +} diff --git a/src/qt/pivx/settings/settingsmultisenddialog.h b/src/qt/pivx/settings/settingsmultisenddialog.h new file mode 100644 index 000000000000..d66bd854368f --- /dev/null +++ b/src/qt/pivx/settings/settingsmultisenddialog.h @@ -0,0 +1,31 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSMULTISENDDIALOG_H +#define SETTINGSMULTISENDDIALOG_H + +#include + +namespace Ui { +class SettingsMultisendDialog; +} + +class SettingsMultisendDialog : public QDialog +{ + Q_OBJECT + +public: + explicit SettingsMultisendDialog(QWidget *parent = nullptr); + ~SettingsMultisendDialog(); + + QString getAddress(); + QString getLabel(); + int getPercentage(); + + bool isOk = false; +private: + Ui::SettingsMultisendDialog *ui; +}; + +#endif // SETTINGSMULTISENDDIALOG_H diff --git a/src/qt/pivx/settings/settingsmultisendwidget.cpp b/src/qt/pivx/settings/settingsmultisendwidget.cpp new file mode 100644 index 000000000000..17f6a3cf5608 --- /dev/null +++ b/src/qt/pivx/settings/settingsmultisendwidget.cpp @@ -0,0 +1,343 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingsmultisendwidget.h" +#include "qt/pivx/settings/forms/ui_settingsmultisendwidget.h" +#include "qt/pivx/settings/settingsmultisenddialog.h" +#include "qt/pivx/qtutils.h" +#include "addresstablemodel.h" +#include "base58.h" +#include "init.h" +#include "walletmodel.h" +#include "wallet/wallet.h" + + +#define DECORATION_SIZE 65 +#define NUM_ITEMS 3 + +MultiSendModel::MultiSendModel(QObject *parent) : QAbstractTableModel(parent){ + updateList(); +} + +void MultiSendModel::updateList(){ + emit dataChanged(index(0, 0, QModelIndex()), index((int) pwalletMain->vMultiSend.size(), 5, QModelIndex()) ); +} + +int MultiSendModel::rowCount(const QModelIndex &parent) const{ + if (parent.isValid()) + return 0; + return (int) pwalletMain->vMultiSend.size(); +} + +QVariant MultiSendModel::data(const QModelIndex &index, int role) const { + if (!index.isValid()) + return QVariant(); + + int row = index.row(); + if (role == Qt::DisplayRole || role == Qt::EditRole) { + switch (index.column()) { + case PERCENTAGE: + return pwalletMain->vMultiSend[row].second; + case ADDRESS: { + return QString::fromStdString(pwalletMain->vMultiSend[row].first); + } + } + } + return QVariant(); +} + +QModelIndex MultiSendModel::index(int row, int column, const QModelIndex& parent) const{ + Q_UNUSED(parent); + return createIndex(row, column, nullptr); +} + +class MultiSendHolder : public FurListRow +{ +public: + MultiSendHolder(); + + explicit MultiSendHolder(bool _isLightTheme) : FurListRow(), isLightTheme(_isLightTheme){} + + QWidget* createHolder(int pos) override{ + QWidget *row = new QWidget(); + QVBoxLayout *verticalLayout_2; + QFrame *frame_2; + QHBoxLayout *horizontalLayout; + QLabel *labelName; + QSpacerItem *horizontalSpacer; + QLabel *labelDate; + QLabel *lblDivisory; + + if (row->objectName().isEmpty()) + row->setObjectName(QStringLiteral("multiSendrow")); + row->resize(475, 65); + row->setStyleSheet(QStringLiteral("")); + setCssProperty(row, "container"); + verticalLayout_2 = new QVBoxLayout(row); + verticalLayout_2->setSpacing(0); + verticalLayout_2->setObjectName(QStringLiteral("verticalLayout_2")); + verticalLayout_2->setContentsMargins(20, 0, 20, 0); + frame_2 = new QFrame(row); + frame_2->setObjectName(QStringLiteral("frame_2")); + frame_2->setStyleSheet(QStringLiteral("border:none;")); + frame_2->setFrameShape(QFrame::StyledPanel); + frame_2->setFrameShadow(QFrame::Raised); + horizontalLayout = new QHBoxLayout(frame_2); + horizontalLayout->setObjectName(QStringLiteral("horizontalLayout")); + horizontalLayout->setContentsMargins(0, -1, 0, -1); + labelName = new QLabel(frame_2); + labelName->setObjectName(QStringLiteral("labelAddress")); + setCssProperty(labelName, "text-list-title1"); + horizontalLayout->addWidget(labelName); + + horizontalSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); + horizontalLayout->addItem(horizontalSpacer); + + labelDate = new QLabel(frame_2); + labelDate->setObjectName(QStringLiteral("labelPercentage")); + setCssProperty(labelDate, "text-list-caption-medium"); + horizontalLayout->addWidget(labelDate); + + verticalLayout_2->addWidget(frame_2); + + lblDivisory = new QLabel(row); + lblDivisory->setObjectName(QStringLiteral("lblDivisory")); + lblDivisory->setMinimumSize(QSize(0, 1)); + lblDivisory->setMaximumSize(QSize(16777215, 1)); + lblDivisory->setStyleSheet(QStringLiteral("background-color:#bababa;")); + lblDivisory->setAlignment(Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft); + verticalLayout_2->addWidget(lblDivisory); + + return row; + } + + void init(QWidget* holder,const QModelIndex &index, bool isHovered, bool isSelected) const override{ + holder->findChild("labelAddress")->setText(index.data(Qt::DisplayRole).toString()); + holder->findChild("labelPercentage")->setText( + QString::number(index.sibling(index.row(), MultiSendModel::PERCENTAGE).data(Qt::DisplayRole).toInt()) + QString("%") + ); + } + + QColor rectColor(bool isHovered, bool isSelected) override{ + return getRowColor(isLightTheme, isHovered, isSelected); + } + + ~MultiSendHolder() override{} + + bool isLightTheme; +}; + + +SettingsMultisendWidget::SettingsMultisendWidget(PWidget *parent) : + PWidget(parent), + ui(new Ui::SettingsMultisendWidget) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + delegate = new FurAbstractListItemDelegate( + DECORATION_SIZE, + new MultiSendHolder(isLightTheme()), + this + ); + + // Containers + setCssProperty(ui->left, "container"); + ui->left->setContentsMargins(10,10,10,10); + + // Title + ui->labelTitle->setText("Multisend"); + setCssTitleScreen(ui->labelTitle); + + ui->labelSubtitle1->setText(tr("MultiSend allows you to automatically send up to 100% of your stake or masternode reward to a list of other PIVX addresses after it matures.")); + setCssSubtitleScreen(ui->labelSubtitle1); + + //Button Group + ui->pushLeft->setText(tr("Active")); + setCssProperty(ui->pushLeft, "btn-check-left"); + ui->pushRight->setText(tr("Disable")); + setCssProperty(ui->pushRight, "btn-check-right"); + + setCssProperty(ui->pushImgEmpty, "img-empty-multisend"); + ui->labelEmpty->setText(tr("No active recipient yet")); + setCssProperty(ui->labelEmpty, "text-empty"); + + // CheckBox + ui->checkBoxStake->setText(tr("Send stakes")); + ui->checkBoxRewards->setText(tr("Send masternode rewards")); + + setCssProperty(ui->listView, "container"); + ui->listView->setItemDelegate(delegate); + ui->listView->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE)); + ui->listView->setMinimumHeight(NUM_ITEMS * (DECORATION_SIZE + 2)); + ui->listView->setAttribute(Qt::WA_MacShowFocusRect, false); + ui->listView->setSelectionBehavior(QAbstractItemView::SelectRows); + + // Buttons + ui->pushButtonSave->setText(tr("ADD RECIPIENT")); + ui->pushButtonClear->setText(tr("CLEAR ALL")); + setCssBtnPrimary(ui->pushButtonSave); + setCssBtnSecondary(ui->pushButtonClear); + + connect(ui->pushButtonSave, SIGNAL(clicked()), this, SLOT(onAddRecipientClicked())); + connect(ui->pushButtonClear, SIGNAL(clicked()), this, SLOT(clearAll())); +} + +void SettingsMultisendWidget::showEvent(QShowEvent *event) { + if (multiSendModel) { + multiSendModel->updateList(); + updateListState(); + } +} + +void SettingsMultisendWidget::loadWalletModel(){ + if(walletModel){ + multiSendModel = new MultiSendModel(this); + ui->listView->setModel(multiSendModel); + ui->listView->setModelColumn(MultiSendModel::ADDRESS); + + ui->pushLeft->setChecked(pwalletMain->isMultiSendEnabled()); + ui->checkBoxStake->setChecked(pwalletMain->fMultiSendStake); + ui->checkBoxRewards->setChecked(pwalletMain->fMultiSendMasternodeReward); + connect(ui->checkBoxStake, SIGNAL(stateChanged(int)), this, SLOT(checkBoxChanged())); + connect(ui->checkBoxRewards, SIGNAL(stateChanged(int)), this, SLOT(checkBoxChanged())); + connect(ui->pushLeft, SIGNAL(clicked()), this, SLOT(activate())); + connect(ui->pushRight, SIGNAL(clicked()), this, SLOT(deactivate())); + + updateListState(); + } +} + +void SettingsMultisendWidget::updateListState(){ + if (multiSendModel->rowCount() > 0) { + ui->listView->setVisible(true); + ui->emptyContainer->setVisible(false); + } else { + ui->listView->setVisible(false); + ui->emptyContainer->setVisible(true); + } +} + +void SettingsMultisendWidget::clearAll(){ + if(!verifyWalletUnlocked()) return; + std::vector > vMultiSendTemp = pwalletMain->vMultiSend; + bool fRemoved = true; + pwalletMain->vMultiSend.clear(); + CWalletDB walletdb(pwalletMain->strWalletFile); + if (!walletdb.EraseMultiSend(vMultiSendTemp)) + fRemoved = false; + if (!walletdb.WriteMultiSend(pwalletMain->vMultiSend)) + fRemoved = false; + + checkBoxChanged(); + multiSendModel->updateList(); + updateListState(); + inform(fRemoved ? tr("Clear succeed") : tr("Clear all failed, could not locate address in wallet file")); +} + +void SettingsMultisendWidget::checkBoxChanged(){ + pwalletMain->fMultiSendStake = ui->checkBoxStake->isChecked(); + pwalletMain->fMultiSendMasternodeReward = ui->checkBoxRewards->isChecked(); +} + +void SettingsMultisendWidget::onAddRecipientClicked() { + if(!verifyWalletUnlocked()) return; + showHideOp(true); + SettingsMultisendDialog* dialog = new SettingsMultisendDialog(window); + openDialogWithOpaqueBackgroundY(dialog, window, 3, 5); + + if(dialog->isOk){ + addMultiSend( + dialog->getAddress(), + dialog->getPercentage(), + dialog->getLabel() + ); + } + dialog->deleteLater(); +} + +void SettingsMultisendWidget::addMultiSend(QString address, int percentage, QString addressLabel){ + std::string strAddress = address.toStdString(); + if (!CBitcoinAddress(strAddress).IsValid()) { + inform(tr("The entered address: %1 is invalid.\nPlease check the address and try again.").arg(address)); + return; + } + if (percentage > 100 || percentage <= 0) { + inform(tr("Invalid percentage, please enter values from 1 to 100.")); + return; + } + + int nMultiSendPercent = percentage; + int nSumMultiSend = 0; + for (int i = 0; i < (int)pwalletMain->vMultiSend.size(); i++) + nSumMultiSend += pwalletMain->vMultiSend[i].second; + if (nSumMultiSend + nMultiSendPercent > 100) { + inform(tr("The total amount of your MultiSend vector is over 100% of your stake reward")); + return; + } + std::pair pMultiSend; + pMultiSend.first = strAddress; + pMultiSend.second = nMultiSendPercent; + pwalletMain->vMultiSend.push_back(pMultiSend); + + if (walletModel && walletModel->getAddressTableModel()) { + // update the address book with the label given or no label if none was given. + CBitcoinAddress address(strAddress); + std::string userInputLabel = addressLabel.toStdString(); + walletModel->updateAddressBookLabels(address.Get(), (userInputLabel.empty()) ? "(no label)" : userInputLabel, "send"); + } + + CWalletDB walletdb(pwalletMain->strWalletFile); + if(!walletdb.WriteMultiSend(pwalletMain->vMultiSend)) { + inform(tr("Error saving MultiSend, failed saving properties to the database.")); + return; + } + + multiSendModel->updateList(); + updateListState(); + inform("MultiSend recipient added."); +} + +void SettingsMultisendWidget::activate(){ + if(pwalletMain->isMultiSendEnabled()) + return; + QString strRet; + if (pwalletMain->vMultiSend.size() < 1) + strRet = tr("Unable to activate MultiSend, no available recipients"); + else if (!(ui->checkBoxStake->isChecked() || ui->checkBoxRewards->isChecked())) { + strRet = tr("Unable to activate MultiSend\nCheck one or both of the check boxes to send on stake and/or masternode rewards"); + } else if (CBitcoinAddress(pwalletMain->vMultiSend[0].first).IsValid()) { + pwalletMain->fMultiSendStake = ui->checkBoxStake->isChecked(); + pwalletMain->fMultiSendMasternodeReward = ui->checkBoxRewards->isChecked(); + + CWalletDB walletdb(pwalletMain->strWalletFile); + if (!walletdb.WriteMSettings(pwalletMain->fMultiSendStake, pwalletMain->fMultiSendMasternodeReward, pwalletMain->nLastMultiSendHeight)) + strRet = tr("MultiSend activated but writing settings to DB failed"); + else + strRet = tr("MultiSend activated"); + } else + strRet = tr("First multiSend address invalid"); + + inform(strRet); +} + +void SettingsMultisendWidget::deactivate(){ + if(pwalletMain->isMultiSendEnabled()) { + QString strRet; + pwalletMain->setMultiSendDisabled(); + CWalletDB walletdb(pwalletMain->strWalletFile); + inform(!walletdb.WriteMSettings(false, false, pwalletMain->nLastMultiSendHeight) ? + tr("MultiSend deactivated but writing settings to DB failed") : + tr("MultiSend deactivated") + ); + } +} + +void SettingsMultisendWidget::changeTheme(bool isLightTheme, QString& theme){ + static_cast(this->delegate->getRowFactory())->isLightTheme = isLightTheme; +} + +SettingsMultisendWidget::~SettingsMultisendWidget(){ + delete ui; +} diff --git a/src/qt/pivx/settings/settingsmultisendwidget.h b/src/qt/pivx/settings/settingsmultisendwidget.h new file mode 100644 index 000000000000..efb2ed2d44b6 --- /dev/null +++ b/src/qt/pivx/settings/settingsmultisendwidget.h @@ -0,0 +1,67 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSMULTISENDWIDGET_H +#define SETTINGSMULTISENDWIDGET_H + +#include +#include +#include "qt/pivx/pwidget.h" +#include "qt/pivx/furabstractlistitemdelegate.h" + +class PIVXGUI; + +namespace Ui { +class SettingsMultisendWidget; +} + +class MultiSendModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + explicit MultiSendModel(QObject *parent = nullptr); + ~MultiSendModel() override{} + + enum ColumnIndex { + ADDRESS = 0, + PERCENTAGE = 1 + }; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override { return 2; } + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + QModelIndex index(int row, int column, const QModelIndex& parent) const override; + void updateList(); +}; + +class SettingsMultisendWidget : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsMultisendWidget(PWidget *parent); + ~SettingsMultisendWidget(); + + void showEvent(QShowEvent *event) override; + void loadWalletModel() override; + void changeTheme(bool isLightTheme, QString &theme) override; + +private slots: + void onAddRecipientClicked(); + void clearAll(); + void checkBoxChanged(); + void activate(); + void deactivate(); + +private: + Ui::SettingsMultisendWidget *ui; + MultiSendModel* multiSendModel = nullptr; + FurAbstractListItemDelegate *delegate = nullptr; + + void addMultiSend(QString address, int percentage, QString addressLabel); + void updateListState(); +}; + +#endif // SETTINGSMULTISENDWIDGET_H diff --git a/src/qt/pivx/settings/settingsnetworkwidget.cpp b/src/qt/pivx/settings/settingsnetworkwidget.cpp new file mode 100644 index 000000000000..451a650655b3 --- /dev/null +++ b/src/qt/pivx/settings/settingsnetworkwidget.cpp @@ -0,0 +1,37 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingsnetworkwidget.h" +#include "qt/pivx/settings/forms/ui_settingsnetworkwidget.h" +#include "optionsmodel.h" +#include "qt/pivx/qtutils.h" + +SettingsNetworkWidget::SettingsNetworkWidget(PIVXGUI* _window, QWidget *parent) : + PWidget(_window, parent), + ui(new Ui::SettingsNetworkWidget) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + // Containers + ui->left->setProperty("cssClass", "container"); + ui->left->setContentsMargins(10,10,10,10); + + // Buttons + ui->pushButtonSave->setText(tr("SAVE")); + ui->pushButtonReset->setText(tr("Reset to default")); + setCssBtnPrimary(ui->pushButtonSave); + setCssBtnSecondary(ui->pushButtonReset); + + connect(ui->pushButtonSave, SIGNAL(clicked()), parent, SLOT(onSaveOptionsClicked())); +} + +void SettingsNetworkWidget::setMapper(QDataWidgetMapper *mapper){ +} + +SettingsNetworkWidget::~SettingsNetworkWidget() +{ + delete ui; +} diff --git a/src/qt/pivx/settings/settingsnetworkwidget.h b/src/qt/pivx/settings/settingsnetworkwidget.h new file mode 100644 index 000000000000..b391b33d1a8c --- /dev/null +++ b/src/qt/pivx/settings/settingsnetworkwidget.h @@ -0,0 +1,30 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSNETWORKWIDGET_H +#define SETTINGSNETWORKWIDGET_H + +#include +#include +#include "qt/pivx/pwidget.h" + +namespace Ui { +class SettingsNetworkWidget; +} + +class SettingsNetworkWidget : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsNetworkWidget(PIVXGUI* _window, QWidget *parent = nullptr); + ~SettingsNetworkWidget(); + + void setMapper(QDataWidgetMapper *mapper); + +private: + Ui::SettingsNetworkWidget *ui; +}; + +#endif // SETTINGSNETWORKWIDGET_H diff --git a/src/qt/pivx/settings/settingssignmessagewidgets.cpp b/src/qt/pivx/settings/settingssignmessagewidgets.cpp new file mode 100644 index 000000000000..24420017c0f0 --- /dev/null +++ b/src/qt/pivx/settings/settingssignmessagewidgets.cpp @@ -0,0 +1,315 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingssignmessagewidgets.h" +#include "qt/pivx/settings/forms/ui_settingssignmessagewidgets.h" +#include "qt/pivx/qtutils.h" +#include "addressbookpage.h" +#include "guiutil.h" +#include "walletmodel.h" + +#include "base58.h" +#include "init.h" +#include "wallet/wallet.h" +#include "askpassphrasedialog.h" + +#include +#include + +#include + +SettingsSignMessageWidgets::SettingsSignMessageWidgets(PIVXGUI* _window, QWidget *parent) : + PWidget(_window, parent), + ui(new Ui::SettingsSignMessageWidgets) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + // Containers + ui->left->setProperty("cssClass", "container"); + ui->left->setContentsMargins(10,10,10,10); + + // Title + ui->labelTitle->setText(tr("Sign/Verify Message")); + ui->labelTitle->setProperty("cssClass", "text-title-screen"); + + // Subtitle + ui->labelSubtitle1->setProperty("cssClass", "text-subtitle"); + + // Address + ui->labelSubtitleAddress->setText(tr("Enter a PIVX address or contact label")); + ui->labelSubtitleAddress->setProperty("cssClass", "text-title"); + + ui->addressIn_SM->setPlaceholderText(tr("Add address")); + ui->addressIn_SM->setProperty("cssClass", "edit-primary-multi-book"); + ui->addressIn_SM->setAttribute(Qt::WA_MacShowFocusRect, 0); + setShadow(ui->addressIn_SM); + + /* Button Group */ + ui->pushSign->setText(tr("Sign")); + ui->pushVerify->setText(tr("Verify")); + setCssProperty(ui->pushSign, "btn-check-right"); + setCssProperty(ui->pushVerify, "btn-check-right"); + ui->labelSubtitleSwitch->setText(tr("Select mode")); + setCssProperty(ui->labelSubtitleSwitch, "text-subtitle"); + ui->pushSign->setChecked(true); + updateMode(); + + // Message + ui->labelSubtitleMessage->setText(tr("Message")); + ui->labelSubtitleMessage->setProperty("cssClass", "text-title"); + + ui->messageIn_SM->setPlaceholderText(tr("Write a message")); + ui->messageIn_SM->setProperty("cssClass","edit-primary"); + setShadow(ui->messageIn_SM); + ui->messageIn_SM->setAttribute(Qt::WA_MacShowFocusRect, 0); + + ui->labelSubtitleSignature->setText(tr("Signature")); + ui->labelSubtitleSignature->setProperty("cssClass", "text-title"); + ui->signatureOut_SM->setPlaceholderText(tr("Signature")); + ui->signatureOut_SM->setAttribute(Qt::WA_MacShowFocusRect, 0); + + initCssEditLine(ui->signatureOut_SM); + setShadow(ui->signatureOut_SM); + + // Buttons + btnContact = ui->addressIn_SM->addAction(QIcon("://ic-contact-arrow-down"), QLineEdit::TrailingPosition); + + ui->pushButtonSave->setText(tr("SIGN")); + ui->pushButtonClear->setText(tr("CLEAR ALL")); + setCssBtnPrimary(ui->pushButtonSave); + setCssBtnSecondary(ui->pushButtonClear); + + ui->statusLabel_SM->setStyleSheet("QLabel { color: transparent; }"); + + connect(ui->pushButtonSave, SIGNAL(clicked()), this, SLOT(onGoClicked())); + connect(btnContact, SIGNAL(triggered()), this, SLOT(onAddressesClicked())); + connect(ui->pushButtonClear, SIGNAL(clicked()), this, SLOT(onClearAll())); + connect(ui->pushSign, &QPushButton::clicked, [this](){onModeSelected(true);}); + connect(ui->pushVerify, &QPushButton::clicked, [this](){onModeSelected(false);}); +} + +SettingsSignMessageWidgets::~SettingsSignMessageWidgets(){ + delete ui; +} + +void SettingsSignMessageWidgets::onModeSelected(bool isSign){ + this->isSign = isSign; + updateMode(); +} + +void SettingsSignMessageWidgets::onGoClicked(){ + if(isSign){ + onSignMessageButtonSMClicked(); + } else { + onVerifyMessage(); + } +} + +void SettingsSignMessageWidgets::updateMode(){ + QString subtitle; + QString go; + if(isSign){ + subtitle = tr("You can sign messages with your addresses to prove you own them. Be careful not to sign anything vague, as phishing attacks may try to trick you into signing your identity over to them. Only sign fully-detailed statements you agree to."); + go = tr("SIGN"); + ui->signatureOut_SM->setReadOnly(true); + ui->signatureOut_SM->clear(); + } else { + subtitle = tr("Enter the signing address, message (ensure you copy line breaks, spaces, tabs, etc. exactly) and signature below to verify the message. Be careful not to read more into the signature than what is in the signed message itself, to avoid being tricked by a man-in-the-middle attack."); + go = tr("VERIFY"); + ui->signatureOut_SM->setReadOnly(false); + } + ui->labelSubtitle1->setText(subtitle); + ui->pushButtonSave->setText(go); +} + +void SettingsSignMessageWidgets::setAddress_SM(const QString& address){ + ui->addressIn_SM->setText(address); + ui->messageIn_SM->setFocus(); +} + +void SettingsSignMessageWidgets::onAddressBookButtonSMClicked(){ + if (walletModel && walletModel->getAddressTableModel()) { + AddressBookPage dlg(AddressBookPage::ForSelection, AddressBookPage::ReceivingTab, this); + dlg.setModel(walletModel->getAddressTableModel()); + if (dlg.exec()) { + setAddress_SM(dlg.getReturnValue()); + } + } +} + +void SettingsSignMessageWidgets::onPasteButtonSMClicked(){ + setAddress_SM(QApplication::clipboard()->text()); +} + +void SettingsSignMessageWidgets::onClearAll() { + ui->addressIn_SM->clear(); + ui->signatureOut_SM->clear(); + ui->messageIn_SM->clear(); + ui->statusLabel_SM->setStyleSheet("QLabel { color: transparent; }"); +} + +void SettingsSignMessageWidgets::onSignMessageButtonSMClicked(){ + + if (!walletModel) + return; + + /* Clear old signature to ensure users don't get confused on error with an old signature displayed */ + ui->signatureOut_SM->clear(); + + CBitcoinAddress addr(ui->addressIn_SM->text().toStdString()); + if (!addr.IsValid()) { + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); + return; + } + CKeyID keyID; + if (!addr.GetKeyID(keyID)) { + // TODO: change css.. + //ui->addressIn_SM->setValid(false); + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); + return; + } + + WalletModel::UnlockContext ctx(walletModel->requestUnlock(AskPassphraseDialog::Context::Sign_Message, true)); + if (!ctx.isValid()) { + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(tr("Wallet unlock was cancelled.")); + return; + } + + CKey key; + if (!pwalletMain->GetKey(keyID, key)) { + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(tr("Private key for the entered address is not available.")); + return; + } + + CDataStream ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << ui->messageIn_SM->document()->toPlainText().toStdString(); + + std::vector vchSig; + if (!key.SignCompact(Hash(ss.begin(), ss.end()), vchSig)) { + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(QString("") + tr("Message signing failed.") + QString("")); + return; + } + + ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }"); + ui->statusLabel_SM->setText(QString("") + tr("Message signed.") + QString("")); + + ui->signatureOut_SM->setText(QString::fromStdString(EncodeBase64(&vchSig[0], vchSig.size()))); +} + +void SettingsSignMessageWidgets::onVerifyMessage(){ + + /** + * ui->addressIn_SM->clear(); + ui->signatureOut_SM->clear(); + ui->messageIn_SM->clear(); + ui->statusLabel_SM->setStyleSheet("QLabel { color: transparent; }"); + */ + + CBitcoinAddress addr(ui->addressIn_SM->text().toStdString()); + if (!addr.IsValid()) { + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(tr("The entered address is invalid.") + QString(" ") + tr("Please check the address and try again.")); + return; + } + CKeyID keyID; + if (!addr.GetKeyID(keyID)) { + //ui->addressIn_SM->setValid(false); + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(tr("The entered address does not refer to a key.") + QString(" ") + tr("Please check the address and try again.")); + return; + } + + bool fInvalid = false; + std::vector vchSig = DecodeBase64(ui->signatureOut_SM->text().toStdString().c_str(), &fInvalid); + + if (fInvalid) { + //ui->signatureOut_SM->setValid(false); + ui->signatureOut_SM->setStyleSheet("QLabel { color: red; }"); + ui->signatureOut_SM->setText(tr("The signature could not be decoded.") + QString(" ") + tr("Please check the signature and try again.")); + return; + } + + CDataStream ss(SER_GETHASH, 0); + ss << strMessageMagic; + ss << ui->messageIn_SM->document()->toPlainText().toStdString(); + + CPubKey pubkey; + if (!pubkey.RecoverCompact(Hash(ss.begin(), ss.end()), vchSig)) { + //ui->signatureOut_SM->setValid(false); + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(tr("The signature did not match the message digest.") + QString(" ") + tr("Please check the signature and try again.")); + return; + } + + if (!(CBitcoinAddress(pubkey.GetID()) == addr)) { + ui->statusLabel_SM->setStyleSheet("QLabel { color: red; }"); + ui->statusLabel_SM->setText(QString("") + tr("Message verification failed.") + QString("")); + return; + } + + ui->statusLabel_SM->setStyleSheet("QLabel { color: green; }"); + ui->statusLabel_SM->setText(QString("") + tr("Message verified.") + QString("")); +} + +void SettingsSignMessageWidgets::onAddressesClicked(){ + int addressSize = walletModel->getAddressTableModel()->sizeRecv(); + if(addressSize == 0) { + inform(tr("No addresses available, you can go to the receive screen and add some there!")); + return; + } + + int height = (addressSize <= 2) ? ui->addressIn_SM->height() * ( 2 * (addressSize + 1 )) : ui->addressIn_SM->height() * 4; + int width = ui->containerAddress->width(); + + if(!menuContacts){ + menuContacts = new ContactsDropdown( + width, + height, + this + ); + menuContacts->setWalletModel(walletModel, AddressTableModel::Receive); + connect(menuContacts, &ContactsDropdown::contactSelected, [this](QString address, QString label){ + setAddress_SM(address); + }); + + } + + if(menuContacts->isVisible()){ + menuContacts->hide(); + return; + } + + menuContacts->resizeList(width, height); + menuContacts->setStyleSheet(this->styleSheet()); + menuContacts->adjustSize(); + + QPoint pos = ui->container_sign->mapToParent(ui->containerAddress->rect().bottomLeft()); + pos.setY(pos.y() + (ui->containerAddress->height() * 1.4) - 10); + menuContacts->move(pos); + menuContacts->show(); +} + +void SettingsSignMessageWidgets::resizeMenu(){ + if(menuContacts && menuContacts->isVisible()){ + int width = ui->containerAddress->width(); + menuContacts->resizeList(width, menuContacts->height()); + menuContacts->resize(width, menuContacts->height()); + QPoint pos = ui->container_sign->mapToParent(ui->containerAddress->rect().bottomLeft()); + pos.setY(pos.y() + (ui->containerAddress->height() * 1.4) - 10); + menuContacts->move(pos); + } +} + +void SettingsSignMessageWidgets::resizeEvent(QResizeEvent *event){ + resizeMenu(); + QWidget::resizeEvent(event); +} diff --git a/src/qt/pivx/settings/settingssignmessagewidgets.h b/src/qt/pivx/settings/settingssignmessagewidgets.h new file mode 100644 index 000000000000..37f41a51bc68 --- /dev/null +++ b/src/qt/pivx/settings/settingssignmessagewidgets.h @@ -0,0 +1,45 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSSIGNMESSAGEWIDGETS_H +#define SETTINGSSIGNMESSAGEWIDGETS_H + +#include +#include "qt/pivx/pwidget.h" +#include "qt/pivx/contactsdropdown.h" + +namespace Ui { +class SettingsSignMessageWidgets; +} + +class SettingsSignMessageWidgets : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsSignMessageWidgets(PIVXGUI* _window, QWidget *parent = nullptr); + ~SettingsSignMessageWidgets(); + + void setAddress_SM(const QString& address); +protected: + void resizeEvent(QResizeEvent *event) override; +public slots: + void onSignMessageButtonSMClicked(); + void onVerifyMessage(); + void onPasteButtonSMClicked(); + void onAddressBookButtonSMClicked(); + void onGoClicked(); + void onClearAll(); + void onAddressesClicked(); + void onModeSelected(bool isSign); + void updateMode(); +private: + Ui::SettingsSignMessageWidgets *ui; + QAction *btnContact; + ContactsDropdown *menuContacts = nullptr; + bool isSign = true; + void resizeMenu(); +}; + +#endif // SETTINGSSIGNMESSAGEWIDGETS_H diff --git a/src/qt/pivx/settings/settingswalletoptionswidget.cpp b/src/qt/pivx/settings/settingswalletoptionswidget.cpp new file mode 100644 index 000000000000..da794c2c8d42 --- /dev/null +++ b/src/qt/pivx/settings/settingswalletoptionswidget.cpp @@ -0,0 +1,103 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingswalletoptionswidget.h" +#include "qt/pivx/settings/forms/ui_settingswalletoptionswidget.h" +#include +#include "optionsmodel.h" +#include "clientmodel.h" +#include "qt/pivx/qtutils.h" + +SettingsWalletOptionsWidget::SettingsWalletOptionsWidget(PIVXGUI* _window, QWidget *parent) : + PWidget(_window, parent), + ui(new Ui::SettingsWalletOptionsWidget) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + // Containers + ui->left->setProperty("cssClass", "container"); + ui->left->setContentsMargins(10,10,10,10); + ui->labelDivider->setProperty("cssClass", "container-divider"); + + // Title + ui->labelTitle->setText(tr("Wallet")); + ui->labelSubtitle1->setText(tr("Customize the internal wallet options")); + setCssTitleScreen(ui->labelTitle); + setCssSubtitleScreen(ui->labelSubtitle1); + + // Combobox + ui->labelTitleStake->setText(tr("Stake split threshold:")); + ui->labelTitleStake->setProperty("cssClass", "text-main-settings"); + + ui->spinBoxStakeSplitThreshold->setProperty("cssClass", "btn-spin-box"); + ui->spinBoxStakeSplitThreshold->setAttribute(Qt::WA_MacShowFocusRect, 0); + setShadow(ui->spinBoxStakeSplitThreshold); + + // Radio buttons + ui->radioButtonSpend->setText(tr("Spend unconfirmed change")); + + // Title + ui->labelTitleNetwork->setText(tr("Network")); + ui->labelSubtitleNetwork->setText(tr("Customize the node network options")); + setCssTitleScreen(ui->labelTitleNetwork); + setCssSubtitleScreen(ui->labelSubtitleNetwork); + + // Proxy + ui->labelSubtitleProxy->setText(tr("Proxy IP:")); + ui->labelSubtitleProxy->setProperty("cssClass", "text-main-settings"); + + ui->lineEditProxy->setPlaceholderText(tr("Enter proxy IP")); + initCssEditLine(ui->lineEditProxy); + + // Port + ui->labelSubtitlePort->setText(tr("Port:")); + ui->labelSubtitlePort->setProperty("cssClass", "text-main-settings"); + + ui->lineEditPort->setPlaceholderText("Enter port"); + initCssEditLine(ui->lineEditPort); + + // Radio buttons + ui->checkBoxMap->setText(tr("Map port using UPnP")); + ui->checkBoxAllow->setText(tr("Allow incoming connections")); + ui->checkBoxConnect->setText(tr("Connect through SOCKS5 proxy (default proxy):")); + + // Buttons + ui->pushButtonSave->setText(tr("SAVE")); + ui->pushButtonReset->setText(tr("Reset to default")); + setCssBtnPrimary(ui->pushButtonSave); + setCssBtnSecondary(ui->pushButtonReset); + setCssBtnSecondary(ui->pushButtonClean); + + connect(ui->pushButtonSave, SIGNAL(clicked()), parent, SLOT(onSaveOptionsClicked())); + connect(ui->pushButtonReset, SIGNAL(clicked()), this, SLOT(onResetClicked())); + connect(ui->pushButtonClean, SIGNAL(clicked()), parent, SLOT(onDiscardChanges())); +} + +void SettingsWalletOptionsWidget::onResetClicked(){ + if (clientModel) { + OptionsModel *optionsModel = clientModel->getOptionsModel(); + QSettings settings; + optionsModel->setWalletDefaultOptions(settings, true); + optionsModel->setNetworkDefaultOptions(settings, true); + inform(tr("Options reset succeed")); + } +} + +void SettingsWalletOptionsWidget::setMapper(QDataWidgetMapper *mapper){ + mapper->addMapping(ui->radioButtonSpend, OptionsModel::SpendZeroConfChange); + mapper->addMapping(ui->spinBoxStakeSplitThreshold, OptionsModel::StakeSplitThreshold); + + // Network + mapper->addMapping(ui->checkBoxMap, OptionsModel::MapPortUPnP); + mapper->addMapping(ui->checkBoxAllow, OptionsModel::Listen); + mapper->addMapping(ui->checkBoxConnect, OptionsModel::ProxyUse); + mapper->addMapping(ui->lineEditProxy, OptionsModel::ProxyIP); + mapper->addMapping(ui->lineEditPort, OptionsModel::ProxyPort); +} + +SettingsWalletOptionsWidget::~SettingsWalletOptionsWidget(){ + delete ui; +} diff --git a/src/qt/pivx/settings/settingswalletoptionswidget.h b/src/qt/pivx/settings/settingswalletoptionswidget.h new file mode 100644 index 000000000000..63fbdc564fcb --- /dev/null +++ b/src/qt/pivx/settings/settingswalletoptionswidget.h @@ -0,0 +1,32 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSWALLETOPTIONSWIDGET_H +#define SETTINGSWALLETOPTIONSWIDGET_H + +#include +#include +#include "qt/pivx/pwidget.h" +namespace Ui { +class SettingsWalletOptionsWidget; +} + +class SettingsWalletOptionsWidget : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsWalletOptionsWidget(PIVXGUI* _window, QWidget *parent = nullptr); + ~SettingsWalletOptionsWidget(); + + void setMapper(QDataWidgetMapper *mapper); + +public slots: + void onResetClicked(); + +private: + Ui::SettingsWalletOptionsWidget *ui; +}; + +#endif // SETTINGSWALLETOPTIONSWIDGET_H diff --git a/src/qt/pivx/settings/settingswalletrepairwidget.cpp b/src/qt/pivx/settings/settingswalletrepairwidget.cpp new file mode 100644 index 000000000000..12e648d3d8db --- /dev/null +++ b/src/qt/pivx/settings/settingswalletrepairwidget.cpp @@ -0,0 +1,175 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingswalletrepairwidget.h" +#include "qt/pivx/settings/forms/ui_settingswalletrepairwidget.h" +#include "qt/pivx/qtutils.h" + +// Repair parameters +const QString SALVAGEWALLET("-salvagewallet"); +const QString RESCAN("-rescan"); +const QString ZAPTXES1("-zapwallettxes=1"); +const QString ZAPTXES2("-zapwallettxes=2"); +const QString UPGRADEWALLET("-upgradewallet"); +const QString REINDEX("-reindex"); +const QString RESYNC("-resync"); + +SettingsWalletRepairWidget::SettingsWalletRepairWidget(PIVXGUI* _window, QWidget *parent) : + PWidget(_window, parent), + ui(new Ui::SettingsWalletRepairWidget) +{ + ui->setupUi(this); + this->setStyleSheet(parent->styleSheet()); + + // Containers + ui->left->setProperty("cssClass", "container"); + ui->left->setContentsMargins(10,10,10,10); + ui->scrollStack->setProperty("cssClass", "container"); + + // Title + ui->labelTitle->setText(tr("Wallet Repair")); + ui->labelTitle->setProperty("cssClass", "text-title-screen"); + + // Subtitle + ui->labelSubtitle1->setText(tr("The buttons below will restart the wallet with command-line options to repair this wallet, fix issues with corrupt blockchain files or missing/obsolete transactions.")); + ui->labelSubtitle1->setProperty("cssClass", "text-subtitle"); + + // Labels + ui->labelMessageSalvage->setText(tr("Attempt to recover private keys from a corrupt wallet.dat.")); + ui->labelMessageSalvage->setProperty("cssClass", "text-main-settings"); + + ui->labelMessageRescan->setText(tr("Rescan the blockchain for missing wallet transactions.")); + ui->labelMessageRescan->setProperty("cssClass", "text-main-settings"); + + ui->labelMessageRecover1->setText(tr("Recover transactions from blockchain (keep-meta-data, e.g. account owner).")); + ui->labelMessageRecover1->setProperty("cssClass", "text-main-settings"); + + ui->labelMessageRecover2->setText(tr("Recover transactions from blockchain (drop meta-data).")); + ui->labelMessageRecover2->setProperty("cssClass", "text-main-settings"); + + ui->labelMessageUpgrade->setText(tr("Upgrade wallet to latest format on startup. (Note: this is NOT an update of the wallet itself)")); + ui->labelMessageUpgrade->setProperty("cssClass", "text-main-settings"); + + ui->labelMessageRebuild->setText(tr("Rebuild blockchain index from current blk000???.dat files.")); + ui->labelMessageRebuild->setProperty("cssClass", "text-main-settings"); + + ui->labelMessageDelete->setText(tr("Deletes all local blockchain folders so the wallet synchronizes from scratch.")); + ui->labelMessageDelete->setProperty("cssClass", "text-main-settings"); + + // Buttons + ui->pushButtonSalvage->setText(tr("Salvage wallet")); + setCssBtnPrimary(ui->pushButtonSalvage); + + ui->pushButtonRescan->setText(tr("Rescan blockchain file")); + setCssBtnPrimary(ui->pushButtonRescan); + + ui->pushButtonRecover1->setText(tr("Recover transactions 1")); + setCssBtnPrimary(ui->pushButtonRecover1); + + ui->pushButtonRecover2->setText(tr("Recover transactions 2")); + setCssBtnPrimary(ui->pushButtonRecover2); + + ui->pushButtonUpgrade->setText(tr("Upgrade wallet format")); + setCssBtnPrimary(ui->pushButtonUpgrade); + + ui->pushButtonRebuild->setText(tr("Rebuild index")); + setCssBtnPrimary(ui->pushButtonRebuild); + + ui->pushButtonDelete->setText(tr("Delete local blockchain ")); + setCssBtnPrimary(ui->pushButtonDelete); + + + // Wallet Repair Buttons + connect(ui->pushButtonSalvage, SIGNAL(clicked()), this, SLOT(walletSalvage())); + connect(ui->pushButtonRescan, SIGNAL(clicked()), this, SLOT(walletRescan())); + connect(ui->pushButtonRecover1, SIGNAL(clicked()), this, SLOT(walletZaptxes1())); + connect(ui->pushButtonRecover2, SIGNAL(clicked()), this, SLOT(walletZaptxes2())); + connect(ui->pushButtonUpgrade, SIGNAL(clicked()), this, SLOT(walletUpgrade())); + connect(ui->pushButtonRebuild, SIGNAL(clicked()), this, SLOT(walletReindex())); + connect(ui->pushButtonDelete, SIGNAL(clicked()), this, SLOT(walletResync())); +} + +/** Restart wallet with "-salvagewallet" */ +void SettingsWalletRepairWidget::walletSalvage() +{ + buildParameterlist(SALVAGEWALLET); +} + +/** Restart wallet with "-rescan" */ +void SettingsWalletRepairWidget::walletRescan() +{ + buildParameterlist(RESCAN); +} + +/** Restart wallet with "-zapwallettxes=1" */ +void SettingsWalletRepairWidget::walletZaptxes1() +{ + buildParameterlist(ZAPTXES1); +} + +/** Restart wallet with "-zapwallettxes=2" */ +void SettingsWalletRepairWidget::walletZaptxes2() +{ + buildParameterlist(ZAPTXES2); +} + +/** Restart wallet with "-upgradewallet" */ +void SettingsWalletRepairWidget::walletUpgrade() +{ + buildParameterlist(UPGRADEWALLET); +} + +/** Restart wallet with "-reindex" */ +void SettingsWalletRepairWidget::walletReindex() +{ + buildParameterlist(REINDEX); +} + +/** Restart wallet with "-resync" */ +void SettingsWalletRepairWidget::walletResync() +{ + QString resyncWarning = tr("This will delete your local blockchain folders and the wallet will synchronize the complete Blockchain from scratch.

"); + resyncWarning += tr("This needs quite some time and downloads a lot of data.

"); + resyncWarning += tr("Your transactions and funds will be visible again after the download has completed.

"); + resyncWarning += tr("Do you want to continue?.
"); + QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm resync Blockchain"), + resyncWarning, + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Cancel); + + if (retval != QMessageBox::Yes) { + // Resync canceled + return; + } + + // Restart and resync + buildParameterlist(RESYNC); +} + +/** Build command-line parameter list for restart */ +void SettingsWalletRepairWidget::buildParameterlist(QString arg) +{ + // Get command-line arguments and remove the application name + QStringList args = QApplication::arguments(); + args.removeFirst(); + + // Remove existing repair-options + args.removeAll(SALVAGEWALLET); + args.removeAll(RESCAN); + args.removeAll(ZAPTXES1); + args.removeAll(ZAPTXES2); + args.removeAll(UPGRADEWALLET); + args.removeAll(REINDEX); + + // Append repair parameter to command line. + args.append(arg); + + // Send command-line arguments to PIVXGUI::handleRestart() + emit handleRestart(args); +} + +SettingsWalletRepairWidget::~SettingsWalletRepairWidget() +{ + delete ui; +} diff --git a/src/qt/pivx/settings/settingswalletrepairwidget.h b/src/qt/pivx/settings/settingswalletrepairwidget.h new file mode 100644 index 000000000000..176ff4637576 --- /dev/null +++ b/src/qt/pivx/settings/settingswalletrepairwidget.h @@ -0,0 +1,43 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSWALLETREPAIRWIDGET_H +#define SETTINGSWALLETREPAIRWIDGET_H + +#include +#include "qt/pivx/pwidget.h" + +namespace Ui { +class SettingsWalletRepairWidget; +} + +class SettingsWalletRepairWidget : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsWalletRepairWidget(PIVXGUI* _window, QWidget *parent = nullptr); + ~SettingsWalletRepairWidget(); + + /** Build parameter list for restart */ + void buildParameterlist(QString arg); + +signals: + /** Get restart command-line parameters and handle restart */ + void handleRestart(QStringList args); + +public slots: + void walletSalvage(); + void walletRescan(); + void walletZaptxes1(); + void walletZaptxes2(); + void walletUpgrade(); + void walletReindex(); + void walletResync(); + +private: + Ui::SettingsWalletRepairWidget *ui; +}; + +#endif // SETTINGSWALLETREPAIRWIDGET_H diff --git a/src/qt/pivx/settings/settingswidget.cpp b/src/qt/pivx/settings/settingswidget.cpp new file mode 100644 index 000000000000..b92fb3cff667 --- /dev/null +++ b/src/qt/pivx/settings/settingswidget.cpp @@ -0,0 +1,407 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/settings/settingswidget.h" +#include "qt/pivx/settings/forms/ui_settingswidget.h" +#include "qt/pivx/settings/settingsbackupwallet.h" +#include "qt/pivx/settings/settingsbittoolwidget.h" +#include "qt/pivx/settings/settingswalletrepairwidget.h" +#include "qt/pivx/settings/settingswalletoptionswidget.h" +#include "qt/pivx/settings/settingsmainoptionswidget.h" +#include "qt/pivx/settings/settingsdisplayoptionswidget.h" +#include "qt/pivx/settings/settingsmultisendwidget.h" +#include "qt/pivx/settings/settingsinformationwidget.h" +#include "qt/pivx/settings/settingsconsolewidget.h" +#include "qt/pivx/qtutils.h" +#include "qt/pivx/defaultdialog.h" +#include "optionsmodel.h" +#include "clientmodel.h" +#include "utilitydialog.h" +#include "wallet/wallet.h" +#include +#include + +SettingsWidget::SettingsWidget(PIVXGUI* parent) : + PWidget(parent), + ui(new Ui::SettingsWidget) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + + /* Containers */ + setCssProperty(ui->scrollArea, "container"); + setCssProperty(ui->left, "container"); + ui->left->setContentsMargins(0,20,0,20); + setCssProperty(ui->right, "container-right"); + ui->right->setContentsMargins(20,10,20,20); + + ui->verticalLayout->setAlignment(Qt::AlignTop); + + /* Light Font */ + QFont fontLight; + fontLight.setWeight(QFont::Light); + + /* Title */ + ui->labelTitle->setText(tr("Settings")); + setCssProperty(ui->labelTitle, "text-title-screen"); + ui->labelTitle->setFont(fontLight); + + setCssProperty(ui->pushButtonFile, "btn-settings-check"); + setCssProperty(ui->pushButtonFile2, "btn-settings-options"); + setCssProperty(ui->pushButtonFile3, "btn-settings-options"); + + setCssProperty(ui->pushButtonConfiguration, "btn-settings-check"); + setCssProperty(ui->pushButtonConfiguration3, "btn-settings-options"); + setCssProperty(ui->pushButtonConfiguration4, "btn-settings-options"); + + setCssProperty(ui->pushButtonOptions, "btn-settings-check"); + setCssProperty(ui->pushButtonOptions1, "btn-settings-options"); + setCssProperty(ui->pushButtonOptions2, "btn-settings-options"); + setCssProperty(ui->pushButtonOptions5, "btn-settings-options"); + + setCssProperty(ui->pushButtonTools, "btn-settings-check"); + setCssProperty(ui->pushButtonTools1, "btn-settings-options"); + setCssProperty(ui->pushButtonTools2, "btn-settings-options"); + setCssProperty(ui->pushButtonTools5, "btn-settings-options"); + + setCssProperty(ui->pushButtonHelp, "btn-settings-check"); + setCssProperty(ui->pushButtonHelp1, "btn-settings-options"); + setCssProperty(ui->pushButtonHelp2, "btn-settings-options"); + + options = { + ui->pushButtonFile2, + ui->pushButtonFile3, + ui->pushButtonOptions1, + ui->pushButtonOptions2, + ui->pushButtonOptions5, + ui->pushButtonConfiguration3, + ui->pushButtonConfiguration4, + ui->pushButtonHelp2, + ui->pushButtonTools1, + ui->pushButtonTools2, + ui->pushButtonTools5, + }; + + ui->pushButtonFile->setChecked(true); + ui->fileButtonsWidget->setVisible(true); + ui->optionsButtonsWidget->setVisible(false); + ui->configurationButtonsWidget->setVisible(false); + ui->toolsButtonsWidget->setVisible(false); + ui->helpButtonsWidget->setVisible(false); + + ui->pushButtonFile2->setChecked(true); + + settingsBackupWallet = new SettingsBackupWallet(window, this); + settingsBitToolWidget = new SettingsBitToolWidget(window, this); + settingsSingMessageWidgets = new SettingsSignMessageWidgets(window, this); + settingsWalletRepairWidget = new SettingsWalletRepairWidget(window, this); + settingsWalletOptionsWidget = new SettingsWalletOptionsWidget(window, this); + settingsMainOptionsWidget = new SettingsMainOptionsWidget(window, this); + settingsDisplayOptionsWidget = new SettingsDisplayOptionsWidget(window, this); + settingsMultisendWidget = new SettingsMultisendWidget(this); + settingsInformationWidget = new SettingsInformationWidget(window, this); + settingsConsoleWidget = new SettingsConsoleWidget(window, this); + + ui->stackedWidgetContainer->addWidget(settingsBackupWallet); + ui->stackedWidgetContainer->addWidget(settingsBitToolWidget); + ui->stackedWidgetContainer->addWidget(settingsSingMessageWidgets); + ui->stackedWidgetContainer->addWidget(settingsWalletRepairWidget); + ui->stackedWidgetContainer->addWidget(settingsWalletOptionsWidget); + ui->stackedWidgetContainer->addWidget(settingsMainOptionsWidget); + ui->stackedWidgetContainer->addWidget(settingsDisplayOptionsWidget); + ui->stackedWidgetContainer->addWidget(settingsMultisendWidget); + ui->stackedWidgetContainer->addWidget(settingsInformationWidget); + ui->stackedWidgetContainer->addWidget(settingsConsoleWidget); + ui->stackedWidgetContainer->setCurrentWidget(settingsBackupWallet); + + // File Section + connect(ui->pushButtonFile, SIGNAL(clicked()), this, SLOT(onFileClicked())); + connect(ui->pushButtonFile2, SIGNAL(clicked()), this, SLOT(onBackupWalletClicked())); + connect(ui->pushButtonFile3, SIGNAL(clicked()), this, SLOT(onMultisendClicked())); + + // Options + connect(ui->pushButtonOptions, SIGNAL(clicked()), this, SLOT(onOptionsClicked())); + connect(ui->pushButtonOptions1, SIGNAL(clicked()), this, SLOT(onMainOptionsClicked())); + connect(ui->pushButtonOptions2, SIGNAL(clicked()), this, SLOT(onWalletOptionsClicked())); + connect(ui->pushButtonOptions5, SIGNAL(clicked()), this, SLOT(onDisplayOptionsClicked())); + + // Configuration + connect(ui->pushButtonConfiguration, SIGNAL(clicked()), this, SLOT(onConfigurationClicked())); + connect(ui->pushButtonConfiguration3, SIGNAL(clicked()), this, SLOT(onBipToolClicked())); + connect(ui->pushButtonConfiguration4, SIGNAL(clicked()), this, SLOT(onSignMessageClicked())); + + // Tools + connect(ui->pushButtonTools, SIGNAL(clicked()), this, SLOT(onToolsClicked())); + connect(ui->pushButtonTools1, SIGNAL(clicked()), this, SLOT(onInformationClicked())); + connect(ui->pushButtonTools2, SIGNAL(clicked()), this, SLOT(onDebugConsoleClicked())); + ui->pushButtonTools2->setShortcut(QKeySequence(SHORT_KEY + Qt::Key_C)); + connect(ui->pushButtonTools5, SIGNAL(clicked()), this, SLOT(onWalletRepairClicked())); + + // Help + connect(ui->pushButtonHelp, SIGNAL(clicked()), this, SLOT(onHelpClicked())); + connect(ui->pushButtonHelp1, SIGNAL(clicked()), window, SLOT(openFAQ())); + connect(ui->pushButtonHelp2, SIGNAL(clicked()), this, SLOT(onAboutClicked())); + + // Get restart command-line parameters and handle restart + connect(settingsWalletRepairWidget, &SettingsWalletRepairWidget::handleRestart, [this](QStringList arg){emit handleRestart(arg);}); + + connect(settingsBackupWallet,&SettingsBackupWallet::message,this, &SettingsWidget::message); + connect(settingsBackupWallet, &SettingsBackupWallet::showHide, this, &SettingsWidget::showHide); + connect(settingsBackupWallet, &SettingsBackupWallet::execDialog, this, &SettingsWidget::execDialog); + connect(settingsMultisendWidget, &SettingsMultisendWidget::showHide, this, &SettingsWidget::showHide); + connect(settingsMultisendWidget, &SettingsMultisendWidget::message, this, &SettingsWidget::message); + connect(settingsMainOptionsWidget, &SettingsMainOptionsWidget::message, this, &SettingsWidget::message); + connect(settingsDisplayOptionsWidget, &SettingsDisplayOptionsWidget::message, this, &SettingsWidget::message); + connect(settingsWalletOptionsWidget, &SettingsWalletOptionsWidget::message, this, &SettingsWidget::message); + + /* Widget-to-option mapper */ + mapper = new QDataWidgetMapper(this); + mapper->setSubmitPolicy(QDataWidgetMapper::ManualSubmit); + mapper->setOrientation(Qt::Vertical); +} + +void SettingsWidget::loadClientModel(){ + if(clientModel) { + this->settingsInformationWidget->setClientModel(this->clientModel); + this->settingsConsoleWidget->setClientModel(this->clientModel); + + OptionsModel *optionsModel = this->clientModel->getOptionsModel(); + if (optionsModel) { + mapper->setModel(optionsModel); + setMapper(); + mapper->toFirst(); + settingsMainOptionsWidget->setClientModel(clientModel); + settingsDisplayOptionsWidget->setClientModel(clientModel); + settingsWalletOptionsWidget->setClientModel(clientModel); + /* keep consistency for action triggered elsewhere */ + connect(optionsModel, SIGNAL(hideOrphansChanged(bool)), this, SLOT(updateHideOrphans(bool))); + + // TODO: Connect show restart needed and apply changes. + } + } +} + +void SettingsWidget::loadWalletModel(){ + this->settingsBackupWallet->setWalletModel(this->walletModel); + this->settingsSingMessageWidgets->setWalletModel(this->walletModel); + this->settingsBitToolWidget->setWalletModel(this->walletModel); + this->settingsMultisendWidget->setWalletModel(this->walletModel); +} + +void SettingsWidget::onResetAction(){ + if (walletModel) { + // confirmation dialog + if (!ask(tr("Confirm options reset"), tr("Client restart required to activate changes.") + "

" + tr("Client will be shutdown, do you want to proceed?"))) + return; + + /* reset all options and close GUI */ + this->clientModel->getOptionsModel()->Reset(); + QApplication::quit(); + } +} + +void SettingsWidget::onSaveOptionsClicked(){ + if(mapper->submit()) { + pwalletMain->MarkDirty(); + if (this->clientModel->getOptionsModel()->isRestartRequired()) { + openStandardDialog(tr("Restart required"), tr("You wallet will be restarted to apply the changes\n"), tr("OK")); + emit handleRestart(QStringList()); + } else { + inform(tr("Options stored")); + } + } else { + inform(tr("Options store failed")); + } +} + +void SettingsWidget::onFileClicked() { + if (ui->pushButtonFile->isChecked()) { + ui->fileButtonsWidget->setVisible(true); + + ui->optionsButtonsWidget->setVisible(false); + ui->toolsButtonsWidget->setVisible(false); + ui->configurationButtonsWidget->setVisible(false); + ui->helpButtonsWidget->setVisible(false); + ui->pushButtonOptions->setChecked(false); + ui->pushButtonTools->setChecked(false); + ui->pushButtonConfiguration->setChecked(false); + ui->pushButtonHelp->setChecked(false); + + } else { + ui->fileButtonsWidget->setVisible(false); + } +} + +void SettingsWidget::onBackupWalletClicked() { + ui->stackedWidgetContainer->setCurrentWidget(settingsBackupWallet); + selectOption(ui->pushButtonFile2); +} + +void SettingsWidget::onSignMessageClicked() { + ui->stackedWidgetContainer->setCurrentWidget(settingsSingMessageWidgets); + selectOption(ui->pushButtonConfiguration4); +} + +void SettingsWidget::onConfigurationClicked() { + if (ui->pushButtonConfiguration->isChecked()) { + ui->configurationButtonsWidget->setVisible(true); + + ui->optionsButtonsWidget->setVisible(false); + ui->toolsButtonsWidget->setVisible(false); + ui->fileButtonsWidget->setVisible(false); + ui->helpButtonsWidget->setVisible(false); + ui->pushButtonOptions->setChecked(false); + ui->pushButtonTools->setChecked(false); + ui->pushButtonFile->setChecked(false); + ui->pushButtonHelp->setChecked(false); + + } else { + ui->configurationButtonsWidget->setVisible(false); + } +} + +void SettingsWidget::onBipToolClicked() { + ui->stackedWidgetContainer->setCurrentWidget(settingsBitToolWidget); + selectOption(ui->pushButtonConfiguration3); +} + +void SettingsWidget::onMultisendClicked() { + ui->stackedWidgetContainer->setCurrentWidget(settingsMultisendWidget); + selectOption(ui->pushButtonFile3); +} + +void SettingsWidget::onOptionsClicked() { + if (ui->pushButtonOptions->isChecked()) { + ui->optionsButtonsWidget->setVisible(true); + + ui->fileButtonsWidget->setVisible(false); + ui->toolsButtonsWidget->setVisible(false); + ui->configurationButtonsWidget->setVisible(false); + ui->helpButtonsWidget->setVisible(false); + ui->pushButtonFile->setChecked(false); + ui->pushButtonTools->setChecked(false); + ui->pushButtonConfiguration->setChecked(false); + ui->pushButtonHelp->setChecked(false); + + } else { + ui->optionsButtonsWidget->setVisible(false); + } +} + +void SettingsWidget::onMainOptionsClicked() { + ui->stackedWidgetContainer->setCurrentWidget(settingsMainOptionsWidget); + selectOption(ui->pushButtonOptions1); +} + +void SettingsWidget::onWalletOptionsClicked() { + ui->stackedWidgetContainer->setCurrentWidget(settingsWalletOptionsWidget); + selectOption(ui->pushButtonOptions2); +} + +void SettingsWidget::onDisplayOptionsClicked() { + ui->stackedWidgetContainer->setCurrentWidget(settingsDisplayOptionsWidget); + selectOption(ui->pushButtonOptions5); +} + + +void SettingsWidget::onToolsClicked() { + if (ui->pushButtonTools->isChecked()) { + ui->toolsButtonsWidget->setVisible(true); + + ui->optionsButtonsWidget->setVisible(false); + ui->fileButtonsWidget->setVisible(false); + ui->configurationButtonsWidget->setVisible(false); + ui->helpButtonsWidget->setVisible(false); + ui->pushButtonOptions->setChecked(false); + ui->pushButtonFile->setChecked(false); + ui->pushButtonConfiguration->setChecked(false); + ui->pushButtonHelp->setChecked(false); + + } else { + ui->toolsButtonsWidget->setVisible(false); + } +} + +void SettingsWidget::onInformationClicked() { + ui->stackedWidgetContainer->setCurrentWidget(settingsInformationWidget); + selectOption(ui->pushButtonTools1); +} + +void SettingsWidget::showDebugConsole(){ + ui->pushButtonTools->setChecked(true); + onToolsClicked(); + ui->pushButtonTools2->setChecked(true); + onDebugConsoleClicked(); +} + +void SettingsWidget::onDebugConsoleClicked() { + ui->stackedWidgetContainer->setCurrentWidget(settingsConsoleWidget); + selectOption(ui->pushButtonTools2); +} + +void SettingsWidget::onWalletRepairClicked() { + ui->stackedWidgetContainer->setCurrentWidget(settingsWalletRepairWidget); + selectOption(ui->pushButtonTools5); +} + + +void SettingsWidget::onHelpClicked() { + if (ui->pushButtonHelp->isChecked()) { + ui->helpButtonsWidget->setVisible(true); + + ui->toolsButtonsWidget->setVisible(false); + ui->optionsButtonsWidget->setVisible(false); + ui->fileButtonsWidget->setVisible(false); + ui->configurationButtonsWidget->setVisible(false); + ui->pushButtonOptions->setChecked(false); + ui->pushButtonFile->setChecked(false); + ui->pushButtonConfiguration->setChecked(false); + ui->pushButtonTools->setChecked(false); + } else { + ui->helpButtonsWidget->setVisible(false); + } +} + +void SettingsWidget::onAboutClicked() { + if (!clientModel) + return; + + HelpMessageDialog dlg(this, true); + dlg.exec(); + +} + +void SettingsWidget::selectOption(QPushButton* option){ + for (QPushButton* wid : options) { + if(wid) wid->setChecked(wid == option); + } +} + +void SettingsWidget::onDiscardChanges(){ + if(clientModel) { + if (!ask(tr("Discard Unsaved Changes"), tr("You are just about to discard all of your unsaved options.\n\nAre you sure?\n"))) + return; + clientModel->getOptionsModel()->refreshDataView(); + } +} + +void SettingsWidget::setMapper(){ + settingsMainOptionsWidget->setMapper(mapper); + settingsWalletOptionsWidget->setMapper(mapper); + settingsDisplayOptionsWidget->setMapper(mapper); +} + +void SettingsWidget::openStandardDialog(QString title, QString body, QString okBtn, QString cancelBtn){ + showHideOp(true); + DefaultDialog *confirmDialog = new DefaultDialog(window); + confirmDialog->setText(title, body, okBtn, cancelBtn); + confirmDialog->adjustSize(); + openDialogWithOpaqueBackground(confirmDialog, window); + confirmDialog->deleteLater(); +} + +SettingsWidget::~SettingsWidget(){ + delete ui; +} diff --git a/src/qt/pivx/settings/settingswidget.h b/src/qt/pivx/settings/settingswidget.h new file mode 100644 index 000000000000..c7692544c54d --- /dev/null +++ b/src/qt/pivx/settings/settingswidget.h @@ -0,0 +1,101 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SETTINGSWIDGET_H +#define SETTINGSWIDGET_H + +#include +#include "qt/pivx/pwidget.h" +#include "qt/pivx/settings/settingsbackupwallet.h" +#include "qt/pivx/settings/settingsbittoolwidget.h" +#include "qt/pivx/settings/settingssignmessagewidgets.h" +#include "qt/pivx/settings/settingswalletrepairwidget.h" +#include "qt/pivx/settings/settingswalletoptionswidget.h" +#include "qt/pivx/settings/settingsmainoptionswidget.h" +#include "qt/pivx/settings/settingsdisplayoptionswidget.h" +#include "qt/pivx/settings/settingsmultisendwidget.h" +#include "qt/pivx/settings/settingsinformationwidget.h" +#include "qt/pivx/settings/settingsconsolewidget.h" + +class PIVXGUI; + +QT_BEGIN_NAMESPACE +class QDataWidgetMapper; +QT_END_NAMESPACE + +namespace Ui { +class SettingsWidget; +} + +class SettingsWidget : public PWidget +{ + Q_OBJECT + +public: + explicit SettingsWidget(PIVXGUI* parent); + ~SettingsWidget(); + + void loadClientModel() override; + void loadWalletModel() override; + void setMapper(); + void showDebugConsole(); + +signals: + /** Get restart command-line parameters and handle restart */ + void handleRestart(QStringList args); + +private slots: + // File + void onFileClicked(); + void onBackupWalletClicked(); + void onSignMessageClicked(); + + // Wallet Configuration + void onConfigurationClicked(); + void onBipToolClicked(); + void onMultisendClicked(); + + // Options + void onOptionsClicked(); + void onMainOptionsClicked(); + void onWalletOptionsClicked(); + void onDisplayOptionsClicked(); + + void onDiscardChanges(); + + // Tools + void onToolsClicked(); + void onInformationClicked(); + void onDebugConsoleClicked(); + void onWalletRepairClicked(); + + // Help + void onHelpClicked(); + void onAboutClicked(); + + void onResetAction(); + void onSaveOptionsClicked(); +private: + Ui::SettingsWidget *ui; + + SettingsBackupWallet *settingsBackupWallet; + SettingsBitToolWidget *settingsBitToolWidget; + SettingsSignMessageWidgets *settingsSingMessageWidgets; + SettingsWalletRepairWidget *settingsWalletRepairWidget; + SettingsWalletOptionsWidget *settingsWalletOptionsWidget; + SettingsMainOptionsWidget *settingsMainOptionsWidget; + SettingsDisplayOptionsWidget *settingsDisplayOptionsWidget; + SettingsMultisendWidget *settingsMultisendWidget; + SettingsInformationWidget *settingsInformationWidget; + SettingsConsoleWidget *settingsConsoleWidget; + + QDataWidgetMapper* mapper; + + QList options; + + void selectOption(QPushButton* option); + void openStandardDialog(QString title = "", QString body = "", QString okBtn = "OK", QString cancelBtn = ""); +}; + +#endif // SETTINGSWIDGET_H diff --git a/src/qt/pivx/snackbar.cpp b/src/qt/pivx/snackbar.cpp new file mode 100644 index 000000000000..5a9ef01707dd --- /dev/null +++ b/src/qt/pivx/snackbar.cpp @@ -0,0 +1,58 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/snackbar.h" +#include "qt/pivx/forms/ui_snackbar.h" +#include "qt/pivx/qtutils.h" +#include + + +SnackBar::SnackBar(PIVXGUI* _window, QWidget *parent) : + QDialog(parent), + ui(new Ui::SnackBar), + window(_window) +{ + ui->setupUi(this); + + this->setStyleSheet(parent->styleSheet()); + ui->snackContainer->setProperty("cssClass", "container-snackbar"); + ui->label->setProperty("cssClass", "text-snackbar"); + ui->pushButton->setProperty("cssClass", "ic-close"); + + connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(close())); + if (window) + connect(window, SIGNAL(windowResizeEvent(QResizeEvent*)), this, SLOT(windowResizeEvent(QResizeEvent*))); + else { + ui->horizontalLayout->setContentsMargins(0,0,0,0); + ui->label->setStyleSheet("font-size: 15px; color:white;"); + } +} + +void SnackBar::windowResizeEvent(QResizeEvent* event){ + this->resize(qobject_cast(parent())->width(), this->height()); + this->move(QPoint(0, window->height() - this->height() )); +} + +void SnackBar::showEvent(QShowEvent *event){ + QTimer::singleShot(3000, this, SLOT(hideAnim())); +} + +void SnackBar::hideAnim(){ + if (window) closeDialog(this, window); + QTimer::singleShot(310, this, SLOT(hide())); +} + + + +void SnackBar::sizeTo(QWidget* widget){ + +} + +void SnackBar::setText(QString text){ + ui->label->setText(text); +} + +SnackBar::~SnackBar(){ + delete ui; +} diff --git a/src/qt/pivx/snackbar.h b/src/qt/pivx/snackbar.h new file mode 100644 index 000000000000..3b86b999f8ac --- /dev/null +++ b/src/qt/pivx/snackbar.h @@ -0,0 +1,35 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SNACKBAR_H +#define SNACKBAR_H + +#include + +class PIVXGUI; + +namespace Ui { +class SnackBar; +} + +class SnackBar : public QDialog +{ + Q_OBJECT + +public: + explicit SnackBar(PIVXGUI* _window = nullptr, QWidget *parent = nullptr); + ~SnackBar(); + + virtual void showEvent(QShowEvent *event) override; + void sizeTo(QWidget *widget); + void setText(QString text); +private slots: + void hideAnim(); + void windowResizeEvent(QResizeEvent *event); +private: + Ui::SnackBar *ui; + PIVXGUI* window = nullptr; +}; + +#endif // SNACKBAR_H diff --git a/src/qt/pivx/splash.cpp b/src/qt/pivx/splash.cpp new file mode 100644 index 000000000000..daed6f08b475 --- /dev/null +++ b/src/qt/pivx/splash.cpp @@ -0,0 +1,107 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/splash.h" +#include "qt/pivx/forms/ui_splash.h" +#include "QFile" + +#include "init.h" +#include "guiinterface.h" +#include "networkstyle.h" +#include "util.h" +#include "version.h" +#include "guiutil.h" + +#ifdef ENABLE_WALLET +#include "wallet/wallet.h" +#endif + +#include +#include + +#include + +Splash::Splash(QWidget *parent) : + QWidget(parent, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint), + ui(new Ui::Splash) +{ + ui->setupUi(this); + setWindowTitle("PIVX Wallet"); + + this->setStyleSheet(GUIUtil::loadStyleSheet()); + this->setAttribute( Qt::WA_TranslucentBackground, true ); + ui->progressBar->setAttribute( Qt::WA_TranslucentBackground, true ); + + ui->progressBar->setTextVisible(false); + ui->progressBar->setMaximum(0); + ui->progressBar->setMinimum(0); + ui->progressBar->setProperty("cssClass", "progress-splash"); + ui->frame->setProperty("cssClass", "container-splash"); + ui->layoutProgress->setProperty("cssClass", "bg-progress"); + ui->imgLogo->setProperty("cssClass", "img-splash-logo"); + + // Resize window and move to center of desktop, disallow resizing + QRect r(QPoint(), size()); + resize(r.size()); + setFixedSize(r.size()); + move(QApplication::desktop()->screenGeometry().center() - r.center()); + + subscribeToCoreSignals(); +} + +Splash::~Splash(){ + unsubscribeFromCoreSignals(); + delete ui; +} + +void Splash::slotFinish(QWidget* mainWin){ + Q_UNUSED(mainWin); + hide(); +} + +static void InitMessage(Splash* splash, const std::string& message){ + QMetaObject::invokeMethod(splash, "showMessage", + Qt::QueuedConnection, + Q_ARG(QString, QString::fromStdString(message)), + Q_ARG(int, Qt::AlignBottom | Qt::AlignHCenter), + Q_ARG(QColor, QColor(100, 100, 100))); +} + +static void ShowProgress(Splash* splash, const std::string& title, int nProgress){ + InitMessage(splash, title + strprintf("%d", nProgress) + "%"); +} + +#ifdef ENABLE_WALLET +static void ConnectWallet(Splash* splash, CWallet* wallet){ + wallet->ShowProgress.connect(boost::bind(ShowProgress, splash, _1, _2)); +} +#endif + +void Splash::subscribeToCoreSignals(){ + // Connect signals to client + uiInterface.InitMessage.connect(boost::bind(InitMessage, this, _1)); + uiInterface.ShowProgress.connect(boost::bind(ShowProgress, this, _1, _2)); +#ifdef ENABLE_WALLET + uiInterface.LoadWallet.connect(boost::bind(ConnectWallet, this, _1)); +#endif +} + +void Splash::unsubscribeFromCoreSignals(){ + // Disconnect signals from client + uiInterface.InitMessage.disconnect(boost::bind(InitMessage, this, _1)); + uiInterface.ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); +#ifdef ENABLE_WALLET + if (pwalletMain) + pwalletMain->ShowProgress.disconnect(boost::bind(ShowProgress, this, _1, _2)); +#endif +} + +void Splash::showMessage(const QString& message, int alignment, const QColor& color){ + ui->lblMessage->setText(message); +} + +void Splash::closeEvent(QCloseEvent* event){ + StartShutdown(); // allows an "emergency" shutdown during startup + event->ignore(); +} diff --git a/src/qt/pivx/splash.h b/src/qt/pivx/splash.h new file mode 100644 index 000000000000..0ecfd836cf9a --- /dev/null +++ b/src/qt/pivx/splash.h @@ -0,0 +1,41 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef SPLASH_H +#define SPLASH_H + +#include + +namespace Ui { +class Splash; +} + +class Splash : public QWidget +{ + Q_OBJECT + +public: + explicit Splash(QWidget *parent = nullptr); + ~Splash(); + +public slots: + /** Slot to call finish() method as it's not defined as slot */ + void slotFinish(QWidget* mainWin); + + /** Show message and progress */ + void showMessage(const QString& message, int alignment, const QColor& color); + +protected: + void closeEvent(QCloseEvent* event); + +private: + Ui::Splash *ui; + + /** Connect core signals to splash screen */ + void subscribeToCoreSignals(); + /** Disconnect core signals to splash screen */ + void unsubscribeFromCoreSignals(); +}; + +#endif // SPLASH_H diff --git a/src/qt/pivx/tooltipmenu.cpp b/src/qt/pivx/tooltipmenu.cpp new file mode 100644 index 000000000000..37d0cd67667b --- /dev/null +++ b/src/qt/pivx/tooltipmenu.cpp @@ -0,0 +1,66 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/tooltipmenu.h" +#include "qt/pivx/forms/ui_tooltipmenu.h" + +#include "qt/pivx/pivxgui.h" +#include "qt/pivx/qtutils.h" +#include + +TooltipMenu::TooltipMenu(PIVXGUI *_window, QWidget *parent) : + PWidget(_window, parent), + ui(new Ui::TooltipMenu) +{ + ui->setupUi(this); + setCssProperty(ui->container, "container-list-menu"); + setCssProperty({ui->btnCopy, ui->btnDelete, ui->btnEdit}, "btn-list-menu"); + connect(ui->btnCopy, SIGNAL(clicked()), this, SLOT(copyClicked())); + connect(ui->btnDelete, SIGNAL(clicked()), this, SLOT(deleteClicked())); + connect(ui->btnEdit, SIGNAL(clicked()), this, SLOT(editClicked())); +} + +void TooltipMenu::setEditBtnText(QString btnText){ + ui->btnEdit->setText(btnText); +} + +void TooltipMenu::setDeleteBtnText(QString btnText){ + ui->btnDelete->setText(btnText); +} + +void TooltipMenu::setCopyBtnText(QString btnText){ + ui->btnCopy->setText(btnText); +} + +void TooltipMenu::setCopyBtnVisible(bool visible){ + ui->btnCopy->setVisible(visible); +} + +void TooltipMenu::setDeleteBtnVisible(bool visible){ + ui->btnDelete->setVisible(visible); +} + +void TooltipMenu::deleteClicked(){ + hide(); + emit onDeleteClicked(); +} + +void TooltipMenu::copyClicked(){ + hide(); + emit onCopyClicked(); +} + +void TooltipMenu::editClicked(){ + hide(); + emit onEditClicked(); +} + +void TooltipMenu::showEvent(QShowEvent *event){ + QTimer::singleShot(5000, this, SLOT(hide())); +} + +TooltipMenu::~TooltipMenu() +{ + delete ui; +} diff --git a/src/qt/pivx/tooltipmenu.h b/src/qt/pivx/tooltipmenu.h new file mode 100644 index 000000000000..2699aab1b420 --- /dev/null +++ b/src/qt/pivx/tooltipmenu.h @@ -0,0 +1,55 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef TOOLTIPMENU_H +#define TOOLTIPMENU_H + +#include "qt/pivx/pwidget.h" +#include +#include + +class PIVXGUI; +class WalletModel; + +namespace Ui { +class TooltipMenu; +} + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +class TooltipMenu : public PWidget +{ + Q_OBJECT + +public: + explicit TooltipMenu(PIVXGUI* _window, QWidget *parent = nullptr); + ~TooltipMenu() override; + + void setIndex(const QModelIndex &index); + virtual void showEvent(QShowEvent *event) override; + + void setEditBtnText(QString btnText); + void setDeleteBtnText(QString btnText); + void setCopyBtnText(QString btnText); + void setCopyBtnVisible(bool visible); + void setDeleteBtnVisible(bool visible); + +signals: + void onDeleteClicked(); + void onCopyClicked(); + void onEditClicked(); + +private slots: + void deleteClicked(); + void copyClicked(); + void editClicked(); + +private: + Ui::TooltipMenu *ui; + QModelIndex index; +}; + +#endif // TOOLTIPMENU_H diff --git a/src/qt/pivx/topbar.cpp b/src/qt/pivx/topbar.cpp new file mode 100644 index 000000000000..b17e21562bc5 --- /dev/null +++ b/src/qt/pivx/topbar.cpp @@ -0,0 +1,521 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/topbar.h" +#include "qt/pivx/forms/ui_topbar.h" +#include +#include "qt/pivx/lockunlock.h" +#include "qt/pivx/qtutils.h" +#include "qt/pivx/receivedialog.h" +#include "askpassphrasedialog.h" + +#include "bitcoinunits.h" +#include "clientmodel.h" +#include "qt/guiconstants.h" +#include "qt/guiutil.h" +#include "optionsmodel.h" +#include "qt/platformstyle.h" +#include "wallet/wallet.h" +#include "walletmodel.h" +#include "addresstablemodel.h" +#include "guiinterface.h" + + +TopBar::TopBar(PIVXGUI* _mainWindow, QWidget *parent) : + PWidget(_mainWindow, parent), + ui(new Ui::TopBar) +{ + ui->setupUi(this); + + // Set parent stylesheet + this->setStyleSheet(_mainWindow->styleSheet()); + + /* Containers */ + ui->containerTop->setProperty("cssClass", "container-top"); + ui->containerTop->setContentsMargins(10,4,10,10); + + std::initializer_list lblTitles = {ui->labelTitle1, ui->labelTitle2, ui->labelTitle3, ui->labelTitle4, ui->labelTitle5, ui->labelTitle6}; + setCssProperty(lblTitles, "text-title-topbar"); + QFont font; + font.setWeight(QFont::Light); + foreach (QWidget* w, lblTitles) { w->setFont(font); } + + // Amount information top + ui->widgetTopAmount->setVisible(false); + setCssProperty({ui->labelAmountTopPiv, ui->labelAmountTopzPiv}, "amount-small-topbar"); + setCssProperty({ui->labelAmountPiv, ui->labelAmountzPiv}, "amount-topbar"); + setCssProperty({ui->labelPendingPiv, ui->labelPendingzPiv, ui->labelImmaturePiv, ui->labelImmaturezPiv}, "amount-small-topbar"); + + // Progress Sync + progressBar = new QProgressBar(ui->layoutSync); + progressBar->setRange(1, 10); + progressBar->setValue(4); + progressBar->setTextVisible(false); + progressBar->setMaximumHeight(2); + progressBar->setMaximumWidth(36); + setCssProperty(progressBar, "progress-sync"); + progressBar->show(); + progressBar->raise(); + progressBar->move(0, 34); + + // New button + ui->pushButtonFAQ->setButtonClassStyle("cssClass", "btn-check-faq"); + ui->pushButtonFAQ->setButtonText("FAQ"); + + ui->pushButtonConnection->setButtonClassStyle("cssClass", "btn-check-connect-inactive"); + ui->pushButtonConnection->setButtonText("No Connection"); + + ui->pushButtonStack->setButtonClassStyle("cssClass", "btn-check-stack-inactive"); + ui->pushButtonStack->setButtonText("Staking Disabled"); + + ui->pushButtonMint->setButtonClassStyle("cssClass", "btn-check-mint-inactive"); + ui->pushButtonMint->setButtonText("Automint Enabled"); + ui->pushButtonMint->setVisible(false); + + ui->pushButtonSync->setButtonClassStyle("cssClass", "btn-check-sync"); + ui->pushButtonSync->setButtonText(" %54 Synchronizing.."); + + ui->pushButtonLock->setButtonClassStyle("cssClass", "btn-check-lock"); + + if(isLightTheme()){ + ui->pushButtonTheme->setButtonClassStyle("cssClass", "btn-check-theme-light"); + ui->pushButtonTheme->setButtonText("Light Theme"); + }else{ + ui->pushButtonTheme->setButtonClassStyle("cssClass", "btn-check-theme-dark"); + ui->pushButtonTheme->setButtonText("Dark Theme"); + } + + setCssProperty(ui->qrContainer, "container-qr"); + setCssProperty(ui->pushButtonQR, "btn-qr"); + + // QR image + QPixmap pixmap("://img-qr-test"); + ui->btnQr->setIcon( + QIcon(pixmap.scaled( + 70, + 70, + Qt::KeepAspectRatio)) + ); + + ui->pushButtonLock->setButtonText("Wallet Locked "); + ui->pushButtonLock->setButtonClassStyle("cssClass", "btn-check-status-lock"); + + + connect(ui->pushButtonQR, SIGNAL(clicked()), this, SLOT(onBtnReceiveClicked())); + connect(ui->btnQr, SIGNAL(clicked()), this, SLOT(onBtnReceiveClicked())); + connect(ui->pushButtonLock, SIGNAL(Mouse_Pressed()), this, SLOT(onBtnLockClicked())); + connect(ui->pushButtonTheme, SIGNAL(Mouse_Pressed()), this, SLOT(onThemeClicked())); + connect(ui->pushButtonFAQ, SIGNAL(Mouse_Pressed()), _mainWindow, SLOT(openFAQ())); +} + +void TopBar::onThemeClicked(){ + // Store theme + bool lightTheme = !isLightTheme(); + + setTheme(lightTheme); + + if(lightTheme){ + ui->pushButtonTheme->setButtonClassStyle("cssClass", "btn-check-theme-light", true); + ui->pushButtonTheme->setButtonText("Light Theme"); + updateStyle(ui->pushButtonTheme); + }else{ + ui->pushButtonTheme->setButtonClassStyle("cssClass", "btn-check-theme-dark", true); + ui->pushButtonTheme->setButtonText("Dark Theme"); + updateStyle(ui->pushButtonTheme); + } + + emit themeChanged(lightTheme); +} + + +void TopBar::onBtnLockClicked(){ + if(walletModel) { + if (walletModel->getEncryptionStatus() == WalletModel::Unencrypted) { + encryptWallet(); + } else { + if (!lockUnlockWidget) { + lockUnlockWidget = new LockUnlock(window); + lockUnlockWidget->setStyleSheet("margin:0px; padding:0px;"); + connect(lockUnlockWidget, SIGNAL(Mouse_Leave()), this, SLOT(lockDropdownMouseLeave())); + connect(ui->pushButtonLock, &ExpandableButton::Mouse_HoverLeave, [this](){ + QMetaObject::invokeMethod(this, "lockDropdownMouseLeave", Qt::QueuedConnection); + }); //, SLOT(lockDropdownMouseLeave())); + connect(lockUnlockWidget, SIGNAL(lockClicked( + const StateClicked&)),this, SLOT(lockDropdownClicked( + const StateClicked&))); + } + + lockUnlockWidget->updateStatus(walletModel->getEncryptionStatus()); + if (ui->pushButtonLock->width() <= 40) { + ui->pushButtonLock->setExpanded(); + } + // Keep it open + ui->pushButtonLock->setKeepExpanded(true); + QMetaObject::invokeMethod(this, "openLockUnlock", Qt::QueuedConnection); + } + } +} + +void TopBar::openLockUnlock(){ + lockUnlockWidget->setFixedWidth(ui->pushButtonLock->width()); + lockUnlockWidget->adjustSize(); + + lockUnlockWidget->move( + ui->pushButtonLock->pos().rx() + window->getNavWidth() + 10, + ui->pushButtonLock->y() + 36 + ); + + lockUnlockWidget->raise(); + lockUnlockWidget->activateWindow(); + lockUnlockWidget->show(); +} + +void TopBar::encryptWallet() { + if (!walletModel) + return; + + showHideOp(true); + AskPassphraseDialog *dlg = new AskPassphraseDialog(AskPassphraseDialog::Mode::Encrypt, window, + walletModel, AskPassphraseDialog::Context::Encrypt); + dlg->adjustSize(); + openDialogWithOpaqueBackgroundY(dlg, window); + + refreshStatus(); + dlg->deleteLater(); +} + +static bool isExecuting = false; +void TopBar::lockDropdownClicked(const StateClicked& state){ + lockUnlockWidget->close(); + if(walletModel && !isExecuting) { + isExecuting = true; + + switch (lockUnlockWidget->lock) { + case 0: { + if (walletModel->getEncryptionStatus() == WalletModel::Locked) + break; + walletModel->setWalletLocked(true); + ui->pushButtonLock->setButtonText("Wallet Locked"); + ui->pushButtonLock->setButtonClassStyle("cssClass", "btn-check-status-lock", true); + break; + } + case 1: { + if (walletModel->getEncryptionStatus() == WalletModel::Unlocked) + break; + showHideOp(true); + AskPassphraseDialog *dlg = new AskPassphraseDialog(AskPassphraseDialog::Mode::Unlock, window, walletModel, + AskPassphraseDialog::Context::ToggleLock); + dlg->adjustSize(); + openDialogWithOpaqueBackgroundY(dlg, window); + if (this->walletModel->getEncryptionStatus() == WalletModel::Unlocked) { + ui->pushButtonLock->setButtonText("Wallet Unlocked"); + ui->pushButtonLock->setButtonClassStyle("cssClass", "btn-check-status-unlock", true); + } + dlg->deleteLater(); + break; + } + case 2: { + if (walletModel->getEncryptionStatus() == WalletModel::UnlockedForAnonymizationOnly) + break; + showHideOp(true); + AskPassphraseDialog *dlg = new AskPassphraseDialog(AskPassphraseDialog::Mode::UnlockAnonymize, window, walletModel, + AskPassphraseDialog::Context::ToggleLock); + dlg->adjustSize(); + openDialogWithOpaqueBackgroundY(dlg, window); + if (this->walletModel->getEncryptionStatus() == WalletModel::UnlockedForAnonymizationOnly) { + ui->pushButtonLock->setButtonText(tr("Wallet Unlocked for staking")); + ui->pushButtonLock->setButtonClassStyle("cssClass", "btn-check-status-staking", true); + } + dlg->deleteLater(); + break; + } + } + + ui->pushButtonLock->setKeepExpanded(false); + ui->pushButtonLock->setSmall(); + ui->pushButtonLock->update(); + + isExecuting = false; + } +} + +void TopBar::lockDropdownMouseLeave(){ + if (lockUnlockWidget->isVisible() && !lockUnlockWidget->isHovered()) { + lockUnlockWidget->hide(); + ui->pushButtonLock->setKeepExpanded(false); + ui->pushButtonLock->setSmall(); + ui->pushButtonLock->update(); + } +} + +void TopBar::onBtnReceiveClicked(){ + if(walletModel) { + showHideOp(true); + ReceiveDialog *receiveDialog = new ReceiveDialog(window); + + receiveDialog->updateQr(walletModel->getAddressTableModel()->getLastUnusedAddress()); + if (openDialogWithOpaqueBackground(receiveDialog, window)) { + inform(tr("Address Copied")); + } + receiveDialog->deleteLater(); + } +} + +void TopBar::showTop(){ + if(ui->bottom_container->isVisible()){ + ui->bottom_container->setVisible(false); + ui->widgetTopAmount->setVisible(true); + this->setFixedHeight(75); + } +} + +void TopBar::showBottom(){ + ui->widgetTopAmount->setVisible(false); + ui->bottom_container->setVisible(true); + this->setFixedHeight(200); + this->adjustSize(); +} + +TopBar::~TopBar(){ + if(timerStakingIcon){ + timerStakingIcon->stop(); + } + delete ui; +} + +void TopBar::loadClientModel(){ + if(clientModel){ + // Keep up to date with client + setNumConnections(clientModel->getNumConnections()); + connect(clientModel, SIGNAL(numConnectionsChanged(int)), this, SLOT(setNumConnections(int))); + + setNumBlocks(clientModel->getNumBlocks()); + connect(clientModel, SIGNAL(numBlocksChanged(int)), this, SLOT(setNumBlocks(int))); + + timerStakingIcon = new QTimer(ui->pushButtonStack); + connect(timerStakingIcon, SIGNAL(timeout()), this, SLOT(updateStakingStatus())); + timerStakingIcon->start(50000); + updateStakingStatus(); + } +} + +void TopBar::updateAutoMintStatus(){ + ui->pushButtonMint->setButtonText(fEnableZeromint ? tr("Automint enabled") : tr("Automint disabled")); + ui->pushButtonMint->setChecked(fEnableZeromint); +} + +void TopBar::updateStakingStatus(){ + if (nLastCoinStakeSearchInterval) { + if (!ui->pushButtonStack->isChecked()) { + ui->pushButtonStack->setButtonText(tr("Staking active")); + ui->pushButtonStack->setChecked(true); + ui->pushButtonStack->setButtonClassStyle("cssClass", "btn-check-stack", true); + } + }else{ + if (ui->pushButtonStack->isChecked()) { + ui->pushButtonStack->setButtonText(tr("Staking not active")); + ui->pushButtonStack->setChecked(false); + ui->pushButtonStack->setButtonClassStyle("cssClass", "btn-check-stack-inactive", true); + } + } +} + +void TopBar::setNumConnections(int count) { + if(count > 0){ + if(!ui->pushButtonConnection->isChecked()) { + ui->pushButtonConnection->setChecked(true); + ui->pushButtonConnection->setButtonClassStyle("cssClass", "btn-check-connect", true); + } + }else{ + if(ui->pushButtonConnection->isChecked()) { + ui->pushButtonConnection->setChecked(false); + ui->pushButtonConnection->setButtonClassStyle("cssClass", "btn-check-connect-inactive", true); + } + } + + ui->pushButtonConnection->setButtonText(tr("%n active connection(s)", "", count)); +} + +void TopBar::setNumBlocks(int count) { + if (!clientModel) + return; + + // Acquire current block source + enum BlockSource blockSource = clientModel->getBlockSource(); + std::string text = ""; + switch (blockSource) { + case BLOCK_SOURCE_NETWORK: + text = "Synchronizing.."; + break; + case BLOCK_SOURCE_DISK: + text = "Importing blocks from disk.."; + break; + case BLOCK_SOURCE_REINDEX: + text = "Reindexing blocks on disk.."; + break; + case BLOCK_SOURCE_NONE: + // Case: not Importing, not Reindexing and no network connection + text = "No block source available.."; + ui->pushButtonSync->setChecked(false); + break; + } + + bool needState = true; + if (masternodeSync.IsBlockchainSynced()) { + // chain synced + emit walletSynced(true); + if (masternodeSync.IsSynced()) { + // Node synced + // TODO: Set synced icon to pushButtonSync here.. + ui->pushButtonSync->setButtonText(tr("Synchronized")); + progressBar->setRange(0,100); + progressBar->setValue(100); + return; + }else{ + + // TODO: Show out of sync warning + int nAttempt = masternodeSync.RequestedMasternodeAttempt < MASTERNODE_SYNC_THRESHOLD ? + masternodeSync.RequestedMasternodeAttempt + 1 : + MASTERNODE_SYNC_THRESHOLD; + int progress = nAttempt + (masternodeSync.RequestedMasternodeAssets - 1) * MASTERNODE_SYNC_THRESHOLD; + if(progress >= 0){ + // todo: MN progress.. + text = std::string("Synchronizing additional data..");//: %p%", progress); + //progressBar->setMaximum(4 * MASTERNODE_SYNC_THRESHOLD); + //progressBar->setValue(progress); + needState = false; + } + } + } else { + emit walletSynced(false); + } + + if(needState) { + // Represent time from last generated block in human readable text + QDateTime lastBlockDate = clientModel->getLastBlockDate(); + QDateTime currentDate = QDateTime::currentDateTime(); + int secs = lastBlockDate.secsTo(currentDate); + + QString timeBehindText; + const int HOUR_IN_SECONDS = 60 * 60; + const int DAY_IN_SECONDS = 24 * 60 * 60; + const int WEEK_IN_SECONDS = 7 * 24 * 60 * 60; + const int YEAR_IN_SECONDS = 31556952; // Average length of year in Gregorian calendar + if (secs < 2 * DAY_IN_SECONDS) { + timeBehindText = tr("%n hour(s)", "", secs / HOUR_IN_SECONDS); + } else if (secs < 2 * WEEK_IN_SECONDS) { + timeBehindText = tr("%n day(s)", "", secs / DAY_IN_SECONDS); + } else if (secs < YEAR_IN_SECONDS) { + timeBehindText = tr("%n week(s)", "", secs / WEEK_IN_SECONDS); + } else { + int years = secs / YEAR_IN_SECONDS; + int remainder = secs % YEAR_IN_SECONDS; + timeBehindText = tr("%1 and %2").arg(tr("%n year(s)", "", years)).arg( + tr("%n week(s)", "", remainder / WEEK_IN_SECONDS)); + } + QString timeBehind(" behind. Scanning block "); + QString str = timeBehindText + timeBehind + QString::number(count); + text = str.toStdString(); + + progressBar->setMaximum(1000000000); + progressBar->setValue(clientModel->getVerificationProgress() * 1000000000.0 + 0.5); + } + + if(text.empty()){ + text = "No block source available.."; + } + + ui->pushButtonSync->setButtonText(tr(text.data())); +} + +void TopBar::loadWalletModel(){ + connect(walletModel, SIGNAL(balanceChanged(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount)), this, + SLOT(updateBalances(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount))); + connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit())); + connect(walletModel, &WalletModel::encryptionStatusChanged, this, &TopBar::refreshStatus); + + // update the display unit, to not use the default ("PIVX") + updateDisplayUnit(); + + refreshStatus(); +} + +void TopBar::refreshStatus(){ + // Check lock status + if (!this->walletModel) + return; + + WalletModel::EncryptionStatus encStatus = walletModel->getEncryptionStatus(); + + switch (encStatus){ + case WalletModel::EncryptionStatus::Unencrypted: + ui->pushButtonLock->setButtonText("Wallet Unencrypted"); + ui->pushButtonLock->setButtonClassStyle("cssClass", "btn-check-status-unlock", true); + break; + case WalletModel::EncryptionStatus::Locked: + ui->pushButtonLock->setButtonText("Wallet Locked"); + ui->pushButtonLock->setButtonClassStyle("cssClass", "btn-check-status-lock", true); + break; + case WalletModel::EncryptionStatus::UnlockedForAnonymizationOnly: + ui->pushButtonLock->setButtonText("Wallet Unlocked for staking"); + ui->pushButtonLock->setButtonClassStyle("cssClass", "btn-check-status-staking", true); + break; + case WalletModel::EncryptionStatus::Unlocked: + ui->pushButtonLock->setButtonText("Wallet Unlocked"); + ui->pushButtonLock->setButtonClassStyle("cssClass", "btn-check-status-unlock", true); + break; + } + updateStyle(ui->pushButtonLock); +} + +void TopBar::updateDisplayUnit() +{ + if (walletModel && walletModel->getOptionsModel()) { + int displayUnitPrev = nDisplayUnit; + nDisplayUnit = walletModel->getOptionsModel()->getDisplayUnit(); + if (displayUnitPrev != nDisplayUnit) + updateBalances(walletModel->getBalance(), walletModel->getUnconfirmedBalance(), walletModel->getImmatureBalance(), + walletModel->getZerocoinBalance(), walletModel->getUnconfirmedZerocoinBalance(), walletModel->getImmatureZerocoinBalance(), + walletModel->getWatchBalance(), walletModel->getWatchUnconfirmedBalance(), walletModel->getWatchImmatureBalance()); + } +} + +void TopBar::updateBalances(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& zerocoinBalance, const CAmount& unconfirmedZerocoinBalance, const CAmount& immatureZerocoinBalance, + const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance){ + + CAmount nLockedBalance = 0; + if (!walletModel) { + nLockedBalance = walletModel->getLockedBalance(); + } + + // PIV Balance + //CAmount nTotalBalance = balance + unconfirmedBalance; + CAmount pivAvailableBalance = balance - immatureBalance - nLockedBalance; + + // zPIV Balance + CAmount matureZerocoinBalance = zerocoinBalance - unconfirmedZerocoinBalance - immatureZerocoinBalance; + + // Set + QString totalPiv = GUIUtil::formatBalance(pivAvailableBalance, nDisplayUnit); + QString totalzPiv = GUIUtil::formatBalance(matureZerocoinBalance, nDisplayUnit, true); + // Top + ui->labelAmountTopPiv->setText(totalPiv); + ui->labelAmountTopzPiv->setText(totalzPiv); + + // Expanded + ui->labelAmountPiv->setText(totalPiv); + ui->labelAmountzPiv->setText(totalzPiv); + + ui->labelPendingPiv->setText(GUIUtil::formatBalance(unconfirmedBalance, nDisplayUnit)); + ui->labelPendingzPiv->setText(GUIUtil::formatBalance(unconfirmedZerocoinBalance, nDisplayUnit, true)); + + ui->labelImmaturePiv->setText(GUIUtil::formatBalance(immatureBalance, nDisplayUnit)); + ui->labelImmaturezPiv->setText(GUIUtil::formatBalance(immatureZerocoinBalance, nDisplayUnit, true)); +} + +void TopBar::resizeEvent(QResizeEvent *event){ + if (lockUnlockWidget && lockUnlockWidget->isVisible()) lockDropdownMouseLeave(); + QWidget::resizeEvent(event); +} \ No newline at end of file diff --git a/src/qt/pivx/topbar.h b/src/qt/pivx/topbar.h new file mode 100644 index 000000000000..2650aae519cc --- /dev/null +++ b/src/qt/pivx/topbar.h @@ -0,0 +1,72 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef TOPBAR_H +#define TOPBAR_H + +#include +#include "qt/pivx/pwidget.h" +#include "qt/pivx/lockunlock.h" +#include "amount.h" +#include +#include + +class PIVXGUI; +class WalletModel; +class ClientModel; + +namespace Ui { +class TopBar; +} + +class TopBar : public PWidget +{ + Q_OBJECT + +public: + explicit TopBar(PIVXGUI* _mainWindow, QWidget *parent = nullptr); + ~TopBar(); + + void showTop(); + void showBottom(); + + void loadWalletModel() override; + void loadClientModel() override; + + void encryptWallet(); +public slots: + void updateBalances(const CAmount& balance, const CAmount& unconfirmedBalance, const CAmount& immatureBalance, + const CAmount& zerocoinBalance, const CAmount& unconfirmedZerocoinBalance, const CAmount& immatureZerocoinBalance, + const CAmount& watchOnlyBalance, const CAmount& watchUnconfBalance, const CAmount& watchImmatureBalance); + void updateDisplayUnit(); + + void setNumConnections(int count); + void setNumBlocks(int count); + void updateAutoMintStatus(); + void updateStakingStatus(); + +signals: + void themeChanged(bool isLight); + void walletSynced(bool isSync); + +protected: + void resizeEvent(QResizeEvent *event) override; +private slots: + void onBtnReceiveClicked(); + void onThemeClicked(); + void onBtnLockClicked(); + void lockDropdownMouseLeave(); + void lockDropdownClicked(const StateClicked&); + void refreshStatus(); + void openLockUnlock(); +private: + Ui::TopBar *ui; + LockUnlock *lockUnlockWidget = nullptr; + QProgressBar* progressBar = nullptr; + + int nDisplayUnit = -1; + QTimer* timerStakingIcon = nullptr; +}; + +#endif // TOPBAR_H diff --git a/src/qt/pivx/txrow.cpp b/src/qt/pivx/txrow.cpp new file mode 100644 index 000000000000..70d775f1e377 --- /dev/null +++ b/src/qt/pivx/txrow.cpp @@ -0,0 +1,108 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/txrow.h" +#include "qt/pivx/forms/ui_txrow.h" + +#include "guiutil.h" +#include "qt/pivx/qtutils.h" + +TxRow::TxRow(bool isLightTheme, QWidget *parent) : + QWidget(parent), + ui(new Ui::TxRow) +{ + ui->setupUi(this); + setConfirmStatus(true); + updateStatus(isLightTheme, false, false); +} + +void TxRow::setConfirmStatus(bool isConfirm){ + if(isConfirm){ + setCssProperty(ui->lblAddress, "text-list-body1"); + setCssProperty(ui->lblDate, "text-list-caption"); + }else{ + setCssProperty(ui->lblAddress, "text-list-body-unconfirmed"); + setCssProperty(ui->lblDate,"text-list-caption-unconfirmed"); + } +} + +void TxRow::updateStatus(bool isLightTheme, bool isHover, bool isSelected){ + if(isLightTheme) + ui->lblDivisory->setStyleSheet("background-color:#bababa"); + else + ui->lblDivisory->setStyleSheet("background-color:#40ffffff"); +} + +void TxRow::setDate(QDateTime date){ + ui->lblDate->setText(GUIUtil::dateTimeStr(date)); +} + +void TxRow::setLabel(QString str){ + ui->lblAddress->setText(str); +} + +void TxRow::setAmount(QString str){ + ui->lblAmount->setText(str); +} + +void TxRow::setType(bool isLightTheme, int type, bool isConfirmed){ + QString path; + QString css; + bool sameIcon = false; + switch (type) { + case TransactionRecord::ZerocoinMint: + path = "://ic-transaction-mint"; + css = "text-list-amount-send"; + break; + case TransactionRecord::Generated: + case TransactionRecord::StakeZPIV: + case TransactionRecord::MNReward: + case TransactionRecord::StakeMint: + path = "://ic-transaction-staked"; + css = "text-list-amount-receive"; + break; + case TransactionRecord::RecvWithObfuscation: + case TransactionRecord::RecvWithAddress: + case TransactionRecord::RecvFromOther: + case TransactionRecord::RecvFromZerocoinSpend: + path = "://ic-transaction-received"; + css = "text-list-amount-receive"; + break; + case TransactionRecord::SendToAddress: + case TransactionRecord::SendToOther: + case TransactionRecord::ZerocoinSpend: + case TransactionRecord::ZerocoinSpend_Change_zPiv: + case TransactionRecord::ZerocoinSpend_FromMe: + path = "://ic-transaction-sent"; + css = "text-list-amount-send"; + break; + case TransactionRecord::SendToSelf: + path = "://ic-transaction-mint"; + css = "text-list-amount-send"; + break; + default: + path = "://ic-pending"; + sameIcon = true; + css = "text-list-amount-unconfirmed"; + break; + } + + if (!isLightTheme && !sameIcon){ + path += "-dark"; + } + + if (!isConfirmed){ + css = "text-list-amount-unconfirmed"; + path += "-inactive"; + setConfirmStatus(false); + }else{ + setConfirmStatus(true); + } + setCssProperty(ui->lblAmount, css); + ui->icon->setIcon(QIcon(path)); +} + +TxRow::~TxRow(){ + delete ui; +} diff --git a/src/qt/pivx/txrow.h b/src/qt/pivx/txrow.h new file mode 100644 index 000000000000..b3f0c067eb42 --- /dev/null +++ b/src/qt/pivx/txrow.h @@ -0,0 +1,37 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef TXROW_H +#define TXROW_H + +#include +#include +#include "transactionrecord.h" + +namespace Ui { +class TxRow; +} + +class TxRow : public QWidget +{ + Q_OBJECT + +public: + explicit TxRow(bool isLightTheme, QWidget *parent = nullptr); + ~TxRow(); + + void updateStatus(bool isLightTheme, bool isHover, bool isSelected); + + void setDate(QDateTime); + void setLabel(QString); + void setAmount(QString); + void setType(bool isLightTheme, int type, bool isConfirmed); + void setConfirmStatus(bool isConfirmed); + +private: + Ui::TxRow *ui; + bool isConfirmed = false; +}; + +#endif // TXROW_H diff --git a/src/qt/pivx/txviewholder.cpp b/src/qt/pivx/txviewholder.cpp new file mode 100644 index 000000000000..89fa16063e90 --- /dev/null +++ b/src/qt/pivx/txviewholder.cpp @@ -0,0 +1,54 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/txviewholder.h" +#include "qt/pivx/txrow.h" +#include "qt/pivx/qtutils.h" +#include "transactiontablemodel.h" +#include + +#define ADDRESS_SIZE 12 + +QWidget* TxViewHolder::createHolder(int pos){ + return new TxRow(isLightTheme); +} + +void TxViewHolder::init(QWidget* holder,const QModelIndex &index, bool isHovered, bool isSelected) const{ + TxRow *txRow = static_cast(holder); + txRow->updateStatus(isLightTheme, isHovered, isSelected); + + QModelIndex rIndex = (filter) ? filter->mapToSource(index) : index; + QDateTime date = rIndex.data(TransactionTableModel::DateRole).toDateTime(); + qint64 amount = rIndex.data(TransactionTableModel::AmountRole).toLongLong(); + QString amountText = BitcoinUnits::formatWithUnit(nDisplayUnit, amount, true, BitcoinUnits::separatorAlways); + QModelIndex indexType = rIndex.sibling(rIndex.row(),TransactionTableModel::Type); + QString label = indexType.data(Qt::DisplayRole).toString(); + int type = rIndex.data(TransactionTableModel::TypeRole).toInt(); + + if(type != TransactionRecord::ZerocoinMint && + type != TransactionRecord::ZerocoinSpend_Change_zPiv && + type != TransactionRecord::StakeZPIV && + type != TransactionRecord::Other){ + QString address = rIndex.data(Qt::DisplayRole).toString(); + if(address.length() > 20) { + address = address.left(ADDRESS_SIZE) + "..." + address.right(ADDRESS_SIZE); + } + label += " " + address; + } else if (type == TransactionRecord::Other) { + label += rIndex.data(Qt::DisplayRole).toString(); + } + + int status = rIndex.data(TransactionTableModel::StatusRole).toInt(); + bool isUnconfirmed = (status == TransactionStatus::Unconfirmed) || (status == TransactionStatus::Immature) + || (status == TransactionStatus::Conflicted) || (status == TransactionStatus::NotAccepted); + + txRow->setDate(date); + txRow->setLabel(label); + txRow->setAmount(amountText); + txRow->setType(isLightTheme, type, !isUnconfirmed); +} + +QColor TxViewHolder::rectColor(bool isHovered, bool isSelected) { + return getRowColor(isLightTheme, isHovered, isSelected); +} diff --git a/src/qt/pivx/txviewholder.h b/src/qt/pivx/txviewholder.h new file mode 100644 index 000000000000..654a3a0628d5 --- /dev/null +++ b/src/qt/pivx/txviewholder.h @@ -0,0 +1,46 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef TXVIEWHOLDER_H +#define TXVIEWHOLDER_H + +#include "qt/pivx/furlistrow.h" +#include "bitcoinunits.h" +#include + +QT_BEGIN_NAMESPACE +class QModelIndex; +QT_END_NAMESPACE + +class TxViewHolder : public FurListRow +{ +public: + TxViewHolder(); + + explicit TxViewHolder(bool _isLightTheme) : FurListRow(), isLightTheme(_isLightTheme){} + + QWidget* createHolder(int pos) override; + + void init(QWidget* holder,const QModelIndex &index, bool isHovered, bool isSelected) const override; + + QColor rectColor(bool isHovered, bool isSelected) override; + + ~TxViewHolder() override{}; + + bool isLightTheme; + + void setDisplayUnit(int displayUnit){ + this->nDisplayUnit = displayUnit; + } + + void setFilter(TransactionFilterProxy *_filter){ + this->filter = _filter; + } + +private: + int nDisplayUnit; + TransactionFilterProxy *filter = nullptr; +}; + +#endif // TXVIEWHOLDER_H diff --git a/src/qt/pivx/walletpassworddialog.cpp b/src/qt/pivx/walletpassworddialog.cpp new file mode 100644 index 000000000000..1edddf5d1fc7 --- /dev/null +++ b/src/qt/pivx/walletpassworddialog.cpp @@ -0,0 +1,112 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/walletpassworddialog.h" +#include "qt/pivx/forms/ui_walletpassworddialog.h" +#include + +WalletPasswordDialog::WalletPasswordDialog(QWidget *parent) : + QDialog(parent), + ui(new Ui::WalletPasswordDialog), + btnWatch(new QCheckBox()) +{ + ui->setupUi(this); + + // Stylesheet + this->setStyleSheet(parent->styleSheet()); + + // Container + + ui->frame->setProperty("cssClass", "container-dialog"); + + // Text + + ui->labelTitle->setText("Encrypt your wallet"); + ui->labelTitle->setProperty("cssClass", "text-title-dialog"); + + + ui->labelMessage->setText("Secure your wallet with a strong password that you won’t lose or forget."); + ui->labelMessage->setProperty("cssClass", "text-main-grey"); + + ui->labelPassword->setText("Password"); + ui->labelPassword->setProperty("cssClass", "text-title"); + + + ui->labelPasswordRepeat->setText("Confirm password"); + ui->labelPasswordRepeat->setProperty("cssClass", "text-title"); + + + // Edit Passwords + + QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect(); + shadowEffect->setColor(QColor(0, 0, 0, 22)); + shadowEffect->setXOffset(0); + shadowEffect->setYOffset(3); + shadowEffect->setBlurRadius(6); + + QGraphicsDropShadowEffect* shadowEffect2 = new QGraphicsDropShadowEffect(); + shadowEffect2->setColor(QColor(0, 0, 0, 22)); + shadowEffect2->setXOffset(0); + shadowEffect2->setYOffset(3); + shadowEffect2->setBlurRadius(6); + + ui->lineEditPassword->setPlaceholderText("At least 6 alphanumerics characters (e.j. Crypt34)"); + ui->lineEditPassword->setProperty("cssClass", "edit-primary-dialog"); + ui->lineEditPassword->setAttribute(Qt::WA_MacShowFocusRect, 0); + ui->lineEditPassword->setEchoMode(QLineEdit::Password); + ui->stackedWidget_2->setGraphicsEffect(shadowEffect); + + ui->lineEditPasswordRepeat->setPlaceholderText("Repeat the new password"); + ui->lineEditPasswordRepeat->setProperty("cssClass", "edit-primary-dialog"); + ui->lineEditPasswordRepeat->setAttribute(Qt::WA_MacShowFocusRect, 0); + ui->lineEditPasswordRepeat->setEchoMode(QLineEdit::Password); + ui->lineEditPasswordRepeat->setGraphicsEffect(shadowEffect2); + + // Show Repeat Password + + ui->layoutRepeat->setVisible(true); + + + // Button Watch + + btnWatch->setProperty("cssClass", "btn-watch-password"); + btnWatch->setCheckable(true); + btnWatch->setChecked(false); + QSize BUTTON_CONTACT_SIZE = QSize(24, 24); + btnWatch->setMinimumSize(BUTTON_CONTACT_SIZE); + btnWatch->setMaximumSize(BUTTON_CONTACT_SIZE); + + ui->stackedWidget_2->addWidget(btnWatch); + + btnWatch->show(); + btnWatch->raise(); + + int posXX = ui->lineEditPassword->width() - 30; + int posYY = 12; + btnWatch->move(450, posYY); + + + // Buttons + + ui->btnEsc->setText(""); + ui->btnEsc->setProperty("cssClass", "ic-close"); + + ui->btnCancel->setProperty("cssClass", "btn-dialog-cancel"); + ui->btnSave->setText("ENCRYPT"); + ui->btnSave->setProperty("cssClass", "btn-primary"); + + connect(btnWatch, SIGNAL(clicked()), this, SLOT(onWatchClicked())); + connect(ui->btnEsc, SIGNAL(clicked()), this, SLOT(close())); + connect(ui->btnCancel, SIGNAL(clicked()), this, SLOT(close())); +} + +void WalletPasswordDialog::onWatchClicked(){ + ui->lineEditPassword->setEchoMode(btnWatch->checkState() == Qt::Checked ? QLineEdit::Normal : QLineEdit::Password ); + ui->lineEditPasswordRepeat->setEchoMode(btnWatch->checkState() == Qt::Checked ? QLineEdit::Normal : QLineEdit::Password ); +} + +WalletPasswordDialog::~WalletPasswordDialog() +{ + delete ui; +} diff --git a/src/qt/pivx/walletpassworddialog.h b/src/qt/pivx/walletpassworddialog.h new file mode 100644 index 000000000000..36b2866976be --- /dev/null +++ b/src/qt/pivx/walletpassworddialog.h @@ -0,0 +1,31 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef WALLETPASSWORDDIALOG_H +#define WALLETPASSWORDDIALOG_H + +#include +#include + +namespace Ui { +class WalletPasswordDialog; +class QCheckBox; +} + +class WalletPasswordDialog : public QDialog +{ + Q_OBJECT + +public: + explicit WalletPasswordDialog(QWidget *parent = nullptr); + ~WalletPasswordDialog(); + +private slots: + void onWatchClicked(); +private: + Ui::WalletPasswordDialog *ui; + QCheckBox *btnWatch; +}; + +#endif // WALLETPASSWORDDIALOG_H diff --git a/src/qt/pivx/welcomecontentwidget.cpp b/src/qt/pivx/welcomecontentwidget.cpp new file mode 100644 index 000000000000..ba32189c43cc --- /dev/null +++ b/src/qt/pivx/welcomecontentwidget.cpp @@ -0,0 +1,312 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "qt/pivx/welcomecontentwidget.h" +#include "qt/pivx/forms/ui_welcomecontentwidget.h" +#include +#include +#include +#include "guiutil.h" +#include +#include +#include + +WelcomeContentWidget::WelcomeContentWidget(QWidget *parent) : + QDialog(parent, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint), + ui(new Ui::WelcomeContentWidget), + backButton(new QPushButton()), + icConfirm1(new QPushButton()), + icConfirm2(new QPushButton()), + icConfirm3(new QPushButton()), + icConfirm4(new QPushButton()), + nextButton(new QPushButton()) +{ + ui->setupUi(this); + + this->setStyleSheet(GUIUtil::loadStyleSheet()); + + ui->frame->setProperty("cssClass", "container-welcome-stack"); + ui->frame_2->setProperty("cssClass", "container-welcome"); + + backButton = new QPushButton(ui->container); + nextButton = new QPushButton(ui->container); + + backButton->show(); + backButton->raise(); + nextButton->show(); + nextButton->raise(); + + backButton->setProperty("cssClass", "btn-welcome-back"); + nextButton->setProperty("cssClass", "btn-welcome-next"); + + QSize BUTTON_SIZE = QSize(60, 60); + backButton->setMinimumSize(BUTTON_SIZE); + backButton->setMaximumSize(BUTTON_SIZE); + + nextButton->setMinimumSize(BUTTON_SIZE); + nextButton->setMaximumSize(BUTTON_SIZE); + + int backX = 0; + int backY = 240; + int nextX = 820; + int nextY = 240; + + // position + backButton->move(backX, backY); + backButton->setStyleSheet("background: url(://ic-arrow-white-left); background-repeat:no-repeat;background-position:center;border: 0;background-color:#5c4b7d;color: #5c4b7d; border-radius:2px;"); + nextButton->move(nextX, nextY); + nextButton->setStyleSheet("background: url(://ic-arrow-white-right);background-repeat:no-repeat;background-position:center;border: 0;background-color:#5c4b7d;color: #5c4b7d; border-radius:2px;"); + + if (pos == 0) { + backButton->setVisible(false); + } + + ui->labelLine1->setProperty("cssClass", "line-welcome"); + ui->labelLine2->setProperty("cssClass", "line-welcome"); + ui->labelLine3->setProperty("cssClass", "line-welcome"); + + + ui->groupBoxName->setProperty("cssClass", "container-welcome-box"); + ui->groupContainer->setProperty("cssClass", "container-welcome-box"); + + ui->pushNumber1->setProperty("cssClass", "btn-welcome-number-check"); + ui->pushNumber1->setEnabled(false); + ui->pushNumber2->setProperty("cssClass", "btn-welcome-number-check"); + ui->pushNumber2->setEnabled(false); + ui->pushNumber3->setProperty("cssClass", "btn-welcome-number-check"); + ui->pushNumber3->setEnabled(false); + ui->pushNumber4->setProperty("cssClass", "btn-welcome-number-check"); + ui->pushNumber4->setEnabled(false); + + ui->pushName1->setProperty("cssClass", "btn-welcome-name-check"); + ui->pushName1->setEnabled(false); + ui->pushName2->setProperty("cssClass", "btn-welcome-name-check"); + ui->pushName2->setEnabled(false); + ui->pushName3->setProperty("cssClass", "btn-welcome-name-check"); + ui->pushName3->setEnabled(false); + ui->pushName4->setProperty("cssClass", "btn-welcome-name-check"); + ui->pushName4->setEnabled(false); + + ui->stackedWidget->setCurrentIndex(0); + + // Frame 1 + ui->page_1->setProperty("cssClass", "container-welcome-step1"); + ui->labelTitle1->setProperty("cssClass", "text-title-welcome"); + ui->comboBoxLanguage->setProperty("cssClass", "btn-combo-welcome"); + ui->comboBoxLanguage->setView(new QListView()); + + // Frame 2 + ui->page_2->setProperty("cssClass", "container-welcome-step2"); + ui->labelTitle2->setProperty("cssClass", "text-title-welcome"); + ui->labelMessage2->setProperty("cssClass", "text-main-white"); + + // Frame 3 + ui->page_3->setProperty("cssClass", "container-welcome-step3"); + ui->labelTitle3->setProperty("cssClass", "text-title-welcome"); + ui->labelMessage3->setProperty("cssClass", "text-main-white"); + + // Frame 4 + ui->page_4->setProperty("cssClass", "container-welcome-step4"); + ui->labelTitle4->setProperty("cssClass", "text-title-welcome"); + ui->labelMessage4->setProperty("cssClass", "text-main-white"); + + // Confirm icons + icConfirm1 = new QPushButton(ui->layoutIcon1_2); + icConfirm2 = new QPushButton(ui->layoutIcon2_2); + icConfirm3 = new QPushButton(ui->layoutIcon3_2); + icConfirm4 = new QPushButton(ui->layoutIcon4_2); + + QSize BUTTON_CONFIRM_SIZE = QSize(22, 22); + int posX = 0; + int posY = 0; + + icConfirm1->setProperty("cssClass", "ic-step-confirm-welcome"); + icConfirm1->setMinimumSize(BUTTON_CONFIRM_SIZE); + icConfirm1->setMaximumSize(BUTTON_CONFIRM_SIZE); + icConfirm1->show(); + icConfirm1->raise(); + icConfirm1->setVisible(false); + icConfirm1->move(posX, posY); + icConfirm2->setProperty("cssClass", "ic-step-confirm-welcome"); + icConfirm2->setMinimumSize(BUTTON_CONFIRM_SIZE); + icConfirm2->setMaximumSize(BUTTON_CONFIRM_SIZE); + icConfirm2->move(posX, posY); + icConfirm2->show(); + icConfirm2->raise(); + icConfirm2->setVisible(false); + icConfirm3->setProperty("cssClass", "ic-step-confirm-welcome"); + icConfirm3->setMinimumSize(BUTTON_CONFIRM_SIZE); + icConfirm3->setMaximumSize(BUTTON_CONFIRM_SIZE); + icConfirm3->move(posX, posY); + icConfirm3->show(); + icConfirm3->raise(); + icConfirm3->setVisible(false); + icConfirm4->setProperty("cssClass", "ic-step-confirm-welcome"); + icConfirm4->setMinimumSize(BUTTON_CONFIRM_SIZE); + icConfirm4->setMaximumSize(BUTTON_CONFIRM_SIZE); + icConfirm4->move(posX, posY); + icConfirm4->show(); + icConfirm4->raise(); + icConfirm4->setVisible(false); + + ui->pushButtonSkip->setProperty("cssClass", "btn-close-white"); + onNextClicked(); + + connect(ui->pushButtonSkip, SIGNAL(clicked()), this, SLOT(close())); + connect(nextButton, SIGNAL(clicked()), this, SLOT(onNextClicked())); + connect(backButton, SIGNAL(clicked()), this, SLOT(onBackClicked())); + + initLanguages(); + + + // Resize window and move to center of desktop, disallow resizing + QRect r(QPoint(), size()); + resize(r.size()); + setFixedSize(r.size()); + move(QApplication::desktop()->screenGeometry().center() - r.center()); +} + +void WelcomeContentWidget::initLanguages(){ + /* Language selector */ + QDir translations(":translations"); + ui->comboBoxLanguage->addItem(QString("(") + tr("default") + QString(")"), QVariant("")); + foreach (const QString& langStr, translations.entryList()) { + QLocale locale(langStr); + + /** check if the locale name consists of 2 parts (language_country) */ + if(langStr.contains("_")){ + /** display language strings as "native language - native country (locale name)", e.g. "Deutsch - Deutschland (de)" */ + ui->comboBoxLanguage->addItem(locale.nativeLanguageName() + QString(" - ") + locale.nativeCountryName() + QString(" (") + langStr + QString(")"), QVariant(langStr)); + } + else{ + /** display language strings as "native language (locale name)", e.g. "Deutsch (de)" */ + ui->comboBoxLanguage->addItem(locale.nativeLanguageName() + QString(" (") + langStr + QString(")"), QVariant(langStr)); + } + } +} + +void WelcomeContentWidget::setModel(OptionsModel *model){ + this->model = model; +} + +void WelcomeContentWidget::checkLanguage(){ + QString sel = ui->comboBoxLanguage->currentData().toString(); + QSettings settings; + if (settings.value("language") != sel){ + settings.setValue("language", sel); + emit onLanguageSelected(); + } +} + +void WelcomeContentWidget::onNextClicked(){ + + switch(pos){ + case 0:{ + ui->stackedWidget->setCurrentIndex(1); + break; + } + case 1:{ + backButton->setVisible(true); + ui->stackedWidget->setCurrentIndex(2); + ui->pushNumber2->setChecked(true); + ui->pushName4->setChecked(false); + ui->pushName3->setChecked(false); + ui->pushName2->setChecked(true); + ui->pushName1->setChecked(true); + icConfirm1->setVisible(true); + break; + } + case 2:{ + ui->stackedWidget->setCurrentIndex(3); + ui->pushNumber3->setChecked(true); + ui->pushName4->setChecked(false); + ui->pushName3->setChecked(true); + ui->pushName2->setChecked(true); + ui->pushName1->setChecked(true); + icConfirm2->setVisible(true); + break; + } + case 3:{ + ui->stackedWidget->setCurrentIndex(4); + ui->pushNumber4->setChecked(true); + ui->pushName4->setChecked(true); + ui->pushName3->setChecked(true); + ui->pushName2->setChecked(true); + ui->pushName1->setChecked(true); + icConfirm3->setVisible(true); + break; + } + case 4:{ + isOk = true; + accept(); + break; + } + } + pos++; + +} + +void WelcomeContentWidget::onBackClicked(){ + if (pos == 0) return; + pos--; + switch(pos){ + case 0:{ + ui->stackedWidget->setCurrentIndex(0); + break; + } + case 1:{ + ui->stackedWidget->setCurrentIndex(1); + ui->pushNumber1->setChecked(true); + ui->pushNumber4->setChecked(false); + ui->pushNumber3->setChecked(false); + ui->pushNumber2->setChecked(false); + ui->pushName4->setChecked(false); + ui->pushName3->setChecked(false); + ui->pushName2->setChecked(false); + ui->pushName1->setChecked(true); + icConfirm1->setVisible(false); + backButton->setVisible(false); + + break; + } + case 2:{ + ui->stackedWidget->setCurrentIndex(2); + ui->pushNumber2->setChecked(true); + ui->pushNumber4->setChecked(false); + ui->pushNumber3->setChecked(false); + ui->pushName4->setChecked(false); + ui->pushName3->setChecked(false); + ui->pushName2->setChecked(true); + ui->pushName1->setChecked(true); + icConfirm2->setVisible(false); + break; + } + case 3:{ + ui->stackedWidget->setCurrentIndex(3); + ui->pushNumber3->setChecked(true); + ui->pushNumber4->setChecked(false); + ui->pushName4->setChecked(false); + ui->pushName3->setChecked(true); + ui->pushName2->setChecked(true); + ui->pushName1->setChecked(true); + icConfirm3->setVisible(false); + break; + } + + } + + if (pos == 0) { + backButton->setVisible(false); + } +} + +void WelcomeContentWidget::onSkipClicked(){ + isOk = true; + accept(); +} + +WelcomeContentWidget::~WelcomeContentWidget() +{ + delete ui; +} diff --git a/src/qt/pivx/welcomecontentwidget.h b/src/qt/pivx/welcomecontentwidget.h new file mode 100644 index 000000000000..acd3455e221b --- /dev/null +++ b/src/qt/pivx/welcomecontentwidget.h @@ -0,0 +1,52 @@ +// Copyright (c) 2019 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef WELCOMECONTENTWIDGET_H +#define WELCOMECONTENTWIDGET_H + +#include +#include +#include +class OptionsModel; + +namespace Ui { +class WelcomeContentWidget; +} + +class WelcomeContentWidget : public QDialog +{ + Q_OBJECT + +public: + explicit WelcomeContentWidget(QWidget *parent = nullptr); + ~WelcomeContentWidget(); + int pos = 0; + bool isOk = false; + + void setModel(OptionsModel *model); + void checkLanguage(); + +signals: + void onLanguageSelected(); + +public slots: + void onNextClicked(); + void onBackClicked(); + void onSkipClicked(); + +private: + Ui::WelcomeContentWidget *ui; + QPushButton *icConfirm1; + QPushButton *icConfirm2; + QPushButton *icConfirm3; + QPushButton *icConfirm4; + QPushButton *backButton; + QPushButton *nextButton; + + OptionsModel *model; + + void initLanguages(); +}; + +#endif // WELCOMECONTENTWIDGET_H diff --git a/src/qt/privacydialog.cpp b/src/qt/privacydialog.cpp index 0ccb721bc55c..47b6ccdd8ea4 100644 --- a/src/qt/privacydialog.cpp +++ b/src/qt/privacydialog.cpp @@ -26,10 +26,10 @@ #include PrivacyDialog::PrivacyDialog(QWidget* parent) : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowCloseButtonHint), - ui(new Ui::PrivacyDialog), - walletModel(0), - currentBalance(-1), - fDenomsMinimized(true) + ui(new Ui::PrivacyDialog), + walletModel(0), + currentBalance(-1), + fDenomsMinimized(true) { nDisplayUnit = 0; // just make sure it's not unitialized ui->setupUi(this); @@ -133,7 +133,7 @@ void PrivacyDialog::setModel(WalletModel* walletModel) walletModel->getWatchBalance(), walletModel->getWatchUnconfirmedBalance(), walletModel->getWatchImmatureBalance()); connect(walletModel, SIGNAL(balanceChanged(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount)), this, - SLOT(setBalance(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount))); + SLOT(setBalance(CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount, CAmount))); connect(walletModel->getOptionsModel(), SIGNAL(zeromintEnableChanged(bool)), this, SLOT(updateAutomintStatus())); connect(walletModel->getOptionsModel(), SIGNAL(zeromintPercentageChanged(int)), this, SLOT(updateAutomintStatus())); } @@ -365,9 +365,9 @@ void PrivacyDialog::sendzPIV() QString strFeeWarning = "You've entered an amount with fractional digits and want the change to be converted to Zerocoin.

"; strFeeWarning += QString::number(dzFee, 'f', 8) + " PIV will be added to the standard transaction fees!
"; QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm additional Fees"), - strFeeWarning, - QMessageBox::Yes | QMessageBox::Cancel, - QMessageBox::Cancel); + strFeeWarning, + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Cancel); if (retval != QMessageBox::Yes) { // Sending canceled @@ -398,9 +398,9 @@ void PrivacyDialog::sendzPIV() // Display message box QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm send coins"), - strQuestionString, - QMessageBox::Yes | QMessageBox::Cancel, - QMessageBox::Cancel); + strQuestionString, + QMessageBox::Yes | QMessageBox::Cancel, + QMessageBox::Cancel); if (retval != QMessageBox::Yes) { // Sending canceled @@ -432,13 +432,14 @@ void PrivacyDialog::sendzPIV() CWalletTx wtxNew; CZerocoinSpendReceipt receipt; bool fSuccess = false; + std::list> out; if(ui->payTo->text().isEmpty()){ // Spend to newly generated local address - fSuccess = pwalletMain->SpendZerocoin(nAmount, wtxNew, receipt, vMintsSelected, fMintChange, fMinimizeChange); + fSuccess = pwalletMain->SpendZerocoin(nAmount, wtxNew, receipt, vMintsSelected, fMintChange, fMinimizeChange, out); } else { // Spend to supplied destination address - fSuccess = pwalletMain->SpendZerocoin(nAmount, wtxNew, receipt, vMintsSelected, fMintChange, fMinimizeChange, &address); + fSuccess = pwalletMain->SpendZerocoin(nAmount, wtxNew, receipt, vMintsSelected, fMintChange, fMinimizeChange, out, &address); } // Display errors during spend @@ -792,10 +793,10 @@ void PrivacyDialog::updateAutomintStatus() QString strAutomintStatus = tr("AutoMint Status:"); if (pwalletMain->isZeromintEnabled ()) { - strAutomintStatus += tr(" enabled."); + strAutomintStatus += tr(" enabled."); } else { - strAutomintStatus += tr(" disabled."); + strAutomintStatus += tr(" disabled."); } strAutomintStatus += tr(" Configured target percentage: ") + QString::number(pwalletMain->getZeromintPercentage()) + "%"; diff --git a/src/qt/res/icons/ic-transaction-mint.png b/src/qt/res/icons/ic-transaction-mint.png new file mode 100644 index 000000000000..019ce7ffea56 Binary files /dev/null and b/src/qt/res/icons/ic-transaction-mint.png differ diff --git a/src/qt/res/icons/ic-transaction-mint.svg b/src/qt/res/icons/ic-transaction-mint.svg new file mode 100755 index 000000000000..b8e53e7d34af --- /dev/null +++ b/src/qt/res/icons/ic-transaction-mint.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/src/qt/res/icons/ic-transaction-received.png b/src/qt/res/icons/ic-transaction-received.png new file mode 100644 index 000000000000..b8def8f192a2 Binary files /dev/null and b/src/qt/res/icons/ic-transaction-received.png differ diff --git a/src/qt/res/icons/ic-transaction-received.svg b/src/qt/res/icons/ic-transaction-received.svg new file mode 100755 index 000000000000..45e847ead432 --- /dev/null +++ b/src/qt/res/icons/ic-transaction-received.svg @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/src/qt/res/icons/ic-transaction-sent.png b/src/qt/res/icons/ic-transaction-sent.png new file mode 100644 index 000000000000..d61c4f60c990 Binary files /dev/null and b/src/qt/res/icons/ic-transaction-sent.png differ diff --git a/src/qt/res/icons/ic-transaction-sent.svg b/src/qt/res/icons/ic-transaction-sent.svg new file mode 100755 index 000000000000..840c58b77521 --- /dev/null +++ b/src/qt/res/icons/ic-transaction-sent.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + diff --git a/src/qt/res/icons/ic-transaction-staked.png b/src/qt/res/icons/ic-transaction-staked.png new file mode 100644 index 000000000000..9e405198cae6 Binary files /dev/null and b/src/qt/res/icons/ic-transaction-staked.png differ diff --git a/src/qt/res/icons/ic-transaction-staked.svg b/src/qt/res/icons/ic-transaction-staked.svg new file mode 100755 index 000000000000..84ec87cbb152 --- /dev/null +++ b/src/qt/res/icons/ic-transaction-staked.svg @@ -0,0 +1,9 @@ + + + + + + + diff --git a/src/qt/res/images/about.png b/src/qt/res/images/about.png index 077bf1fc6b9f..598b4f313c10 100644 Binary files a/src/qt/res/images/about.png and b/src/qt/res/images/about.png differ diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index 18f3fd9d4f57..c03dada40c8a 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -26,7 +26,7 @@ TransactionFilterProxy::TransactionFilterProxy(QObject* parent) : QSortFilterPro minAmount(0), limitRows(-1), showInactive(true), - fHideOrphans(false) + fHideOrphans(true) { } @@ -58,6 +58,11 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex& return false; if (amount < minAmount) return false; + if (fOnlyZc && !isZcTx(type)){ + return false; + } + if (fOnlyStakes && !isStakeTx(type)) + return false; return true; } @@ -110,6 +115,16 @@ void TransactionFilterProxy::setHideOrphans(bool fHide) invalidateFilter(); } +void TransactionFilterProxy::setShowZcTxes(bool fOnlyZc){ + this->fOnlyZc = fOnlyZc; + invalidateFilter(); +} + +void TransactionFilterProxy::setOnlyStakes(bool fOnlyStakes){ + this->fOnlyStakes = fOnlyStakes; + invalidateFilter(); +} + int TransactionFilterProxy::rowCount(const QModelIndex& parent) const { if (limitRows != -1) { @@ -125,3 +140,18 @@ bool TransactionFilterProxy::isOrphan(const int status, const int type) type == TransactionRecord::StakeZPIV || type == TransactionRecord::MNReward) && (status == TransactionStatus::Conflicted || status == TransactionStatus::NotAccepted) ); } + +bool TransactionFilterProxy::isZcTx(int type) const { + return (type == TransactionRecord::ZerocoinMint || type == TransactionRecord::ZerocoinSpend || type == TransactionRecord::ZerocoinSpend_Change_zPiv + || type == TransactionRecord::ZerocoinSpend_FromMe || type == TransactionRecord::RecvFromZerocoinSpend); +} + +bool TransactionFilterProxy::isStakeTx(int type) const { + return (type == TransactionRecord::StakeMint || type == TransactionRecord::Generated || type == TransactionRecord::StakeZPIV); +} + +/*QVariant TransactionFilterProxy::dataFromSourcePos(int sourceRow, int role) const { + QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); + return index.data(index, role); +} + */ \ No newline at end of file diff --git a/src/qt/transactionfilterproxy.h b/src/qt/transactionfilterproxy.h index 0372448a546c..e4c523e4e8ca 100644 --- a/src/qt/transactionfilterproxy.h +++ b/src/qt/transactionfilterproxy.h @@ -37,6 +37,11 @@ class TransactionFilterProxy : public QSortFilterProxyModel }; void setDateRange(const QDateTime& from, const QDateTime& to); + void clearDateRange() { + if (dateFrom != MIN_DATE || dateTo == MAX_DATE) + setDateRange(MIN_DATE, MAX_DATE); + } + void setAddressPrefix(const QString& addrPrefix); /** @note Type filter takes a bit field created with TYPE() or ALL_TYPES @@ -54,9 +59,17 @@ class TransactionFilterProxy : public QSortFilterProxyModel /** Set whether to hide orphan stakes. */ void setHideOrphans(bool fHide); + /** Only zc txes **/ + void setShowZcTxes(bool fOnlyZc); + + /** Only stakes txes **/ + void setOnlyStakes(bool fOnlyStakes); + int rowCount(const QModelIndex& parent = QModelIndex()) const; static bool isOrphan(const int status, const int type); + //QVariant dataFromSourcePos(int sourceRow, int role) const; + protected: bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const; @@ -69,7 +82,12 @@ class TransactionFilterProxy : public QSortFilterProxyModel CAmount minAmount; int limitRows; bool showInactive; - bool fHideOrphans; + bool fHideOrphans = true; + bool fOnlyZc = false; + bool fOnlyStakes = false; + + bool isZcTx(int type) const; + bool isStakeTx(int type) const; }; #endif // BITCOIN_QT_TRANSACTIONFILTERPROXY_H diff --git a/src/qt/transactionrecord.cpp b/src/qt/transactionrecord.cpp index d51f2329080b..e248407451dd 100644 --- a/src/qt/transactionrecord.cpp +++ b/src/qt/transactionrecord.cpp @@ -50,7 +50,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* } if (wtx.IsCoinStake()) { - TransactionRecord sub(hash, nTime); + TransactionRecord sub(hash, nTime, wtx.GetTotalSize()); CTxDestination address; if (!wtx.HasZerocoinSpendInputs() && !ExtractDestination(wtx.vout[1].scriptPubKey, address)) return parts; @@ -97,7 +97,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* continue; isminetype mine = wallet->IsMine(txout); - TransactionRecord sub(hash, nTime); + TransactionRecord sub(hash, nTime, wtx.GetTotalSize()); sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; sub.type = TransactionRecord::ZerocoinSpend_Change_zPiv; sub.address = mapValue["zerocoinmint"]; @@ -118,7 +118,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* // a zerocoinspend that was sent to an address held by this wallet isminetype mine = wallet->IsMine(txout); if (mine) { - TransactionRecord sub(hash, nTime); + TransactionRecord sub(hash, nTime, wtx.GetTotalSize()); sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; if (fZSpendFromMe) { sub.type = TransactionRecord::ZerocoinSpend_FromMe; @@ -139,7 +139,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* continue; // zerocoin spend that was sent to someone else - TransactionRecord sub(hash, nTime); + TransactionRecord sub(hash, nTime, wtx.GetTotalSize()); sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; sub.debit = -txout.nValue; sub.type = TransactionRecord::ZerocoinSpend; @@ -156,7 +156,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* for (const CTxOut& txout : wtx.vout) { isminetype mine = wallet->IsMine(txout); if (mine) { - TransactionRecord sub(hash, nTime); + TransactionRecord sub(hash, nTime, wtx.GetTotalSize()); CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; @@ -207,14 +207,14 @@ QList TransactionRecord::decomposeTransaction(const CWallet* } if (fAllFromMeDenom && fAllToMeDenom && nFromMe * nToMe) { - parts.append(TransactionRecord(hash, nTime, TransactionRecord::ObfuscationDenominate, "", -nDebit, nCredit)); + parts.append(TransactionRecord(hash, nTime, wtx.GetTotalSize(), TransactionRecord::ObfuscationDenominate, "", -nDebit, nCredit)); parts.last().involvesWatchAddress = false; // maybe pass to TransactionRecord as constructor argument } else if (fAllFromMe && fAllToMe) { // Payment to self // TODO: this section still not accurate but covers most cases, // might need some additional work however - TransactionRecord sub(hash, nTime); + TransactionRecord sub(hash, nTime, wtx.GetTotalSize()); // Payment to self by default sub.type = TransactionRecord::SendToSelf; sub.address = ""; @@ -238,6 +238,12 @@ QList TransactionRecord::decomposeTransaction(const CWallet* if (wallet->IsDenominatedAmount(txout.nValue)) sub.type = TransactionRecord::ObfuscationCreateDenominations; if (nDebit - wtx.GetValueOut() == OBFUSCATION_COLLATERAL) sub.type = TransactionRecord::ObfuscationCollateralPayment; } + + // Label for payment to self + CTxDestination address; + if (ExtractDestination(wtx.vout[0].scriptPubKey, address)) { + sub.address = CBitcoinAddress(address).ToString(); + } } CAmount nChange = wtx.GetChange(); @@ -254,7 +260,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; - TransactionRecord sub(hash, nTime); + TransactionRecord sub(hash, nTime, wtx.GetTotalSize()); sub.idx = parts.size(); sub.involvesWatchAddress = involvesWatchAddress; @@ -301,7 +307,7 @@ QList TransactionRecord::decomposeTransaction(const CWallet* // // Mixed debit transaction, can't break down payees // - parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); + parts.append(TransactionRecord(hash, nTime, wtx.GetTotalSize(), TransactionRecord::Other, "", nNet, 0)); parts.last().involvesWatchAddress = involvesWatchAddress; } } @@ -407,3 +413,29 @@ int TransactionRecord::getOutputIndex() const { return idx; } + + +std::string TransactionRecord::statusToString(){ + switch (status.status){ + case TransactionStatus::MaturesWarning: + return "Abandoned (not mature because no nodes have confirmed)"; + case TransactionStatus::Confirmed: + return "Confirmed"; + case TransactionStatus::OpenUntilDate: + return "OpenUntilDate"; + case TransactionStatus::OpenUntilBlock: + return "OpenUntilBlock"; + case TransactionStatus::Unconfirmed: + return "Unconfirmed"; + case TransactionStatus::Confirming: + return "Confirming"; + case TransactionStatus::Conflicted: + return "Conflicted"; + case TransactionStatus::Immature: + return "Immature"; + case TransactionStatus::NotAccepted: + return "Not Accepted"; + default: + return "No status"; + } +} \ No newline at end of file diff --git a/src/qt/transactionrecord.h b/src/qt/transactionrecord.h index dd67f44bbfcf..b74cb8f58280 100644 --- a/src/qt/transactionrecord.h +++ b/src/qt/transactionrecord.h @@ -100,17 +100,17 @@ class TransactionRecord /** Number of confirmation recommended for accepting a transaction */ static const int RecommendedNumConfirmations = 6; - TransactionRecord() : hash(), time(0), type(Other), address(""), debit(0), credit(0), idx(0) + TransactionRecord(unsigned int size) : hash(), time(0), type(Other), address(""), debit(0), credit(0), size(size), idx(0) { } - TransactionRecord(uint256 hash, qint64 time) : hash(hash), time(time), type(Other), address(""), debit(0), - credit(0), idx(0) + TransactionRecord(uint256 hash, qint64 time, unsigned int size) : hash(hash), time(time), type(Other), address(""), debit(0), + credit(0), size(size), idx(0) { } - TransactionRecord(uint256 hash, qint64 time, Type type, const std::string& address, const CAmount& debit, const CAmount& credit) : hash(hash), time(time), type(type), address(address), debit(debit), credit(credit), - idx(0) + TransactionRecord(uint256 hash, qint64 time, unsigned int size, Type type, const std::string& address, const CAmount& debit, const CAmount& credit) : hash(hash), time(time), type(type), address(address), debit(debit), credit(credit), + size(size), idx(0) { } @@ -127,6 +127,7 @@ class TransactionRecord std::string address; CAmount debit; CAmount credit; + unsigned int size; /**@}*/ /** Subtransaction index, for sort key */ @@ -151,6 +152,10 @@ class TransactionRecord /** Return whether a status update is needed. */ bool statusUpdateNeeded(); + + /** Return transaction status + */ + std::string statusToString(); }; #endif // BITCOIN_QT_TRANSACTIONRECORD_H diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index 18522174bf73..d06dfb32fd4d 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -69,6 +69,7 @@ class TransactionTablePriv * this is sorted by sha256. */ QList cachedWallet; + bool hasZcTxes = false; /* Query entire wallet anew from core. */ @@ -78,13 +79,29 @@ class TransactionTablePriv cachedWallet.clear(); { LOCK2(cs_main, wallet->cs_wallet); - for (std::map::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it) { - if (TransactionRecord::showTransaction(it->second)) - cachedWallet.append(TransactionRecord::decomposeTransaction(wallet, it->second)); + for (auto it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it) { + if (TransactionRecord::showTransaction(it->second)) { + QList records = TransactionRecord::decomposeTransaction(wallet, it->second); + for (const TransactionRecord& record : records) { + updateHasZcTxesIfNeeded(record); + if (hasZcTxes) break; + } + cachedWallet.append(records); + } } } } + void updateHasZcTxesIfNeeded(const TransactionRecord& record) { + if (hasZcTxes) return; + if (record.type == TransactionRecord::ZerocoinMint || + record.type == TransactionRecord::ZerocoinSpend || + record.type == TransactionRecord::ZerocoinSpend_Change_zPiv || + record.type == TransactionRecord::ZerocoinSpend_FromMe) { + hasZcTxes = true; + } + } + /* Update our model of the wallet incrementally, to synchronize our model of the wallet with that of the core. @@ -137,6 +154,7 @@ class TransactionTablePriv int insert_idx = lowerIndex; foreach (const TransactionRecord& rec, toInsert) { cachedWallet.insert(insert_idx, rec); + updateHasZcTxesIfNeeded(rec); insert_idx += 1; } parent->endInsertRows(); @@ -165,6 +183,11 @@ class TransactionTablePriv return cachedWallet.size(); } + bool containsZcTxes() + { + return hasZcTxes; + } + TransactionRecord* index(int idx) { if (idx >= 0 && idx < cachedWallet.size()) { @@ -239,6 +262,8 @@ void TransactionTableModel::updateTransaction(const QString& hash, int status, b updated.SetHex(hash.toStdString()); priv->updateWallet(updated, status, showTransaction); + + emit txArrived(hash); } void TransactionTableModel::updateConfirmations() @@ -263,6 +288,14 @@ int TransactionTableModel::columnCount(const QModelIndex& parent) const return columns.length(); } +int TransactionTableModel::size() const{ + return priv->size(); +} + +bool TransactionTableModel::hasZcTxes() { + return priv->containsZcTxes(); +} + QString TransactionTableModel::formatTxStatus(const TransactionRecord* wtx) const { QString status; @@ -319,10 +352,10 @@ QString TransactionTableModel::lookupAddress(const std::string& address, bool to QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(address)); QString description; if (!label.isEmpty()) { - description += label; + description += label + QString(" "); } if (label.isEmpty() || tooltip) { - description += QString(" (") + QString::fromStdString(address) + QString(")"); + description += QString::fromStdString(address); } return description; } @@ -369,7 +402,6 @@ QString TransactionTableModel::formatTxType(const TransactionRecord* wtx) const return tr("Minted Change as zPIV from zPIV Spend"); case TransactionRecord::ZerocoinSpend_FromMe: return tr("Converted zPIV to PIV"); - default: return QString(); } @@ -391,7 +423,7 @@ QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord* wtx case TransactionRecord::SendToAddress: case TransactionRecord::SendToOther: case TransactionRecord::ZerocoinSpend: - return QIcon(":/icons/tx_output"); + return QIcon("://ic-transaction-sent"); default: return QIcon(":/icons/tx_inout"); } @@ -424,12 +456,19 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord* wtx, b return QString::fromStdString(wtx->address) + watchAddress; case TransactionRecord::ZerocoinMint: case TransactionRecord::ZerocoinSpend_Change_zPiv: - return tr("Anonymous (zPIV Transaction)"); case TransactionRecord::StakeZPIV: - return tr("Anonymous (zPIV Stake)"); - case TransactionRecord::SendToSelf: - default: - return tr("(n/a)") + watchAddress; + return tr("Anonymous"); + case TransactionRecord::SendToSelf: { + QString label = walletModel->getAddressTableModel()->labelForAddress(QString::fromStdString(wtx->address)); + return label.isEmpty() ? "" : label; + } + default: { + if (watchAddress.isEmpty()) { + return tr("No information"); + } else { + return tr("(n/a)") + watchAddress; + } + } } } @@ -601,6 +640,8 @@ QVariant TransactionTableModel::data(const QModelIndex& index, int role) const return COLOR_BLACK; case TypeRole: return rec->type; + case SizeRole: + return rec->size; case DateRole: return QDateTime::fromTime_t(static_cast(rec->time)); case WatchonlyRole: diff --git a/src/qt/transactiontablemodel.h b/src/qt/transactiontablemodel.h index e8c2f661bd11..907aeb363ef1 100644 --- a/src/qt/transactiontablemodel.h +++ b/src/qt/transactiontablemodel.h @@ -64,16 +64,23 @@ class TransactionTableModel : public QAbstractTableModel /** Formatted amount, without brackets when unconfirmed */ FormattedAmountRole, /** Transaction status (TransactionRecord::Status) */ - StatusRole + StatusRole, + /** Transaction size in bytes */ + SizeRole }; int rowCount(const QModelIndex& parent) const; int columnCount(const QModelIndex& parent) const; + int size() const; + bool hasZcTxes(); QVariant data(const QModelIndex& index, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; bool processingQueuedTransactions() { return fProcessingQueuedTransactions; } +signals: + void txArrived(const QString& hash); + private: CWallet* wallet; WalletModel* walletModel; diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index cd4cc317e611..5e036d835cab 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -14,6 +14,8 @@ #include "intro.h" #include "guiutil.h" +#include "qt/pivx/qtutils.cpp" + #include "clientversion.h" #include "init.h" #include "util.h" @@ -32,6 +34,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget* parent, bool about) : QDialog(pare ui(new Ui::HelpMessageDialog) { ui->setupUi(this); + this->setStyleSheet(parent->styleSheet()); GUIUtil::restoreWindowGeometry("nHelpMessageDialogWindow", this->size(), this); QString version = tr("PIVX Core") + " " + tr("version") + " " + QString::fromStdString(FormatFullVersion()); @@ -44,6 +47,8 @@ HelpMessageDialog::HelpMessageDialog(QWidget* parent, bool about) : QDialog(pare version += " " + tr("(%1-bit)").arg(32); #endif + setCssBtnPrimary(ui->pushButtonOk); + connect(ui->pushButtonOk, &QPushButton::clicked, this, &HelpMessageDialog::close); if (about) { setWindowTitle(tr("About PIVX Core")); @@ -54,7 +59,7 @@ HelpMessageDialog::HelpMessageDialog(QWidget* parent, bool about) : QDialog(pare // Make URLs clickable QRegExp uri("<(.*)>", Qt::CaseSensitive, QRegExp::RegExp2); uri.setMinimal(true); // use non-greedy matching - licenseInfoHTML.replace(uri, "\\1"); + licenseInfoHTML.replace(uri, "\\1"); // Replace newlines with HTML breaks licenseInfoHTML.replace("\n\n", "

"); @@ -143,11 +148,6 @@ void HelpMessageDialog::showOrPrint() #endif } -void HelpMessageDialog::on_okButton_accepted() -{ - close(); -} - /** "Shutdown" window */ ShutdownWindow::ShutdownWindow(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) @@ -159,7 +159,7 @@ ShutdownWindow::ShutdownWindow(QWidget* parent, Qt::WindowFlags f) : QWidget(par setLayout(layout); } -void ShutdownWindow::showShutdownWindow(BitcoinGUI* window) +void ShutdownWindow::showShutdownWindow(QMainWindow* window) { if (!window) return; diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h index 2e0d7f501f4b..bb1592a3f16f 100644 --- a/src/qt/utilitydialog.h +++ b/src/qt/utilitydialog.h @@ -8,8 +8,8 @@ #include #include +#include -class BitcoinGUI; class ClientModel; namespace Ui @@ -32,9 +32,6 @@ class HelpMessageDialog : public QDialog private: Ui::HelpMessageDialog* ui; QString text; - -private slots: - void on_okButton_accepted(); }; @@ -45,7 +42,7 @@ class ShutdownWindow : public QWidget public: ShutdownWindow(QWidget* parent = 0, Qt::WindowFlags f = 0); - static void showShutdownWindow(BitcoinGUI* window); + static void showShutdownWindow(QMainWindow* window); protected: void closeEvent(QCloseEvent* event); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 360f19637955..612d1344beff 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -21,6 +21,8 @@ #include "wallet/wallet.h" #include "wallet/walletdb.h" // for BackupWallet #include +#include +#include "zpiv/deterministicmint.h" #include #include @@ -56,6 +58,10 @@ WalletModel::~WalletModel() unsubscribeFromCoreSignals(); } +bool WalletModel::isTestnet() const { + return Params().NetworkID() == CBaseChainParams::TESTNET; +} + CAmount WalletModel::getBalance(const CCoinControl* coinControl) const { if (coinControl) { @@ -131,6 +137,11 @@ void WalletModel::updateStatus() emit encryptionStatusChanged(newEncryptionStatus); } +bool WalletModel::isWalletUnlocked() const { + EncryptionStatus status = getEncryptionStatus(); + return status == Unencrypted || status == Unlocked; +} + void WalletModel::pollBalanceChanged() { // Get required locks upfront. This avoids the GUI from getting stuck on @@ -208,6 +219,11 @@ void WalletModel::checkBalanceChanged() } } +void WalletModel::setWalletDefaultFee(CAmount fee) +{ + payTxFee = CFeeRate(fee); +} + void WalletModel::updateTransaction() { // Balance and number of transactions might have changed @@ -216,13 +232,21 @@ void WalletModel::updateTransaction() void WalletModel::updateAddressBook(const QString& address, const QString& label, bool isMine, const QString& purpose, int status) { - if (addressTableModel) - addressTableModel->updateEntry(address, label, isMine, purpose, status); + try { + if (addressTableModel) + addressTableModel->updateEntry(address, label, isMine, purpose, status); + }catch (...){ + std::cout << "Exception updateAddressBook" << std::endl; + } } void WalletModel::updateAddressBook(const QString &pubCoin, const QString &isUsed, int status) { - if(addressTableModel) - addressTableModel->updateEntry(pubCoin, isUsed, status); + try{ + if(addressTableModel) + addressTableModel->updateEntry(pubCoin, isUsed, status); + }catch (...){ + std::cout << "Exception updateAddressBook" << std::endl; + } } @@ -238,13 +262,17 @@ void WalletModel::updateMultiSigFlag(bool fHaveMultiSig) emit notifyMultiSigChanged(fHaveMultiSig); } +bool WalletModel::getMint(const uint256& hashSerial, CZerocoinMint& mint){ + return wallet->GetMint(hashSerial, mint); +} + bool WalletModel::validateAddress(const QString& address) { CBitcoinAddress addressParsed(address.toStdString()); return addressParsed.IsValid(); } -void WalletModel::updateAddressBookLabels(const CTxDestination& dest, const std::string& strName, const std::string& strPurpose) +bool WalletModel::updateAddressBookLabels(const CTxDestination& dest, const std::string& strName, const std::string& strPurpose) { LOCK(wallet->cs_wallet); @@ -252,10 +280,11 @@ void WalletModel::updateAddressBookLabels(const CTxDestination& dest, const std: // Check if we have a new address or an updated label if (mi == wallet->mapAddressBook.end()) { - wallet->SetAddressBook(dest, strName, strPurpose); + return wallet->SetAddressBook(dest, strName, strPurpose); } else if (mi->second.name != strName) { - wallet->SetAddressBook(dest, strName, ""); // "" means don't change purpose + return wallet->SetAddressBook(dest, strName, ""); // "" means don't change purpose } + return false; } WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransaction& transaction, const CCoinControl* coinControl) @@ -369,6 +398,12 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction& tran return AnonymizeOnlyUnlocked; } + // Double check tx before do anything + CValidationState state; + if(!CheckTransaction(*transaction.getTransaction(), true, true, state, true)){ + return TransactionCommitFailed; + } + { LOCK2(cs_main, wallet->cs_wallet); CWalletTx* newTx = transaction.getTransaction(); @@ -388,9 +423,6 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction& tran } CReserveKey* keyChange = transaction.getPossibleKeyChange(); - - transaction.getRecipients(); - if (!wallet->CommitTransaction(*newTx, *keyChange, (recipients[0].useSwiftTX) ? "ix" : "tx")) return TransactionCommitFailed; @@ -419,6 +451,132 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction& tran return SendCoinsReturn(OK); } +const CWalletTx* WalletModel::getTx(uint256 id){ + return wallet->GetWalletTx(id); +} + +bool WalletModel::isCoinStake(QString id){ + uint256 hashTx; + hashTx.SetHex(id.toStdString()); + const CWalletTx* tx = getTx(hashTx); + return tx->IsCoinStake(); +} + +bool WalletModel::isCoinStakeMine(QString id){ + uint256 hashTx; + hashTx.SetHex(id.toStdString()); + const CWalletTx* tx = getTx(hashTx); + return tx->IsCoinStake() && wallet->IsMine(tx->vin[0]); +} + +bool WalletModel::mintCoins(CAmount value, CCoinControl* coinControl ,std::string &strError){ + CWalletTx wtx; + std::vector vMints; + strError = wallet->MintZerocoin(value, wtx, vMints, coinControl); + return strError.empty(); +} + + +bool WalletModel::createZpivSpend( + CWalletTx &wtxNew, + std::vector &vMintsSelected, + bool fMintChange, + bool fMinimizeChange, + CZerocoinSpendReceipt &receipt, + std::list> outputs, + std::string changeAddress + ){ + + CBitcoinAddress *changeAdd = (!changeAddress.empty()) ? new CBitcoinAddress(changeAddress) : nullptr; + CAmount value = 0; + for(std::pair pair : outputs){ + value += pair.second; + } + + if (wallet->IsLocked()) { + receipt.SetStatus("Error: Wallet locked, unable to create transaction!", ZPIV_WALLET_LOCKED); + return false; + } + + CReserveKey reserveKey(wallet); + std::vector vNewMints; + if (!wallet->CreateZerocoinSpendTransaction( + value, + wtxNew, + reserveKey, + receipt, + vMintsSelected, + vNewMints, + false, // No more mints + fMinimizeChange, + outputs, + changeAdd + )) { + return false; + } + + // Double check tx before do anything + CValidationState state; + return CheckTransaction(wtxNew, true, true, state, true); +} + +bool WalletModel::sendZpiv( + std::vector &vMintsSelected, + bool fMintChange, + bool fMinimizeChange, + CZerocoinSpendReceipt &receipt, + std::list> outputs, + std::string changeAddress + ){ + + CBitcoinAddress *changeAdd = (!changeAddress.empty()) ? new CBitcoinAddress(changeAddress) : nullptr; + CAmount value = 0; + for(std::pair pair : outputs){ + value += pair.second; + } + + CWalletTx wtxNew; + return wallet->SpendZerocoin( + value, + wtxNew, + receipt, + vMintsSelected, + false, // No more mints + fMinimizeChange, + outputs, + changeAdd + ); + +} + +bool WalletModel::convertBackZpiv( + CAmount value, + std::vector &vMintsSelected, + bool fMintChange, + bool fMinimizeChange, + CZerocoinSpendReceipt &receipt, + CBitcoinAddress addressTo +){ + + // address to must be from us. + if(!isMine(addressTo)){ + receipt.SetStatus(_("To convert zPIV back to PIV the return address must be from your wallet"), ZPIV_SPEND_ERROR); + return false; + } + + CWalletTx wtxNew; + return wallet->SpendZerocoin( + value, + wtxNew, + receipt, + vMintsSelected, + false, // No more mints + fMinimizeChange, + std::list>(), + &addressTo + ); +} + OptionsModel* WalletModel::getOptionsModel() { return optionsModel; @@ -680,6 +838,33 @@ bool WalletModel::getPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const return wallet->GetPubKey(address, vchPubKeyOut); } +int64_t WalletModel::getCreationTime() const { + return wallet->nTimeFirstKey; +} + +int64_t WalletModel::getKeyCreationTime(const CPubKey& key){ + return pwalletMain->GetKeyCreationTime(key); +} + +int64_t WalletModel::getKeyCreationTime(const CBitcoinAddress& address){ + if(this->isMine(address)) { + return pwalletMain->GetKeyCreationTime(address); + } + return 0; +} + +CBitcoinAddress WalletModel::getNewAddress(std::string label) const{ + if (!wallet->IsLocked()) + wallet->TopUpKeyPool(); + + // Generate a new key that is added to wallet + CPubKey newKey = wallet->GenerateNewKey(); + CKeyID keyID = newKey.GetID(); + + pwalletMain->SetAddressBook(keyID, label, "receive"); + return CBitcoinAddress(keyID); +} + // returns a list of COutputs from COutPoints void WalletModel::getOutputs(const std::vector& vOutpoints, std::vector& vOutputs) { @@ -798,3 +983,11 @@ bool WalletModel::isUsed(CBitcoinAddress address) { return wallet->IsUsed(address); } + +std::string WalletModel::resetMintZerocoin(){ + return wallet->ResetMintZerocoin(); +} + +std::string WalletModel::resetSpentZerocoin(){ + return wallet->ResetSpentZerocoin(); +} diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 73e464bd87d2..a58bc238dfb5 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -4,8 +4,8 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_QT_WALLETMODEL_H -#define BITCOIN_QT_WALLETMODEL_H +#ifndef PIVX_QT_WALLETMODEL_H +#define PIVX_QT_WALLETMODEL_H #include "askpassphrasedialog.h" #include "paymentrequestplus.h" @@ -52,7 +52,7 @@ class SendCoinsRecipient QString address; QString label; AvailableCoinsType inputType; - bool useSwiftTX; + bool useSwiftTX = false; CAmount amount; // If from a payment request, this is used for storing the memo QString message; @@ -98,7 +98,7 @@ class SendCoinsRecipient } }; -/** Interface to Bitcoin wallet from Qt view code. */ +/** Interface to PIVX wallet from Qt view code. */ class WalletModel : public QObject { Q_OBJECT @@ -133,6 +133,8 @@ class WalletModel : public QObject TransactionTableModel* getTransactionTableModel(); RecentRequestsTableModel* getRecentRequestsTableModel(); + bool isTestnet() const; + CAmount getBalance(const CCoinControl* coinControl = NULL) const; CAmount getUnconfirmedBalance() const; CAmount getImmatureBalance() const; @@ -145,12 +147,16 @@ class WalletModel : public QObject CAmount getWatchUnconfirmedBalance() const; CAmount getWatchImmatureBalance() const; EncryptionStatus getEncryptionStatus() const; + bool isWalletUnlocked() const; CKey generateNewKey() const; //for temporary paper wallet key generation bool setAddressBook(const CTxDestination& address, const std::string& strName, const std::string& strPurpose); void encryptKey(const CKey key, const std::string& pwd, const std::string& slt, std::vector& crypted); void decryptKey(const std::vector& crypted, const std::string& slt, const std::string& pwd, CKey& key); void emitBalanceChanged(); // Force update of UI-elements even when no values have changed + // return minted zPIV + bool getMint(const uint256& hashSerial, CZerocoinMint& mint); + // Check address for validity bool validateAddress(const QString& address); @@ -160,11 +166,47 @@ class WalletModel : public QObject StatusCode status; }; + void setWalletDefaultFee(CAmount fee = DEFAULT_TRANSACTION_FEE); + + const CWalletTx* getTx(uint256 id); + bool isCoinStake(QString id); + bool isCoinStakeMine(QString id); + // prepare transaction for getting txfee before sending coins SendCoinsReturn prepareTransaction(WalletModelTransaction& transaction, const CCoinControl* coinControl = NULL); // Send coins to a list of recipients SendCoinsReturn sendCoins(WalletModelTransaction& transaction); + // Mint zPIV + bool mintCoins(CAmount value, CCoinControl* coinControl, std::string &strError); + + bool createZpivSpend( + CWalletTx &wtxNew, + std::vector &vMintsSelected, + bool fMintChange, + bool fMinimizeChange, + CZerocoinSpendReceipt &receipt, + std::list> outputs, + std::string changeAddress = "" + ); + + bool sendZpiv( + std::vector &vMintsSelected, + bool fMintChange, + bool fMinimizeChange, + CZerocoinSpendReceipt &receipt, + std::list> outputs, + std::string changeAddress = "" + ); + + bool convertBackZpiv( + CAmount value, + std::vector &vMintsSelected, + bool fMintChange, + bool fMinimizeChange, + CZerocoinSpendReceipt &receipt, + CBitcoinAddress addressTo + ); // Wallet encryption bool setWalletEncrypted(bool encrypted, const SecureString& passphrase); @@ -203,6 +245,10 @@ class WalletModel : public QObject UnlockContext requestUnlock(AskPassphraseDialog::Context context, bool relock = false); bool getPubKey(const CKeyID& address, CPubKey& vchPubKeyOut) const; + int64_t getCreationTime() const; + int64_t getKeyCreationTime(const CPubKey& key); + int64_t getKeyCreationTime(const CBitcoinAddress& address); + CBitcoinAddress getNewAddress(std::string label = "") const; bool isMine(CBitcoinAddress address); bool isUsed(CBitcoinAddress address); void getOutputs(const std::vector& vOutpoints, std::vector& vOutputs); @@ -220,6 +266,9 @@ class WalletModel : public QObject void loadReceiveRequests(std::vector& vReceiveRequests); bool saveReceiveRequest(const std::string& sAddress, const int64_t nId, const std::string& sRequest); + std::string resetMintZerocoin(); + std::string resetSpentZerocoin(); + private: CWallet* wallet; bool fHaveWatchOnly; @@ -303,7 +352,7 @@ public slots: /* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */ void pollBalanceChanged(); /* Update address book labels in the database */ - void updateAddressBookLabels(const CTxDestination& address, const std::string& strName, const std::string& strPurpose); + bool updateAddressBookLabels(const CTxDestination& address, const std::string& strName, const std::string& strPurpose); }; -#endif // BITCOIN_QT_WALLETMODEL_H +#endif // PIVX_QT_WALLETMODEL_H diff --git a/src/qt/zpivcontroldialog.cpp b/src/qt/zpivcontroldialog.cpp index a2d8f6c39909..a379c07c304f 100644 --- a/src/qt/zpivcontroldialog.cpp +++ b/src/qt/zpivcontroldialog.cpp @@ -8,6 +8,7 @@ #include "zpiv/accumulators.h" #include "main.h" #include "walletmodel.h" +#include "guiutil.h" std::set ZPivControlDialog::setSelectedMints; @@ -28,11 +29,34 @@ ZPivControlDialog::ZPivControlDialog(QWidget *parent) : { ui->setupUi(this); setMints.clear(); - privacyDialog = (PrivacyDialog*)parent; + + /* Open CSS when configured */ + this->setStyleSheet(GUIUtil::loadStyleSheet()); + + ui->frame->setProperty("cssClass", "container-dialog"); + + // Title + ui->labelTitle->setText(tr("Select zPIV Denominations to Spend")); + ui->labelTitle->setProperty("cssClass", "text-title-dialog"); + + + // Label Style + ui->labelZPiv->setProperty("cssClass", "text-main-purple"); + ui->labelZPiv_int->setProperty("cssClass", "text-main-purple"); + ui->labelQuantity->setProperty("cssClass", "text-main-purple"); + ui->labelQuantity_int->setProperty("cssClass", "text-main-purple"); + + ui->layoutAmount->setProperty("cssClass", "container-border-purple"); + ui->layoutQuantity->setProperty("cssClass", "container-border-purple"); + + // Buttons + + ui->btnEsc->setText(""); + ui->btnEsc->setProperty("cssClass", "ic-close"); + ui->pushButtonAll->setProperty("cssClass", "btn-check"); // click on checkbox connect(ui->treeWidget, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(updateSelection(QTreeWidgetItem*, int))); - // push select/deselect all button connect(ui->pushButtonAll, SIGNAL(clicked()), this, SLOT(ButtonAllClicked())); } @@ -192,7 +216,7 @@ void ZPivControlDialog::updateLabels() ui->labelQuantity_int->setText(QString::number(setSelectedMints.size())); //update PrivacyDialog labels - privacyDialog->setZPivControlLabels(nAmount, setSelectedMints.size()); + //privacyDialog->setZPivControlLabels(nAmount, setSelectedMints.size()); } std::vector ZPivControlDialog::GetSelectedMints() diff --git a/src/qt/zpivcontroldialog.h b/src/qt/zpivcontroldialog.h index ea5a2ce584d4..100a19d7dc65 100644 --- a/src/qt/zpivcontroldialog.h +++ b/src/qt/zpivcontroldialog.h @@ -44,7 +44,6 @@ class ZPivControlDialog : public QDialog private: Ui::ZPivControlDialog *ui; WalletModel* model; - PrivacyDialog* privacyDialog; void updateList(); void updateLabels(); diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 4df04be63791..300fd8eed931 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1047,7 +1047,11 @@ UniValue createrawzerocoinpublicspend(const UniValue& params, bool fHelp) CZerocoinSpendReceipt receipt; CReserveKey reserveKey(pwalletMain); std::vector vNewMints; - if (!pwalletMain->CreateZerocoinSpendTransaction(nAmount, rawTx, reserveKey, receipt, vMintsSelected, vNewMints, false, true, addr_ptr, true)) + std::list> outputs; + if (addr_ptr) { + outputs.push_back(std::pair(addr_ptr, nAmount)); + } + if (!pwalletMain->CreateZerocoinSpendTransaction(nAmount, rawTx, reserveKey, receipt, vMintsSelected, vNewMints, false, true, outputs, nullptr, true)) throw JSONRPCError(RPC_WALLET_ERROR, receipt.GetStatusMessage()); // output the raw transaction diff --git a/src/test/zerocoin_transactions_tests.cpp b/src/test/zerocoin_transactions_tests.cpp index b245d0451278..2107772dd715 100644 --- a/src/test/zerocoin_transactions_tests.cpp +++ b/src/test/zerocoin_transactions_tests.cpp @@ -40,13 +40,14 @@ BOOST_AUTO_TEST_CASE(zerocoin_spend_test) CAmount nAmount = COIN; CZerocoinSpendReceipt receipt; - cWallet.SpendZerocoin(nAmount, *wtx, receipt, vMints, fMintChange, fMinimizeChange); + std::list> outputs; + cWallet.SpendZerocoin(nAmount, *wtx, receipt, vMints, fMintChange, fMinimizeChange, outputs); BOOST_CHECK_MESSAGE(receipt.GetStatus() == ZPIV_TRX_FUNDS_PROBLEMS, strprintf("Failed Invalid Amount Check: %s", receipt.GetStatusMessage())); nAmount = 1; CZerocoinSpendReceipt receipt2; - cWallet.SpendZerocoin(nAmount, *wtx, receipt2, vMints, fMintChange, fMinimizeChange); + cWallet.SpendZerocoin(nAmount, *wtx, receipt2, vMints, fMintChange, fMinimizeChange, outputs); // if using "wallet.dat", instead of "unlocked.dat" need this /// BOOST_CHECK_MESSAGE(vString == "Error: Wallet locked, unable to create transaction!"," Locked Wallet Check Failed"); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 16099c27c7bd..3dfea5a20dec 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -14,7 +14,7 @@ #include "util.h" #include "utilstrencodings.h" #include "utiltime.h" -#include "wallet.h" +#include "wallet/wallet.h" #include #include diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index dc473bd1cd73..20a913ddeeff 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -28,6 +28,7 @@ #include #include +#include int64_t nWalletUnlockTime; @@ -3014,13 +3015,15 @@ extern UniValue DoZpivSpend(const CAmount nAmount, bool fMintChange, bool fMinim CZerocoinSpendReceipt receipt; bool fSuccess; + std::list> outputs; if(address_str != "") { // Spend to supplied destination address address = CBitcoinAddress(address_str); if(!address.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address"); - fSuccess = pwalletMain->SpendZerocoin(nAmount, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange, &address, ispublicspend); + outputs.push_back(std::pair(&address, nAmount)); + fSuccess = pwalletMain->SpendZerocoin(nAmount, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange, outputs); } else // Spend to newly generated local address - fSuccess = pwalletMain->SpendZerocoin(nAmount, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange, nullptr, ispublicspend); + fSuccess = pwalletMain->SpendZerocoin(nAmount, wtx, receipt, vMintsSelected, fMintChange, fMinimizeChange, outputs); if (!fSuccess) throw JSONRPCError(RPC_WALLET_ERROR, receipt.GetStatusMessage()); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 32ed01e5e4dd..a3b84a702e21 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -115,6 +115,23 @@ CPubKey CWallet::GenerateNewKey() return pubkey; } +int64_t CWallet::GetKeyCreationTime(CPubKey pubkey) +{ + return mapKeyMetadata[pubkey.GetID()].nCreateTime; +} + +int64_t CWallet::GetKeyCreationTime(const CBitcoinAddress& address) +{ + CKeyID keyID; + if (address.GetKeyID(keyID)) { + CPubKey keyRet; + if (GetPubKey(keyID, keyRet)) { + return GetKeyCreationTime(keyRet); + } + } + return 0; +} + CBitcoinAddress CWallet::GenerateNewAutoMintKey() { CBitcoinAddress btcAddress; @@ -4105,7 +4122,8 @@ bool CWallet::CreateZerocoinSpendTransaction( std::vector& vNewMints, bool fMintChange, bool fMinimizeChange, - CBitcoinAddress* address, + std::list> addressesTo, + CBitcoinAddress* changeAddress, bool isPublicSpend) { // Check available funds @@ -4241,8 +4259,6 @@ bool CWallet::CreateZerocoinSpendTransaction( txNew.vout.clear(); //if there is an address to send to then use it, if not generate a new address to send to - CScript scriptZerocoinSpend; - CScript scriptChange; CAmount nChange = nValueSelected - nValue; if (nChange < 0) { @@ -4250,28 +4266,32 @@ bool CWallet::CreateZerocoinSpendTransaction( return false; } - if (nChange > 0 && !address) { + if (nChange > 0 && !changeAddress) { receipt.SetStatus(_("Need address because change is not exact"), nStatus); return false; } - if (address) { - scriptZerocoinSpend = GetScriptForDestination(address->Get()); - if (nChange) { + // add an outputs for each address + for (std::pair pair : addressesTo){ + CScript scriptZerocoinSpend = GetScriptForDestination(pair.first->Get()); + //add output to pivx address to the transaction (the actual primary spend taking place) + // TODO: check value? + CTxOut txOutZerocoinSpend(pair.second, scriptZerocoinSpend); + txNew.vout.push_back(txOutZerocoinSpend); + } + + //add change output if we are spending too much (only applies to spending multiple at once) + if (nChange) { + CScript scriptChange; + // Change address + if(changeAddress){ + scriptChange = GetScriptForDestination(changeAddress->Get()); + }else{ // Reserve a new key pair from key pool CPubKey vchPubKey; assert(reserveKey.GetReservedKey(vchPubKey)); // should never fail scriptChange = GetScriptForDestination(vchPubKey.GetID()); } - } else { - // Reserve a new key pair from key pool - CPubKey vchPubKey; - assert(reserveKey.GetReservedKey(vchPubKey)); // should never fail - scriptZerocoinSpend = GetScriptForDestination(vchPubKey.GetID()); - } - - //add change output if we are spending too much (only applies to spending multiple at once) - if (nChange) { //mint change as zerocoins if (fMintChange) { CAmount nFeeRet = 0; @@ -4286,10 +4306,6 @@ bool CWallet::CreateZerocoinSpendTransaction( } } - //add output to pivx address to the transaction (the actual primary spend taking place) - CTxOut txOutZerocoinSpend(nValue, scriptZerocoinSpend); - txNew.vout.push_back(txOutZerocoinSpend); - //hash with only the output info in it to be used in Signature of Knowledge uint256 hashTxOut = txNew.GetHash(); @@ -4614,7 +4630,17 @@ std::string CWallet::MintZerocoin(CAmount nValue, CWalletTx& wtxNew, std::vector return ""; } -bool CWallet::SpendZerocoin(CAmount nAmount, CWalletTx& wtxNew, CZerocoinSpendReceipt& receipt, std::vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* addressTo, bool isPublicSpend) +bool CWallet::SpendZerocoin( + CAmount nAmount, + CWalletTx& wtxNew, + CZerocoinSpendReceipt& receipt, + std::vector& vMintsSelected, + bool fMintChange, + bool fMinimizeChange, + std::list> addressesTo, + CBitcoinAddress* changeAddress, + bool isPublicSpend +) { // Default: assume something goes wrong. Depending on the problem this gets more specific below int nStatus = ZPIV_SPEND_ERROR; @@ -4626,7 +4652,19 @@ bool CWallet::SpendZerocoin(CAmount nAmount, CWalletTx& wtxNew, CZerocoinSpendRe CReserveKey reserveKey(this); std::vector vNewMints; - if (!CreateZerocoinSpendTransaction(nAmount, wtxNew, reserveKey, receipt, vMintsSelected, vNewMints, fMintChange, fMinimizeChange, addressTo, isPublicSpend)) { + if (!CreateZerocoinSpendTransaction( + nAmount, + wtxNew, + reserveKey, + receipt, + vMintsSelected, + vNewMints, + fMintChange, + fMinimizeChange, + addressesTo, + changeAddress, + isPublicSpend + )) { return false; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index cb8b941d1a5b..fec00b7f6a29 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -196,25 +196,52 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface void SyncMetaData(std::pair); public: + + static const int STAKE_SPLIT_THRESHOLD = 2000; + bool MintableCoins(); bool SelectStakeCoins(std::list >& listInputs, CAmount nTargetAmount, int blockHeight, bool fPrecompute = false); bool IsCollateralAmount(CAmount nInputAmount) const; // Zerocoin additions bool CreateZerocoinMintTransaction(const CAmount nValue, CMutableTransaction& txNew, std::vector& vDMints, CReserveKey* reservekey, int64_t& nFeeRet, std::string& strFailReason, const CCoinControl* coinControl = NULL, const bool isZCSpendChange = false); - bool CreateZerocoinSpendTransaction(CAmount nValue, CWalletTx& wtxNew, CReserveKey& reserveKey, CZerocoinSpendReceipt& receipt, std::vector& vSelectedMints, std::vector& vNewMints, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* address = NULL, bool isPublicSpend = true); + + bool CreateZerocoinSpendTransaction( + CAmount nValue, + CWalletTx& wtxNew, + CReserveKey& reserveKey, + CZerocoinSpendReceipt& receipt, + std::vector& vSelectedMints, + std::vector& vNewMints, + bool fMintChange, + bool fMinimizeChange, + std::list> addressesTo, + CBitcoinAddress* changeAddress = nullptr, + bool isPublicSpend = true); + bool CheckCoinSpend(libzerocoin::CoinSpend& spend, libzerocoin::Accumulator& accumulator, CZerocoinSpendReceipt& receipt); - bool MintToTxIn(CZerocoinMint mint, const uint256& hashTxOut, CTxIn& newTxIn, CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr, bool publicCoinSpend = true); + bool MintToTxIn(CZerocoinMint zerocoinSelected, const uint256& hashTxOut, CTxIn& newTxIn, CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr, bool publicCoinSpend = true); bool MintsToInputVector(std::map& mapMintsSelected, const uint256& hashTxOut, std::vector& vin, CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr); - // Public coin spend input creation bool MintsToInputVectorPublicSpend(std::map& mapMintsSelected, const uint256& hashTxOut, std::vector& vin, - CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr); + CZerocoinSpendReceipt& receipt, libzerocoin::SpendType spendType, CBlockIndex* pindexCheckpoint = nullptr); std::string MintZerocoinFromOutPoint(CAmount nValue, CWalletTx& wtxNew, std::vector& vDMints, const std::vector vOutpts); std::string MintZerocoin(CAmount nValue, CWalletTx& wtxNew, std::vector& vDMints, const CCoinControl* coinControl = NULL); - bool SpendZerocoin(CAmount nValue, CWalletTx& wtxNew, CZerocoinSpendReceipt& receipt, std::vector& vMintsSelected, bool fMintChange, bool fMinimizeChange, CBitcoinAddress* addressTo = NULL, bool isPublicSpend = true); + + bool SpendZerocoin( + CAmount nAmount, + CWalletTx& wtxNew, + CZerocoinSpendReceipt& receipt, + std::vector& vMintsSelected, + bool fMintChange, + bool fMinimizeChange, + std::list> addressesTo, + CBitcoinAddress* changeAddress = nullptr, + bool isPublicSpend = true + ); + std::string ResetMintZerocoin(); std::string ResetSpentZerocoin(); void ReconsiderZerocoins(std::list& listMintsRestored, std::list& listDMintsRestored); @@ -313,7 +340,7 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface // Stake Settings nHashDrift = 45; - nStakeSplitThreshold = 2000; + nStakeSplitThreshold = STAKE_SPLIT_THRESHOLD; nHashInterval = 22; nStakeSetUpdateTime = 300; // 5 minutes @@ -415,6 +442,8 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface // Generate a new key CPubKey GenerateNewKey(); CBitcoinAddress GenerateNewAutoMintKey(); + int64_t GetKeyCreationTime(CPubKey pubkey); + int64_t GetKeyCreationTime(const CBitcoinAddress& address); //! Adds a key to the store, and saves it to disk. bool AddKeyPubKey(const CKey& key, const CPubKey& pubkey);